--- a/Cargo.lock +++ b/Cargo.lock @@ -730,6 +730,7 @@ version = "0.5.0-pre97" dependencies = [ "insta", + "jrsonnet-gcmodule", "jrsonnet-ir", "peg", ] --- a/crates/jrsonnet-evaluator/src/arr/mod.rs +++ b/crates/jrsonnet-evaluator/src/arr/mod.rs @@ -38,7 +38,7 @@ Self::new(RangeArray::empty()) } - pub fn expr(ctx: Context, exprs: Rc>>) -> Self { + pub fn expr(ctx: Context, exprs: Rc>) -> Self { Self::new(ExprArray::new(ctx, exprs)) } --- a/crates/jrsonnet-evaluator/src/arr/spec.rs +++ b/crates/jrsonnet-evaluator/src/arr/spec.rs @@ -118,11 +118,11 @@ #[derive(Debug, Trace, Clone)] pub struct ExprArray { ctx: Context, - src: Rc>>, + src: Rc>, cached: Cc>>, } impl ExprArray { - pub fn new(ctx: Context, src: Rc>>) -> Self { + pub fn new(ctx: Context, src: Rc>) -> Self { Self { ctx, cached: Cc::new(RefCell::new(vec![ArrayThunk::Waiting; src.len()])), --- a/crates/jrsonnet-evaluator/src/async_import.rs +++ b/crates/jrsonnet-evaluator/src/async_import.rs @@ -139,7 +139,7 @@ if let Expr::Str(s) = &***v { out.0.push(Import { path: ResolvePathOwned::Str(s.to_string()), - expression: matches!(&**expr, Expr::Import(ImportKind::Normal, _)), + expression: todo!(), }); } // Non-string import will fail in runtime --- a/crates/jrsonnet-evaluator/src/evaluate/mod.rs +++ b/crates/jrsonnet-evaluator/src/evaluate/mod.rs @@ -53,7 +53,7 @@ Expr::Str(_) | Expr::Num(_) | Expr::Literal(LiteralType::False | LiteralType::True | LiteralType::Null) => true, - Expr::Arr(a) => a.iter().all(|e| is_trivial(&**e)), + Expr::Arr(a) => a.iter().all(|e| is_trivial(&*e)), _ => false, } } @@ -71,7 +71,7 @@ } Val::Arr(ArrValue::eager( n.iter() - .map(|e| evaluate_trivial(&**e)) + .map(|e| evaluate_trivial(&*e)) .map(|e| e.expect("checked trivial")) .collect(), )) @@ -80,12 +80,7 @@ }) } -pub fn evaluate_method( - ctx: Context, - name: IStr, - params: ExprParams, - body: Rc>, -) -> Val { +pub fn evaluate_method(ctx: Context, name: IStr, params: ExprParams, body: Rc) -> Val { Val::Func(FuncVal::Normal(Cc::new(FuncDesc { name, ctx, @@ -97,18 +92,21 @@ pub fn evaluate_field_name(ctx: Context, field_name: &FieldName) -> Result> { Ok(match field_name { FieldName::Fixed(n) => Some(n.clone()), - FieldName::Dyn(expr) => in_frame( - CallLocation::new(&expr.span()), - || "evaluating field name".to_string(), - || { - let value = evaluate(ctx, expr)?; - if matches!(value, Val::Null) { - Ok(None) - } else { - Ok(Some(IStr::from_untyped(value)?)) - } - }, - )?, + FieldName::Dyn(expr) => { + // FIXME: Span + let value = evaluate(ctx, expr)?; + if matches!(value, Val::Null) { + None + } else { + Some(IStr::from_untyped(value)?) + } + } // + // in_frame( + // CallLocation::new(&expr.span()), + // || "evaluating field name".to_string(), + // || { + // }, + // )?, }) } @@ -119,46 +117,48 @@ ) -> Result<()> { match specs.first() { None => callback(ctx)?, - Some(CompSpec::IfSpec(IfSpecData(cond))) => { + Some(CompSpec::IfSpec(Spanned(IfSpecData(cond), _))) => { if bool::from_untyped(evaluate(ctx.clone(), cond)?)? { evaluate_comp(ctx, &specs[1..], callback)?; } } - Some(CompSpec::ForSpec(ForSpecData(var, expr))) => match evaluate(ctx.clone(), expr)? { - Val::Arr(list) => { - for item in list.iter_lazy() { - let fctx = Pending::new(); - let mut new_bindings = FxHashMap::with_capacity(var.binds_len()); - destruct(var, item, fctx.clone(), &mut new_bindings)?; - let ctx = ctx.clone().extend_bindings(new_bindings).into_future(fctx); + Some(CompSpec::ForSpec(Spanned(ForSpecData(var, expr), _))) => { + match evaluate(ctx.clone(), expr)? { + Val::Arr(list) => { + for item in list.iter_lazy() { + let fctx = Pending::new(); + let mut new_bindings = FxHashMap::with_capacity(var.binds_len()); + destruct(var, item, fctx.clone(), &mut new_bindings)?; + let ctx = ctx.clone().extend_bindings(new_bindings).into_future(fctx); - evaluate_comp(ctx, &specs[1..], callback)?; + evaluate_comp(ctx, &specs[1..], callback)?; + } } - } - #[cfg(feature = "exp-object-iteration")] - Val::Obj(obj) => { - for field in obj.fields( - // TODO: Should there be ability to preserve iteration order? - #[cfg(feature = "exp-preserve-order")] - false, - ) { - let fctx = Pending::new(); - let mut new_bindings = FxHashMap::with_capacity(var.binds_len()); - let obj = obj.clone(); - let value = Thunk::evaluated(Val::Arr(ArrValue::lazy(vec![ - Thunk::evaluated(Val::string(field.clone())), - Thunk!(move || obj.get(field).transpose().expect( - "field exists, as field name was obtained from object.fields()", - )), - ]))); - destruct(var, value, fctx.clone(), &mut new_bindings)?; - let ctx = ctx.clone().extend_bindings(new_bindings).into_future(fctx); + #[cfg(feature = "exp-object-iteration")] + Val::Obj(obj) => { + for field in obj.fields( + // TODO: Should there be ability to preserve iteration order? + #[cfg(feature = "exp-preserve-order")] + false, + ) { + let fctx = Pending::new(); + let mut new_bindings = FxHashMap::with_capacity(var.binds_len()); + let obj = obj.clone(); + let value = Thunk::evaluated(Val::Arr(ArrValue::lazy(vec![ + Thunk::evaluated(Val::string(field.clone())), + Thunk!(move || obj.get(field).transpose().expect( + "field exists, as field name was obtained from object.fields()", + )), + ]))); + destruct(var, value, fctx.clone(), &mut new_bindings)?; + let ctx = ctx.clone().extend_bindings(new_bindings).into_future(fctx); - evaluate_comp(ctx, &specs[1..], callback)?; + evaluate_comp(ctx, &specs[1..], callback)?; + } } + _ => bail!(InComprehensionCanOnlyIterateOverArray), } - _ => bail!(InComprehensionCanOnlyIterateOverArray), - }, + } } Ok(()) } @@ -221,7 +221,7 @@ #[derive(Trace)] struct UnboundValue { uctx: B, - value: Rc>, + value: Rc, name: IStr, } impl> Unbound for UnboundValue { @@ -235,7 +235,8 @@ .field(name.clone()) .with_add(*plus) .with_visibility(*visibility) - .with_location(value.span()) + // FIXME + // .with_location(value.span()) .bindable(UnboundValue { uctx, value: value.clone(), @@ -251,7 +252,7 @@ #[derive(Trace)] struct UnboundMethod { uctx: B, - value: Rc>, + value: Rc, params: ExprParams, name: IStr, } @@ -270,7 +271,7 @@ builder .field(name.clone()) .with_visibility(*visibility) - .with_location(value.span()) + // .with_location(value.span()) .bindable(UnboundMethod { uctx, value: value.clone(), @@ -337,7 +338,7 @@ pub fn evaluate_apply( ctx: Context, - value: &Spanned, + value: &Expr, args: &ArgsDesc, loc: CallLocation<'_>, tailstrict: bool, @@ -379,16 +380,16 @@ Ok(()) } -pub fn evaluate_named_param(ctx: Context, expr: &Spanned, name: ParamName) -> Result { +pub fn evaluate_named_param(ctx: Context, expr: &Expr, name: ParamName) -> Result { match name { ParamName::Named(name) => evaluate_named(ctx, expr, name), ParamName::Unnamed => evaluate(ctx, expr), } } -pub fn evaluate_named(ctx: Context, expr: &Spanned, name: IStr) -> Result { +pub fn evaluate_named(ctx: Context, expr: &Expr, name: IStr) -> Result { use Expr::*; - Ok(match &**expr { + Ok(match &*expr { Function(params, body) => evaluate_method(ctx, name, params.clone(), body.clone()), _ => evaluate(ctx, expr)?, }) @@ -417,7 +418,7 @@ // because the standalone super literal is not supported, that is because in other // implementations `in super` treated differently from `in smth_else`. BinaryOp(bin) - if matches!(&*bin.rhs, Expr::Literal(LiteralType::Super)) + if matches!(&bin.rhs, Expr::Literal(LiteralType::Super)) && bin.op == BinaryOpType::In => { let sup_this = ctx.try_sup_this()?; @@ -433,12 +434,12 @@ UnaryOp(o, v) => evaluate_unary_op(*o, &evaluate(ctx, v)?)?, Var(name) => in_frame( CallLocation::new(&name.span()), - || format!("local <{name}> access"), + || format!("local <{}> access", &**name), || ctx.binding((**name).clone())?.evaluate(), )?, Index { indexable, parts } => ensure_sufficient_stack(|| { let mut parts = parts.iter(); - let mut indexable = if matches!(&***indexable, Expr::Literal(LiteralType::Super)) { + let mut indexable = if matches!(&**indexable, Expr::Literal(LiteralType::Super)) { let part = parts.next().expect("at least part should exist"); // sup_this existence check might also be skipped here for null-coalesce... // But I believe this might cause errors. @@ -463,7 +464,7 @@ let name = name.into_flat(); match sup_this .get_super(name.clone()) - .with_description_src(&part.value, || format!("field <{name}> access"))? + .with_description_src(&part.span, || format!("field <{name}> access"))? { Some(v) => v, #[cfg(feature = "exp-null-coaelse")] @@ -485,7 +486,7 @@ indexable = match (indexable, evaluate(ctx.clone(), &part.value)?) { (Val::Obj(v), Val::Str(key)) => match v .get(key.clone().into_flat()) - .with_description_src(&part.value, || format!("field <{key}> access"))? + .with_description_src(&part.span, || format!("field <{key}> access"))? { Some(v) => v, #[cfg(feature = "exp-null-coaelse")] @@ -497,7 +498,7 @@ key.clone().into_flat(), suggestions, ))) - .with_description_src(&part.value, || format!("field <{key}> access")); + .with_description_src(&part.span, || format!("field <{key}> access")); } }, (Val::Obj(_), n) => bail!(ValueIndexMustBeTypeGot( @@ -605,17 +606,21 @@ evaluate_assert(ctx.clone(), &assert.assert)?; evaluate(ctx, &assert.rest)? } - ErrorStmt(e) => in_frame( - CallLocation::new(&e.span()), + ErrorStmt(s, e) => in_frame( + CallLocation::new(&s), || "error statement".to_owned(), || bail!(RuntimeError(evaluate(ctx, e)?.to_string()?,)), )?, IfElse(if_else) => { - if in_frame( - CallLocation::new(&if_else.cond.0.span()), - || "if condition".to_owned(), - || bool::from_untyped(evaluate(ctx.clone(), &if_else.cond.0)?), - )? { + if + // FIXME + //in_frame( + // CallLocation::new(&if_else.cond.0.span()), + // || "if condition".to_owned(), + // || + bool::from_untyped(evaluate(ctx.clone(), &if_else.cond.0)?)? + // )? + { evaluate(ctx, &if_else.cond_then)? } else { match &if_else.cond_else { @@ -626,14 +631,13 @@ } Slice(slice) => { fn parse_idx( - loc: CallLocation<'_>, ctx: Context, expr: Option<&Spanned>, desc: &'static str, ) -> Result> { if let Some(value) = expr { Ok(in_frame( - loc, + CallLocation::new(&value.span()), || format!("slice {desc}"), || >::from_untyped(evaluate(ctx, value)?), )?) @@ -643,24 +647,23 @@ } let indexable = evaluate(ctx.clone(), &slice.value)?; - let loc = CallLocation::new(&loc); - let start = parse_idx(loc, ctx.clone(), slice.slice.start.as_ref(), "start")?; - let end = parse_idx(loc, ctx.clone(), slice.slice.end.as_ref(), "end")?; - let step = parse_idx(loc, ctx, slice.slice.step.as_ref(), "step")?; + let start = parse_idx(ctx.clone(), slice.slice.start.as_ref(), "start")?; + let end = parse_idx(ctx.clone(), slice.slice.end.as_ref(), "end")?; + let step = parse_idx(ctx, slice.slice.step.as_ref(), "step")?; IndexableVal::into_untyped(indexable.into_indexable()?.slice(start, end, step)?)? } Import(kind, path) => { - let Expr::Str(path) = &***path else { + let Expr::Str(path) = &**path else { bail!("computed imports are not supported") }; - let tmp = loc.clone().0; with_state(|s| { - let resolved_path = s.resolve_from(tmp.source_path(), path)?; - Ok(match kind { + let span = kind.span(); + let resolved_path = s.resolve_from(span.0.source_path(), path)?; + Ok(match &**kind { ImportKind::Normal => in_frame( - CallLocation::new(&loc), + CallLocation::new(&span), || format!("import {:?}", path.clone()), || s.import_resolved(resolved_path), )?, --- a/crates/jrsonnet-evaluator/src/evaluate/operator.rs +++ b/crates/jrsonnet-evaluator/src/evaluate/operator.rs @@ -147,9 +147,9 @@ pub fn evaluate_binary_op_special( ctx: Context, - a: &Spanned, + a: &Expr, op: BinaryOpType, - b: &Spanned, + b: &Expr, ) -> Result { use BinaryOpType::*; use Val::*; --- a/crates/jrsonnet-evaluator/src/function/mod.rs +++ b/crates/jrsonnet-evaluator/src/function/mod.rs @@ -3,8 +3,8 @@ use educe::Educe; use jrsonnet_gcmodule::{Cc, Trace}; use jrsonnet_interner::IStr; +use jrsonnet_ir::{ArgsDesc, Destruct, Expr, ExprParams, Span, Spanned}; pub use jrsonnet_macros::builtin; -use jrsonnet_ir::{ArgsDesc, Destruct, Expr, ExprParams, Span, Spanned}; use self::{ builtin::{Builtin, StaticBuiltin}, @@ -71,7 +71,7 @@ /// Function parameter definition pub params: ExprParams, /// Function body - pub body: Rc>, + pub body: Rc, } impl FuncDesc { /// Create body context, but fill arguments without defaults with lazy error @@ -256,7 +256,7 @@ #[cfg(feature = "exp-destruct")] _ => return false, }; - **desc.body == Expr::Var(id.clone()) + matches!(&*desc.body, Expr::Var(v) if &**v == id) } _ => false, } --- a/crates/jrsonnet-evaluator/src/function/parse.rs +++ b/crates/jrsonnet-evaluator/src/function/parse.rs @@ -2,7 +2,7 @@ use jrsonnet_ir::{ function::{FunctionSignature, ParamName}, - ArgsDesc, Expr, ExprParams, Spanned, + ArgsDesc, Expr, ExprParams, }; use rustc_hash::FxHashMap; @@ -15,7 +15,7 @@ Context, Pending, Thunk, Val, }; -fn eval_arg(ctx: Context, arg: &Rc>, tailstrict: bool) -> Result> { +fn eval_arg(ctx: Context, arg: &Rc, tailstrict: bool) -> Result> { if tailstrict { Ok(Thunk::evaluated(evaluate(ctx, arg)?)) } else { --- a/crates/jrsonnet-evaluator/src/lib.rs +++ b/crates/jrsonnet-evaluator/src/lib.rs @@ -5,7 +5,7 @@ extern crate self as jrsonnet_evaluator; mod arr; -pub mod async_import; +// pub mod async_import; mod ctx; mod dynamic; pub mod error; @@ -187,7 +187,7 @@ struct FileData { string: Option, bytes: Option, - parsed: Option>>, + parsed: Option>, evaluated: Option, evaluating: bool, --- a/crates/jrsonnet-ir/src/expr.rs +++ b/crates/jrsonnet-ir/src/expr.rs @@ -17,7 +17,7 @@ /// {fixed: 2} Fixed(IStr), /// {["dyn"+"amic"]: 3} - Dyn(Spanned), + Dyn(Expr), } #[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)] @@ -46,7 +46,7 @@ pub plus: bool, pub params: Option, pub visibility: Visibility, - pub value: Rc>, + pub value: Rc, } #[derive(Debug, PartialEq, Acyclic)] @@ -152,7 +152,7 @@ #[derive(Debug, PartialEq, Acyclic)] pub struct ExprParam { pub destruct: Destruct, - pub default: Option>>, + pub default: Option>, } /// Defined function parameters @@ -194,11 +194,11 @@ #[derive(Debug, PartialEq, Acyclic)] pub struct ArgsDesc { - pub unnamed: Vec>>, - pub named: Vec<(IStr, Rc>)>, + pub unnamed: Vec>, + pub named: Vec<(IStr, Rc)>, } impl ArgsDesc { - pub fn new(unnamed: Vec>>, named: Vec<(IStr, Rc>)>) -> Self { + pub fn new(unnamed: Vec>, named: Vec<(IStr, Rc)>) -> Self { Self { unnamed, named } } } @@ -277,12 +277,12 @@ pub enum BindSpec { Field { into: Destruct, - value: Rc>, + value: Rc, }, Function { name: IStr, params: ExprParams, - value: Rc>, + value: Rc, }, } impl BindSpec { @@ -295,15 +295,15 @@ } #[derive(Debug, PartialEq, Acyclic)] -pub struct IfSpecData(pub Spanned); +pub struct IfSpecData(pub Expr); #[derive(Debug, PartialEq, Acyclic)] -pub struct ForSpecData(pub Destruct, pub Spanned); +pub struct ForSpecData(pub Destruct, pub Expr); #[derive(Debug, PartialEq, Acyclic)] pub enum CompSpec { - IfSpec(IfSpecData), - ForSpec(ForSpecData), + IfSpec(Spanned), + ForSpec(Spanned), } #[derive(Debug, PartialEq, Acyclic)] @@ -346,14 +346,14 @@ #[derive(Debug, PartialEq, Acyclic)] pub struct AssertExpr { pub assert: AssertStmt, - pub rest: Spanned, + pub rest: Expr, } #[derive(Debug, PartialEq, Acyclic)] pub struct BinaryOp { - pub lhs: Spanned, + pub lhs: Expr, pub op: BinaryOpType, - pub rhs: Spanned, + pub rhs: Expr, } #[derive(Debug, PartialEq, Acyclic)] @@ -366,13 +366,13 @@ #[derive(Debug, PartialEq, Acyclic)] pub struct IfElse { pub cond: IfSpecData, - pub cond_then: Spanned, - pub cond_else: Option>, + pub cond_then: Expr, + pub cond_else: Option, } #[derive(Debug, PartialEq, Acyclic)] pub struct Slice { - pub value: Spanned, + pub value: Expr, pub slice: SliceDesc, } @@ -389,7 +389,7 @@ Var(Spanned), /// Array of expressions: [1, 2, "Hello"] - Arr(Rc>>), + Arr(Rc>), /// Array comprehension: /// ```jsonnet /// ingredients: [ @@ -401,35 +401,35 @@ /// ] /// ], /// ``` - ArrComp(Rc>, Vec), + ArrComp(Rc, Vec), /// Object: {a: 2} Obj(ObjBody), /// Object extension: var1 {b: 2} - ObjExtend(Rc>, ObjBody), + ObjExtend(Rc, ObjBody), /// -2 - UnaryOp(UnaryOpType, Box>), + UnaryOp(UnaryOpType, Box), /// 2 - 2 BinaryOp(Box), /// assert 2 == 2 : "Math is broken" AssertExpr(Rc), /// local a = 2; { b: a } - LocalExpr(Vec, Box>), + LocalExpr(Vec, Box), /// import* "hello" - Import(ImportKind, Box>), + Import(Spanned, Box), /// error "I'm broken" - ErrorStmt(Box>), + ErrorStmt(Span, Box), /// a(b, c) - Apply(Box>, Spanned, bool), + Apply(Box, Spanned, bool), /// a[b], a.b, a?.b Index { - indexable: Box>, + indexable: Box, parts: Vec, }, /// function(x) x - Function(ExprParams, Rc>), + Function(ExprParams, Rc), /// if true == false then 1 else 2 IfElse(Box), Slice(Box), @@ -437,7 +437,8 @@ #[derive(Debug, PartialEq, Acyclic)] pub struct IndexPart { - pub value: Spanned, + pub span: Span, + pub value: Expr, #[cfg(feature = "exp-null-coaelse")] pub null_coaelse: bool, } @@ -461,7 +462,7 @@ } #[derive(Clone, PartialEq, Acyclic)] -pub struct Spanned(T, Span); +pub struct Spanned(pub T, pub Span); impl Deref for Spanned { type Target = T; fn deref(&self) -> &Self::Target { --- a/crates/jrsonnet-peg-parser/Cargo.toml +++ b/crates/jrsonnet-peg-parser/Cargo.toml @@ -7,6 +7,7 @@ version.workspace = true [dependencies] +jrsonnet-gcmodule.workspace = true jrsonnet-ir.workspace = true peg.workspace = true --- a/crates/jrsonnet-peg-parser/src/lib.rs +++ b/crates/jrsonnet-peg-parser/src/lib.rs @@ -1,7 +1,9 @@ +use jrsonnet_gcmodule::Acyclic; use jrsonnet_ir::{ - BinaryOp, Expr, ExprParams, IStr, IndexPart, Member, Slice, SliceDesc, Source, Span, Spanned, - ExprParam, ArgsDesc, AssertExpr, ImportKind, LiteralType, IfElse, CompSpec, ForSpecData, IfSpecData, ObjMembers, ObjBody, - ObjComp, FieldMember, Visibility, FieldName, unescape, AssertStmt, BindSpec, Destruct, DestructRest, + unescape, ArgsDesc, AssertExpr, AssertStmt, BinaryOp, BindSpec, CompSpec, Destruct, + DestructRest, Expr, ExprParam, ExprParams, FieldMember, FieldName, ForSpecData, IStr, IfElse, + IfSpecData, ImportKind, IndexPart, LiteralType, Member, ObjBody, ObjComp, ObjMembers, Slice, + SliceDesc, Source, Span, Spanned, Visibility, }; use peg::parser; use std::rc::Rc; @@ -63,7 +65,7 @@ = params:param(s) ** comma() comma()? { ExprParams::new(params) } / { ExprParams::new(Vec::new()) } - pub rule arg(s: &ParserSettings) -> (Option, Rc>) + pub rule arg(s: &ParserSettings) -> (Option, Rc) = name:(quiet! { (s:id() _ "=" !['='] _ {s})? } / expected!("")) expr:expr(s) {(name, Rc::new(expr))} pub rule args(s: &ParserSettings) -> ArgsDesc @@ -133,7 +135,7 @@ / name:id() _ "(" _ params:params(s) _ ")" _ "=" _ value:expr(s) {BindSpec::Function{name, params, value: Rc::new(value)}} pub rule assertion(s: &ParserSettings) -> AssertStmt - = keyword("assert") _ cond:expr(s) msg:(_ ":" _ e:expr(s) {e})? { AssertStmt(cond, msg) } + = keyword("assert") _ cond:spanned(, s) msg:(_ ":" _ e:spanned(, s) {e})? { AssertStmt(cond, msg) } pub rule whole_line() -> &'input str = str:$((!['\n'][_])* "\n") {str} @@ -241,7 +243,7 @@ pub rule forspec(s: &ParserSettings) -> ForSpecData = keyword("for") _ id:destruct(s) _ keyword("in") _ cond:expr(s) {ForSpecData(id, cond)} rule compspec(s: &ParserSettings) -> CompSpec - = i:ifspec(s) { CompSpec::IfSpec(i) } / f:forspec(s) {CompSpec::ForSpec(f)} + = i:spanned(, s) { CompSpec::IfSpec(i) } / f:spanned(, s) {CompSpec::ForSpec(f)} pub rule compspecs(s: &ParserSettings) -> Vec = specs:compspec(s) ++ _ {? if !matches!(specs[0], CompSpec::ForSpec(_)) { @@ -267,8 +269,12 @@ } else { Err("!!!numbers are finite") }} + + rule spanned(x: rule, s: &ParserSettings) -> Spanned + = a:position!() n:x() b:position!() { Spanned::new(n, Span(s.source.clone(), a as u32, b as u32)) } + pub rule var_expr(s: &ParserSettings) -> Expr - = n:id() { Expr::Var(n) } + = n:spanned(, s) { Expr::Var(n) } pub rule id_loc(s: &ParserSettings) -> Spanned = a:position!() n:id() b:position!() { Spanned::new(Expr::Str(n), Span(s.source.clone(), a as u32,b as u32)) } pub rule if_then_else_expr(s: &ParserSettings) -> Expr @@ -302,7 +308,7 @@ / array_expr(s) / array_comp_expr(s) - / kind:import_kind() _ path:expr(s) {Expr::Import(kind, Box::new(path))} + / kind:spanned(, s) _ path:expr(s) {Expr::Import(kind, Box::new(path))} / var_expr(s) / local_expr(s) @@ -313,10 +319,10 @@ assert, rest })) } - / keyword("error") _ expr:expr(s) { Expr::ErrorStmt(Box::new(expr)) } + / err_kw:spanned(, s) _ expr:expr(s) { Expr::ErrorStmt(err_kw.1, Box::new(expr)) } rule slice_part(s: &ParserSettings) -> Option> - = _ e:(e:expr(s) _{e})? {e} + = _ e:(e:spanned(, s) _{e})? {e} pub rule slice_desc(s: &ParserSettings) -> SliceDesc = start:slice_part(s) ":" pair:(end:slice_part(s) step:(":" e:slice_part(s){e})? {(end, step.flatten())})? { let (end, step) = if let Some((end, step)) = pair { @@ -340,11 +346,8 @@ } use jrsonnet_ir::BinaryOpType::*; use jrsonnet_ir::UnaryOpType::*; - rule expr(s: &ParserSettings) -> Spanned + rule expr(s: &ParserSettings) -> Expr = precedence! { - "(" _ e:expr(s) _ ")" {e} - start:position!() v:@ end:position!() { Spanned::new(v, Span(s.source.clone(), start as u32, end as u32)) } - -- a:(@) _ binop(<"||">) _ b:@ {expr_bin!(a Or b)} a:(@) _ binop(<"??">) _ ensure_null_coaelse() b:@ { #[cfg(feature = "exp-null-coaelse")] return expr_bin!(a NullCoaelse b); @@ -385,29 +388,32 @@ -- 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:args(s) _ ")" ts:(_ keyword("tailstrict"))? {Expr::Apply(Box::new(a), args, ts.is_some())} + 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)} -- e:expr_basic(s) {e} + "(" _ e:expr(s) _ ")" {e} } pub rule index_part(s: &ParserSettings) -> IndexPart = n:("?" _ ensure_null_coaelse())? "." _ value:id_loc(s) {IndexPart { - value, + span: value.1, + value: value.0, #[cfg(feature = "exp-null-coaelse")] null_coaelse: n.is_some(), }} - / n:("?" _ "." _ ensure_null_coaelse())? "[" _ value:expr(s) _ "]" {IndexPart { - value, + / n:("?" _ "." _ ensure_null_coaelse())? value:spanned(<"[" _ v:expr(s) _ "]" {v}>, s) {IndexPart { + span: value.1, + value: value.0, #[cfg(feature = "exp-null-coaelse")] null_coaelse: n.is_some(), }} - pub rule jsonnet(s: &ParserSettings) -> Spanned = _ e:expr(s) _ {e} + pub rule jsonnet(s: &ParserSettings) -> Expr = _ e:expr(s) _ {e} } } pub type ParseError = peg::error::ParseError; -pub fn parse(str: &str, settings: &ParserSettings) -> Result, ParseError> { +pub fn parse(str: &str, settings: &ParserSettings) -> Result { jsonnet_parser::jsonnet(str, settings) } /// Used for importstr values