difftreelog
refactor(ir) flatten
in: master
11 files changed
crates/jrsonnet-ir-parser/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-ir-parser/src/lib.rs
+++ b/crates/jrsonnet-ir-parser/src/lib.rs
@@ -1,13 +1,11 @@
-use std::rc::Rc;
-
use jrsonnet_gcmodule::Acyclic;
use jrsonnet_ir::{
- ArgsDesc, AssertExpr, AssertStmt, BinaryOp, BinaryOpType, BindSpec, CompSpec, Destruct, Expr,
- ExprParam, ExprParams, FieldMember, FieldName, ForSpecData, IStr, IfElse, IfSpecData,
- ImportKind, IndexPart, LiteralType, Member, NumValue, ObjBody, ObjComp, ObjMembers, Slice,
- SliceDesc, Source, Span, Spanned, UnaryOpType, Visibility, unescape,
+ unescape, ArgsDesc, AssertExpr, AssertStmt, BinaryOp, BinaryOpType, BindSpec, CompSpec,
+ Destruct, Expr, ExprParam, ExprParams, FieldMember, FieldName, ForSpecData, IStr, IfElse,
+ IfSpecData, ImportKind, IndexPart, LiteralType, Member, NumValue, ObjBody, ObjComp, ObjMembers,
+ Slice, SliceDesc, Source, Span, Spanned, UnaryOpType, Visibility,
};
-use jrsonnet_lexer::{Lexeme, Lexer, Span as LexSpan, SyntaxKind, T, collect_lexed_str_block};
+use jrsonnet_lexer::{collect_lexed_str_block, Lexeme, Lexer, Span as LexSpan, SyntaxKind, T};
pub struct ParserSettings {
pub source: Source,
@@ -16,7 +14,7 @@
#[derive(Debug, Clone)]
pub struct ParseError {
pub message: String,
- pub location: LexSpan,
+ pub location: Span,
}
impl std::fmt::Display for ParseError {
@@ -128,12 +126,13 @@
if self.offset == self.lexemes.len() {
let pos = self.lexemes.last().map_or(0, |v| v.range.1);
return ParseError {
- location: LexSpan(pos, pos),
+ location: Span(self.source.clone(), pos, pos),
message,
};
}
+ let LexSpan(start, end) = self.lexemes[self.offset].range;
ParseError {
- location: self.lexemes[self.offset].range,
+ location: Span(self.source.clone(), start, end),
message,
}
}
@@ -293,7 +292,7 @@
fn destruct(p: &mut Parser<'_>) -> Result<Destruct> {
if p.at(SyntaxKind::IDENT) {
- return Ok(Destruct::Full(ident(p)?));
+ return Ok(Destruct::Full(spanned(p, ident)?));
}
#[cfg(not(feature = "exp-destruct"))]
return Err(p.error(format!("expected identifier, got {}", p.current_desc())));
@@ -407,7 +406,7 @@
loop {
let d = destruct(p)?;
let default = if p.try_eat(T![=]) {
- Some(Rc::new(expr(p)?))
+ Some(expr(p)?)
} else {
None
};
@@ -441,16 +440,15 @@
if is_named {
let name: IStr = ident(p)?;
p.eat(T![=])?;
- let value = Rc::new(expr(p)?);
names.push(name);
- values.push(value);
+ values.push(expr(p)?);
named_started = true;
} else {
if named_started {
return Err(p.error("positional argument after named argument".into()));
}
- unnamed.push(Rc::new(expr(p)?));
+ unnamed.push(expr(p)?);
}
if !p.try_eat(T![,]) {
break;
@@ -472,23 +470,21 @@
return Ok(BindSpec::Field { into: d, value });
}
}
- let name = ident(p)?;
+ let name_spanned = spanned(p, ident)?;
if p.try_eat(T!['(']) {
let ps = params(p)?;
p.eat(T![')'])?;
p.eat(T![=])?;
- let value = Rc::new(expr(p)?);
Ok(BindSpec::Function {
- name,
+ name: name_spanned.value,
params: ps,
- value,
+ value: expr(p)?,
})
} else {
p.eat(T![=])?;
- let value = Rc::new(expr(p)?);
Ok(BindSpec::Field {
- into: Destruct::Full(name),
- value,
+ into: Destruct::Full(name_spanned),
+ value: expr(p)?,
})
}
}
@@ -529,24 +525,22 @@
let ps = params(p)?;
p.eat(T![')'])?;
let vis = visibility(p)?;
- let value = Rc::new(expr(p)?);
Ok(FieldMember {
name,
plus: false,
params: Some(ps),
visibility: vis,
- value,
+ value: expr(p)?,
})
} else {
let plus = p.try_eat(T![+]);
let vis = visibility(p)?;
- let value = Rc::new(expr(p)?);
Ok(FieldMember {
name,
plus,
params: None,
visibility: vis,
- value,
+ value: expr(p)?,
})
}
}
@@ -589,8 +583,8 @@
fn objinside(p: &mut Parser<'_>) -> Result<ObjBody> {
if p.at(T!['}']) {
return Ok(ObjBody::MemberList(ObjMembers {
- locals: Rc::new(Vec::new()),
- asserts: Rc::new(Vec::new()),
+ locals: Vec::new(),
+ asserts: Vec::new(),
fields: Vec::new(),
}));
}
@@ -627,8 +621,8 @@
}
}
Ok(ObjBody::ObjComp(ObjComp {
- locals: Rc::new(locals),
- field: Rc::new(
+ locals,
+ field: Box::new(
field_member.ok_or_else(|| p.error("missing object comprehension field".into()))?,
),
compspecs: specs,
@@ -645,8 +639,8 @@
}
}
Ok(ObjBody::MemberList(ObjMembers {
- locals: Rc::new(locals),
- asserts: Rc::new(asserts),
+ locals,
+ asserts,
fields,
}))
}
@@ -678,13 +672,13 @@
p.eat(T!['['])?;
if p.at(T![']']) {
p.eat(T![']'])?;
- return Ok(Expr::Arr(Rc::new(Vec::new())));
+ return Ok(Expr::Arr(Vec::new()));
}
let first = expr(p)?;
if p.at(T![for]) {
let specs = compspecs(p)?;
p.eat(T![']'])?;
- Ok(Expr::ArrComp(Rc::new(first), specs))
+ Ok(Expr::ArrComp(Box::new(first), specs))
} else if p.at(T![,]) && {
let next = p.offset + 1;
next < p.lexemes.len() && p.lexemes[next].kind == T![for]
@@ -692,7 +686,7 @@
p.eat(T![,])?;
let specs = compspecs(p)?;
p.eat(T![']'])?;
- Ok(Expr::ArrComp(Rc::new(first), specs))
+ Ok(Expr::ArrComp(Box::new(first), specs))
} else {
let mut elems = vec![first];
while p.try_eat(T![,]) {
@@ -702,7 +696,7 @@
elems.push(expr(p)?);
}
p.eat(T![']'])?;
- Ok(Expr::Arr(Rc::new(elems)))
+ Ok(Expr::Arr(elems))
}
}
@@ -735,14 +729,14 @@
let ps = params(p)?;
p.eat(T![')'])?;
let body = expr(p)?;
- Ok(Expr::Function(ps, Rc::new(body)))
+ Ok(Expr::Function(ps, Box::new(body)))
}
T![assert] => {
let a = assert_stmt(p)?;
p.eat(T![;])?;
let rest = expr(p)?;
- Ok(Expr::AssertExpr(Rc::new(AssertExpr { assert: a, rest })))
+ Ok(Expr::AssertExpr(Box::new(AssertExpr { assert: a, rest })))
}
T![error] => {
@@ -891,7 +885,7 @@
p.eat(T!['{'])?;
let body = objinside(p)?;
p.eat(T!['}'])?;
- e = Expr::ObjExtend(Rc::new(e), body);
+ e = Expr::ObjExtend(Box::new(e), body);
} else {
break;
}
@@ -1007,7 +1001,7 @@
if let Some(desc) = lexeme.kind.error_description() {
return Err(ParseError {
message: desc.to_owned(),
- location: lexeme.range,
+ location: Span(p.source.clone(), lexeme.range.0, lexeme.range.1),
});
}
}
crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__array_comp.snapdiffbeforeafterboth--- a/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__array_comp.snap
+++ b/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__array_comp.snap
@@ -10,7 +10,7 @@
ForSpec(
ForSpecData {
destruct: Full(
- "x",
+ "x" from virtual:<test>:7-8,
),
over: Var(
"arr" from virtual:<test>:12-15,
crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__function_and_call.snapdiffbeforeafterboth--- a/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__function_and_call.snap
+++ b/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__function_and_call.snap
@@ -10,13 +10,13 @@
exprs: [
ExprParam {
destruct: Full(
- "x",
+ "x" from virtual:<test>:8-9,
),
default: None,
},
ExprParam {
destruct: Full(
- "y",
+ "y" from virtual:<test>:11-12,
),
default: Some(
Num(
crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@array_comp.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@array_comp.jsonnet.snap
+++ b/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@array_comp.jsonnet.snap
@@ -35,7 +35,7 @@
ForSpec(
ForSpecData {
destruct: Full(
- "x",
+ "x" from virtual:<test>:23-24,
),
over: Var(
"arr" from virtual:<test>:28-31,
@@ -52,7 +52,7 @@
ForSpec(
ForSpecData {
destruct: Full(
- "a",
+ "a" from virtual:<test>:41-42,
),
over: Var(
"b" from virtual:<test>:46-47,
@@ -70,7 +70,7 @@
ForSpec(
ForSpecData {
destruct: Full(
- "e",
+ "e" from virtual:<test>:57-58,
),
over: Var(
"f" from virtual:<test>:62-63,
crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@default_nondefault.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@default_nondefault.jsonnet.snap
+++ b/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@default_nondefault.jsonnet.snap
@@ -11,7 +11,7 @@
exprs: [
ExprParam {
destruct: Full(
- "foo",
+ "foo" from virtual:<test>:8-11,
),
default: Some(
Str(
@@ -21,7 +21,7 @@
},
ExprParam {
destruct: Full(
- "bar",
+ "bar" from virtual:<test>:21-24,
),
default: None,
},
crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@subexp.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@subexp.jsonnet.snap
+++ b/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@subexp.jsonnet.snap
@@ -20,7 +20,7 @@
locals: [
Field {
into: Full(
- "x",
+ "x" from virtual:<test>:11-12,
),
value: Num(
1.0,
crates/jrsonnet-ir/src/expr.rsdiffbeforeafterboth1use std::{2 fmt::{self, Debug, Display},3 ops::{Deref, RangeInclusive},4 rc::Rc,5};67use jrsonnet_gcmodule::Acyclic;8use jrsonnet_interner::IStr;910use crate::{11 NumValue,12 function::{FunctionSignature, ParamDefault, ParamName, ParamParse},13 source::Source,14};1516#[derive(Debug, PartialEq, Acyclic)]17pub enum FieldName {18 /// {fixed: 2}19 Fixed(IStr),20 /// {["dyn"+"amic"]: 3}21 Dyn(Expr),22}2324#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]25#[repr(u8)]26pub enum Visibility {27 /// :28 Normal,29 /// ::30 Hidden,31 /// :::32 Unhide,33}3435impl Visibility {36 pub fn is_visible(&self) -> bool {37 matches!(self, Self::Normal | Self::Unhide)38 }39}4041#[derive(Debug, PartialEq, Acyclic)]42pub struct AssertStmt {43 pub assertion: Spanned<Expr>,44 pub message: Option<Expr>,45}4647#[derive(Debug, PartialEq, Acyclic)]48pub struct FieldMember {49 pub name: Spanned<FieldName>,50 pub plus: bool,51 pub params: Option<ExprParams>,52 pub visibility: Visibility,53 pub value: Rc<Expr>,54}5556#[derive(Debug, PartialEq, Acyclic)]57pub enum Member {58 Field(FieldMember),59 BindStmt(BindSpec),60 AssertStmt(AssertStmt),61}6263#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]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#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]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,115 #[cfg(feature = "exp-null-coaelse")]116 NullCoaelse,117118 // Equialent to std.objectHasEx(a, b, true)119 In,120}121122impl Display for BinaryOpType {123 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {124 use BinaryOpType::*;125 write!(126 f,127 "{}",128 match self {129 Mul => "*",130 Div => "/",131 Mod => "%",132 Add => "+",133 Sub => "-",134 Lhs => "<<",135 Rhs => ">>",136 Lt => "<",137 Gt => ">",138 Lte => "<=",139 Gte => ">=",140 BitAnd => "&",141 BitOr => "|",142 BitXor => "^",143 Eq => "==",144 Neq => "!=",145 And => "&&",146 Or => "||",147 In => "in",148 #[cfg(feature = "exp-null-coaelse")]149 NullCoaelse => "??",150 }151 )152 }153}154155/// name, default value156#[derive(Debug, PartialEq, Acyclic)]157pub struct ExprParam {158 pub destruct: Destruct,159 pub default: Option<Rc<Expr>>,160}161162/// Defined function parameters163#[derive(Debug, Clone, PartialEq, Acyclic)]164pub struct ExprParams {165 pub exprs: Rc<Vec<ExprParam>>,166 pub signature: FunctionSignature,167 pub(crate) binds_len: usize,168}169impl ExprParams {170 pub fn len(&self) -> usize {171 self.exprs.len()172 }173 pub fn is_empty(&self) -> bool {174 self.exprs.is_empty()175 }176177 pub fn binds_len(&self) -> usize {178 self.binds_len179 }180 pub fn new(exprs: Vec<ExprParam>) -> Self {181 Self {182 signature: FunctionSignature::new(183 exprs184 .iter()185 .map(|p| {186 ParamParse::new(187 p.destruct.name(),188 ParamDefault::exists(p.default.is_some()),189 )190 })191 .collect(),192 ),193 binds_len: exprs.iter().map(|v| v.destruct.binds_len()).sum(),194 exprs: Rc::new(exprs),195 }196 }197}198199#[derive(Debug, PartialEq, Acyclic)]200pub struct ArgsDesc {201 pub unnamed: Vec<Rc<Expr>>,202 pub names: Vec<IStr>,203 pub values: Vec<Rc<Expr>>,204}205impl ArgsDesc {206 pub fn new(unnamed: Vec<Rc<Expr>>, names: Vec<IStr>, values: Vec<Rc<Expr>>) -> Self {207 Self {208 unnamed,209 names,210 values,211 }212 }213}214215#[derive(Debug, Clone, PartialEq, Eq, Acyclic)]216pub enum DestructRest {217 /// ...rest218 Keep(IStr),219 /// ...220 Drop,221}222223#[derive(Debug, Clone, PartialEq, Acyclic)]224pub enum Destruct {225 Full(IStr),226 #[cfg(feature = "exp-destruct")]227 Skip,228 #[cfg(feature = "exp-destruct")]229 Array {230 start: Vec<Destruct>,231 rest: Option<DestructRest>,232 end: Vec<Destruct>,233 },234 #[cfg(feature = "exp-destruct")]235 Object {236 #[allow(clippy::type_complexity)]237 fields: Vec<(IStr, Option<Destruct>, Option<Rc<Spanned<Expr>>>)>,238 rest: Option<DestructRest>,239 },240}241impl Destruct {242 /// Name of destructure, used for function parameter names243 pub fn name(&self) -> ParamName {244 match self {245 Self::Full(name) => ParamName::Named(name.clone()),246 #[cfg(feature = "exp-destruct")]247 _ => ParamName::Unnamed,248 }249 }250 pub fn binds_len(&self) -> usize {251 #[cfg(feature = "exp-destruct")]252 fn cap_rest(rest: &Option<DestructRest>) -> usize {253 match rest {254 Some(DestructRest::Keep(_)) => 1,255 Some(DestructRest::Drop) => 0,256 None => 0,257 }258 }259 match self {260 Self::Full(_) => 1,261 #[cfg(feature = "exp-destruct")]262 Self::Skip => 0,263 #[cfg(feature = "exp-destruct")]264 Self::Array { start, rest, end } => {265 start.iter().map(Destruct::binds_len).sum::<usize>()266 + end.iter().map(Destruct::binds_len).sum::<usize>()267 + cap_rest(rest)268 }269 #[cfg(feature = "exp-destruct")]270 Self::Object { fields, rest } => {271 let mut out = 0;272 for (_, into, _) in fields {273 match into {274 Some(v) => out += v.binds_len(),275 // Field is destructured to default name276 None => out += 1,277 }278 }279 out + cap_rest(rest)280 }281 }282 }283}284285#[derive(Debug, PartialEq, Acyclic)]286pub enum BindSpec {287 Field {288 into: Destruct,289 value: Rc<Expr>,290 },291 Function {292 name: IStr,293 params: ExprParams,294 value: Rc<Expr>,295 },296}297impl BindSpec {298 pub fn binds_len(&self) -> usize {299 match self {300 BindSpec::Field { into, .. } => into.binds_len(),301 BindSpec::Function { .. } => 1,302 }303 }304}305306#[derive(Debug, PartialEq, Acyclic)]307pub struct IfSpecData {308 pub span: Span,309 pub cond: Expr,310}311312#[derive(Debug, PartialEq, Acyclic)]313pub struct ForSpecData {314 pub destruct: Destruct,315 pub over: Expr,316}317318#[derive(Debug, PartialEq, Acyclic)]319pub enum CompSpec {320 IfSpec(IfSpecData),321 ForSpec(ForSpecData),322}323324#[derive(Debug, PartialEq, Acyclic)]325pub struct ObjComp {326 pub locals: Rc<Vec<BindSpec>>,327 pub field: Rc<FieldMember>,328 pub compspecs: Vec<CompSpec>,329}330331#[derive(Debug, PartialEq, Acyclic)]332pub struct ObjMembers {333 pub locals: Rc<Vec<BindSpec>>,334 pub asserts: Rc<Vec<AssertStmt>>,335 pub fields: Vec<FieldMember>,336}337338#[derive(Debug, PartialEq, Acyclic)]339pub enum ObjBody {340 MemberList(ObjMembers),341 ObjComp(ObjComp),342}343344#[derive(Debug, PartialEq, Eq, Clone, Copy, Acyclic)]345pub enum LiteralType {346 This,347 Super,348 Dollar,349 Null,350 True,351 False,352}353354#[derive(Debug, PartialEq, Acyclic)]355pub struct SliceDesc {356 pub start: Option<Spanned<Expr>>,357 pub end: Option<Spanned<Expr>>,358 pub step: Option<Spanned<Expr>>,359}360361#[derive(Debug, PartialEq, Acyclic)]362pub struct AssertExpr {363 pub assert: AssertStmt,364 pub rest: Expr,365}366367#[derive(Debug, PartialEq, Acyclic)]368pub struct BinaryOp {369 pub lhs: Expr,370 pub op: BinaryOpType,371 pub rhs: Expr,372}373374#[derive(Debug, PartialEq, Acyclic)]375pub enum ImportKind {376 Normal,377 Str,378 Bin,379}380381#[derive(Debug, PartialEq, Acyclic)]382pub struct IfElse {383 pub cond: IfSpecData,384 pub cond_then: Expr,385 pub cond_else: Option<Expr>,386}387388#[derive(Debug, PartialEq, Acyclic)]389pub struct Slice {390 pub value: Expr,391 pub slice: SliceDesc,392}393394/// Syntax base395#[derive(Debug, PartialEq, Acyclic)]396pub enum Expr {397 Literal(LiteralType),398399 /// String value: "hello"400 Str(IStr),401 /// Number: 1, 2.0, 2e+20402 Num(NumValue),403 /// Variable name: test404 Var(Spanned<IStr>),405406 /// Array of expressions: [1, 2, "Hello"]407 Arr(Rc<Vec<Expr>>),408 /// Array comprehension:409 /// ```jsonnet410 /// ingredients: [411 /// { kind: kind, qty: 4 / 3 }412 /// for kind in [413 /// 'Honey Syrup',414 /// 'Lemon Juice',415 /// 'Farmers Gin',416 /// ]417 /// ],418 /// ```419 ArrComp(Rc<Expr>, Vec<CompSpec>),420421 /// Object: {a: 2}422 Obj(ObjBody),423 /// Object extension: var1 {b: 2}424 ObjExtend(Rc<Expr>, ObjBody),425426 /// -2427 UnaryOp(UnaryOpType, Box<Expr>),428 /// 2 - 2429 BinaryOp(Box<BinaryOp>),430 /// assert 2 == 2 : "Math is broken"431 AssertExpr(Rc<AssertExpr>),432 /// local a = 2; { b: a }433 LocalExpr(Vec<BindSpec>, Box<Expr>),434435 /// import* "hello"436 Import(Spanned<ImportKind>, Box<Expr>),437 /// error "I'm broken"438 ErrorStmt(Span, Box<Expr>),439 /// a(b, c)440 Apply(Box<Expr>, Spanned<ArgsDesc>, bool),441 /// a[b], a.b, a?.b442 Index {443 indexable: Box<Expr>,444 parts: Vec<IndexPart>,445 },446 /// function(x) x447 Function(ExprParams, Rc<Expr>),448 /// if true == false then 1 else 2449 IfElse(Box<IfElse>),450 Slice(Box<Slice>),451}452453#[derive(Debug, PartialEq, Acyclic)]454pub struct IndexPart {455 pub span: Span,456 pub value: Expr,457 #[cfg(feature = "exp-null-coaelse")]458 pub null_coaelse: bool,459}460461/// file, begin offset, end offset462#[derive(Clone, PartialEq, Eq, Acyclic)]463#[repr(C)]464pub struct Span(pub Source, pub u32, pub u32);465impl Span {466 pub fn belongs_to(&self, other: &Span) -> bool {467 other.0 == self.0 && other.1 <= self.1 && other.2 >= self.2468 }469 pub fn range(&self) -> RangeInclusive<usize> {470 let start = self.1;471 let mut end = self.2;472 if end > start {473 // Because it is originally exclusive474 end -= 1;475 }476 start as usize..=end as usize477 }478}479480#[cfg(target_pointer_width = "64")]481static_assertions::assert_eq_size!(Span, (usize, usize));482483impl Debug for Span {484 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {485 write!(f, "{:?}:{:?}-{:?}", self.0, self.1, self.2)486 }487}488489#[derive(Clone, PartialEq, Acyclic)]490pub struct Spanned<T: Acyclic> {491 pub value: T,492 pub span: Span,493}494impl<T: Acyclic> Deref for Spanned<T> {495 type Target = T;496 fn deref(&self) -> &Self::Target {497 &self.value498 }499}500impl<T: Acyclic> Spanned<T> {501 #[inline]502 pub fn new(value: T, span: Span) -> Self {503 Self { value, span }504 }505 pub fn map<U: Acyclic>(self, v: impl FnOnce(T) -> U) -> Spanned<U> {506 Spanned {507 span: self.span,508 value: v(self.value),509 }510 }511 pub fn as_ref<'a>(&'a self) -> Spanned<&'a T>512 where513 &'a T: Acyclic,514 {515 Spanned {516 span: self.span.clone(),517 value: &self.value,518 }519 }520}521522impl<T: Debug + Acyclic> Debug for Spanned<T> {523 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {524 let expr = &**self;525 if f.alternate() {526 write!(f, "{:#?}", expr)?;527 } else {528 write!(f, "{:?}", expr)?;529 }530 write!(f, " from {:?}", self.span)?;531 Ok(())532 }533}1use std::{2 fmt::{self, Debug, Display},3 ops::{Deref, RangeInclusive},4};56use jrsonnet_gcmodule::Acyclic;7use jrsonnet_interner::IStr;89use crate::{10 function::{FunctionSignature, ParamDefault, ParamName, ParamParse},11 source::Source,12 NumValue,13};1415#[derive(Debug, PartialEq, Acyclic)]16pub enum FieldName {17 /// {fixed: 2}18 Fixed(IStr),19 /// {["dyn"+"amic"]: 3}20 Dyn(Expr),21}2223#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]24#[repr(u8)]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#[derive(Debug, PartialEq, Acyclic)]41pub struct AssertStmt {42 pub assertion: Spanned<Expr>,43 pub message: Option<Expr>,44}4546#[derive(Debug, PartialEq, Acyclic)]47pub struct FieldMember {48 pub name: Spanned<FieldName>,49 pub plus: bool,50 pub params: Option<ExprParams>,51 pub visibility: Visibility,52 pub value: Expr,53}5455#[derive(Debug, PartialEq, Acyclic)]56pub enum Member {57 Field(FieldMember),58 BindStmt(BindSpec),59 AssertStmt(AssertStmt),60}6162#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]63pub enum UnaryOpType {64 Plus,65 Minus,66 BitNot,67 Not,68}6970impl Display for UnaryOpType {71 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> 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#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]87pub enum BinaryOpType {88 Mul,89 Div,9091 /// Implemented as intrinsic, put here for completeness92 Mod,9394 Add,95 Sub,9697 Lhs,98 Rhs,99100 Lt,101 Gt,102 Lte,103 Gte,104105 BitAnd,106 BitOr,107 BitXor,108109 Eq,110 Neq,111112 And,113 Or,114 #[cfg(feature = "exp-null-coaelse")]115 NullCoaelse,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 #[cfg(feature = "exp-null-coaelse")]148 NullCoaelse => "??",149 }150 )151 }152}153154/// name, default value155#[derive(Debug, PartialEq, Acyclic)]156pub struct ExprParam {157 pub destruct: Destruct,158 pub default: Option<Expr>,159}160161/// Defined function parameters162#[derive(Debug, PartialEq, Acyclic)]163pub struct ExprParams {164 pub exprs: Vec<ExprParam>,165 pub signature: FunctionSignature,166 pub(crate) binds_len: usize,167}168impl ExprParams {169 pub fn len(&self) -> usize {170 self.exprs.len()171 }172 pub fn is_empty(&self) -> bool {173 self.exprs.is_empty()174 }175176 pub fn binds_len(&self) -> usize {177 self.binds_len178 }179 pub fn new(exprs: Vec<ExprParam>) -> Self {180 Self {181 signature: FunctionSignature::new(182 exprs183 .iter()184 .map(|p| {185 ParamParse::new(186 p.destruct.name(),187 ParamDefault::exists(p.default.is_some()),188 )189 })190 .collect(),191 ),192 binds_len: exprs.iter().map(|v| v.destruct.binds_len()).sum(),193 exprs,194 }195 }196}197198#[derive(Debug, PartialEq, Acyclic)]199pub struct ArgsDesc {200 pub unnamed: Vec<Expr>,201 pub names: Vec<IStr>,202 pub values: Vec<Expr>,203}204impl ArgsDesc {205 pub fn new(unnamed: Vec<Expr>, names: Vec<IStr>, values: Vec<Expr>) -> Self {206 Self {207 unnamed,208 names,209 values,210 }211 }212}213214#[derive(Debug, Clone, PartialEq, Eq, Acyclic)]215pub enum DestructRest {216 /// ...rest217 Keep(IStr),218 /// ...219 Drop,220}221222#[derive(Debug, Clone, PartialEq, Acyclic)]223pub enum Destruct {224 Full(Spanned<IStr>),225 #[cfg(feature = "exp-destruct")]226 Skip,227 #[cfg(feature = "exp-destruct")]228 Array {229 start: Vec<Destruct>,230 rest: Option<DestructRest>,231 end: Vec<Destruct>,232 },233 #[cfg(feature = "exp-destruct")]234 Object {235 #[allow(clippy::type_complexity)]236 fields: Vec<(IStr, Option<Destruct>, Option<Rc<Spanned<Expr>>>)>,237 rest: Option<DestructRest>,238 },239}240impl Destruct {241 /// Name of destructure, used for function parameter names242 pub fn name(&self) -> ParamName {243 match self {244 Self::Full(name) => ParamName::Named(name.value.clone()),245 #[cfg(feature = "exp-destruct")]246 _ => ParamName::Unnamed,247 }248 }249 pub fn binds_len(&self) -> usize {250 #[cfg(feature = "exp-destruct")]251 fn cap_rest(rest: &Option<DestructRest>) -> usize {252 match rest {253 Some(DestructRest::Keep(_)) => 1,254 Some(DestructRest::Drop) => 0,255 None => 0,256 }257 }258 match self {259 Self::Full(_) => 1,260 #[cfg(feature = "exp-destruct")]261 Self::Skip => 0,262 #[cfg(feature = "exp-destruct")]263 Self::Array { start, rest, end } => {264 start.iter().map(Destruct::binds_len).sum::<usize>()265 + end.iter().map(Destruct::binds_len).sum::<usize>()266 + cap_rest(rest)267 }268 #[cfg(feature = "exp-destruct")]269 Self::Object { fields, rest } => {270 let mut out = 0;271 for (_, into, _) in fields {272 match into {273 Some(v) => out += v.binds_len(),274 // Field is destructured to default name275 None => out += 1,276 }277 }278 out + cap_rest(rest)279 }280 }281 }282}283284#[derive(Debug, PartialEq, Acyclic)]285pub enum BindSpec {286 Field {287 into: Destruct,288 value: Expr,289 },290 Function {291 name: IStr,292 params: ExprParams,293 value: Expr,294 },295}296impl BindSpec {297 pub fn binds_len(&self) -> usize {298 match self {299 BindSpec::Field { into, .. } => into.binds_len(),300 BindSpec::Function { .. } => 1,301 }302 }303}304305#[derive(Debug, PartialEq, Acyclic)]306pub struct IfSpecData {307 pub span: Span,308 pub cond: Expr,309}310311#[derive(Debug, PartialEq, Acyclic)]312pub struct ForSpecData {313 pub destruct: Destruct,314 pub over: Expr,315}316317#[derive(Debug, PartialEq, Acyclic)]318pub enum CompSpec {319 IfSpec(IfSpecData),320 ForSpec(ForSpecData),321}322323#[derive(Debug, PartialEq, Acyclic)]324pub struct ObjComp {325 pub locals: Vec<BindSpec>,326 pub field: Box<FieldMember>,327 pub compspecs: Vec<CompSpec>,328}329330#[derive(Debug, PartialEq, Acyclic)]331pub struct ObjMembers {332 pub locals: Vec<BindSpec>,333 pub asserts: Vec<AssertStmt>,334 pub fields: Vec<FieldMember>,335}336337#[derive(Debug, PartialEq, Acyclic)]338pub enum ObjBody {339 MemberList(ObjMembers),340 ObjComp(ObjComp),341}342343#[derive(Debug, PartialEq, Eq, Clone, Copy, Acyclic)]344pub enum LiteralType {345 This,346 Super,347 Dollar,348 Null,349 True,350 False,351}352353#[derive(Debug, PartialEq, Acyclic)]354pub struct SliceDesc {355 pub start: Option<Spanned<Expr>>,356 pub end: Option<Spanned<Expr>>,357 pub step: Option<Spanned<Expr>>,358}359360#[derive(Debug, PartialEq, Acyclic)]361pub struct AssertExpr {362 pub assert: AssertStmt,363 pub rest: Expr,364}365366#[derive(Debug, PartialEq, Acyclic)]367pub struct BinaryOp {368 pub lhs: Expr,369 pub op: BinaryOpType,370 pub rhs: Expr,371}372373#[derive(Debug, PartialEq, Acyclic, Clone, Copy)]374pub enum ImportKind {375 Normal,376 Str,377 Bin,378}379380#[derive(Debug, PartialEq, Acyclic)]381pub struct IfElse {382 pub cond: IfSpecData,383 pub cond_then: Expr,384 pub cond_else: Option<Expr>,385}386387#[derive(Debug, PartialEq, Acyclic)]388pub struct Slice {389 pub value: Expr,390 pub slice: SliceDesc,391}392393/// Syntax base394#[derive(Debug, PartialEq, Acyclic)]395pub enum Expr {396 Literal(LiteralType),397398 /// String value: "hello"399 Str(IStr),400 /// Number: 1, 2.0, 2e+20401 Num(NumValue),402 /// Variable name: test403 Var(Spanned<IStr>),404405 /// Array of expressions: [1, 2, "Hello"]406 Arr(Vec<Expr>),407 /// Array comprehension:408 /// ```jsonnet409 /// ingredients: [410 /// { kind: kind, qty: 4 / 3 }411 /// for kind in [412 /// 'Honey Syrup',413 /// 'Lemon Juice',414 /// 'Farmers Gin',415 /// ]416 /// ],417 /// ```418 ArrComp(Box<Expr>, Vec<CompSpec>),419420 /// Object: {a: 2}421 Obj(ObjBody),422 /// Object extension: var1 {b: 2}423 ObjExtend(Box<Expr>, ObjBody),424425 /// -2426 UnaryOp(UnaryOpType, Box<Expr>),427 /// 2 - 2428 BinaryOp(Box<BinaryOp>),429 /// assert 2 == 2 : "Math is broken"430 AssertExpr(Box<AssertExpr>),431 /// local a = 2; { b: a }432 LocalExpr(Vec<BindSpec>, Box<Expr>),433434 /// import* "hello"435 Import(Spanned<ImportKind>, Box<Expr>),436 /// error "I'm broken"437 ErrorStmt(Span, Box<Expr>),438 /// a(b, c)439 Apply(Box<Expr>, Spanned<ArgsDesc>, bool),440 /// a[b], a.b, a?.b441 Index {442 indexable: Box<Expr>,443 parts: Vec<IndexPart>,444 },445 /// function(x) x446 Function(ExprParams, Box<Expr>),447 /// if true == false then 1 else 2448 IfElse(Box<IfElse>),449 Slice(Box<Slice>),450}451452#[derive(Debug, PartialEq, Acyclic)]453pub struct IndexPart {454 pub span: Span,455 pub value: Expr,456 #[cfg(feature = "exp-null-coaelse")]457 pub null_coaelse: bool,458}459460/// file, begin offset, end offset461#[derive(Clone, PartialEq, Eq, Acyclic)]462#[repr(C)]463pub struct Span(pub Source, pub u32, pub u32);464impl Span {465 pub fn belongs_to(&self, other: &Span) -> bool {466 other.0 == self.0 && other.1 <= self.1 && other.2 >= self.2467 }468 pub fn range(&self) -> RangeInclusive<usize> {469 let start = self.1;470 let mut end = self.2;471 if end > start {472 // Because it is originally exclusive473 end -= 1;474 }475 start as usize..=end as usize476 }477}478479#[cfg(target_pointer_width = "64")]480static_assertions::assert_eq_size!(Span, (usize, usize));481482impl Debug for Span {483 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {484 write!(f, "{:?}:{:?}-{:?}", self.0, self.1, self.2)485 }486}487488#[derive(Clone, PartialEq, Acyclic)]489pub struct Spanned<T: Acyclic> {490 pub value: T,491 pub span: Span,492}493impl<T: Acyclic> Deref for Spanned<T> {494 type Target = T;495 fn deref(&self) -> &Self::Target {496 &self.value497 }498}499impl<T: Acyclic> Spanned<T> {500 #[inline]501 pub fn new(value: T, span: Span) -> Self {502 Self { value, span }503 }504 pub fn map<U: Acyclic>(self, v: impl FnOnce(T) -> U) -> Spanned<U> {505 Spanned {506 span: self.span,507 value: v(self.value),508 }509 }510 pub fn as_ref<'a>(&'a self) -> Spanned<&'a T>511 where512 &'a T: Acyclic,513 {514 Spanned {515 span: self.span.clone(),516 value: &self.value,517 }518 }519}520521impl<T: Debug + Acyclic> Debug for Spanned<T> {522 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {523 let expr = &**self;524 if f.alternate() {525 write!(f, "{:#?}", expr)?;526 } else {527 write!(f, "{:?}", expr)?;528 }529 write!(f, " from {:?}", self.span)?;530 Ok(())531 }532}crates/jrsonnet-peg-parser/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-peg-parser/src/lib.rs
+++ b/crates/jrsonnet-peg-parser/src/lib.rs
@@ -61,13 +61,13 @@
rule keyword(id: &'static str) -> ()
= #{|input, pos| input.parse_string_literal(pos, id)} end_of_ident()
- pub rule param(s: &ParserSettings) -> ExprParam = destruct:destruct(s) expr:(_ "=" _ expr:expr(s){expr})? { ExprParam { destruct, default: expr.map(Rc::new) } }
+ pub rule param(s: &ParserSettings) -> ExprParam = destruct:destruct(s) default:(_ "=" _ default:expr(s){default})? { ExprParam { destruct, default } }
pub rule params(s: &ParserSettings) -> ExprParams
= params:param(s) ** comma() comma()? { ExprParams::new(params) }
/ { ExprParams::new(Vec::new()) }
- pub rule arg(s: &ParserSettings) -> (Option<IStr>, Rc<Expr>)
- = name:(quiet! { (s:id() _ "=" !['='] _ {s})? } / expected!("<argument name>")) expr:expr(s) {(name, Rc::new(expr))}
+ pub rule arg(s: &ParserSettings) -> (Option<IStr>, Expr)
+ = name:(quiet! { (s:id() _ "=" !['='] _ {s})? } / expected!("<argument name>")) expr:expr(s) {(name, expr)}
pub rule args(s: &ParserSettings) -> ArgsDesc
= args:arg(s)**comma() comma()? {?
@@ -123,7 +123,7 @@
#[cfg(not(feature = "exp-destruct"))] Err("!!!experimental destructuring was not enabled")
}
pub rule destruct(s: &ParserSettings) -> Destruct
- = v:id() {Destruct::Full(v)}
+ = v:spanned(<id()>, s) {Destruct::Full(v)}
/ "?" {?
#[cfg(feature = "exp-destruct")] return Ok(Destruct::Skip);
#[cfg(not(feature = "exp-destruct"))] Err("!!!experimental destructuring was not enabled")
@@ -132,8 +132,8 @@
/ obj:destruct_object(s) {obj}
pub rule bind(s: &ParserSettings) -> BindSpec
- = into:destruct(s) _ "=" _ value:expr(s) {BindSpec::Field{into, value: Rc::new(value)}}
- / name:id() _ "(" _ params:params(s) _ ")" _ "=" _ value:expr(s) {BindSpec::Function{name, params, value: Rc::new(value)}}
+ = into:destruct(s) _ "=" _ value:expr(s) {BindSpec::Field{into, value}}
+ / name:id() _ "(" _ params:params(s) _ ")" _ "=" _ value:expr(s) {BindSpec::Function{name, params, value}}
pub rule assertion(s: &ParserSettings) -> AssertStmt
= keyword("assert") _ assertion:spanned(<expr(s)>, s) message:(_ ":" _ e:expr(s) {e})? { AssertStmt{assertion, message} }
@@ -187,14 +187,14 @@
plus: plus.is_some(),
params: None,
visibility,
- value: Rc::new(value),
+ value,
}}
/ name:spanned(<field_name(s)>, s) _ "(" _ params:params(s) _ ")" _ visibility:visibility() _ value:expr(s) {FieldMember{
name,
plus: false,
params: Some(params),
visibility,
- value: Rc::new(value),
+ value,
}}
pub rule obj_local(s: &ParserSettings) -> BindSpec
= keyword("local") _ bind:bind(s) {bind}
@@ -217,8 +217,8 @@
}
}
ObjBody::ObjComp(ObjComp {
- locals: Rc::new(locals),
- field: field.map(Rc::new).ok_or("<missing object comprehension field>")?,
+ locals,
+ field: Box::new(field.ok_or("<missing object comprehension field>")?),
compspecs
})
} else {
@@ -233,8 +233,8 @@
}
}
ObjBody::MemberList(ObjMembers {
- locals: Rc::new(locals),
- asserts: Rc::new(asserts),
+ locals,
+ asserts,
fields
})
})
@@ -259,10 +259,10 @@
pub rule obj_expr(s: &ParserSettings) -> Expr
= "{" _ body:objinside(s) _ "}" {Expr::Obj(body)}
pub rule array_expr(s: &ParserSettings) -> Expr
- = "[" _ elems:(expr(s) ** comma()) _ comma()? "]" {Expr::Arr(Rc::new(elems))}
+ = "[" _ elems:(expr(s) ** comma()) _ comma()? "]" {Expr::Arr(elems)}
pub rule array_comp_expr(s: &ParserSettings) -> Expr
= "[" _ expr:expr(s) _ comma()? _ specs:(r: compspecs(s) _ {r}) "]" {
- Expr::ArrComp(Rc::new(expr), specs)
+ Expr::ArrComp(Box::new(expr), specs)
}
pub rule number_expr(s: &ParserSettings) -> Expr
= n:number() {? if let Some(n) = NumValue::new(n) {
@@ -315,8 +315,8 @@
/ local_expr(s)
/ if_then_else_expr(s)
- / keyword("function") _ "(" _ params:params(s) _ ")" _ expr:expr(s) {Expr::Function(params, Rc::new(expr))}
- / assert:assertion(s) _ ";" _ rest:expr(s) { Expr::AssertExpr(Rc::new(AssertExpr{
+ / keyword("function") _ "(" _ params:params(s) _ ")" _ expr:expr(s) {Expr::Function(params, Box::new(expr))}
+ / assert:assertion(s) _ ";" _ rest:expr(s) { Expr::AssertExpr(Box::new(AssertExpr{
assert, rest
})) }
@@ -390,7 +390,7 @@
value:(@) _ "[" _ slice:slice_desc(s) _ "]" {Expr::Slice(Box::new(Slice{value, slice}))}
indexable:(@) _ parts:index_part(s)+ {Expr::Index{indexable: Box::new(indexable), parts}}
a:(@) _ args:spanned(<"(" _ a:args(s) _ ")" {a}>, s) ts:(_ keyword("tailstrict"))? {Expr::Apply(Box::new(a), args, ts.is_some())}
- a:(@) _ "{" _ body:objinside(s) _ "}" {Expr::ObjExtend(Rc::new(a), body)}
+ a:(@) _ "{" _ body:objinside(s) _ "}" {Expr::ObjExtend(Box::new(a), body)}
--
e:expr_basic(s) {e}
"(" _ e:expr(s) _ ")" {e}
crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@array_comp.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@array_comp.jsonnet.snap
+++ b/crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@array_comp.jsonnet.snap
@@ -35,7 +35,7 @@
ForSpec(
ForSpecData {
destruct: Full(
- "x",
+ "x" from virtual:<test>:23-24,
),
over: Var(
"arr" from virtual:<test>:28-31,
@@ -52,7 +52,7 @@
ForSpec(
ForSpecData {
destruct: Full(
- "a",
+ "a" from virtual:<test>:41-42,
),
over: Var(
"b" from virtual:<test>:46-47,
@@ -70,7 +70,7 @@
ForSpec(
ForSpecData {
destruct: Full(
- "e",
+ "e" from virtual:<test>:57-58,
),
over: Var(
"f" from virtual:<test>:62-63,
crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@default_nondefault.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@default_nondefault.jsonnet.snap
+++ b/crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@default_nondefault.jsonnet.snap
@@ -11,7 +11,7 @@
exprs: [
ExprParam {
destruct: Full(
- "foo",
+ "foo" from virtual:<test>:8-11,
),
default: Some(
Str(
@@ -21,7 +21,7 @@
},
ExprParam {
destruct: Full(
- "bar",
+ "bar" from virtual:<test>:21-24,
),
default: None,
},
crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@subexp.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@subexp.jsonnet.snap
+++ b/crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@subexp.jsonnet.snap
@@ -20,7 +20,7 @@
locals: [
Field {
into: Full(
- "x",
+ "x" from virtual:<test>:11-12,
),
value: Num(
1.0,