difftreelog
feat(ir) source url
in: master
7 files changed
crates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/lib.rs
+++ b/crates/jrsonnet-evaluator/src/lib.rs
@@ -35,14 +35,14 @@
pub use ctx::*;
pub use dynamic::*;
-pub use error::{Error, ErrorKind::*, Result, ResultExt};
+pub use error::{Error, ErrorKind::*, Result, ResultExt, StackTraceElement};
pub use evaluate::ensure_sufficient_stack;
use function::CallLocation;
pub use import::*;
use jrsonnet_gcmodule::{Cc, Trace, cc_dyn};
pub use jrsonnet_interner::{IBytes, IStr};
use jrsonnet_ir::Expr;
-pub use jrsonnet_ir::{NumValue, Source, SourcePath, Span};
+pub use jrsonnet_ir::{NumValue, Source, SourcePath, SourceUrl, SourceVirtual, Span};
#[doc(hidden)]
pub use jrsonnet_macros;
@@ -396,9 +396,17 @@
file.parsed = Some(
parse_jsonnet(&code, file_name.clone())
.map(Rc::new)
- .map_err(|e| ImportSyntaxError {
- path: file_name.clone(),
- error: Box::new(e),
+ .map_err(|e| {
+ let span = e.location.clone();
+ let mut err = Error::from(ImportSyntaxError {
+ path: file_name.clone(),
+ error: Box::new(e),
+ });
+ err.trace_mut().0.push(StackTraceElement {
+ location: Some(span),
+ desc: "parse imported".to_string(),
+ });
+ err
})?,
);
}
crates/jrsonnet-evaluator/src/trace/mod.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/trace/mod.rs
+++ b/crates/jrsonnet-evaluator/src/trace/mod.rs
@@ -82,18 +82,24 @@
) -> Result<(), std::fmt::Error> {
if start.line == end.line {
if start.column == end.column {
- write!(out, "{}:{}", start.line, end.column.saturating_sub(1))?;
+ write!(out, "{}:{}", start.line, start.column)?;
} else {
- write!(out, "{}:{}-{}", start.line, start.column - 1, end.column)?;
+ write!(
+ out,
+ "{}:{}-{}",
+ start.line,
+ start.column,
+ end.column.saturating_sub(1)
+ )?;
}
} else {
write!(
out,
"{}:{}-{}:{}",
- start.line,
- end.column.saturating_sub(1),
start.line,
- end.column
+ start.column,
+ end.line,
+ end.column.saturating_sub(1)
)?;
}
Ok(())
@@ -131,22 +137,13 @@
|| path.source_path().to_string(),
|r| self.resolver.resolve(r),
);
- let mut offset = error.location.1 as usize;
- let is_eof = if offset >= path.code().len() {
- offset = path.code().len().saturating_sub(1);
- true
- } else {
- false
- };
+ let offset = (error.location.1 as usize).min(path.code().len());
#[expect(clippy::cast_possible_truncation, reason = "code is limited by 4gb")]
- let mut location = path
+ let location = path
.map_source_locations(&[offset as u32])
.into_iter()
.next()
.unwrap();
- if is_eof {
- location.column += 1;
- }
write!(n, ":").unwrap();
print_code_location(&mut n, &location, &location).unwrap();
crates/jrsonnet-formatter/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-formatter/src/lib.rs
+++ b/crates/jrsonnet-formatter/src/lib.rs
@@ -895,10 +895,16 @@
}
}
+#[derive(Default)]
pub struct FormatOptions {
// 0 for hard tabs, otherwise number of spaces
pub indent: u8,
}
+impl FormatOptions {
+ pub fn new() -> Self {
+ Self::default()
+ }
+}
#[allow(
clippy::result_large_err,
crates/jrsonnet-ir-parser/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-ir-parser/src/lib.rs
+++ b/crates/jrsonnet-ir-parser/src/lib.rs
@@ -220,10 +220,7 @@
fn ident(p: &mut Parser<'_>) -> Result<IStr> {
if !p.at(SyntaxKind::IDENT) {
- return Err(p.error(format!(
- "expected identifier, got {}",
- p.current_desc()
- )));
+ return Err(p.error(format!("expected identifier, got {}", p.current_desc())));
}
let text = p.text();
p.eat_any();
crates/jrsonnet-ir/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-ir/src/lib.rs
+++ b/crates/jrsonnet-ir/src/lib.rs
@@ -15,7 +15,7 @@
pub use location::CodeLocation;
pub use source::{
Source, SourceDefaultIgnoreJpath, SourceDirectory, SourceFifo, SourceFile, SourcePath,
- SourcePathT, SourceVirtual,
+ SourcePathT, SourceUrl, SourceVirtual,
};
// It seels to be a wrong place for this kind of stuff, but as it would also be used for static analysis and
crates/jrsonnet-ir/src/location.rsdiffbeforeafterboth1#[allow(clippy::module_name_repetitions)]2#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]3pub struct CodeLocation {4 pub offset: usize,56 pub line: usize,7 pub column: usize,89 pub line_start_offset: usize,10 pub line_end_offset: usize,11}1213#[allow(clippy::module_name_repetitions)]14pub fn location_to_offset(mut file: &str, mut line: usize, column: usize) -> Option<usize> {15 let mut offset = 0;16 while line > 1 {17 let pos = file.find('\n')?;18 offset += pos + 1;19 file = &file[pos + 1..];20 line -= 1;21 }22 offset += column - 1;23 Some(offset)24}2526#[allow(clippy::module_name_repetitions)]27pub fn offset_to_location<const S: usize>(file: &str, offsets: &[u32; S]) -> [CodeLocation; S] {28 if offsets.is_empty() {29 return [CodeLocation::default(); S];30 }31 let mut line = 1;32 let mut column = 1;33 let max_offset = *offsets.iter().max().expect("offsets is not empty");3435 let mut offset_map = offsets36 .iter()37 .enumerate()38 .map(|(pos, offset)| (*offset, pos))39 .collect::<Vec<_>>();40 offset_map.sort_by_key(|v| v.0);41 offset_map.reverse();4243 let mut out = [CodeLocation::default(); S];44 let mut with_no_known_line_ending = vec![];45 let mut this_line_offset = 0;46 for (pos, ch) in file47 .chars()48 .enumerate()49 .chain(std::iter::once((file.len(), ' ')))50 {51 column += 1;52 match offset_map.last() {53 Some(x) if x.0 == pos as u32 => {54 let out_idx = x.1;55 with_no_known_line_ending.push(out_idx);56 out[out_idx].offset = pos;57 out[out_idx].line = line;58 out[out_idx].column = column;59 out[out_idx].line_start_offset = this_line_offset;60 offset_map.pop();61 }62 _ => {}63 }64 if ch == '\n' {65 line += 1;66 column = 1;6768 for idx in with_no_known_line_ending.drain(..) {69 out[idx].line_end_offset = pos;70 }71 this_line_offset = pos + 1;7273 if pos == max_offset as usize + 1 {74 break;75 }76 }77 }78 let file_end = file.chars().count();79 for idx in with_no_known_line_ending {80 out[idx].line_end_offset = file_end;81 }8283 out84}8586#[cfg(test)]87pub mod tests {88 use super::{CodeLocation, offset_to_location};8990 #[test]91 fn test() {92 assert_eq!(93 offset_to_location(94 "hello world\n_______________________________________________________",95 &[0, 14]96 ),97 [98 CodeLocation {99 offset: 0,100 line: 1,101 column: 2,102 line_start_offset: 0,103 line_end_offset: 11,104 },105 CodeLocation {106 offset: 14,107 line: 2,108 column: 4,109 line_start_offset: 12,110 line_end_offset: 67111 }112 ]113 )114 }115}1#[allow(clippy::module_name_repetitions)]2#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]3pub struct CodeLocation {4 pub offset: usize,56 pub line: usize,7 pub column: usize,89 pub line_start_offset: usize,10 pub line_end_offset: usize,11}1213#[allow(clippy::module_name_repetitions)]14pub fn location_to_offset(mut file: &str, mut line: usize, column: usize) -> Option<usize> {15 let mut offset = 0;16 while line > 1 {17 let pos = file.find('\n')?;18 offset += pos + 1;19 file = &file[pos + 1..];20 line -= 1;21 }22 offset += column - 1;23 Some(offset)24}2526#[allow(clippy::module_name_repetitions)]27pub fn offset_to_location<const S: usize>(file: &str, offsets: &[u32; S]) -> [CodeLocation; S] {28 if offsets.is_empty() {29 return [CodeLocation::default(); S];30 }31 let mut line = 1;32 let mut column = 0;33 let max_offset = *offsets.iter().max().expect("offsets is not empty");3435 let mut offset_map = offsets36 .iter()37 .enumerate()38 .map(|(pos, offset)| (*offset, pos))39 .collect::<Vec<_>>();40 offset_map.sort_by_key(|v| v.0);41 offset_map.reverse();4243 let mut out = [CodeLocation::default(); S];44 let mut with_no_known_line_ending = vec![];45 let mut this_line_offset = 0;46 for (pos, ch) in file47 .chars()48 .enumerate()49 .chain(std::iter::once((file.len(), ' ')))50 {51 column += 1;52 match offset_map.last() {53 Some(x) if x.0 == pos as u32 => {54 let out_idx = x.1;55 with_no_known_line_ending.push(out_idx);56 out[out_idx].offset = pos;57 out[out_idx].line = line;58 out[out_idx].column = column;59 out[out_idx].line_start_offset = this_line_offset;60 offset_map.pop();61 }62 _ => {}63 }64 if ch == '\n' {65 line += 1;66 column = 0;6768 for idx in with_no_known_line_ending.drain(..) {69 out[idx].line_end_offset = pos;70 }71 this_line_offset = pos + 1;7273 if pos == max_offset as usize + 1 {74 break;75 }76 }77 }78 let file_end = file.chars().count();79 for idx in with_no_known_line_ending {80 out[idx].line_end_offset = file_end;81 }8283 out84}8586#[cfg(test)]87pub mod tests {88 use super::{CodeLocation, offset_to_location};8990 #[test]91 fn test() {92 assert_eq!(93 offset_to_location(94 "hello world\n_______________________________________________________",95 &[0, 14]96 ),97 [98 CodeLocation {99 offset: 0,100 line: 1,101 column: 1,102 line_start_offset: 0,103 line_end_offset: 11,104 },105 CodeLocation {106 offset: 14,107 line: 2,108 column: 3,109 line_start_offset: 12,110 line_end_offset: 67111 }112 ]113 )114 }115}crates/jrsonnet-ir/src/source.rsdiffbeforeafterboth--- a/crates/jrsonnet-ir/src/source.rs
+++ b/crates/jrsonnet-ir/src/source.rs
@@ -8,6 +8,7 @@
use jrsonnet_gcmodule::Acyclic;
use jrsonnet_interner::{IBytes, IStr};
+use url::Url;
use crate::location::{CodeLocation, location_to_offset, offset_to_location};
@@ -186,6 +187,28 @@
any_ext_impl!(SourcePathT);
}
+#[derive(Acyclic, Hash, PartialEq, Eq, Debug)]
+pub struct SourceUrl(Url);
+impl SourceUrl {
+ pub fn new(url: Url) -> Self {
+ Self(url)
+ }
+}
+impl Display for SourceUrl {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{}", self.0)
+ }
+}
+impl SourcePathT for SourceUrl {
+ fn is_default(&self) -> bool {
+ false
+ }
+ fn path(&self) -> Option<&Path> {
+ None
+ }
+ any_ext_impl!(SourcePathT);
+}
+
/// Represents path to the directory on the disk
///
/// See also [`SourceFile`]