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
before · crates/jrsonnet-parser/src/expr.rs
1use std::{2	fmt::{Debug, Display},3	ops::Deref,4	path::{Path, PathBuf},5	rc::Rc,6};78use gcmodule::Trace;9use jrsonnet_interner::IStr;10#[cfg(feature = "serde")]11use serde::{Deserialize, Serialize};1213#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]14#[derive(Debug, PartialEq, Trace)]15pub enum FieldName {16	/// {fixed: 2}17	Fixed(IStr),18	/// {["dyn"+"amic"]: 3}19	Dyn(LocExpr),20}2122#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]23#[derive(Debug, Clone, Copy, PartialEq, Trace)]24pub enum Visibility {25	/// :26	Normal,27	/// ::28	Hidden,29	/// :::30	Unhide,31}3233impl Visibility {34	pub fn is_visible(&self) -> bool {35		matches!(self, Self::Normal | Self::Unhide)36	}37}3839#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]40#[derive(Clone, Debug, PartialEq, Trace)]41pub struct AssertStmt(pub LocExpr, pub Option<LocExpr>);4243#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]44#[derive(Debug, PartialEq, Trace)]45pub struct FieldMember {46	pub name: FieldName,47	pub plus: bool,48	pub params: Option<ParamsDesc>,49	pub visibility: Visibility,50	pub value: LocExpr,51}5253#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]54#[derive(Debug, PartialEq, Trace)]55pub enum Member {56	Field(FieldMember),57	BindStmt(BindSpec),58	AssertStmt(AssertStmt),59}6061#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]62#[derive(Debug, Clone, Copy, PartialEq, Trace)]63pub enum UnaryOpType {64	Plus,65	Minus,66	BitNot,67	Not,68}6970impl Display for UnaryOpType {71	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {72		use UnaryOpType::*;73		write!(74			f,75			"{}",76			match self {77				Plus => "+",78				Minus => "-",79				BitNot => "~",80				Not => "!",81			}82		)83	}84}8586#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]87#[derive(Debug, Clone, Copy, PartialEq, Trace)]88pub enum BinaryOpType {89	Mul,90	Div,9192	/// Implemented as intrinsic, put here for completeness93	Mod,9495	Add,96	Sub,9798	Lhs,99	Rhs,100101	Lt,102	Gt,103	Lte,104	Gte,105106	BitAnd,107	BitOr,108	BitXor,109110	Eq,111	Neq,112113	And,114	Or,115116	// Equialent to std.objectHasEx(a, b, true)117	In,118}119120impl Display for BinaryOpType {121	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {122		use BinaryOpType::*;123		write!(124			f,125			"{}",126			match self {127				Mul => "*",128				Div => "/",129				Mod => "%",130				Add => "+",131				Sub => "-",132				Lhs => "<<",133				Rhs => ">>",134				Lt => "<",135				Gt => ">",136				Lte => "<=",137				Gte => ">=",138				BitAnd => "&",139				BitOr => "|",140				BitXor => "^",141				Eq => "==",142				Neq => "!=",143				And => "&&",144				Or => "||",145				In => "in",146			}147		)148	}149}150151/// name, default value152#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]153#[derive(Debug, PartialEq, Trace)]154pub struct Param(pub IStr, pub Option<LocExpr>);155156/// Defined function parameters157#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]158#[derive(Debug, Clone, PartialEq, Trace)]159pub struct ParamsDesc(pub Rc<Vec<Param>>);160161impl Deref for ParamsDesc {162	type Target = Vec<Param>;163	fn deref(&self) -> &Self::Target {164		&self.0165	}166}167168#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]169#[derive(Debug, PartialEq, Trace)]170pub struct ArgsDesc {171	pub unnamed: Vec<LocExpr>,172	pub named: Vec<(IStr, LocExpr)>,173}174impl ArgsDesc {175	pub fn new(unnamed: Vec<LocExpr>, named: Vec<(IStr, LocExpr)>) -> Self {176		Self { unnamed, named }177	}178}179180#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]181#[derive(Debug, Clone, PartialEq, Trace)]182pub enum DestructRest {183	/// ...rest184	Keep(IStr),185	/// ...186	Drop,187}188189#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]190#[derive(Debug, Clone, PartialEq, Trace)]191pub enum Destruct {192	Full(IStr),193	#[cfg(feature = "exp-destruct")]194	Skip,195	#[cfg(feature = "exp-destruct")]196	Array {197		start: Vec<Destruct>,198		rest: Option<DestructRest>,199		end: Vec<Destruct>,200	},201	#[cfg(feature = "exp-destruct")]202	Object {203		fields: Vec<(IStr, Option<Destruct>)>,204		rest: Option<DestructRest>,205	},206}207impl Destruct {208	pub fn name(&self) -> Option<IStr> {209		match self {210			Self::Full(name) => Some(name.clone()),211			#[cfg(feature = "exp-destruct")]212			_ => None,213		}214	}215}216217#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]218#[derive(Debug, Clone, PartialEq, Trace)]219pub enum BindSpec {220	Field {221		into: Destruct,222		value: LocExpr,223	},224	Function {225		name: IStr,226		params: ParamsDesc,227		value: LocExpr,228	},229}230231#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]232#[derive(Debug, PartialEq, Trace)]233pub struct IfSpecData(pub LocExpr);234235#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]236#[derive(Debug, PartialEq, Trace)]237pub struct ForSpecData(pub IStr, pub LocExpr);238239#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]240#[derive(Debug, PartialEq, Trace)]241pub enum CompSpec {242	IfSpec(IfSpecData),243	ForSpec(ForSpecData),244}245246#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]247#[derive(Debug, PartialEq, Trace)]248pub struct ObjComp {249	pub pre_locals: Vec<BindSpec>,250	pub key: LocExpr,251	pub plus: bool,252	pub value: LocExpr,253	pub post_locals: Vec<BindSpec>,254	pub compspecs: Vec<CompSpec>,255}256257#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]258#[derive(Debug, PartialEq, Trace)]259pub enum ObjBody {260	MemberList(Vec<Member>),261	ObjComp(ObjComp),262}263264#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]265#[derive(Debug, PartialEq, Clone, Copy, Trace)]266pub enum LiteralType {267	This,268	Super,269	Dollar,270	Null,271	True,272	False,273}274275#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]276#[derive(Debug, PartialEq, Trace)]277pub struct SliceDesc {278	pub start: Option<LocExpr>,279	pub end: Option<LocExpr>,280	pub step: Option<LocExpr>,281}282283/// Syntax base284#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]285#[derive(Debug, PartialEq, Trace)]286pub enum Expr {287	Literal(LiteralType),288289	/// String value: "hello"290	Str(IStr),291	/// Number: 1, 2.0, 2e+20292	Num(f64),293	/// Variable name: test294	Var(IStr),295296	/// Array of expressions: [1, 2, "Hello"]297	Arr(Vec<LocExpr>),298	/// Array comprehension:299	/// ```jsonnet300	///  ingredients: [301	///    { kind: kind, qty: 4 / 3 }302	///    for kind in [303	///      'Honey Syrup',304	///      'Lemon Juice',305	///      'Farmers Gin',306	///    ]307	///  ],308	/// ```309	ArrComp(LocExpr, Vec<CompSpec>),310311	/// Object: {a: 2}312	Obj(ObjBody),313	/// Object extension: var1 {b: 2}314	ObjExtend(LocExpr, ObjBody),315316	/// (obj)317	Parened(LocExpr),318319	/// -2320	UnaryOp(UnaryOpType, LocExpr),321	/// 2 - 2322	BinaryOp(LocExpr, BinaryOpType, LocExpr),323	/// assert 2 == 2 : "Math is broken"324	AssertExpr(AssertStmt, LocExpr),325	/// local a = 2; { b: a }326	LocalExpr(Vec<BindSpec>, LocExpr),327328	/// import "hello"329	Import(PathBuf),330	/// importStr "file.txt"331	ImportStr(PathBuf),332	/// importBin "file.txt"333	ImportBin(PathBuf),334	/// error "I'm broken"335	ErrorStmt(LocExpr),336	/// a(b, c)337	Apply(LocExpr, ArgsDesc, bool),338	/// a[b]339	Index(LocExpr, LocExpr),340	/// function(x) x341	Function(ParamsDesc, LocExpr),342	/// std.thisFile343	IntrinsicThisFile,344	/// std.id,345	IntrinsicId,346	/// std.primitiveEquals347	Intrinsic(IStr),348	/// if true == false then 1 else 2349	IfElse {350		cond: IfSpecData,351		cond_then: LocExpr,352		cond_else: Option<LocExpr>,353	},354	Slice(LocExpr, SliceDesc),355}356357/// file, begin offset, end offset358#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]359#[derive(Clone, PartialEq, Trace)]360#[skip_trace]361pub struct ExprLocation(pub Rc<Path>, pub usize, pub usize);362impl ExprLocation {363	pub fn belongs_to(&self, other: &ExprLocation) -> bool {364		other.0 == self.0 && other.1 <= self.1 && other.2 >= self.2365	}366}367368impl Debug for ExprLocation {369	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {370		write!(f, "{:?}:{:?}-{:?}", self.0, self.1, self.2)371	}372}373374/// Holds AST expression and its location in source file375#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]376#[derive(Clone, PartialEq, Trace)]377pub struct LocExpr(pub Rc<Expr>, pub ExprLocation);378379impl Debug for LocExpr {380	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {381		if f.alternate() {382			write!(f, "{:#?}", self.0)?;383		} else {384			write!(f, "{:?}", self.0)?;385		}386		write!(f, " from {:?}", self.1)?;387		Ok(())388	}389}
after · crates/jrsonnet-parser/src/expr.rs
1use std::{2	fmt::{self, Debug, Display},3	ops::Deref,4	rc::Rc,5};67use gcmodule::Trace;8use jrsonnet_interner::IStr;9#[cfg(feature = "serde")]10use serde::{Deserialize, Serialize};1112use crate::source::Source;1314#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]15#[derive(Debug, PartialEq, Trace)]16pub enum FieldName {17	/// {fixed: 2}18	Fixed(IStr),19	/// {["dyn"+"amic"]: 3}20	Dyn(LocExpr),21}2223#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]24#[derive(Debug, Clone, Copy, PartialEq, Trace)]25pub enum Visibility {26	/// :27	Normal,28	/// ::29	Hidden,30	/// :::31	Unhide,32}3334impl Visibility {35	pub fn is_visible(&self) -> bool {36		matches!(self, Self::Normal | Self::Unhide)37	}38}3940#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]41#[derive(Clone, Debug, PartialEq, Trace)]42pub struct AssertStmt(pub LocExpr, pub Option<LocExpr>);4344#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]45#[derive(Debug, PartialEq, Trace)]46pub struct FieldMember {47	pub name: FieldName,48	pub plus: bool,49	pub params: Option<ParamsDesc>,50	pub visibility: Visibility,51	pub value: LocExpr,52}5354#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]55#[derive(Debug, PartialEq, Trace)]56pub enum Member {57	Field(FieldMember),58	BindStmt(BindSpec),59	AssertStmt(AssertStmt),60}6162#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]63#[derive(Debug, Clone, Copy, PartialEq, Trace)]64pub enum UnaryOpType {65	Plus,66	Minus,67	BitNot,68	Not,69}7071impl Display for UnaryOpType {72	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {73		use UnaryOpType::*;74		write!(75			f,76			"{}",77			match self {78				Plus => "+",79				Minus => "-",80				BitNot => "~",81				Not => "!",82			}83		)84	}85}8687#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]88#[derive(Debug, Clone, Copy, PartialEq, Trace)]89pub enum BinaryOpType {90	Mul,91	Div,9293	/// Implemented as intrinsic, put here for completeness94	Mod,9596	Add,97	Sub,9899	Lhs,100	Rhs,101102	Lt,103	Gt,104	Lte,105	Gte,106107	BitAnd,108	BitOr,109	BitXor,110111	Eq,112	Neq,113114	And,115	Or,116117	// Equialent to std.objectHasEx(a, b, true)118	In,119}120121impl Display for BinaryOpType {122	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {123		use BinaryOpType::*;124		write!(125			f,126			"{}",127			match self {128				Mul => "*",129				Div => "/",130				Mod => "%",131				Add => "+",132				Sub => "-",133				Lhs => "<<",134				Rhs => ">>",135				Lt => "<",136				Gt => ">",137				Lte => "<=",138				Gte => ">=",139				BitAnd => "&",140				BitOr => "|",141				BitXor => "^",142				Eq => "==",143				Neq => "!=",144				And => "&&",145				Or => "||",146				In => "in",147			}148		)149	}150}151152/// name, default value153#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]154#[derive(Debug, PartialEq, Trace)]155pub struct Param(pub IStr, pub Option<LocExpr>);156157/// Defined function parameters158#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]159#[derive(Debug, Clone, PartialEq, Trace)]160pub struct ParamsDesc(pub Rc<Vec<Param>>);161162impl Deref for ParamsDesc {163	type Target = Vec<Param>;164	fn deref(&self) -> &Self::Target {165		&self.0166	}167}168169#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]170#[derive(Debug, PartialEq, Trace)]171pub struct ArgsDesc {172	pub unnamed: Vec<LocExpr>,173	pub named: Vec<(IStr, LocExpr)>,174}175impl ArgsDesc {176	pub fn new(unnamed: Vec<LocExpr>, named: Vec<(IStr, LocExpr)>) -> Self {177		Self { unnamed, named }178	}179}180181#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]182#[derive(Debug, Clone, PartialEq, Trace)]183pub enum DestructRest {184	/// ...rest185	Keep(IStr),186	/// ...187	Drop,188}189190#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]191#[derive(Debug, Clone, PartialEq, Trace)]192pub enum Destruct {193	Full(IStr),194	#[cfg(feature = "exp-destruct")]195	Skip,196	#[cfg(feature = "exp-destruct")]197	Array {198		start: Vec<Destruct>,199		rest: Option<DestructRest>,200		end: Vec<Destruct>,201	},202	#[cfg(feature = "exp-destruct")]203	Object {204		fields: Vec<(IStr, Option<Destruct>)>,205		rest: Option<DestructRest>,206	},207}208impl Destruct {209	pub fn name(&self) -> Option<IStr> {210		match self {211			Self::Full(name) => Some(name.clone()),212			#[cfg(feature = "exp-destruct")]213			_ => None,214		}215	}216}217218#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]219#[derive(Debug, Clone, PartialEq, Trace)]220pub enum BindSpec {221	Field {222		into: Destruct,223		value: LocExpr,224	},225	Function {226		name: IStr,227		params: ParamsDesc,228		value: LocExpr,229	},230}231232#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]233#[derive(Debug, PartialEq, Trace)]234pub struct IfSpecData(pub LocExpr);235236#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]237#[derive(Debug, PartialEq, Trace)]238pub struct ForSpecData(pub IStr, pub LocExpr);239240#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]241#[derive(Debug, PartialEq, Trace)]242pub enum CompSpec {243	IfSpec(IfSpecData),244	ForSpec(ForSpecData),245}246247#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]248#[derive(Debug, PartialEq, Trace)]249pub struct ObjComp {250	pub pre_locals: Vec<BindSpec>,251	pub key: LocExpr,252	pub plus: bool,253	pub value: LocExpr,254	pub post_locals: Vec<BindSpec>,255	pub compspecs: Vec<CompSpec>,256}257258#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]259#[derive(Debug, PartialEq, Trace)]260pub enum ObjBody {261	MemberList(Vec<Member>),262	ObjComp(ObjComp),263}264265#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]266#[derive(Debug, PartialEq, Clone, Copy, Trace)]267pub enum LiteralType {268	This,269	Super,270	Dollar,271	Null,272	True,273	False,274}275276#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]277#[derive(Debug, PartialEq, Trace)]278pub struct SliceDesc {279	pub start: Option<LocExpr>,280	pub end: Option<LocExpr>,281	pub step: Option<LocExpr>,282}283284/// Syntax base285#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]286#[derive(Debug, PartialEq, Trace)]287pub enum Expr {288	Literal(LiteralType),289290	/// String value: "hello"291	Str(IStr),292	/// Number: 1, 2.0, 2e+20293	Num(f64),294	/// Variable name: test295	Var(IStr),296297	/// Array of expressions: [1, 2, "Hello"]298	Arr(Vec<LocExpr>),299	/// Array comprehension:300	/// ```jsonnet301	///  ingredients: [302	///    { kind: kind, qty: 4 / 3 }303	///    for kind in [304	///      'Honey Syrup',305	///      'Lemon Juice',306	///      'Farmers Gin',307	///    ]308	///  ],309	/// ```310	ArrComp(LocExpr, Vec<CompSpec>),311312	/// Object: {a: 2}313	Obj(ObjBody),314	/// Object extension: var1 {b: 2}315	ObjExtend(LocExpr, ObjBody),316317	/// (obj)318	Parened(LocExpr),319320	/// -2321	UnaryOp(UnaryOpType, LocExpr),322	/// 2 - 2323	BinaryOp(LocExpr, BinaryOpType, LocExpr),324	/// assert 2 == 2 : "Math is broken"325	AssertExpr(AssertStmt, LocExpr),326	/// local a = 2; { b: a }327	LocalExpr(Vec<BindSpec>, LocExpr),328329	/// import "hello"330	Import(IStr),331	/// importStr "file.txt"332	ImportStr(IStr),333	/// importBin "file.txt"334	ImportBin(IStr),335	/// error "I'm broken"336	ErrorStmt(LocExpr),337	/// a(b, c)338	Apply(LocExpr, ArgsDesc, bool),339	/// a[b]340	Index(LocExpr, LocExpr),341	/// function(x) x342	Function(ParamsDesc, LocExpr),343	/// std.thisFile344	IntrinsicThisFile,345	/// std.id,346	IntrinsicId,347	/// std.primitiveEquals348	Intrinsic(IStr),349	/// if true == false then 1 else 2350	IfElse {351		cond: IfSpecData,352		cond_then: LocExpr,353		cond_else: Option<LocExpr>,354	},355	Slice(LocExpr, SliceDesc),356}357358/// file, begin offset, end offset359#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]360#[derive(Clone, PartialEq, Trace)]361#[skip_trace]362#[repr(C)]363pub struct ExprLocation(pub Source, pub u32, pub u32);364impl ExprLocation {365	pub fn belongs_to(&self, other: &ExprLocation) -> bool {366		other.0 == self.0 && other.1 <= self.1 && other.2 >= self.2367	}368}369370#[cfg(target_pointer_width = "64")]371static_assertions::assert_eq_size!(ExprLocation, [u8; 16]);372373impl Debug for ExprLocation {374	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {375		write!(f, "{:?}:{:?}-{:?}", self.0, self.1, self.2)376	}377}378379/// Holds AST expression and its location in source file380#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]381#[derive(Clone, PartialEq, Trace)]382pub struct LocExpr(pub Rc<Expr>, pub ExprLocation);383384#[cfg(target_pointer_width = "64")]385static_assertions::assert_eq_size!(LocExpr, [u8; 24]);386387impl Debug for LocExpr {388	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {389		if f.alternate() {390			write!(f, "{:#?}", self.0)?;391		} else {392			write!(f, "{:?}", self.0)?;393		}394		write!(f, " from {:?}", self.1)?;395		Ok(())396	}397}
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),
+		}
+	}
+}