git.delta.rocks / jrsonnet / refs/commits / 4ad9956e5f9b

difftreelog

refactor keep source code alongside source path

Yaroslav Bolyukin2022-08-05parent: #68c8ac0.patch.diff
in: master

18 files changed

modifiedbindings/jsonnet/src/import.rsdiffbeforeafterboth
16 error::{Error::*, Result},16 error::{Error::*, Result},
17 throw, ImportResolver, State,17 throw, ImportResolver, State,
18};18};
19use jrsonnet_parser::SourcePath;
1920
20pub 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 }
6263
63 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 }
7475
75 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 }
8081
108 }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()))?;
modifiedbindings/jsonnet/src/lib.rsdiffbeforeafterboth
1010
11use 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};
1717
18use 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 vm
115 .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 vm
144 .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 vm
189 .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 vm
216 .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 vm
259 .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 vm
286 .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))
modifiedbindings/jsonnet/src/vars_tlas.rsdiffbeforeafterboth
32 .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/// # Safety
modifiedcmds/jrsonnet/src/main.rsdiffbeforeafterboth
133133
134 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(&current_dir().expect("cwd"), &input)?)?143 s.import(&current_dir().expect("cwd"), &input)?
144 };144 };
145145
146 let val = s.with_tla(val)?;146 let val = s.with_tla(val)?;
modifiedcrates/jrsonnet-cli/src/stdlib.rsdiffbeforeafterboth
118 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(())
modifiedcrates/jrsonnet-evaluator/src/error.rsdiffbeforeafterboth
22
3use 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;
88
138138
139 #[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 },
modifiedcrates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth
416 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 }
modifiedcrates/jrsonnet-evaluator/src/import.rsdiffbeforeafterboth
6};6};
77
8use fs::File;8use fs::File;
9use jrsonnet_parser::SourcePath;
910
10use 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 correspond
18 /// 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>;
2122
23 /// Load resolved file
24 /// 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>>;
2327
24 /// # Safety28 /// # Safety
25 ///29 ///
32/// Dummy resolver, can't resolve/load any file36/// Dummy resolver, can't resolve/load any file
33pub 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 }
3842
39 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 }
4246
59 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 }
7886
79 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()))?;
modifiedcrates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth
48 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};
5454
65pub 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};
7070
71pub trait Unbound: Trace {71pub trait Unbound: Trace {
170 breakpoints: Breakpoints,170 breakpoints: Breakpoints,
171171
172 /// 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 stacktraces
173 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 source
175 /// TODO: look into nix approach, storing source code in `Source` object
176 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>);
250247
251impl State {248impl State {
249 /// Should only be called with path retrieved from [`resolve_path`], may panic otherwise
252 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);
255253
283 }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 otherwise
286 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);
289288
309 }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 otherwise
312 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);
315315
344 }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 }
391
392 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) => data
396 .files
397 .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 }
418395
419 /// Creates context with all passed global variables396 /// Creates context with all passed global variables
420 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,
568548
569/// Internals549/// Internals
570impl 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 execution
586impl State {566impl State {
587 /// Parses and evaluates the given snippet567 /// Parses and evaluates the given snippet
588 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_files
634 .insert(source_name, code.to_owned());
635 self.settings_mut()610 self.settings_mut()
636 .tla_vars611 .tla_vars
637 .insert(name, TlaArg::Code(parsed));612 .insert(name, TlaArg::Code(parsed));
638 Ok(())613 Ok(())
639 }614 }
640615
641 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_resolver
644 .resolve_file(from, path.as_ref())619 .resolve_file_relative(from, path.as_ref())
645 }620 }
646621
647 pub fn import_resolver(&self) -> Ref<dyn ImportResolver> {622 pub fn import_resolver(&self) -> Ref<dyn ImportResolver> {
deletedcrates/jrsonnet-evaluator/src/trace/location.rsdiffbeforeafterboth

no changes

modifiedcrates/jrsonnet-evaluator/src/trace/mod.rsdiffbeforeafterboth
1mod location;
2
3use std::path::{Path, PathBuf};1use std::path::{Path, PathBuf};
42
5use jrsonnet_parser::Source;3use jrsonnet_parser::{CodeLocation, Source};
6pub use location::*;
74
8use crate::{error::Error, LocError, State};5use crate::{error::Error, LocError, State};
96
84 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;
9890
99 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 true
108 } else {100 } else {
109 false101 false
110 };102 };
111 let mut location = offset_to_location(source_code, &[offset as u32])103 let mut location = path
104 .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 first
137 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 };
192184
193 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 = path
216 .map_source_locations(&[offset as u32])
229 .into_iter()217 .into_iter()
230 .next()218 .next()
231 .unwrap();219 .unwrap();
234222
235 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();
286274
287 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 {
modifiedcrates/jrsonnet-interner/src/lib.rsdiffbeforeafterboth
32}32}
3333
34impl 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 &str
modifiedcrates/jrsonnet-parser/src/lib.rsdiffbeforeafterboth
7pub 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};
1315
14pub struct ParserSettings {16pub struct ParserSettings {
15 pub file_name: Source,17 pub file_name: Source,
addedcrates/jrsonnet-parser/src/location.rsdiffbeforeafterboth

no changes

modifiedcrates/jrsonnet-parser/src/source.rsdiffbeforeafterboth
6};6};
77
8use 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};
12
13use crate::location::{location_to_offset, offset_to_location, CodeLocation};
1114
12#[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 disk
15 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 caching
21 Custom(String),
22 /// This file is only located in memory, and can't be cached
16 Virtual(Cow<'static, str>),23 Virtual(Cow<'static, str>),
17}24}
25impl Trace for SourcePath {
26 fn trace(&self, _tracer: &mut Tracer) {}
27
28 fn is_type_tracked() -> bool {
29 false
30 }
31}
32
33impl 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}
1839
19/// Either real file, or virtual40/// Either real file, or virtual
20/// 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_mut
21#[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 ());
2546
26impl Trace for Source {47impl Trace for Source {
3354
34impl Source {55impl Source {
35 /// Fails when path contains inner /../ or /./ references, or not absolute56 /// Fails when path contains inner /../ or /./ references, or not absolute
36 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 || path
39 .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 }
4669
47 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 }
5073
51 pub fn short_display(&self) -> ShortDisplay {74 pub fn short_display(&self) -> ShortDisplay {
52 ShortDisplay(self.clone())75 ShortDisplay(self.clone())
53 }76 }
5477
55 /// Returns None if file is virtual78 /// Returns Some if this file is loaded from FS
56 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 .1
88 }
89
90 pub fn source_path(&self) -> &SourcePath {
91 &self.0 .0 as &SourcePath
92 }
93
63 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 }
68
69 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}
modifiedcrates/jrsonnet-stdlib/build.rsdiffbeforeafterboth
8 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 )
modifiedcrates/jrsonnet-stdlib/src/expr.rsdiffbeforeafterboth
15 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()
modifiedcrates/jrsonnet-stdlib/src/lib.rsdiffbeforeafterboth
183183
184pub 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}
214214
215pub 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}
219219
220pub struct ContextInitializer {220pub struct ContextInitializer {
260 .ext_vars260 .ext_vars
261 .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 source
302 .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(this
348 .settings350 .settings
349 .borrow()351 .borrow()