Skip to content

Commit

Permalink
refactor: saner imports from TLA/std.extVars
Browse files Browse the repository at this point in the history
  • Loading branch information
CertainLach committed Nov 24, 2024
1 parent 6baa18d commit d6e9b62
Show file tree
Hide file tree
Showing 13 changed files with 166 additions and 145 deletions.
10 changes: 7 additions & 3 deletions bindings/jsonnet/src/import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use std::{
use jrsonnet_evaluator::{
bail,
error::{ErrorKind::*, Result},
ImportResolver,
AsPathLike, ImportResolver, ResolvePath,
};
use jrsonnet_gcmodule::Trace;
use jrsonnet_parser::{SourceDirectory, SourceFile, SourcePath};
Expand All @@ -41,7 +41,7 @@ pub struct CallbackImportResolver {
out: RefCell<HashMap<SourcePath, Vec<u8>>>,
}
impl ImportResolver for CallbackImportResolver {
fn resolve_from(&self, from: &SourcePath, path: &str) -> Result<SourcePath> {
fn resolve_from(&self, from: &SourcePath, path: &dyn AsPathLike) -> Result<SourcePath> {
let base = if let Some(p) = from.downcast_ref::<SourceFile>() {
let mut o = p.path().to_owned();
o.pop();
Expand All @@ -54,7 +54,11 @@ impl ImportResolver for CallbackImportResolver {
unreachable!("can't resolve this path");
};
let base = unsafe { crate::unparse_path(&base) };
let rel = CString::new(path).unwrap();
let rel = path.as_path();
let rel = match rel {
ResolvePath::Str(s) => CString::new(s.as_bytes()).unwrap(),
ResolvePath::Path(p) => unsafe { crate::unparse_path(p) },
};
let found_here: *mut c_char = null_mut();

let mut buf = null_mut();
Expand Down
16 changes: 6 additions & 10 deletions bindings/jsonnet/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use jrsonnet_evaluator::{
stack::set_stack_depth_limit,
tb,
trace::{CompactFormat, PathResolver, TraceFormat},
FileImportResolver, IStr, ImportResolver, Result, State, Val,
AsPathLike, FileImportResolver, IStr, ImportResolver, Result, State, Val,
};
use jrsonnet_gcmodule::Trace;
use jrsonnet_parser::SourcePath;
Expand Down Expand Up @@ -61,18 +61,18 @@ unsafe fn parse_path(input: &CStr) -> Cow<Path> {
}
}

unsafe fn unparse_path(input: &Path) -> Cow<CStr> {
unsafe fn unparse_path(input: &Path) -> CString {
#[cfg(target_family = "unix")]
{
use std::os::unix::ffi::OsStrExt;
let str = CString::new(input.as_os_str().as_bytes()).expect("input has zero byte in it");
Cow::Owned(str)
str
}
#[cfg(not(target_family = "unix"))]
{
let str = input.as_os_str().to_str().expect("bad utf-8");
let cstr = CString::new(str).expect("input has NUL inside");
Cow::Owned(cstr)
cstr
}
}

Expand All @@ -93,18 +93,14 @@ impl ImportResolver for VMImportResolver {
self.inner.borrow().load_file_contents(resolved)
}

fn resolve_from(&self, from: &SourcePath, path: &str) -> Result<SourcePath> {
fn resolve_from(&self, from: &SourcePath, path: &dyn AsPathLike) -> Result<SourcePath> {
self.inner.borrow().resolve_from(from, path)
}

fn resolve_from_default(&self, path: &str) -> Result<SourcePath> {
fn resolve_from_default(&self, path: &dyn AsPathLike) -> Result<SourcePath> {
self.inner.borrow().resolve_from_default(path)
}

fn resolve(&self, path: &Path) -> Result<SourcePath> {
self.inner.borrow().resolve(path)
}

fn as_any(&self) -> &dyn Any {
self
}
Expand Down
12 changes: 2 additions & 10 deletions bindings/jsonnet/src/vars_tlas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
use std::{ffi::CStr, os::raw::c_char};

use jrsonnet_evaluator::{function::TlaArg, IStr};
use jrsonnet_parser::{ParserSettings, Source};

use crate::VM;

Expand Down Expand Up @@ -84,14 +83,7 @@ pub unsafe extern "C" fn jsonnet_tla_code(vm: &mut VM, name: *const c_char, code
let code = unsafe { CStr::from_ptr(code) };

let name: IStr = name.to_str().expect("name is not utf-8").into();
let code: IStr = code.to_str().expect("code is not utf-8").into();
let code = jrsonnet_parser::parse(
&code,
&ParserSettings {
source: Source::new_virtual(format!("<top-level-arg:{name}>").into(), code.clone()),
},
)
.expect("can't parse TLA code");
let code: String = code.to_str().expect("code is not utf-8").to_owned();

vm.tla_args.insert(name, TlaArg::Code(code));
vm.tla_args.insert(name, TlaArg::InlineCode(code));
}
2 changes: 1 addition & 1 deletion cmds/jrsonnet/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ fn main_real(opts: Opts) -> Result<(), Error> {
let input_str = std::str::from_utf8(&input)?;
s.evaluate_snippet("<stdin>".to_owned(), input_str)?
} else {
s.import(&input)?
s.import(input.as_str())?
};

let tla = opts.tla.tla_opts()?;
Expand Down
42 changes: 24 additions & 18 deletions crates/jrsonnet-cli/src/stdlib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::{fs::read_to_string, str::FromStr};
use std::str::FromStr;

use clap::Parser;
use jrsonnet_evaluator::{trace::PathResolver, Result};
use jrsonnet_evaluator::{function::TlaArg, trace::PathResolver, Result};
use jrsonnet_stdlib::ContextInitializer;

#[derive(Clone)]
Expand Down Expand Up @@ -54,25 +54,20 @@ impl FromStr for ExtStr {
#[derive(Clone)]
pub struct ExtFile {
pub name: String,
pub value: String,
pub path: String,
}

impl FromStr for ExtFile {
type Err = String;

fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
let out: Vec<&str> = s.split('=').collect();
if out.len() != 2 {
let Some((name, path)) = s.split_once('=') else {
return Err("bad ext-file syntax".to_owned());
}
let file = read_to_string(out[1]);
match file {
Ok(content) => Ok(Self {
name: out[0].into(),
value: content,
}),
Err(e) => Err(format!("{e}")),
}
};
Ok(Self {
name: name.into(),
path: path.into(),
})
}
}

Expand Down Expand Up @@ -110,16 +105,27 @@ impl StdOpts {
}
let ctx = ContextInitializer::new(PathResolver::new_cwd_fallback());
for ext in &self.ext_str {
ctx.add_ext_str((&ext.name as &str).into(), (&ext.value as &str).into());
ctx.settings_mut().ext_vars.insert(
ext.name.as_str().into(),
TlaArg::String(ext.value.as_str().into()),
);
}
for ext in &self.ext_str_file {
ctx.add_ext_str((&ext.name as &str).into(), (&ext.value as &str).into());
ctx.settings_mut().ext_vars.insert(
ext.name.as_str().into(),
TlaArg::ImportStr(ext.path.clone()),
);
}
for ext in &self.ext_code {
ctx.add_ext_code(&ext.name as &str, &ext.value as &str)?;
ctx.settings_mut().ext_vars.insert(
ext.name.as_str().into(),
TlaArg::InlineCode(ext.value.clone()),
);
}
for ext in &self.ext_code_file {
ctx.add_ext_code(&ext.name as &str, &ext.value as &str)?;
ctx.settings_mut()
.ext_vars
.insert(ext.name.as_str().into(), TlaArg::Import(ext.path.clone()));
}
Ok(Some(ctx))
}
Expand Down
55 changes: 21 additions & 34 deletions crates/jrsonnet-cli/src/tla.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
use clap::Parser;
use jrsonnet_evaluator::{
error::{ErrorKind, Result},
function::TlaArg,
gc::GcHashMap,
IStr,
};
use jrsonnet_parser::{ParserSettings, Source};
use jrsonnet_evaluator::{error::Result, function::TlaArg, gc::GcHashMap, IStr};

use crate::{ExtFile, ExtStr};

Expand Down Expand Up @@ -34,35 +28,28 @@ pub struct TlaOpts {
impl TlaOpts {
pub fn tla_opts(&self) -> Result<GcHashMap<IStr, TlaArg>> {
let mut out = GcHashMap::new();
for (name, value) in self
.tla_str
.iter()
.map(|c| (&c.name, &c.value))
.chain(self.tla_str_file.iter().map(|c| (&c.name, &c.value)))
{
out.insert(name.into(), TlaArg::String(value.into()));
for ext in &self.tla_str {
out.insert(
ext.name.as_str().into(),
TlaArg::String(ext.value.as_str().into()),
);
}
for ext in &self.tla_str_file {
out.insert(
ext.name.as_str().into(),
TlaArg::ImportStr(ext.name.as_str().into()),
);
}
for ext in &self.tla_code {
out.insert(
ext.name.as_str().into(),
TlaArg::InlineCode(ext.value.clone()),
);
}
for (name, code) in self
.tla_code
.iter()
.map(|c| (&c.name, &c.value))
.chain(self.tla_code_file.iter().map(|c| (&c.name, &c.value)))
{
let source = Source::new_virtual(format!("<top-level-arg:{name}>").into(), code.into());
for ext in &self.tla_code_file {
out.insert(
(name as &str).into(),
TlaArg::Code(
jrsonnet_parser::parse(
code,
&ParserSettings {
source: source.clone(),
},
)
.map_err(|e| ErrorKind::ImportSyntaxError {
path: source,
error: Box::new(e),
})?,
),
ext.name.as_str().into(),
TlaArg::Import(ext.path.clone()),
);
}
Ok(out)
Expand Down
8 changes: 0 additions & 8 deletions crates/jrsonnet-evaluator/src/async_import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,8 +236,6 @@ pub trait AsyncImportResolver {
) -> impl Future<Output = Result<SourcePath, Self::Error>> {
async { self.resolve_from(&SourcePath::default(), path).await }
}
/// Resolves absolute path, doesn't supports jpath and other fancy things
fn resolve(&self, path: &Path) -> impl Future<Output = Result<SourcePath, Self::Error>>;

/// Load resolved file
/// This should only be called with value returned
Expand Down Expand Up @@ -273,12 +271,6 @@ impl ImportResolver for ResolvedImportResolver {
self.resolve_from(&SourcePath::default(), path)
}

fn resolve(&self, path: &Path) -> crate::Result<SourcePath> {
bail!(crate::error::ErrorKind::AbsoluteImportNotSupported(
path.to_owned()
))
}

fn as_any(&self) -> &dyn std::any::Any {
self
}
Expand Down
11 changes: 3 additions & 8 deletions crates/jrsonnet-evaluator/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use std::{
cmp::Ordering,
convert::Infallible,
fmt::{Debug, Display},
path::PathBuf,
};

use jrsonnet_gcmodule::Trace;
Expand All @@ -16,7 +15,7 @@ use crate::{
stdlib::format::FormatError,
typed::TypeLocError,
val::ConvertNumValueError,
ObjValue,
ObjValue, ResolvePathOwned,
};

pub(crate) fn format_found(list: &[IStr], what: &str) -> String {
Expand Down Expand Up @@ -180,9 +179,7 @@ pub enum ErrorKind {
StandaloneSuper,

#[error("can't resolve {1} from {0}")]
ImportFileNotFound(SourcePath, String),
#[error("can't resolve absolute {0}")]
AbsoluteImportFileNotFound(PathBuf),
ImportFileNotFound(SourcePath, ResolvePathOwned),
#[error("resolved file not found: {:?}", .0)]
ResolvedFileNotFound(SourcePath),
#[error("can't import {0}: is a directory")]
Expand All @@ -192,9 +189,7 @@ pub enum ErrorKind {
#[error("import io error: {0}")]
ImportIo(String),
#[error("tried to import {1} from {0}, but imports are not supported")]
ImportNotSupported(SourcePath, String),
#[error("tried to import {0}, but absolute imports are not supported")]
AbsoluteImportNotSupported(PathBuf),
ImportNotSupported(SourcePath, ResolvePathOwned),
#[error("can't import from virtual file")]
CantImportFromVirtualFile,
#[error(
Expand Down
2 changes: 1 addition & 1 deletion crates/jrsonnet-evaluator/src/evaluate/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -680,7 +680,7 @@ pub fn evaluate(ctx: Context, expr: &LocExpr) -> Result<Val> {
};
let tmp = loc.clone().0;
let s = ctx.state();
let resolved_path = s.resolve_from(tmp.source_path(), path as &str)?;
let resolved_path = s.resolve_from(tmp.source_path(), path)?;
match i {
Import(_) => in_frame(
CallLocation::new(&loc),
Expand Down
30 changes: 21 additions & 9 deletions crates/jrsonnet-evaluator/src/function/arglike.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use hashbrown::HashMap;
use jrsonnet_gcmodule::Trace;
use jrsonnet_interner::IStr;
use jrsonnet_parser::{ArgsDesc, LocExpr};
use jrsonnet_parser::{ArgsDesc, LocExpr, SourceFifo, SourcePath};

use crate::{evaluate, gc::GcHashMap, typed::Typed, Context, Result, Thunk, Val};

Expand Down Expand Up @@ -40,22 +40,34 @@ impl<T> OptionalContext for T where T: Typed + Clone {}
#[derive(Clone, Trace)]
pub enum TlaArg {
String(IStr),
Code(LocExpr),
Val(Val),
Lazy(Thunk<Val>),
Import(String),
ImportStr(String),
InlineCode(String),
}
impl ArgLike for TlaArg {
fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {
fn evaluate_arg(&self, ctx: Context, _tailstrict: bool) -> Result<Thunk<Val>> {
match self {
Self::String(s) => Ok(Thunk::evaluated(Val::string(s.clone()))),
Self::Code(code) => Ok(if tailstrict {
Thunk::evaluated(evaluate(ctx, code)?)
} else {
let code = code.clone();
Thunk!(move || evaluate(ctx, &code))
}),
Self::Val(val) => Ok(Thunk::evaluated(val.clone())),
Self::Lazy(lazy) => Ok(lazy.clone()),
Self::Import(p) => {
let resolved = ctx.state().resolve_from_default(&p.as_str())?;
Ok(Thunk!(move || ctx.state().import_resolved(resolved)))
}
Self::ImportStr(p) => {
let resolved = ctx.state().resolve_from_default(&p.as_str())?;
Ok(Thunk!(move || ctx
.state()
.import_resolved_str(resolved)
.map(Val::string)))
}
Self::InlineCode(p) => {
let resolved =
SourcePath::new(SourceFifo("<inline code>".to_owned(), p.as_bytes().into()));
Ok(Thunk!(move || ctx.state().import_resolved(resolved)))
}
}
}
}
Expand Down
Loading

0 comments on commit d6e9b62

Please sign in to comment.