Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: saner imports from TLA/std.extVars #183

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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())?
Copy link
Owner Author

@CertainLach CertainLach Nov 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not entirely correct, as now input file import also follows JPATH handling, which isn't behavior used by official jsonnet. JPATH handling should be disabled here.

To be split into resolve/import_resolved calls, with JPATH being applied in between those calls?

};

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
52 changes: 18 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,37 +28,27 @@ 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 (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 {
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::InlineCode(ext.value.clone()),
);
}
for ext in &self.tla_code_file {
out.insert(ext.name.as_str().into(), TlaArg::Import(ext.path.clone()));
}
Ok(out)
}
}
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