difftreelog
refactor keep source code alongside source path
in: master
18 files changed
bindings/jsonnet/src/import.rsdiffbeforeafterboth16 error::{Error::*, Result},16 error::{Error::*, Result},17 throw, ImportResolver, State,17 throw, ImportResolver, State,18};18};19use jrsonnet_parser::SourcePath;192020pub type JsonnetImportCallback = unsafe extern "C" fn(21pub type JsonnetImportCallback = unsafe extern "C" fn(21 ctx: *mut c_void,22 ctx: *mut c_void,29pub struct CallbackImportResolver {30pub struct CallbackImportResolver {30 cb: JsonnetImportCallback,31 cb: JsonnetImportCallback,31 ctx: *mut c_void,32 ctx: *mut c_void,32 out: RefCell<HashMap<PathBuf, Vec<u8>>>,33 out: RefCell<HashMap<SourcePath, Vec<u8>>>,33}34}34impl ImportResolver for CallbackImportResolver {35impl ImportResolver for CallbackImportResolver {35 fn resolve_file(&self, from: &Path, path: &str) -> Result<PathBuf> {36 fn resolve_file_relative(&self, from: &Path, path: &str) -> Result<SourcePath> {36 let base = CString::new(from.to_str().unwrap()).unwrap().into_raw();37 let base = CString::new(from.to_str().unwrap()).unwrap().into_raw();37 let rel = CString::new(path).unwrap().into_raw();38 let rel = CString::new(path).unwrap().into_raw();38 let found_here: *mut c_char = null_mut();39 let found_here: *mut c_char = null_mut();61 }62 }626363 let found_here_raw = unsafe { CStr::from_ptr(found_here) };64 let found_here_raw = unsafe { CStr::from_ptr(found_here) };64 let found_here_buf = PathBuf::from(found_here_raw.to_str().unwrap());65 let found_here_buf = SourcePath::Path(PathBuf::from(found_here_raw.to_str().unwrap()));65 unsafe {66 unsafe {66 let _ = CString::from_raw(found_here);67 let _ = CString::from_raw(found_here);67 }68 }747575 Ok(found_here_buf)76 Ok(found_here_buf)76 }77 }77 fn load_file_contents(&self, resolved: &Path) -> Result<Vec<u8>> {78 fn load_file_contents(&self, resolved: &SourcePath) -> Result<Vec<u8>> {78 Ok(self.out.borrow().get(resolved).unwrap().clone())79 Ok(self.out.borrow().get(resolved).unwrap().clone())79 }80 }8081108 }109 }109}110}110impl ImportResolver for NativeImportResolver {111impl ImportResolver for NativeImportResolver {111 fn resolve_file(&self, from: &Path, path: &str) -> Result<PathBuf> {112 fn resolve_file_relative(&self, from: &Path, path: &str) -> Result<SourcePath> {112 let mut new_path = from.to_owned();113 let mut new_path = from.to_owned();113 new_path.push(path);114 new_path.push(path);114 if new_path.exists() {115 if new_path.exists() {115 Ok(new_path)116 Ok(SourcePath::Path(new_path))116 } else {117 } else {117 for library_path in self.library_paths.borrow().iter() {118 for library_path in self.library_paths.borrow().iter() {118 let mut cloned = library_path.clone();119 let mut cloned = library_path.clone();119 cloned.push(path);120 cloned.push(path);120 if cloned.exists() {121 if cloned.exists() {121 return Ok(cloned);122 return Ok(SourcePath::Path(cloned));122 }123 }123 }124 }124 throw!(ImportFileNotFound(from.to_owned(), path.to_owned()))125 throw!(ImportFileNotFound(from.to_owned(), path.to_owned()))125 }126 }126 }127 }127 fn load_file_contents(&self, id: &Path) -> Result<Vec<u8>> {128 fn load_file_contents(&self, id: &SourcePath) -> Result<Vec<u8>> {129 let path = match id {130 SourcePath::Path(path) => path,131 _ => unreachable!("NativeImportResolver::resolve_file may only return plain paths"),132 };128 let mut file = File::open(id).map_err(|_e| ResolvedFileNotFound(id.to_owned()))?;133 let mut file = File::open(path).map_err(|_e| ResolvedFileNotFound(id.clone()))?;129 let mut out = Vec::new();134 let mut out = Vec::new();130 file.read_to_end(&mut out)135 file.read_to_end(&mut out)131 .map_err(|e| ImportIo(e.to_string()))?;136 .map_err(|e| ImportIo(e.to_string()))?;bindings/jsonnet/src/lib.rsdiffbeforeafterboth101011use std::{11use std::{12 alloc::Layout,12 alloc::Layout,13 env,13 ffi::{CStr, CString},14 ffi::{CStr, CString},14 os::raw::{c_char, c_double, c_int, c_uint},15 os::raw::{c_char, c_double, c_int, c_uint},15 path::PathBuf,16};16};171718use import::NativeImportResolver;18use import::NativeImportResolver;112) -> *const c_char {112) -> *const c_char {113 let filename = CStr::from_ptr(filename);113 let filename = CStr::from_ptr(filename);114 match vm114 match vm115 .import(PathBuf::from(filename.to_str().unwrap()))115 .import(116 &env::current_dir().expect("cwd"),117 filename.to_str().unwrap(),118 )116 .and_then(|v| vm.with_tla(v))119 .and_then(|v| vm.with_tla(v))117 .and_then(|v| vm.manifest(v))120 .and_then(|v| vm.manifest(v))143 match vm146 match vm144 .evaluate_snippet(147 .evaluate_snippet(filename.to_str().unwrap().into(), snippet.to_str().unwrap())145 filename.to_str().unwrap().into(),146 snippet.to_str().unwrap().into(),147 )148 .and_then(|v| vm.with_tla(v))148 .and_then(|v| vm.with_tla(v))149 .and_then(|v| vm.manifest(v))149 .and_then(|v| vm.manifest(v))186) -> *const c_char {186) -> *const c_char {187 let filename = CStr::from_ptr(filename);187 let filename = CStr::from_ptr(filename);188 match vm188 match vm189 .import(PathBuf::from(filename.to_str().unwrap()))189 .import(190 &env::current_dir().expect("cwd"),191 filename.to_str().unwrap(),192 )190 .and_then(|v| vm.with_tla(v))193 .and_then(|v| vm.with_tla(v))191 .and_then(|v| vm.manifest_multi(v))194 .and_then(|v| vm.manifest_multi(v))215 match vm218 match vm216 .evaluate_snippet(219 .evaluate_snippet(filename.to_str().unwrap().into(), snippet.to_str().unwrap())217 filename.to_str().unwrap().into(),218 snippet.to_str().unwrap().into(),219 )220 .and_then(|v| vm.with_tla(v))220 .and_then(|v| vm.with_tla(v))221 .and_then(|v| vm.manifest_multi(v))221 .and_then(|v| vm.manifest_multi(v))256) -> *const c_char {256) -> *const c_char {257 let filename = CStr::from_ptr(filename);257 let filename = CStr::from_ptr(filename);258 match vm258 match vm259 .import(PathBuf::from(filename.to_str().unwrap()))259 .import(260 &env::current_dir().expect("cwd"),261 filename.to_str().unwrap(),262 )260 .and_then(|v| vm.with_tla(v))263 .and_then(|v| vm.with_tla(v))261 .and_then(|v| vm.manifest_stream(v))264 .and_then(|v| vm.manifest_stream(v))285 match vm288 match vm286 .evaluate_snippet(289 .evaluate_snippet(filename.to_str().unwrap().into(), snippet.to_str().unwrap())287 filename.to_str().unwrap().into(),288 snippet.to_str().unwrap().into(),289 )290 .and_then(|v| vm.with_tla(v))290 .and_then(|v| vm.with_tla(v))291 .and_then(|v| vm.manifest_stream(v))291 .and_then(|v| vm.manifest_stream(v))bindings/jsonnet/src/vars_tlas.rsdiffbeforeafterboth32 .as_any()32 .as_any()33 .downcast_ref::<jrsonnet_stdlib::ContextInitializer>()33 .downcast_ref::<jrsonnet_stdlib::ContextInitializer>()34 .expect("only stdlib context initializer supported")34 .expect("only stdlib context initializer supported")35 .add_ext_code(name.to_str().unwrap(), value.to_str().unwrap().into())35 .add_ext_code(name.to_str().unwrap(), value.to_str().unwrap())36 .unwrap()36 .unwrap()37}37}38/// # Safety38/// # Safetycmds/jrsonnet/src/main.rsdiffbeforeafterboth133133134 let input = opts.input.input.ok_or(Error::MissingInputArgument)?;134 let input = opts.input.input.ok_or(Error::MissingInputArgument)?;135 let val = if opts.input.exec {135 let val = if opts.input.exec {136 s.evaluate_snippet("<cmdline>".to_owned(), (&input as &str).into())?136 s.evaluate_snippet("<cmdline>".to_owned(), &input as &str)?137 } else if input == "-" {137 } else if input == "-" {138 let mut input = Vec::new();138 let mut input = Vec::new();139 std::io::stdin().read_to_end(&mut input)?;139 std::io::stdin().read_to_end(&mut input)?;140 let input_str = std::str::from_utf8(&input)?.into();140 let input_str = std::str::from_utf8(&input)?;141 s.evaluate_snippet("<stdin>".to_owned(), input_str)?141 s.evaluate_snippet("<stdin>".to_owned(), input_str)?142 } else {142 } else {143 s.import(s.resolve_file(¤t_dir().expect("cwd"), &input)?)?143 s.import(¤t_dir().expect("cwd"), &input)?144 };144 };145145146 let val = s.with_tla(val)?;146 let val = s.with_tla(val)?;crates/jrsonnet-cli/src/stdlib.rsdiffbeforeafterboth118 ctx.add_ext_str((&ext.name as &str).into(), (&ext.value as &str).into());118 ctx.add_ext_str((&ext.name as &str).into(), (&ext.value as &str).into());119 }119 }120 for ext in self.ext_code.iter() {120 for ext in self.ext_code.iter() {121 ctx.add_ext_code(&ext.name as &str, (&ext.value as &str).into())?;121 ctx.add_ext_code(&ext.name as &str, &ext.value as &str)?;122 }122 }123 for ext in self.ext_code_file.iter() {123 for ext in self.ext_code_file.iter() {124 ctx.add_ext_code(&ext.name as &str, (&ext.value as &str).into())?;124 ctx.add_ext_code(&ext.name as &str, &ext.value as &str)?;125 }125 }126 s.settings_mut().context_initializer = Box::new(ctx);126 s.settings_mut().context_initializer = Box::new(ctx);127 Ok(())127 Ok(())crates/jrsonnet-evaluator/src/error.rsdiffbeforeafterboth223use jrsonnet_gcmodule::Trace;3use jrsonnet_gcmodule::Trace;4use jrsonnet_interner::IStr;4use jrsonnet_interner::IStr;5use jrsonnet_parser::{BinaryOpType, ExprLocation, Source, UnaryOpType};5use jrsonnet_parser::{BinaryOpType, ExprLocation, Source, SourcePath, UnaryOpType};6use jrsonnet_types::ValType;6use jrsonnet_types::ValType;7use thiserror::Error;7use thiserror::Error;88138138139 #[error("can't resolve {1} from {0}")]139 #[error("can't resolve {1} from {0}")]140 ImportFileNotFound(PathBuf, String),140 ImportFileNotFound(PathBuf, String),141 #[error("resolved file not found: {0}")]141 #[error("resolved file not found: {:?}", .0)]142 ResolvedFileNotFound(PathBuf),142 ResolvedFileNotFound(SourcePath),143 #[error("imported file is not valid utf-8: {0:?}")]143 #[error("imported file is not valid utf-8: {0:?}")]144 ImportBadFileUtf8(PathBuf),144 ImportBadFileUtf8(SourcePath),145 #[error("import io error: {0}")]145 #[error("import io error: {0}")]146 ImportIo(String),146 ImportIo(String),147 #[error("tried to import {1} from {0}, but imports is not supported")]147 #[error("tried to import {1} from {0}, but imports is not supported")]151 #[error(151 #[error(152 "syntax error: expected {}, got {:?}",152 "syntax error: expected {}, got {:?}",153 .error.expected,153 .error.expected,154 .source_code.chars().nth(error.location.offset)154 .path.code().chars().nth(error.location.offset)155 .map_or_else(|| "EOF".into(), |c| c.to_string())155 .map_or_else(|| "EOF".into(), |c| c.to_string())156 )]156 )]157 ImportSyntaxError {157 ImportSyntaxError {158 path: Source,158 path: Source,159 source_code: IStr,160 #[trace(skip)]159 #[trace(skip)]161 error: Box<jrsonnet_parser::ParseError>,160 error: Box<jrsonnet_parser::ParseError>,162 },161 },crates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth416 Literal(LiteralType::This) => {416 Literal(LiteralType::This) => {417 Val::Obj(ctx.this().clone().ok_or(CantUseSelfOutsideOfObject)?)417 Val::Obj(ctx.this().clone().ok_or(CantUseSelfOutsideOfObject)?)418 }418 }419 Literal(LiteralType::Super) => {419 Literal(LiteralType::Super) => Val::Obj(420 Val::Obj(ctx.super_obj().clone().ok_or(NoSuperFound)?.with_this(420 ctx.super_obj().clone().ok_or(NoSuperFound)?.with_this(421 ctx.this()421 ctx.this()422 .clone()422 .clone()423 .expect("if super exists - then this should to"),423 .expect("if super exists - then this should to"),424 ))424 ),425 }425 ),426 Literal(LiteralType::Dollar) => {426 Literal(LiteralType::Dollar) => {427 Val::Obj(ctx.dollar().clone().ok_or(NoTopLevelObjectFound)?)427 Val::Obj(ctx.dollar().clone().ok_or(NoTopLevelObjectFound)?)428 }428 }643 Import(_) => s.push(643 Import(_) => s.push(644 CallLocation::new(loc),644 CallLocation::new(loc),645 || format!("import {:?}", path.clone()),645 || format!("import {:?}", path.clone()),646 || s.import(resolved_path.clone()),646 || s.import_resolved(resolved_path),647 )?,647 )?,648 ImportStr(_) => Val::Str(s.import_str(resolved_path)?),648 ImportStr(_) => Val::Str(s.import_resolved_str(resolved_path)?),649 ImportBin(_) => Val::Arr(ArrValue::Bytes(s.import_bin(resolved_path)?)),649 ImportBin(_) => Val::Arr(ArrValue::Bytes(s.import_resolved_bin(resolved_path)?)),650 _ => unreachable!(),650 _ => unreachable!(),651 }651 }652 }652 }crates/jrsonnet-evaluator/src/import.rsdiffbeforeafterboth6};6};778use fs::File;8use fs::File;9use jrsonnet_parser::SourcePath;91010use crate::{11use crate::{11 error::{Error::*, Result},12 error::{Error::*, Result},17 /// Resolves real file path, e.g. `(/home/user/manifests, b.libjsonnet)` can correspond18 /// Resolves real file path, e.g. `(/home/user/manifests, b.libjsonnet)` can correspond18 /// both to `/home/user/manifests/b.libjsonnet` and to `/home/user/${vendor}/b.libjsonnet`19 /// both to `/home/user/manifests/b.libjsonnet` and to `/home/user/${vendor}/b.libjsonnet`19 /// where `${vendor}` is a library path.20 /// where `${vendor}` is a library path.20 fn resolve_file(&self, from: &Path, path: &str) -> Result<PathBuf>;21 fn resolve_file_relative(&self, from: &Path, path: &str) -> Result<SourcePath>;212223 /// Load resolved file24 /// This should only be called with value returned from `resolve_file`, this cannot be resolved using associated type,25 /// as evaluator uses object instead of generic for [`ImportResolver`]22 fn load_file_contents(&self, resolved: &Path) -> Result<Vec<u8>>;26 fn load_file_contents(&self, resolved: &SourcePath) -> Result<Vec<u8>>;232724 /// # Safety28 /// # Safety25 ///29 ///32/// Dummy resolver, can't resolve/load any file36/// Dummy resolver, can't resolve/load any file33pub struct DummyImportResolver;37pub struct DummyImportResolver;34impl ImportResolver for DummyImportResolver {38impl ImportResolver for DummyImportResolver {35 fn resolve_file(&self, from: &Path, path: &str) -> Result<PathBuf> {39 fn resolve_file_relative(&self, from: &Path, path: &str) -> Result<SourcePath> {36 throw!(ImportNotSupported(from.into(), path.into()))40 throw!(ImportNotSupported(from.into(), path.into()))37 }41 }384239 fn load_file_contents(&self, _resolved: &Path) -> Result<Vec<u8>> {43 fn load_file_contents(&self, _resolved: &SourcePath) -> Result<Vec<u8>> {40 panic!("dummy resolver can't load any file")44 panic!("dummy resolver can't load any file")41 }45 }424659 pub library_paths: Vec<PathBuf>,63 pub library_paths: Vec<PathBuf>,60}64}61impl ImportResolver for FileImportResolver {65impl ImportResolver for FileImportResolver {62 fn resolve_file(&self, from: &Path, path: &str) -> Result<PathBuf> {66 fn resolve_file_relative(&self, from: &Path, path: &str) -> Result<SourcePath> {63 let mut direct = from.to_path_buf();67 let mut direct = from.to_path_buf();64 direct.push(path);68 direct.push(path);65 if direct.exists() {69 if direct.exists() {66 Ok(direct.canonicalize().map_err(|e| ImportIo(e.to_string()))?)70 Ok(SourcePath::Path(71 direct.canonicalize().map_err(|e| ImportIo(e.to_string()))?,72 ))67 } else {73 } else {68 for library_path in &self.library_paths {74 for library_path in &self.library_paths {69 let mut cloned = library_path.clone();75 let mut cloned = library_path.clone();70 cloned.push(path);76 cloned.push(path);71 if cloned.exists() {77 if cloned.exists() {72 return Ok(cloned.canonicalize().map_err(|e| ImportIo(e.to_string()))?);78 return Ok(SourcePath::Path(79 cloned.canonicalize().map_err(|e| ImportIo(e.to_string()))?,80 ));73 }81 }74 }82 }75 throw!(ImportFileNotFound(from.to_owned(), path.to_owned()))83 throw!(ImportFileNotFound(from.to_owned(), path.to_owned()))76 }84 }77 }85 }788679 fn load_file_contents(&self, id: &Path) -> Result<Vec<u8>> {87 fn load_file_contents(&self, id: &SourcePath) -> Result<Vec<u8>> {88 let path = match id {89 SourcePath::Path(path) => path,90 _ => {91 panic!("this resolver can only resolve to path")92 }93 };80 let mut file = File::open(id).map_err(|_e| ResolvedFileNotFound(id.to_owned()))?;94 let mut file = File::open(path).map_err(|_e| ResolvedFileNotFound(id.clone()))?;81 let mut out = Vec::new();95 let mut out = Vec::new();82 file.read_to_end(&mut out)96 file.read_to_end(&mut out)83 .map_err(|e| ImportIo(e.to_string()))?;97 .map_err(|e| ImportIo(e.to_string()))?;crates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth48 cell::{Ref, RefCell, RefMut},48 cell::{Ref, RefCell, RefMut},49 collections::HashMap,49 collections::HashMap,50 fmt::{self, Debug},50 fmt::{self, Debug},51 path::{Path, PathBuf},51 path::Path,52 rc::Rc,52 rc::Rc,53};53};545465pub use jrsonnet_parser as parser;65pub use jrsonnet_parser as parser;66use jrsonnet_parser::*;66use jrsonnet_parser::*;67pub use obj::*;67pub use obj::*;68use trace::{location_to_offset, offset_to_location, CodeLocation, CompactFormat, TraceFormat};68use trace::{CompactFormat, TraceFormat};69pub use val::{ManifestFormat, Thunk, Val};69pub use val::{ManifestFormat, Thunk, Val};707071pub trait Unbound: Trace {71pub trait Unbound: Trace {170 breakpoints: Breakpoints,170 breakpoints: Breakpoints,171171172 /// Contains file source codes and evaluation results for imports and pretty-printed stacktraces172 /// Contains file source codes and evaluation results for imports and pretty-printed stacktraces173 files: GcHashMap<PathBuf, FileData>,173 files: GcHashMap<SourcePath, FileData>,174 /// Contains tla arguments and others, which aren't needed to be obtained by name, however may be used for receiving source175 /// TODO: look into nix approach, storing source code in `Source` object176 volatile_files: GcHashMap<String, String>,177}174}178struct FileData {175struct FileData {179 string: Option<IStr>,176 string: Option<IStr>,249pub struct State(Rc<EvaluationStateInternals>);246pub struct State(Rc<EvaluationStateInternals>);250247251impl State {248impl State {249 /// Should only be called with path retrieved from [`resolve_path`], may panic otherwise252 pub fn import_str(&self, path: PathBuf) -> Result<IStr> {250 pub fn import_resolved_str(&self, path: SourcePath) -> Result<IStr> {253 let mut data = self.data_mut();251 let mut data = self.data_mut();254 let mut file = data.files.raw_entry_mut().from_key(&path);252 let mut file = data.files.raw_entry_mut().from_key(&path);255253283 }281 }284 Ok(file.string.as_ref().expect("just set").clone())282 Ok(file.string.as_ref().expect("just set").clone())285 }283 }284 /// Should only be called with path retrieved from [`resolve_path`], may panic otherwise286 pub fn import_bin(&self, path: PathBuf) -> Result<IBytes> {285 pub fn import_resolved_bin(&self, path: SourcePath) -> Result<IBytes> {287 let mut data = self.data_mut();286 let mut data = self.data_mut();288 let mut file = data.files.raw_entry_mut().from_key(&path);287 let mut file = data.files.raw_entry_mut().from_key(&path);289288309 }308 }310 Ok(file.bytes.as_ref().expect("just set").clone())309 Ok(file.bytes.as_ref().expect("just set").clone())311 }310 }311 /// Should only be called with path retrieved from [`resolve_path`], may panic otherwise312 pub fn import(&self, path: PathBuf) -> Result<Val> {312 pub fn import_resolved(&self, path: SourcePath) -> Result<Val> {313 let mut data = self.data_mut();313 let mut data = self.data_mut();314 let mut file = data.files.raw_entry_mut().from_key(&path);314 let mut file = data.files.raw_entry_mut().from_key(&path);315315344 }344 }345 let code = file.string.as_ref().expect("just set");345 let code = file.string.as_ref().expect("just set");346 let file_name = Source::new(path.clone()).expect("resolver should return correct name");346 let file_name =347 Source::new(path.clone(), code.clone()).expect("resolver should return correct name");347 if file.parsed.is_none() {348 if file.parsed.is_none() {348 file.parsed = Some(349 file.parsed = Some(349 jrsonnet_parser::parse(350 jrsonnet_parser::parse(354 )355 )355 .map_err(|e| ImportSyntaxError {356 .map_err(|e| ImportSyntaxError {356 path: file_name.clone(),357 path: file_name.clone(),357 source_code: code.clone(),358 error: Box::new(e),358 error: Box::new(e),359 })?,359 })?,360 );360 );389 }389 }390 }390 }391392 pub fn get_source(&self, name: Source) -> Option<String> {391 pub fn import(&self, from: &Path, path: &str) -> Result<Val> {393 let data = self.data();392 let resolved = self.resolve_file(from, path)?;394 match name.repr() {393 self.import_resolved(resolved)395 Ok(real) => data396 .files397 .get(real)398 .and_then(|f| f.string.as_ref())399 .map(ToString::to_string),400 Err(e) => data.volatile_files.get(e).map(ToOwned::to_owned),401 }402 }394 }403 pub fn map_source_locations(&self, file: Source, locs: &[u32]) -> Vec<CodeLocation> {404 offset_to_location(&self.get_source(file).unwrap_or_else(|| "".into()), locs)405 }406 pub fn map_from_source_location(407 &self,408 file: Source,409 line: usize,410 column: usize,411 ) -> Option<usize> {412 location_to_offset(413 &self.get_source(file).expect("file not found"),414 line,415 column,416 )417 }418395419 /// Creates context with all passed global variables396 /// Creates context with all passed global variables420 pub fn create_default_context(&self, source: Source) -> Context {397 pub fn create_default_context(&self, source: Source) -> Context {555 func.evaluate(532 func.evaluate(556 self.clone(),533 self.clone(),557 self.create_default_context(Source::new_virtual(Cow::Borrowed("<tla>"))),534 self.create_default_context(Source::new_virtual(535 Cow::Borrowed("<tla>"),536 IStr::empty(),537 )),558 CallLocation::native(),538 CallLocation::native(),559 &self.settings().tla_vars,539 &self.settings().tla_vars,568548569/// Internals549/// Internals570impl State {550impl State {571 fn data(&self) -> Ref<EvaluationData> {551 // fn data(&self) -> Ref<EvaluationData> {572 self.0.data.borrow()552 // self.0.data.borrow()573 }553 // }574 fn data_mut(&self) -> RefMut<EvaluationData> {554 fn data_mut(&self) -> RefMut<EvaluationData> {575 self.0.data.borrow_mut()555 self.0.data.borrow_mut()576 }556 }585/// Raw methods evaluate passed values but don't perform TLA execution565/// Raw methods evaluate passed values but don't perform TLA execution586impl State {566impl State {587 /// Parses and evaluates the given snippet567 /// Parses and evaluates the given snippet588 pub fn evaluate_snippet(&self, name: String, code: String) -> Result<Val> {568 pub fn evaluate_snippet(&self, name: String, code: impl Into<IStr>) -> Result<Val> {569 let code = code.into();589 let source = Source::new_virtual(Cow::Owned(name.clone()));570 let source = Source::new_virtual(Cow::Owned(name), code.clone());590 let parsed = jrsonnet_parser::parse(571 let parsed = jrsonnet_parser::parse(591 &code,572 &code,592 &ParserSettings {573 &ParserSettings {595 )576 )596 .map_err(|e| ImportSyntaxError {577 .map_err(|e| ImportSyntaxError {597 path: source.clone(),578 path: source.clone(),598 source_code: code.clone().into(),599 error: Box::new(e),579 error: Box::new(e),600 })?;580 })?;601 self.data_mut().volatile_files.insert(name, code);602 evaluate(self.clone(), self.create_default_context(source), &parsed)581 evaluate(self.clone(), self.create_default_context(source), &parsed)603 }582 }604}583}617 }596 }618 pub fn add_tla_code(&self, name: IStr, code: &str) -> Result<()> {597 pub fn add_tla_code(&self, name: IStr, code: &str) -> Result<()> {619 let source_name = format!("<top-level-arg:{}>", name);598 let source_name = format!("<top-level-arg:{}>", name);620 let source = Source::new_virtual(Cow::Owned(source_name.clone()));599 let source = Source::new_virtual(Cow::Owned(source_name.clone()), code.into());621 let parsed = jrsonnet_parser::parse(600 let parsed = jrsonnet_parser::parse(622 code,601 code,623 &ParserSettings {602 &ParserSettings {626 )605 )627 .map_err(|e| ImportSyntaxError {606 .map_err(|e| ImportSyntaxError {628 path: source,607 path: source,629 source_code: code.into(),630 error: Box::new(e),608 error: Box::new(e),631 })?;609 })?;632 self.data_mut()633 .volatile_files634 .insert(source_name, code.to_owned());635 self.settings_mut()610 self.settings_mut()636 .tla_vars611 .tla_vars637 .insert(name, TlaArg::Code(parsed));612 .insert(name, TlaArg::Code(parsed));638 Ok(())613 Ok(())639 }614 }640615641 pub fn resolve_file(&self, from: &Path, path: &str) -> Result<PathBuf> {616 pub fn resolve_file(&self, from: &Path, path: &str) -> Result<SourcePath> {642 self.settings()617 self.settings()643 .import_resolver618 .import_resolver644 .resolve_file(from, path.as_ref())619 .resolve_file_relative(from, path.as_ref())645 }620 }646621647 pub fn import_resolver(&self) -> Ref<dyn ImportResolver> {622 pub fn import_resolver(&self) -> Ref<dyn ImportResolver> {crates/jrsonnet-evaluator/src/trace/location.rsdiffbeforeafterbothno changes
crates/jrsonnet-evaluator/src/trace/mod.rsdiffbeforeafterboth1mod location;23use std::path::{Path, PathBuf};1use std::path::{Path, PathBuf};425use jrsonnet_parser::Source;3use jrsonnet_parser::{CodeLocation, Source};6pub use location::*;748use crate::{error::Error, LocError, State};5use crate::{error::Error, LocError, State};9684 fn write_trace(81 fn write_trace(85 &self,82 &self,86 out: &mut dyn std::fmt::Write,83 out: &mut dyn std::fmt::Write,87 s: &State,84 _s: &State,88 error: &LocError,85 error: &LocError,89 ) -> Result<(), std::fmt::Error> {86 ) -> Result<(), std::fmt::Error> {90 write!(out, "{}", error.error())?;87 write!(out, "{}", error.error())?;91 if let Error::ImportSyntaxError {88 if let Error::ImportSyntaxError { path, error } = error.error() {92 path,93 source_code,94 error,95 } = error.error()96 {97 use std::fmt::Write;89 use std::fmt::Write;989099 writeln!(out)?;91 writeln!(out)?;100 let mut n = match path.repr() {92 let mut n = match path.path() {101 Ok(r) => self.resolver.resolve(r),93 Some(r) => self.resolver.resolve(r),102 Err(v) => v.to_string(),94 None => path.short_display().to_string(),103 };95 };104 let mut offset = error.location.offset;96 let mut offset = error.location.offset;105 let is_eof = if offset >= source_code.len() {97 let is_eof = if offset >= path.code().len() {106 offset = source_code.len().saturating_sub(1);98 offset = path.code().len().saturating_sub(1);107 true99 true108 } else {100 } else {109 false101 false110 };102 };111 let mut location = offset_to_location(source_code, &[offset as u32])103 let mut location = path104 .map_source_locations(&[offset as u32])112 .into_iter()105 .into_iter()113 .next()106 .next()114 .unwrap();107 .unwrap();129 use std::fmt::Write;122 use std::fmt::Write;130 #[allow(clippy::option_if_let_else)]123 #[allow(clippy::option_if_let_else)]131 if let Some(location) = location {124 if let Some(location) = location {132 let mut resolved_path = match location.0.repr() {125 let mut resolved_path = match location.0.path() {133 Ok(r) => self.resolver.resolve(r),126 Some(r) => self.resolver.resolve(r),134 Err(v) => v.to_string(),127 None => location.0.short_display().to_string(),135 };128 };136 // TODO: Process all trace elements first129 // TODO: Process all trace elements first137 let location =130 let location = location.0.map_source_locations(&[location.1, location.2]);138 s.map_source_locations(location.0.clone(), &[location.1, location.2]);139 write!(resolved_path, ":").unwrap();131 write!(resolved_path, ":").unwrap();140 print_code_location(&mut resolved_path, &location[0], &location[1]).unwrap();132 print_code_location(&mut resolved_path, &location[0], &location[1]).unwrap();141 write!(resolved_path, ":").unwrap();133 write!(resolved_path, ":").unwrap();176 fn write_trace(168 fn write_trace(177 &self,169 &self,178 out: &mut dyn std::fmt::Write,170 out: &mut dyn std::fmt::Write,179 s: &State,171 _s: &State,180 error: &LocError,172 error: &LocError,181 ) -> Result<(), std::fmt::Error> {173 ) -> Result<(), std::fmt::Error> {182 write!(out, "{}", error.error())?;174 write!(out, "{}", error.error())?;183 for item in &error.trace().0 {175 for item in &error.trace().0 {184 writeln!(out)?;176 writeln!(out)?;185 let desc = &item.desc;177 let desc = &item.desc;186 if let Some(source) = &item.location {178 if let Some(source) = &item.location {187 let start_end = s.map_source_locations(source.0.clone(), &[source.1, source.2]);179 let start_end = source.0.map_source_locations(&[source.1, source.2]);188 let resolved_path = match source.0.repr() {180 let resolved_path = match source.0.path() {189 Ok(r) => r.display().to_string(),181 Some(r) => r.display().to_string(),190 Err(v) => v.to_string(),182 None => source.0.short_display().to_string(),191 };183 };192184193 write!(185 write!(213 fn write_trace(205 fn write_trace(214 &self,206 &self,215 out: &mut dyn std::fmt::Write,207 out: &mut dyn std::fmt::Write,216 s: &State,208 _s: &State,217 error: &LocError,209 error: &LocError,218 ) -> Result<(), std::fmt::Error> {210 ) -> Result<(), std::fmt::Error> {219 write!(out, "{}", error.error())?;211 write!(out, "{}", error.error())?;220 if let Error::ImportSyntaxError {212 if let Error::ImportSyntaxError { path, error } = error.error() {221 path,222 source_code,223 error,224 } = error.error()225 {226 writeln!(out)?;213 writeln!(out)?;227 let offset = error.location.offset;214 let offset = error.location.offset;228 let location = offset_to_location(source_code, &[offset as u32])215 let location = path216 .map_source_locations(&[offset as u32])229 .into_iter()217 .into_iter()230 .next()218 .next()231 .unwrap();219 .unwrap();234222235 self.print_snippet(223 self.print_snippet(236 out,224 out,237 source_code,225 path.code(),238 path,226 path,239 &location,227 &location,240 &end_location,228 &end_location,246 writeln!(out)?;234 writeln!(out)?;247 let desc = &item.desc;235 let desc = &item.desc;248 if let Some(source) = &item.location {236 if let Some(source) = &item.location {249 let start_end = s.map_source_locations(source.0.clone(), &[source.1, source.2]);237 let start_end = source.0.map_source_locations(&[source.1, source.2]);250 self.print_snippet(238 self.print_snippet(251 out,239 out,252 &s.get_source(source.0.clone()).unwrap(),240 &source.0.code(),253 &source.0,241 &source.0,254 &start_end[0],242 &start_end[0],255 &start_end[1],243 &start_end[1],284 .take(end.line_end_offset - end.line_start_offset)272 .take(end.line_end_offset - end.line_start_offset)285 .collect();273 .collect();286274287 let origin = match origin.repr() {275 let origin = match origin.path() {288 Ok(r) => self.resolver.resolve(r),276 Some(r) => self.resolver.resolve(r),289 Err(v) => v.to_string(),277 None => origin.short_display().to_string(),290 };278 };291 let snippet = Snippet {279 let snippet = Snippet {292 opt: FormatOptions {280 opt: FormatOptions {crates/jrsonnet-interner/src/lib.rsdiffbeforeafterboth32}32}333334impl IStr {34impl IStr {35 #[must_use]36 pub fn empty() -> Self {37 "".into()38 }35 #[must_use]39 #[must_use]36 pub fn as_str(&self) -> &str {40 pub fn as_str(&self) -> &str {37 self as &str41 self as &strcrates/jrsonnet-parser/src/lib.rsdiffbeforeafterboth7pub use expr::*;7pub use expr::*;8pub use jrsonnet_interner::IStr;8pub use jrsonnet_interner::IStr;9pub use peg;9pub use peg;10mod location;10mod source;11mod source;11mod unescape;12mod unescape;13pub use location::CodeLocation;12pub use source::Source;14pub use source::{Source, SourcePath};131514pub struct ParserSettings {16pub struct ParserSettings {15 pub file_name: Source,17 pub file_name: Source,crates/jrsonnet-parser/src/location.rsdiffbeforeafterbothno changes
crates/jrsonnet-parser/src/source.rsdiffbeforeafterboth6};6};778use jrsonnet_gcmodule::{Trace, Tracer};8use jrsonnet_gcmodule::{Trace, Tracer};9use jrsonnet_interner::IStr;9#[cfg(feature = "serde")]10#[cfg(feature = "serde")]10use serde::{Deserialize, Serialize};11use serde::{Deserialize, Serialize};1213use crate::location::{location_to_offset, offset_to_location, CodeLocation};111412#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]15#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]13#[derive(PartialEq, Eq, Debug, Hash)]16#[derive(PartialEq, Eq, Debug, Hash, Clone)]14enum Inner {17pub enum SourcePath {18 /// This file is located on disk15 Real(PathBuf),19 Path(PathBuf),20 /// This file is located somewhere else (I.e http), but it can refer to relative paths, and is egilible for caching21 Custom(String),22 /// This file is only located in memory, and can't be cached16 Virtual(Cow<'static, str>),23 Virtual(Cow<'static, str>),17}24}25impl Trace for SourcePath {26 fn trace(&self, _tracer: &mut Tracer) {}2728 fn is_type_tracked() -> bool {29 false30 }31}3233impl SourcePath {34 /// Should import resolver be able to read file by this path?35 pub fn can_load(&self) -> bool {36 matches!(self, Self::Path(_) | Self::Custom(_))37 }38}183919/// Either real file, or virtual40/// Either real file, or virtual20/// Hash of FileName always have same value as raw Path, to make it possible to use with raw_entry_mut41/// Hash of FileName always have same value as raw Path, to make it possible to use with raw_entry_mut21#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]42#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]22#[derive(Clone, PartialEq, Eq, Debug)]43#[derive(Clone, PartialEq, Eq, Debug)]23pub struct Source(Rc<Inner>);44pub struct Source(Rc<(SourcePath, IStr)>);24static_assertions::assert_eq_size!(Source, *const ());45static_assertions::assert_eq_size!(Source, *const ());254626impl Trace for Source {47impl Trace for Source {335434impl Source {55impl Source {35 /// Fails when path contains inner /../ or /./ references, or not absolute56 /// Fails when path contains inner /../ or /./ references, or not absolute36 pub fn new(path: PathBuf) -> Option<Self> {57 pub fn new(path: SourcePath, code: IStr) -> Option<Self> {58 if let SourcePath::Path(path) = &path {37 if !path.is_absolute()59 if !path.is_absolute()38 || path60 || path39 .components()61 .components()40 .any(|c| matches!(c, Component::CurDir | Component::ParentDir))62 .any(|c| matches!(c, Component::CurDir | Component::ParentDir))41 {63 {42 return None;64 return None;43 }65 }66 }44 Some(Self(Rc::new(Inner::Real(path))))67 Some(Self(Rc::new((path, code))))45 }68 }466947 pub fn new_virtual(n: Cow<'static, str>) -> Self {70 pub fn new_virtual(n: Cow<'static, str>, code: IStr) -> Self {48 Self(Rc::new(Inner::Virtual(n)))71 Self(Rc::new((SourcePath::Virtual(n), code)))49 }72 }507351 pub fn short_display(&self) -> ShortDisplay {74 pub fn short_display(&self) -> ShortDisplay {52 ShortDisplay(self.clone())75 ShortDisplay(self.clone())53 }76 }547755 /// Returns None if file is virtual78 /// Returns Some if this file is loaded from FS56 pub fn path(&self) -> Option<&Path> {79 pub fn path(&self) -> Option<&Path> {57 match self.inner() {80 match self.source_path() {58 Inner::Real(r) => Some(r),81 SourcePath::Path(r) => Some(r),82 SourcePath::Custom(_) => None,59 Inner::Virtual(_) => None,83 SourcePath::Virtual(_) => None,60 }84 }61 }85 }62 pub fn repr(&self) -> Result<&Path, &str> {86 pub fn code(&self) -> &str {87 &self.0 .188 }8990 pub fn source_path(&self) -> &SourcePath {91 &self.0 .0 as &SourcePath92 }9363 match self.inner() {94 pub fn map_source_locations(&self, locs: &[u32]) -> Vec<CodeLocation> {64 Inner::Real(r) => Ok(r),65 Inner::Virtual(v) => Err(v.as_ref()),95 offset_to_location(&self.0 .1, locs)66 }96 }67 }6869 fn inner(&self) -> &Inner {97 pub fn map_from_source_location(&self, line: usize, column: usize) -> Option<usize> {70 &self.0 as &Inner98 location_to_offset(&self.0 .1, line, column)71 }99 }72}100}73pub struct ShortDisplay(Source);101pub struct ShortDisplay(Source);74impl fmt::Display for ShortDisplay {102impl fmt::Display for ShortDisplay {75 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {103 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {76 match &self.0 .0 as &Inner {104 match &self.0 .0 .0 as &SourcePath {77 Inner::Real(r) => {105 SourcePath::Path(r) => {78 write!(106 write!(79 f,107 f,80 "{}",108 "{}",81 r.file_name().expect("path is valid").to_string_lossy()109 r.file_name().expect("path is valid").to_string_lossy()82 )110 )83 }111 }112 SourcePath::Custom(r) => write!(f, "{}", r),84 Inner::Virtual(n) => write!(f, "{}", n),113 SourcePath::Virtual(n) => write!(f, "{}", n),85 }114 }86 }115 }87}116}crates/jrsonnet-stdlib/build.rsdiffbeforeafterboth8 include_str!("./src/std.jsonnet"),8 include_str!("./src/std.jsonnet"),9 &ParserSettings {9 &ParserSettings {10 file_name: Source::new_virtual(Cow::Borrowed("<std>")),10 file_name: Source::new_virtual(11 Cow::Borrowed("<std>"),12 include_str!("./src/std.jsonnet").into(),13 ),11 },14 },12 )15 )crates/jrsonnet-stdlib/src/expr.rsdiffbeforeafterboth15 jrsonnet_parser::parse(15 jrsonnet_parser::parse(16 STDLIB_STR,16 STDLIB_STR,17 &ParserSettings {17 &ParserSettings {18 file_name: Source::new_virtual(Cow::Borrowed("<std>")),18 file_name: Source::new_virtual(Cow::Borrowed("<std>"), STDLIB_STR.into()),19 },19 },20 )20 )21 .unwrap()21 .unwrap()crates/jrsonnet-stdlib/src/lib.rsdiffbeforeafterboth183183184pub struct StdTracePrinter;184pub struct StdTracePrinter;185impl TracePrinter for StdTracePrinter {185impl TracePrinter for StdTracePrinter {186 fn print_trace(&self, s: State, loc: CallLocation, value: IStr) {186 fn print_trace(&self, _s: State, loc: CallLocation, value: IStr) {187 eprint!("TRACE:");187 eprint!("TRACE:");188 if let Some(loc) = loc.0 {188 if let Some(loc) = loc.0 {189 let locs = s.map_source_locations(loc.0.clone(), &[loc.1]);189 let locs = loc.0.map_source_locations(&[loc.1]);190 eprint!(" {}:{}", loc.0.short_display(), locs[0].line);190 eprint!(" {}:{}", loc.0.short_display(), locs[0].line);191 }191 }192 eprintln!(" {}", value);192 eprintln!(" {}", value);212 }212 }213}213}214214215pub fn extvar_source(name: &str) -> Source {215pub fn extvar_source(name: &str, code: impl Into<IStr>) -> Source {216 let source_name = format!("<extvar:{}>", name);216 let source_name = format!("<extvar:{}>", name);217 Source::new_virtual(Cow::Owned(source_name))217 Source::new_virtual(Cow::Owned(source_name), code.into())218}218}219219220pub struct ContextInitializer {220pub struct ContextInitializer {260 .ext_vars260 .ext_vars261 .insert(name, TlaArg::String(value));261 .insert(name, TlaArg::String(value));262 }262 }263 pub fn add_ext_code(&self, name: &str, code: String) -> Result<()> {263 pub fn add_ext_code(&self, name: &str, code: impl Into<IStr>) -> Result<()> {264 let code = code.into();264 let source = extvar_source(name);265 let source = extvar_source(name, code.clone());265 let parsed = jrsonnet_parser::parse(266 let parsed = jrsonnet_parser::parse(266 &code,267 &code,267 &jrsonnet_parser::ParserSettings {268 &jrsonnet_parser::ParserSettings {270 )271 )271 .map_err(|e| ImportSyntaxError {272 .map_err(|e| ImportSyntaxError {272 path: source,273 path: source,273 source_code: code.clone().into(),274 error: Box::new(e),274 error: Box::new(e),275 })?;275 })?;276 // self.data_mut().volatile_files.insert(source_name, code);276 // self.data_mut().volatile_files.insert(source_name, code);297 .hide()297 .hide()298 .value(298 .value(299 s,299 s,300 Val::Str(match source.repr() {300 Val::Str(301 source302 .path()301 Ok(p) => p.display().to_string().into(),303 .map(|p| p.display().to_string())302 // Virtual files end up as empty strings in std.thisFile304 .unwrap_or_else(String::new)303 Err(_e) => "".into(),305 .into(),304 }),306 ),305 )307 )306 .expect("this object builder is empty");308 .expect("this object builder is empty");307 let stdlib_with_this_file = builder.build();309 let stdlib_with_this_file = builder.build();343 settings: Rc<RefCell<Settings>>,345 settings: Rc<RefCell<Settings>>,344))]346))]345fn builtin_ext_var(this: &builtin_ext_var, s: State, x: IStr) -> Result<Any> {347fn builtin_ext_var(this: &builtin_ext_var, s: State, x: IStr) -> Result<Any> {346 let ctx = s.create_default_context(extvar_source(&x));348 let ctx = s.create_default_context(extvar_source(&x, ""));347 Ok(Any(this349 Ok(Any(this348 .settings350 .settings349 .borrow()351 .borrow()