git.delta.rocks / jrsonnet / refs/commits / 0374cd028e16

difftreelog

refactor virtual file handling

Yaroslav Bolyukin2022-05-26parent: #c11576e.patch.diff
in: master

4 files changed

modifiedcrates/jrsonnet-parser/Cargo.tomldiffbeforeafterboth
--- a/crates/jrsonnet-parser/Cargo.toml
+++ b/crates/jrsonnet-parser/Cargo.toml
@@ -11,6 +11,7 @@
 
 [dependencies]
 jrsonnet-interner = { path = "../jrsonnet-interner", version = "0.4.2" }
+static_assertions = "1.1.0"
 
 peg = "0.8.0"
 
modifiedcrates/jrsonnet-parser/src/expr.rsdiffbeforeafterboth
1use std::{1use std::{
2 fmt::{Debug, Display},2 fmt::{self, Debug, Display},
3 ops::Deref,3 ops::Deref,
4 path::{Path, PathBuf},
5 rc::Rc,4 rc::Rc,
6};5};
76
10#[cfg(feature = "serde")]9#[cfg(feature = "serde")]
11use serde::{Deserialize, Serialize};10use serde::{Deserialize, Serialize};
11
12use crate::source::Source;
1213
13#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]14#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
14#[derive(Debug, PartialEq, Trace)]15#[derive(Debug, PartialEq, Trace)]
68}69}
6970
70impl Display for UnaryOpType {71impl Display for UnaryOpType {
71 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {72 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72 use UnaryOpType::*;73 use UnaryOpType::*;
73 write!(74 write!(
74 f,75 f,
118}119}
119120
120impl Display for BinaryOpType {121impl Display for BinaryOpType {
121 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {122 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122 use BinaryOpType::*;123 use BinaryOpType::*;
123 write!(124 write!(
124 f,125 f,
326 LocalExpr(Vec<BindSpec>, LocExpr),327 LocalExpr(Vec<BindSpec>, LocExpr),
327328
328 /// import "hello"329 /// import "hello"
329 Import(PathBuf),330 Import(IStr),
330 /// importStr "file.txt"331 /// importStr "file.txt"
331 ImportStr(PathBuf),332 ImportStr(IStr),
332 /// importBin "file.txt"333 /// importBin "file.txt"
333 ImportBin(PathBuf),334 ImportBin(IStr),
334 /// error "I'm broken"335 /// error "I'm broken"
335 ErrorStmt(LocExpr),336 ErrorStmt(LocExpr),
336 /// a(b, c)337 /// a(b, c)
358#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]359#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
359#[derive(Clone, PartialEq, Trace)]360#[derive(Clone, PartialEq, Trace)]
360#[skip_trace]361#[skip_trace]
362#[repr(C)]
361pub struct ExprLocation(pub Rc<Path>, pub usize, pub usize);363pub struct ExprLocation(pub Source, pub u32, pub u32);
362impl ExprLocation {364impl ExprLocation {
363 pub fn belongs_to(&self, other: &ExprLocation) -> bool {365 pub fn belongs_to(&self, other: &ExprLocation) -> bool {
364 other.0 == self.0 && other.1 <= self.1 && other.2 >= self.2366 other.0 == self.0 && other.1 <= self.1 && other.2 >= self.2
365 }367 }
366}368}
369
370#[cfg(target_pointer_width = "64")]
371static_assertions::assert_eq_size!(ExprLocation, [u8; 16]);
367372
368impl Debug for ExprLocation {373impl Debug for ExprLocation {
369 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {374 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
370 write!(f, "{:?}:{:?}-{:?}", self.0, self.1, self.2)375 write!(f, "{:?}:{:?}-{:?}", self.0, self.1, self.2)
371 }376 }
372}377}
376#[derive(Clone, PartialEq, Trace)]381#[derive(Clone, PartialEq, Trace)]
377pub struct LocExpr(pub Rc<Expr>, pub ExprLocation);382pub struct LocExpr(pub Rc<Expr>, pub ExprLocation);
383
384#[cfg(target_pointer_width = "64")]
385static_assertions::assert_eq_size!(LocExpr, [u8; 24]);
378386
379impl Debug for LocExpr {387impl Debug for LocExpr {
380 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {388 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
381 if f.alternate() {389 if f.alternate() {
382 write!(f, "{:#?}", self.0)?;390 write!(f, "{:#?}", self.0)?;
383 } else {391 } else {
modifiedcrates/jrsonnet-parser/src/lib.rsdiffbeforeafterboth
--- a/crates/jrsonnet-parser/src/lib.rs
+++ b/crates/jrsonnet-parser/src/lib.rs
@@ -1,19 +1,18 @@
 #![allow(clippy::redundant_closure_call)]
 
-use std::{
-	path::{Path, PathBuf},
-	rc::Rc,
-};
+use std::rc::Rc;
 
 use peg::parser;
 mod expr;
 pub use expr::*;
 pub use jrsonnet_interner::IStr;
 pub use peg;
+mod source;
 mod unescape;
+pub use source::Source;
 
 pub struct ParserSettings {
-	pub file_name: Rc<Path>,
+	pub file_name: Source,
 }
 
 macro_rules! expr_bin {
@@ -232,7 +231,7 @@
 		pub rule var_expr(s: &ParserSettings) -> Expr
 			= n:id() { expr::Expr::Var(n) }
 		pub rule id_loc(s: &ParserSettings) -> LocExpr
-			= a:position!() n:id() b:position!() { LocExpr(Rc::new(expr::Expr::Str(n)), ExprLocation(s.file_name.clone(), a,b)) }
+			= a:position!() n:id() b:position!() { LocExpr(Rc::new(expr::Expr::Str(n)), ExprLocation(s.file_name.clone(), a as u32,b as u32)) }
 		pub rule if_then_else_expr(s: &ParserSettings) -> Expr
 			= cond:ifspec(s) _ keyword("then") _ cond_then:expr(s) cond_else:(_ keyword("else") _ e:expr(s) {e})? {Expr::IfElse{
 				cond,
@@ -263,9 +262,9 @@
 			/ array_expr(s)
 			/ array_comp_expr(s)
 
-			/ keyword("importstr") _ path:string() {Expr::ImportStr(PathBuf::from(path))}
-			/ keyword("importbin") _ path:string() {Expr::ImportBin(PathBuf::from(path))}
-			/ keyword("import") _ path:string() {Expr::Import(PathBuf::from(path))}
+			/ keyword("importstr") _ path:string() {Expr::ImportStr(path.into())}
+			/ keyword("importbin") _ path:string() {Expr::ImportBin(path.into())}
+			/ keyword("import") _ path:string() {Expr::Import(path.into())}
 
 			/ var_expr(s)
 			/ local_expr(s)
@@ -299,7 +298,7 @@
 		use UnaryOpType::*;
 		rule expr(s: &ParserSettings) -> LocExpr
 			= precedence! {
-				start:position!() v:@ end:position!() { LocExpr(Rc::new(v), ExprLocation(s.file_name.clone(), start, end)) }
+				start:position!() v:@ end:position!() { LocExpr(Rc::new(v), ExprLocation(s.file_name.clone(), start as u32, end as u32)) }
 				--
 				a:(@) _ binop(<"||">) _ b:@ {expr_bin!(a Or b)}
 				--
@@ -357,7 +356,7 @@
 	let len = str.len();
 	LocExpr(
 		Rc::new(Expr::Str(str)),
-		ExprLocation(settings.file_name.clone(), 0, len),
+		ExprLocation(settings.file_name.clone(), 0, len as u32),
 	)
 }
 
@@ -368,14 +367,14 @@
 	use BinaryOpType::*;
 
 	use super::{expr::*, parse};
-	use crate::ParserSettings;
+	use crate::{source::Source, ParserSettings};
 
 	macro_rules! parse {
 		($s:expr) => {
 			parse(
 				$s,
 				&ParserSettings {
-					file_name: PathBuf::from("test.jsonnet").into(),
+					file_name: Source::new(PathBuf::from("test.jsonnet")).unwrap(),
 				},
 			)
 			.unwrap()
@@ -386,7 +385,11 @@
 		($expr:expr, $from:expr, $to:expr$(,)?) => {
 			LocExpr(
 				std::rc::Rc::new($expr),
-				ExprLocation(PathBuf::from("test.jsonnet").into(), $from, $to),
+				ExprLocation(
+					Source::new(PathBuf::from("test.jsonnet")).unwrap(),
+					$from,
+					$to,
+				),
 			)
 		};
 	}
@@ -453,11 +456,15 @@
 	fn imports() {
 		assert_eq!(
 			parse!("import \"hello\""),
-			el!(Expr::Import(PathBuf::from("hello")), 0, 14),
+			el!(Expr::Import("hello".into()), 0, 14),
 		);
 		assert_eq!(
 			parse!("importstr \"garnish.txt\""),
-			el!(Expr::ImportStr(PathBuf::from("garnish.txt")), 0, 23)
+			el!(Expr::ImportStr("garnish.txt".into()), 0, 23)
+		);
+		assert_eq!(
+			parse!("importbin \"garnish.bin\""),
+			el!(Expr::ImportBin("garnish.bin".into()), 0, 23)
 		);
 	}
 
@@ -720,7 +727,7 @@
 	fn add_location_info_to_all_sub_expressions() {
 		use Expr::*;
 
-		let file_name: std::rc::Rc<std::path::Path> = PathBuf::from("test.jsonnet").into();
+		let file_name = Source::new(PathBuf::from("test.jsonnet")).unwrap();
 		let expr = parse(
 			"{} { local x = 1, x: x } + {}",
 			&ParserSettings {
@@ -759,12 +766,5 @@
 				29
 			),
 		);
-	}
-	// From source code
-	/*
-	#[bench]
-	fn bench_parse_peg(b: &mut Bencher) {
-		b.iter(|| parse!(jrsonnet_stdlib::STDLIB_STR))
 	}
-	*/
 }
addedcrates/jrsonnet-parser/src/source.rsdiffbeforeafterboth
--- /dev/null
+++ b/crates/jrsonnet-parser/src/source.rs
@@ -0,0 +1,93 @@
+use std::{
+	borrow::Cow,
+	fmt,
+	path::{Component, Path, PathBuf},
+	rc::Rc,
+};
+
+use gcmodule::{Trace, Tracer};
+#[cfg(feature = "serde")]
+use serde::{Deserialize, Serialize};
+
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[derive(PartialEq, Eq, Debug, Hash)]
+enum Inner {
+	Real(PathBuf),
+	Virtual(Cow<'static, str>),
+}
+
+/// Either real file, or virtual
+/// Hash of FileName always have same value as raw Path, to make it possible to use with raw_entry_mut
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub struct Source(Rc<Inner>);
+static_assertions::assert_eq_size!(Source, *const ());
+
+impl Trace for Source {
+	fn trace(&self, _tracer: &mut Tracer) {}
+
+	fn is_type_tracked() -> bool {
+		false
+	}
+}
+
+impl Source {
+	/// Fails when path contains inner /../ or /./ references, or not absolute
+	pub fn new(path: PathBuf) -> Option<Self> {
+		if !path.is_absolute()
+			|| path
+				.components()
+				.any(|c| matches!(c, Component::CurDir | Component::ParentDir))
+		{
+			return None;
+		}
+		Some(Self(Rc::new(Inner::Real(path))))
+	}
+
+	pub fn new_virtual(n: Cow<'static, str>) -> Self {
+		Self(Rc::new(Inner::Virtual(n)))
+	}
+
+	pub fn short_display(&self) -> ShortDisplay {
+		ShortDisplay(self.clone())
+	}
+	pub fn full_path(&self) -> String {
+		match self.inner() {
+			Inner::Real(r) => r.display().to_string(),
+			Inner::Virtual(v) => v.to_string(),
+		}
+	}
+
+	/// Returns None if file is virtual
+	pub fn path(&self) -> Option<&Path> {
+		match self.inner() {
+			Inner::Real(r) => Some(r),
+			Inner::Virtual(_) => None,
+		}
+	}
+	pub fn repr(&self) -> Result<&Path, &str> {
+		match self.inner() {
+			Inner::Real(r) => Ok(r),
+			Inner::Virtual(v) => Err(v.as_ref()),
+		}
+	}
+
+	fn inner(&self) -> &Inner {
+		&self.0 as &Inner
+	}
+}
+pub struct ShortDisplay(Source);
+impl fmt::Display for ShortDisplay {
+	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+		match &self.0 .0 as &Inner {
+			Inner::Real(r) => {
+				write!(
+					f,
+					"{}",
+					r.file_name().expect("path is valid").to_string_lossy()
+				)
+			}
+			Inner::Virtual(n) => write!(f, "{}", n),
+		}
+	}
+}