difftreelog
refactor saner imports from TLA/std.extVars
in: master
13 files changed
bindings/jsonnet/src/import.rsdiffbeforeafterboth14use jrsonnet_evaluator::{14use jrsonnet_evaluator::{15 bail,15 bail,16 error::{ErrorKind::*, Result},16 error::{ErrorKind::*, Result},17 ImportResolver,17 AsPathLike, ImportResolver, ResolvePath,18};18};19use jrsonnet_gcmodule::Acyclic;19use jrsonnet_gcmodule::Acyclic;20use jrsonnet_parser::{SourceDirectory, SourceFile, SourcePath};20use jrsonnet_parser::{SourceDirectory, SourceFile, SourcePath};38 out: RefCell<HashMap<SourcePath, Vec<u8>>>,38 out: RefCell<HashMap<SourcePath, Vec<u8>>>,39}39}40impl ImportResolver for CallbackImportResolver {40impl ImportResolver for CallbackImportResolver {41 fn resolve_from(&self, from: &SourcePath, path: &str) -> Result<SourcePath> {41 fn resolve_from(&self, from: &SourcePath, path: &dyn AsPathLike) -> Result<SourcePath> {42 let base = if let Some(p) = from.downcast_ref::<SourceFile>() {42 let base = if let Some(p) = from.downcast_ref::<SourceFile>() {43 let mut o = p.path().to_owned();43 let mut o = p.path().to_owned();44 o.pop();44 o.pop();51 unreachable!("can't resolve this path");51 unreachable!("can't resolve this path");52 };52 };53 let base = unsafe { crate::unparse_path(&base) };53 let base = unsafe { crate::unparse_path(&base) };54 let rel = path.as_path();54 let rel = CString::new(path).unwrap();55 let rel = match rel {56 ResolvePath::Str(s) => CString::new(s.as_bytes()).unwrap(),57 ResolvePath::Path(p) => unsafe { crate::unparse_path(p) },58 };55 let found_here: *mut c_char = null_mut();59 let found_here: *mut c_char = null_mut();566057 let mut buf = null_mut();61 let mut buf = null_mut();bindings/jsonnet/src/lib.rsdiffbeforeafterboth28 rustc_hash::FxHashMap,28 rustc_hash::FxHashMap,29 stack::set_stack_depth_limit,29 stack::set_stack_depth_limit,30 trace::{CompactFormat, PathResolver, TraceFormat},30 trace::{CompactFormat, PathResolver, TraceFormat},31 FileImportResolver, IStr, ImportResolver, Result, State, Val,31 AsPathLike, FileImportResolver, IStr, ImportResolver, Result, State, Val,32};32};33use jrsonnet_gcmodule::Acyclic;33use jrsonnet_gcmodule::Acyclic;34use jrsonnet_parser::SourcePath;34use jrsonnet_parser::SourcePath;62 }62 }63}63}646465unsafe fn unparse_path(input: &Path) -> Cow<'_, CStr> {65unsafe fn unparse_path(input: &Path) -> CString {66 #[cfg(target_family = "unix")]66 #[cfg(target_family = "unix")]67 {67 {68 use std::os::unix::ffi::OsStrExt;68 use std::os::unix::ffi::OsStrExt;69 let str = CString::new(input.as_os_str().as_bytes()).expect("input has zero byte in it");69 let str = CString::new(input.as_os_str().as_bytes()).expect("input has zero byte in it");70 Cow::Owned(str)70 str71 }71 }72 #[cfg(not(target_family = "unix"))]72 #[cfg(not(target_family = "unix"))]73 {73 {74 let str = input.as_os_str().to_str().expect("bad utf-8");74 let str = input.as_os_str().to_str().expect("bad utf-8");75 let cstr = CString::new(str).expect("input has NUL inside");75 let cstr = CString::new(str).expect("input has NUL inside");76 Cow::Owned(cstr)76 cstr77 }77 }78}78}797993 self.inner.borrow().load_file_contents(resolved)93 self.inner.borrow().load_file_contents(resolved)94 }94 }959596 fn resolve_from(&self, from: &SourcePath, path: &str) -> Result<SourcePath> {96 fn resolve_from(&self, from: &SourcePath, path: &dyn AsPathLike) -> Result<SourcePath> {97 self.inner.borrow().resolve_from(from, path)97 self.inner.borrow().resolve_from(from, path)98 }98 }9999100 fn resolve_from_default(&self, path: &str) -> Result<SourcePath> {100 fn resolve_from_default(&self, path: &dyn AsPathLike) -> Result<SourcePath> {101 self.inner.borrow().resolve_from_default(path)101 self.inner.borrow().resolve_from_default(path)102 }102 }103104 fn resolve(&self, path: &Path) -> Result<SourcePath> {105 self.inner.borrow().resolve(path)106 }107}103}108104109pub struct VM {105pub struct VM {bindings/jsonnet/src/vars_tlas.rsdiffbeforeafterboth3use std::{ffi::CStr, os::raw::c_char};3use std::{ffi::CStr, os::raw::c_char};445use jrsonnet_evaluator::{function::TlaArg, IStr};5use jrsonnet_evaluator::{function::TlaArg, IStr};6use jrsonnet_parser::{ParserSettings, Source};768use crate::VM;7use crate::VM;9884 let code = unsafe { CStr::from_ptr(code) };83 let code = unsafe { CStr::from_ptr(code) };858486 let name: IStr = name.to_str().expect("name is not utf-8").into();85 let name: IStr = name.to_str().expect("name is not utf-8").into();87 let code: IStr = code.to_str().expect("code is not utf-8").into();86 let code: String = code.to_str().expect("code is not utf-8").to_owned();88 let code = jrsonnet_parser::parse(89 &code,90 &ParserSettings {91 source: Source::new_virtual(format!("<top-level-arg:{name}>").into(), code.clone()),92 },93 )94 .expect("can't parse TLA code");958796 vm.tla_args.insert(name, TlaArg::Code(code));88 vm.tla_args.insert(name, TlaArg::InlineCode(code));97}89}9890cmds/jrsonnet/src/main.rsdiffbeforeafterboth182 let input_str = std::str::from_utf8(&input)?;182 let input_str = std::str::from_utf8(&input)?;183 s.evaluate_snippet("<stdin>".to_owned(), input_str)?183 s.evaluate_snippet("<stdin>".to_owned(), input_str)?184 } else {184 } else {185 s.import(&input)?185 s.import(input.as_str())?186 };186 };187187188 let tla = opts.tla.tla_opts()?;188 let tla = opts.tla.tla_opts()?;crates/jrsonnet-cli/src/stdlib.rsdiffbeforeafterboth1use std::{fs::read_to_string, str::FromStr};1use std::str::FromStr;223use clap::Parser;3use clap::Parser;4use jrsonnet_evaluator::{trace::PathResolver, Result};4use jrsonnet_evaluator::{function::TlaArg, trace::PathResolver, Result};5use jrsonnet_stdlib::ContextInitializer;5use jrsonnet_stdlib::ContextInitializer;667#[derive(Clone)]7#[derive(Clone)]54#[derive(Clone)]54#[derive(Clone)]55pub struct ExtFile {55pub struct ExtFile {56 pub name: String,56 pub name: String,57 pub value: String,57 pub path: String,58}58}595960impl FromStr for ExtFile {60impl FromStr for ExtFile {61 type Err = String;61 type Err = String;626263 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {63 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {64 let out: Vec<&str> = s.split('=').collect();64 let Some((name, path)) = s.split_once('=') else {65 if out.len() != 2 {66 return Err("bad ext-file syntax".to_owned());65 return Err("bad ext-file syntax".to_owned());67 }66 };68 let file = read_to_string(out[1]);69 match file {70 Ok(content) => Ok(Self {67 Ok(Self {71 name: out[0].into(),68 name: name.into(),72 value: content,69 path: path.into(),73 }),70 })74 Err(e) => Err(format!("{e}")),75 }76 }71 }77}72}7873110 }105 }111 let ctx = ContextInitializer::new(PathResolver::new_cwd_fallback());106 let ctx = ContextInitializer::new(PathResolver::new_cwd_fallback());112 for ext in &self.ext_str {107 for ext in &self.ext_str {113 ctx.add_ext_str((&ext.name as &str).into(), (&ext.value as &str).into());108 ctx.settings_mut().ext_vars.insert(109 ext.name.as_str().into(),110 TlaArg::String(ext.value.as_str().into()),111 );114 }112 }115 for ext in &self.ext_str_file {113 for ext in &self.ext_str_file {116 ctx.add_ext_str((&ext.name as &str).into(), (&ext.value as &str).into());114 ctx.settings_mut().ext_vars.insert(115 ext.name.as_str().into(),116 TlaArg::ImportStr(ext.path.clone()),117 );117 }118 }118 for ext in &self.ext_code {119 for ext in &self.ext_code {119 ctx.add_ext_code(&ext.name as &str, &ext.value as &str)?;120 ctx.settings_mut().ext_vars.insert(121 ext.name.as_str().into(),122 TlaArg::InlineCode(ext.value.clone()),123 );120 }124 }121 for ext in &self.ext_code_file {125 for ext in &self.ext_code_file {126 ctx.settings_mut()127 .ext_vars122 ctx.add_ext_code(&ext.name as &str, &ext.value as &str)?;128 .insert(ext.name.as_str().into(), TlaArg::Import(ext.path.clone()));123 }129 }124 Ok(Some(ctx))130 Ok(Some(ctx))125 }131 }crates/jrsonnet-cli/src/tla.rsdiffbeforeafterboth1use clap::Parser;1use clap::Parser;2use jrsonnet_evaluator::{2use jrsonnet_evaluator::{IStr, error::Result, function::TlaArg, gc::WithCapacityExt as _, rustc_hash::FxHashMap};3 error::{ErrorKind, Result},4 function::TlaArg,5 gc::WithCapacityExt as _,6 rustc_hash::FxHashMap,7 IStr,8};9use jrsonnet_parser::{ParserSettings, Source};10311use crate::{ExtFile, ExtStr};4use crate::{ExtFile, ExtStr};12535impl TlaOpts {28impl TlaOpts {36 pub fn tla_opts(&self) -> Result<FxHashMap<IStr, TlaArg>> {29 pub fn tla_opts(&self) -> Result<FxHashMap<IStr, TlaArg>> {37 let mut out = FxHashMap::new();30 let mut out = FxHashMap::new();38 for (name, value) in self31 for ext in &self.tla_str {39 .tla_str40 .iter()41 .map(|c| (&c.name, &c.value))42 .chain(self.tla_str_file.iter().map(|c| (&c.name, &c.value)))43 {44 out.insert(name.into(), TlaArg::String(value.into()));32 out.insert(33 ext.name.as_str().into(),34 TlaArg::String(ext.value.as_str().into()),35 );45 }36 }37 for ext in &self.tla_str_file {38 out.insert(39 ext.name.as_str().into(),40 TlaArg::ImportStr(ext.name.as_str().into()),41 );42 }46 for (name, code) in self43 for ext in &self.tla_code {47 .tla_code48 .iter()49 .map(|c| (&c.name, &c.value))50 .chain(self.tla_code_file.iter().map(|c| (&c.name, &c.value)))44 out.insert(51 {45 ext.name.as_str().into(),52 let source = Source::new_virtual(format!("<top-level-arg:{name}>").into(), code.into());46 TlaArg::InlineCode(ext.value.clone()),47 );48 }49 for ext in &self.tla_code_file {53 out.insert(50 out.insert(ext.name.as_str().into(), TlaArg::Import(ext.path.clone()));54 (name as &str).into(),51 }55 TlaArg::Code(56 jrsonnet_parser::parse(57 code,58 &ParserSettings {59 source: source.clone(),60 },61 )62 .map_err(|e| ErrorKind::ImportSyntaxError {63 path: source,64 error: Box::new(e),65 })?,66 ),67 );68 }69 Ok(out)52 Ok(out)70 }53 }71}54}crates/jrsonnet-evaluator/src/async_import.rsdiffbeforeafterboth1use std::{any::Any, cell::RefCell, future::Future, path::Path};1use std::{any::Any, cell::RefCell, future::Future};223use jrsonnet_gcmodule::Acyclic;3use jrsonnet_gcmodule::Acyclic;4use jrsonnet_interner::IStr;5use jrsonnet_parser::{4use jrsonnet_parser::{6 ArgsDesc, AssertStmt, BindSpec, CompSpec, Destruct, Expr, FieldMember, FieldName, ForSpecData,5 ArgsDesc, AssertStmt, BindSpec, CompSpec, Destruct, Expr, FieldMember, FieldName, ForSpecData,7 IfSpecData, LocExpr, Member, ObjBody, Param, ParamsDesc, ParserSettings, SliceDesc, Source,6 IfSpecData, LocExpr, Member, ObjBody, Param, ParamsDesc, ParserSettings, SliceDesc, Source,8 SourcePath,7 SourcePath,9};8};10use rustc_hash::FxHashMap;9use rustc_hash::FxHashMap;111012use crate::{bail, FileData, ImportResolver, State};11use crate::{AsPathLike, FileData, ImportResolver, ResolvePathOwned, State};131214pub struct Import {13pub struct Import {15 path: IStr,14 path: ResolvePathOwned,16 expression: bool,15 expression: bool,17}16}1817137 Expr::Import(v) | Expr::ImportStr(v) | Expr::ImportBin(v) => {136 Expr::Import(v) | Expr::ImportStr(v) | Expr::ImportBin(v) => {138 if let Expr::Str(s) = &*v.expr() {137 if let Expr::Str(s) = &*v.expr() {139 out.0.push(Import {138 out.0.push(Import {140 path: s.clone(),139 path: ResolvePathOwned::Str(s.to_string()),141 expression: matches!(&*expr.expr(), Expr::Import(_)),140 expression: matches!(&*expr.expr(), Expr::Import(_)),142 });141 });143 }142 }229 fn resolve_from(228 fn resolve_from(230 &self,229 &self,231 from: &SourcePath,230 from: &SourcePath,232 path: &str,231 path: &dyn AsPathLike,233 ) -> impl Future<Output = Result<SourcePath, Self::Error>>;232 ) -> impl Future<Output = Result<SourcePath, Self::Error>>;234 fn resolve_from_default(233 fn resolve_from_default(235 &self,234 &self,236 path: &str,235 path: &dyn AsPathLike,237 ) -> impl Future<Output = Result<SourcePath, Self::Error>> {236 ) -> impl Future<Output = Result<SourcePath, Self::Error>> {238 async { self.resolve_from(&SourcePath::default(), path).await }237 async { self.resolve_from(&SourcePath::default(), path).await }239 }238 }240 /// Resolves absolute path, doesn't supports jpath and other fancy things241 fn resolve(&self, path: &Path) -> impl Future<Output = Result<SourcePath, Self::Error>>;242239243 /// Load resolved file240 /// Load resolved file244 /// This should only be called with value returned241 /// This should only be called with value returned253250254#[derive(Acyclic)]251#[derive(Acyclic)]255struct ResolvedImportResolver {252struct ResolvedImportResolver {256 resolved: RefCell<FxHashMap<(SourcePath, IStr), (SourcePath, bool)>>,253 resolved: RefCell<FxHashMap<(SourcePath, ResolvePathOwned), (SourcePath, bool)>>,257}254}258impl ImportResolver for ResolvedImportResolver {255impl ImportResolver for ResolvedImportResolver {259 fn load_file_contents(&self, _resolved: &SourcePath) -> crate::Result<Vec<u8>> {256 fn load_file_contents(&self, _resolved: &SourcePath) -> crate::Result<Vec<u8>> {260 unreachable!("all files should be loaded at this point");257 unreachable!("all files should be loaded at this point");261 }258 }262259263 fn resolve_from(&self, from: &SourcePath, path: &str) -> crate::Result<SourcePath> {260 fn resolve_from(&self, from: &SourcePath, path: &dyn AsPathLike) -> crate::Result<SourcePath> {264 Ok(self261 Ok(self265 .resolved262 .resolved266 .borrow()263 .borrow()267 .get(&(from.clone(), path.into()))264 .get(&(from.clone(), path.as_path().to_owned()))268 .expect("all imports should be resolved at this point")265 .expect("all imports should be resolved at this point")269 .0266 .0270 .clone())267 .clone())271 }268 }272269273 fn resolve_from_default(&self, path: &str) -> crate::Result<SourcePath> {270 fn resolve_from_default(&self, path: &dyn AsPathLike) -> crate::Result<SourcePath> {274 self.resolve_from(&SourcePath::default(), path)271 self.resolve_from(&SourcePath::default(), path)275 }272 }276277 fn resolve(&self, path: &Path) -> crate::Result<SourcePath> {278 bail!(crate::error::ErrorKind::AbsoluteImportNotSupported(279 path.to_owned()280 ))281 }282}273}283274284enum Job {275enum Job {288}279}289280290#[allow(clippy::future_not_send)]281#[allow(clippy::future_not_send)]291pub async fn async_import<H>(s: State, handler: H, path: impl AsRef<Path>) -> Result<(), H::Error>282pub async fn async_import<H>(s: State, handler: H, path: &dyn AsPathLike) -> Result<(), H::Error>292where283where293 H: AsyncImportResolver,284 H: AsyncImportResolver,294{285{299 let mut resolved_map = resolved.resolved.borrow_mut();290 let mut resolved_map = resolved.resolved.borrow_mut();300291301 let mut queue = vec![Job::LoadFile {292 let mut queue = vec![Job::LoadFile {302 path: handler.resolve(path.as_ref()).await?,293 path: handler.resolve_from_default(path).await?,303 parse: true,294 parse: true,304 }];295 }];305 while let Some(job) = queue.pop() {296 while let Some(job) = queue.pop() {crates/jrsonnet-evaluator/src/error.rsdiffbeforeafterboth2 cmp::Ordering,2 cmp::Ordering,3 convert::Infallible,3 convert::Infallible,4 fmt::{Debug, Display},4 fmt::{Debug, Display},5 path::PathBuf,6};5};768use jrsonnet_gcmodule::Trace;7use jrsonnet_gcmodule::Trace;16 stdlib::format::FormatError,15 stdlib::format::FormatError,17 typed::TypeLocError,16 typed::TypeLocError,18 val::ConvertNumValueError,17 val::ConvertNumValueError,19 ObjValue,18 ObjValue, ResolvePathOwned,20};19};212022pub(crate) fn format_found(list: &[IStr], what: &str) -> String {21pub(crate) fn format_found(list: &[IStr], what: &str) -> String {180 StandaloneSuper,179 StandaloneSuper,181180182 #[error("can't resolve {1} from {0}")]181 #[error("can't resolve {1} from {0}")]183 ImportFileNotFound(SourcePath, String),182 ImportFileNotFound(SourcePath, ResolvePathOwned),184 #[error("can't resolve absolute {0}")]185 AbsoluteImportFileNotFound(PathBuf),186 #[error("resolved file not found: {:?}", .0)]183 #[error("resolved file not found: {:?}", .0)]187 ResolvedFileNotFound(SourcePath),184 ResolvedFileNotFound(SourcePath),188 #[error("can't import {0}: is a directory")]185 #[error("can't import {0}: is a directory")]192 #[error("import io error: {0}")]189 #[error("import io error: {0}")]193 ImportIo(String),190 ImportIo(String),194 #[error("tried to import {1} from {0}, but imports are not supported")]191 #[error("tried to import {1} from {0}, but imports are not supported")]195 ImportNotSupported(SourcePath, String),192 ImportNotSupported(SourcePath, ResolvePathOwned),196 #[error("tried to import {0}, but absolute imports are not supported")]197 AbsoluteImportNotSupported(PathBuf),198 #[error("can't import from virtual file")]193 #[error("can't import from virtual file")]199 CantImportFromVirtualFile,194 CantImportFromVirtualFile,200 #[error(195 #[error(crates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth682 };682 };683 let tmp = loc.clone().0;683 let tmp = loc.clone().0;684 let s = ctx.state();684 let s = ctx.state();685 let resolved_path = s.resolve_from(tmp.source_path(), path as &str)?;685 let resolved_path = s.resolve_from(tmp.source_path(), path)?;686 match i {686 match i {687 Import(_) => in_frame(687 Import(_) => in_frame(688 CallLocation::new(&loc),688 CallLocation::new(&loc),crates/jrsonnet-evaluator/src/function/arglike.rsdiffbeforeafterboth223use jrsonnet_gcmodule::Trace;3use jrsonnet_gcmodule::Trace;4use jrsonnet_interner::IStr;4use jrsonnet_interner::IStr;5use jrsonnet_parser::{ArgsDesc, LocExpr};5use jrsonnet_parser::{ArgsDesc, LocExpr, SourceFifo, SourcePath};667use crate::{evaluate, typed::Typed, Context, Result, Thunk, Val};7use crate::{evaluate, typed::Typed, Context, Result, Thunk, Val};8841#[derive(Clone, Trace)]41#[derive(Clone, Trace)]42pub enum TlaArg {42pub enum TlaArg {43 String(IStr),43 String(IStr),44 Code(LocExpr),45 Val(Val),44 Val(Val),46 Lazy(Thunk<Val>),45 Lazy(Thunk<Val>),46 Import(String),47 ImportStr(String),48 InlineCode(String),47}49}48impl ArgLike for TlaArg {50impl ArgLike for TlaArg {49 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {51 fn evaluate_arg(&self, ctx: Context, _tailstrict: bool) -> Result<Thunk<Val>> {50 match self {52 match self {51 Self::String(s) => Ok(Thunk::evaluated(Val::string(s.clone()))),53 Self::String(s) => Ok(Thunk::evaluated(Val::string(s.clone()))),54 Self::Val(val) => Ok(Thunk::evaluated(val.clone())),55 Self::Lazy(lazy) => Ok(lazy.clone()),52 Self::Code(code) => Ok(if tailstrict {56 Self::Import(p) => {53 Thunk::evaluated(evaluate(ctx, code)?)54 } else {55 let code = code.clone();57 let resolved = ctx.state().resolve_from_default(&p.as_str())?;56 Thunk!(move || evaluate(ctx, &code))58 Ok(Thunk!(move || ctx.state().import_resolved(resolved)))57 }),59 }58 Self::Val(val) => Ok(Thunk::evaluated(val.clone())),60 Self::ImportStr(p) => {61 let resolved = ctx.state().resolve_from_default(&p.as_str())?;62 Ok(Thunk!(move || ctx63 .state()64 .import_resolved_str(resolved)65 .map(Val::string)))66 }59 Self::Lazy(lazy) => Ok(lazy.clone()),67 Self::InlineCode(p) => {68 let resolved =69 SourcePath::new(SourceFifo("<inline code>".to_owned(), p.as_bytes().into()));70 Ok(Thunk!(move || ctx.state().import_resolved(resolved)))71 }60 }72 }61 }73 }62}74}crates/jrsonnet-evaluator/src/import.rsdiffbeforeafterboth1use std::{1use std::{2 any::Any,2 any::Any,3 borrow::Cow,3 env::current_dir,4 env::current_dir,4 fs,5 fmt, fs,5 io::{ErrorKind, Read},6 io::{ErrorKind, Read},6 path::{Path, PathBuf},7 path::{Path, PathBuf},7};8};899use fs::File;10use fs::File;10use jrsonnet_gcmodule::Acyclic;11use jrsonnet_gcmodule::Acyclic;11use jrsonnet_interner::IBytes;12use jrsonnet_interner::IBytes;12use jrsonnet_parser::{SourceDirectory, SourceFifo, SourceFile, SourcePath};13use jrsonnet_parser::{IStr, SourceDirectory, SourceFifo, SourceFile, SourcePath};131414use crate::{15use crate::{15 bail,16 bail,16 error::{ErrorKind::*, Result},17 error::{ErrorKind::*, Result},17};18};19#[derive(Clone, Debug, Acyclic, Eq, Hash, PartialEq)]20pub enum ResolvePathOwned {21 Str(String),22 Path(PathBuf),23}24impl fmt::Display for ResolvePathOwned {25 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {26 match self {27 ResolvePathOwned::Str(s) => write!(f, "{s}"),28 ResolvePathOwned::Path(p) => write!(f, "{}", p.display()),29 }30 }31}32#[derive(Clone, Copy)]33pub enum ResolvePath<'s> {34 Str(&'s str),35 Path(&'s Path),36}37impl ResolvePath<'_> {38 pub fn to_owned(self) -> ResolvePathOwned {39 match self {40 ResolvePath::Str(s) => ResolvePathOwned::Str(s.to_owned()),41 ResolvePath::Path(p) => ResolvePathOwned::Path(p.to_owned()),42 }43 }44}45impl AsRef<Path> for ResolvePath<'_> {46 fn as_ref(&self) -> &Path {47 match self {48 ResolvePath::Str(s) => s.as_ref(),49 ResolvePath::Path(p) => p,50 }51 }52}53pub trait AsPathLike {54 fn as_path(&self) -> ResolvePath<'_>;55}56impl<T> AsPathLike for &T57where58 T: AsPathLike + ?Sized,59{60 fn as_path(&self) -> ResolvePath<'_> {61 (*self).as_path()62 }63}64impl AsPathLike for str {65 fn as_path(&self) -> ResolvePath<'_> {66 ResolvePath::Str(self)67 }68}69impl AsPathLike for IStr {70 fn as_path(&self) -> ResolvePath<'_> {71 ResolvePath::Str(self)72 }73}74impl AsPathLike for Cow<'_, Path> {75 fn as_path(&self) -> ResolvePath<'_> {76 ResolvePath::Path(self.as_ref())77 }78}79impl AsPathLike for Path {80 fn as_path(&self) -> ResolvePath<'_> {81 ResolvePath::Path(self)82 }83}84impl AsPathLike for ResolvePathOwned {85 fn as_path(&self) -> ResolvePath<'_> {86 match self {87 ResolvePathOwned::Str(s) => ResolvePath::Str(s),88 ResolvePathOwned::Path(path_buf) => ResolvePath::Path(path_buf),89 }90 }91}189219/// Implements file resolution logic for `import` and `importStr`93/// Implements file resolution logic for `import` and `importStr`20pub trait ImportResolver: Acyclic + Any {94pub trait ImportResolver: Acyclic + Any {24 ///98 ///25 /// `from` should only be returned from [`ImportResolver::resolve`], or from other defined file, any other value99 /// `from` should only be returned from [`ImportResolver::resolve`], or from other defined file, any other value26 /// may result in panic100 /// may result in panic27 fn resolve_from(&self, from: &SourcePath, path: &str) -> Result<SourcePath> {101 fn resolve_from(&self, from: &SourcePath, path: &dyn AsPathLike) -> Result<SourcePath> {28 bail!(ImportNotSupported(from.clone(), path.into()))102 bail!(ImportNotSupported(from.clone(), path.as_path().to_owned()))29 }103 }30 fn resolve_from_default(&self, path: &str) -> Result<SourcePath> {104 fn resolve_from_default(&self, path: &dyn AsPathLike) -> Result<SourcePath> {31 self.resolve_from(&SourcePath::default(), path)105 self.resolve_from(&SourcePath::default(), path)32 }106 }33 /// Resolves absolute path, doesn't supports jpath and other fancy things34 fn resolve(&self, path: &Path) -> Result<SourcePath> {35 bail!(AbsoluteImportNotSupported(path.to_owned()))36 }3710738 /// Load resolved file108 /// Load resolved file39 /// This should only be called with value returned from [`ImportResolver::resolve_file`]/[`ImportResolver::resolve`],109 /// This should only be called with value returned from [`ImportResolver::resolve_file`]/[`ImportResolver::resolve`],105}175}106176107impl ImportResolver for FileImportResolver {177impl ImportResolver for FileImportResolver {108 fn resolve_from(&self, from: &SourcePath, path: &str) -> Result<SourcePath> {178 fn resolve_from(&self, from: &SourcePath, path: &dyn AsPathLike) -> Result<SourcePath> {179 let path = path.as_path();109 let mut direct = if let Some(f) = from.downcast_ref::<SourceFile>() {180 let mut direct = if let Some(f) = from.downcast_ref::<SourceFile>() {110 let mut o = f.path().to_owned();181 let mut o = f.path().to_owned();111 o.pop();182 o.pop();131 }202 }132 bail!(ImportFileNotFound(from.clone(), path.to_owned()))203 bail!(ImportFileNotFound(from.clone(), path.to_owned()))133 }204 }134 fn resolve(&self, path: &Path) -> Result<SourcePath> {135 let Some(source) = check_path(path)? else {136 bail!(AbsoluteImportFileNotFound(path.to_owned()))137 };138 Ok(source)139 }140205141 fn load_file_contents(&self, id: &SourcePath) -> Result<Vec<u8>> {206 fn load_file_contents(&self, id: &SourcePath) -> Result<Vec<u8>> {142 let path = if let Some(f) = id.downcast_ref::<SourceFile>() {207 let path = if let Some(f) = id.downcast_ref::<SourceFile>() {155 Ok(out)220 Ok(out)156 }221 }157222158 fn resolve_from_default(&self, path: &str) -> Result<SourcePath> {223 fn resolve_from_default(&self, path: &dyn AsPathLike) -> Result<SourcePath> {159 self.resolve_from(&SourcePath::default(), path)224 self.resolve_from(&SourcePath::default(), path)160 }225 }161}226}crates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth29 cell::{RefCell, RefMut},29 cell::{RefCell, RefMut},30 collections::hash_map::Entry,30 collections::hash_map::Entry,31 fmt::{self, Debug},31 fmt::{self, Debug},32 path::Path,33 rc::Rc,32 rc::Rc,34};33};3534349 }348 }350349351 /// Has same semantics as `import 'path'` called from `from` file350 /// Has same semantics as `import 'path'` called from `from` file352 pub fn import_from(&self, from: &SourcePath, path: &str) -> Result<Val> {351 pub fn import_from(&self, from: &SourcePath, path: impl AsPathLike) -> Result<Val> {353 let resolved = self.resolve_from(from, path)?;352 let resolved = self.resolve_from(from, &path)?;354 self.import_resolved(resolved)353 self.import_resolved(resolved)355 }354 }356 pub fn import(&self, path: impl AsRef<Path>) -> Result<Val> {355 pub fn import(&self, path: impl AsPathLike) -> Result<Val> {357 let resolved = self.resolve(path)?;356 let resolved = self.resolve_from_default(&path)?;358 self.import_resolved(resolved)357 self.import_resolved(resolved)359 }358 }360359468impl State {467impl State {469 // Only panics in case of [`ImportResolver`] contract violation468 // Only panics in case of [`ImportResolver`] contract violation470 #[allow(clippy::missing_panics_doc)]469 #[allow(clippy::missing_panics_doc)]471 pub fn resolve_from(&self, from: &SourcePath, path: &str) -> Result<SourcePath> {470 pub fn resolve_from(&self, from: &SourcePath, path: &dyn AsPathLike) -> Result<SourcePath> {472 self.import_resolver().resolve_from(from, path.as_ref())471 self.import_resolver().resolve_from(from, path)473 }472 }474475 // Only panics in case of [`ImportResolver`] contract violation476 #[allow(clippy::missing_panics_doc)]473 #[allow(clippy::missing_panics_doc)]477 pub fn resolve(&self, path: impl AsRef<Path>) -> Result<SourcePath> {474 pub fn resolve_from_default(&self, path: &dyn AsPathLike) -> Result<SourcePath> {478 self.import_resolver().resolve(path.as_ref())475 self.import_resolver().resolve_from_default(path)479 }476 }480 pub fn import_resolver(&self) -> &dyn ImportResolver {477 pub fn import_resolver(&self) -> &dyn ImportResolver {481 &*self.0.import_resolver478 &*self.0.import_resolvercrates/jrsonnet-stdlib/src/lib.rsdiffbeforeafterboth12pub use encoding::*;12pub use encoding::*;13pub use hash::*;13pub use hash::*;14use jrsonnet_evaluator::{14use jrsonnet_evaluator::{15 error::{ErrorKind::*, Result},15 error::Result,16 function::{CallLocation, FuncVal, TlaArg},16 function::{CallLocation, FuncVal, TlaArg},17 trace::PathResolver,17 trace::PathResolver,18 val::NumValue,18 val::NumValue,377 .ext_vars377 .ext_vars378 .insert(name, TlaArg::String(value));378 .insert(name, TlaArg::String(value));379 }379 }380 pub fn add_ext_code(&self, name: &str, code: impl Into<IStr>) -> Result<()> {380 pub fn add_ext_code(&self, name: &str, code: impl AsRef<str>) -> Result<()> {381 let code = code.into();382 let source = extvar_source(name, code.clone());383 let parsed = jrsonnet_parser::parse(384 &code,385 &jrsonnet_parser::ParserSettings {386 source: source.clone(),387 },388 )389 .map_err(|e| ImportSyntaxError {390 path: source,391 error: Box::new(e),392 })?;393 // self.data_mut().volatile_files.insert(source_name, code);381 // self.data_mut().volatile_files.insert(source_name, code);394 self.settings_mut()382 self.settings_mut()395 .ext_vars383 .ext_vars396 .insert(name.into(), TlaArg::Code(parsed));384 .insert(name.into(), TlaArg::InlineCode(code.as_ref().to_owned()));397 Ok(())385 Ok(())398 }386 }399 pub fn add_native(&self, name: impl Into<IStr>, cb: impl Into<FuncVal>) {387 pub fn add_native(&self, name: impl Into<IStr>, cb: impl Into<FuncVal>) {