difftreelog
refactor(ir) explicit Rc wrapping
in: master
51 files changed
Cargo.lockdiffbeforeafterboth717name = "jrsonnet-parser"717name = "jrsonnet-parser"718version = "0.5.0-pre97"718version = "0.5.0-pre97"719dependencies = [719dependencies = [720 "insta",720 "jrsonnet-gcmodule",721 "jrsonnet-gcmodule",721 "jrsonnet-interner",722 "jrsonnet-interner",722 "peg",723 "peg",crates/jrsonnet-evaluator/src/arr/mod.rsdiffbeforeafterboth1use std::{1use std::{2 any::Any,2 any::Any,3 fmt::{self},3 fmt::{self},4 num::NonZeroU32,4 num::NonZeroU32, rc::Rc,5};5};667use jrsonnet_gcmodule::{cc_dyn, Cc};7use jrsonnet_gcmodule::{cc_dyn, Cc};8use jrsonnet_interner::IBytes;8use jrsonnet_interner::IBytes;9use jrsonnet_parser::LocExpr;9use jrsonnet_parser::{Expr, Spanned};101011use crate::{function::FuncVal, Context, Result, Thunk, Val};11use crate::{function::FuncVal, Context, Result, Thunk, Val};121237 Self::new(RangeArray::empty())37 Self::new(RangeArray::empty())38 }38 }393940 pub fn expr(ctx: Context, exprs: impl IntoIterator<Item = LocExpr>) -> Self {40 pub fn expr(ctx: Context, exprs: Rc<Vec<Spanned<Expr>>>) -> Self {41 Self::new(ExprArray::new(ctx, exprs))41 Self::new(ExprArray::new(ctx, exprs))42 }42 }4343crates/jrsonnet-evaluator/src/arr/spec.rsdiffbeforeafterboth1use std::rc::Rc;1use std::{any::Any, cell::RefCell, fmt::Debug, iter, mem::replace};2use std::{any::Any, cell::RefCell, fmt::Debug, mem::replace};233use jrsonnet_gcmodule::{Cc, Trace};4use jrsonnet_gcmodule::{Cc, Trace};4use jrsonnet_interner::{IBytes, IStr};5use jrsonnet_interner::{IBytes, IStr};5use jrsonnet_parser::LocExpr;6use jrsonnet_parser::{Expr, Spanned};677use super::ArrValue;8use super::ArrValue;8use crate::{9use crate::{103}104}104105105#[derive(Debug, Trace, Clone)]106#[derive(Debug, Trace, Clone)]106enum ArrayThunk<T: 'static + Trace> {107enum ArrayThunk {107 Computed(Val),108 Computed(Val),108 Errored(Error),109 Errored(Error),109 Waiting(T),110 Waiting,110 Pending,111 Pending,111}112}112113113#[derive(Debug, Trace, Clone)]114#[derive(Debug, Trace, Clone)]114pub struct ExprArray {115pub struct ExprArray {115 ctx: Context,116 ctx: Context,117 src: Rc<Vec<Spanned<Expr>>>,116 cached: Cc<RefCell<Vec<ArrayThunk<LocExpr>>>>,118 cached: Cc<RefCell<Vec<ArrayThunk>>>,117}119}118impl ExprArray {120impl ExprArray {119 pub fn new(ctx: Context, items: impl IntoIterator<Item = LocExpr>) -> Self {121 pub fn new(ctx: Context, src: Rc<Vec<Spanned<Expr>>>) -> Self {120 Self {122 Self {121 ctx,123 ctx,122 cached: Cc::new(RefCell::new(124 cached: Cc::new(RefCell::new(vec![ArrayThunk::Waiting; src.len()])),123 items.into_iter().map(ArrayThunk::Waiting).collect(),125 src,124 )),125 }126 }126 }127 }137 ArrayThunk::Computed(c) => return Ok(Some(c.clone())),138 ArrayThunk::Computed(c) => return Ok(Some(c.clone())),138 ArrayThunk::Errored(e) => return Err(e.clone()),139 ArrayThunk::Errored(e) => return Err(e.clone()),139 ArrayThunk::Pending => return Err(InfiniteRecursionDetected.into()),140 ArrayThunk::Pending => return Err(InfiniteRecursionDetected.into()),140 ArrayThunk::Waiting(..) => {}141 ArrayThunk::Waiting => {}141 };142 };142143143 let ArrayThunk::Waiting(expr) =144 let ArrayThunk::Waiting =144 replace(&mut self.cached.borrow_mut()[index], ArrayThunk::Pending)145 replace(&mut self.cached.borrow_mut()[index], ArrayThunk::Pending)145 else {146 else {146 unreachable!()147 unreachable!()147 };148 };148149149 let new_value = match evaluate(self.ctx.clone(), &expr) {150 let new_value = match evaluate(self.ctx.clone(), &self.src[index]) {150 Ok(v) => v,151 Ok(v) => v,151 Err(e) => {152 Err(e) => {152 self.cached.borrow_mut()[index] = ArrayThunk::Errored(e.clone());153 self.cached.borrow_mut()[index] = ArrayThunk::Errored(e.clone());163 match &self.cached.borrow()[index] {164 match &self.cached.borrow()[index] {164 ArrayThunk::Computed(c) => return Some(Thunk::evaluated(c.clone())),165 ArrayThunk::Computed(c) => return Some(Thunk::evaluated(c.clone())),165 ArrayThunk::Errored(e) => return Some(Thunk::errored(e.clone())),166 ArrayThunk::Errored(e) => return Some(Thunk::errored(e.clone())),166 ArrayThunk::Waiting(_) | ArrayThunk::Pending => {}167 ArrayThunk::Waiting | ArrayThunk::Pending => {}167 };168 };168169169 #[derive(Trace)]170 #[derive(Trace)]406#[derive(Trace, Debug, Clone)]407#[derive(Trace, Debug, Clone)]407pub struct MappedArray<const WITH_INDEX: bool> {408pub struct MappedArray<const WITH_INDEX: bool> {408 inner: ArrValue,409 inner: ArrValue,409 cached: Cc<RefCell<Vec<ArrayThunk<()>>>>,410 cached: Cc<RefCell<Vec<ArrayThunk>>>,410 mapper: FuncVal,411 mapper: FuncVal,411}412}412impl<const WITH_INDEX: bool> MappedArray<WITH_INDEX> {413impl<const WITH_INDEX: bool> MappedArray<WITH_INDEX> {413 pub fn new(inner: ArrValue, mapper: FuncVal) -> Self {414 pub fn new(inner: ArrValue, mapper: FuncVal) -> Self {414 let len = inner.len();415 let len = inner.len();415 Self {416 Self {416 inner,417 inner,417 cached: Cc::new(RefCell::new(vec![ArrayThunk::Waiting(()); len])),418 cached: Cc::new(RefCell::new(vec![ArrayThunk::Waiting; len])),418 mapper,419 mapper,419 }420 }420 }421 }439 ArrayThunk::Computed(c) => return Ok(Some(c.clone())),440 ArrayThunk::Computed(c) => return Ok(Some(c.clone())),440 ArrayThunk::Errored(e) => return Err(e.clone()),441 ArrayThunk::Errored(e) => return Err(e.clone()),441 ArrayThunk::Pending => return Err(InfiniteRecursionDetected.into()),442 ArrayThunk::Pending => return Err(InfiniteRecursionDetected.into()),442 ArrayThunk::Waiting(..) => {}443 ArrayThunk::Waiting => {}443 };444 };444445445 let ArrayThunk::Waiting(()) =446 let ArrayThunk::Waiting =446 replace(&mut self.cached.borrow_mut()[index], ArrayThunk::Pending)447 replace(&mut self.cached.borrow_mut()[index], ArrayThunk::Pending)447 else {448 else {448 unreachable!()449 unreachable!()472 match &self.cached.borrow()[index] {473 match &self.cached.borrow()[index] {473 ArrayThunk::Computed(c) => return Some(Thunk::evaluated(c.clone())),474 ArrayThunk::Computed(c) => return Some(Thunk::evaluated(c.clone())),474 ArrayThunk::Errored(e) => return Some(Thunk::errored(e.clone())),475 ArrayThunk::Errored(e) => return Some(Thunk::errored(e.clone())),475 ArrayThunk::Waiting(()) | ArrayThunk::Pending => {}476 ArrayThunk::Waiting | ArrayThunk::Pending => {}476 };477 };477478478 #[derive(Trace)]479 #[derive(Trace)]crates/jrsonnet-evaluator/src/async_import.rsdiffbeforeafterboth1use std::rc::Rc;1use std::{any::Any, cell::RefCell, future::Future};2use std::{any::Any, cell::RefCell, future::Future};233use jrsonnet_gcmodule::Acyclic;4use jrsonnet_gcmodule::Acyclic;4use jrsonnet_parser::{5use jrsonnet_parser::{5 ArgsDesc, AssertStmt, BindSpec, CompSpec, Destruct, Expr, FieldMember, FieldName, ForSpecData,6 ArgsDesc, AssertExpr, AssertStmt, BindSpec, CompSpec, Destruct, Expr, FieldMember, FieldName,6 IfSpecData, LocExpr, Member, ObjBody, Param, ParamsDesc, ParserSettings, SliceDesc, Source,7 ForSpecData, IfElse, IfSpecData, ImportKind, Member, ObjBody, Param, ParamsDesc,7 SourcePath,8 ParserSettings, Slice, SliceDesc, Source, SourcePath, Spanned,8};9};9use rustc_hash::FxHashMap;10use rustc_hash::FxHashMap;1011192020// Visits all nodes, trying to find import statements21// Visits all nodes, trying to find import statements21#[allow(clippy::too_many_lines)]22#[allow(clippy::too_many_lines)]22pub fn find_imports(expr: &LocExpr, out: &mut FoundImports) {23pub fn find_imports(expr: &Spanned<Expr>, out: &mut FoundImports) {23 fn in_destruct(dest: &Destruct, #[allow(unused_variables)] out: &mut FoundImports) {24 fn in_destruct(dest: &Destruct, #[allow(unused_variables)] out: &mut FoundImports) {24 match dest {25 match dest {25 #[cfg(feature = "exp-destruct")]26 #[cfg(feature = "exp-destruct")]120 find_imports(value, out);121 find_imports(value, out);121 }122 }122 Member::BindStmt(_) => todo!(),123 Member::BindStmt(_) => todo!(),123 Member::AssertStmt(AssertStmt(expr, expr2)) => {124 Member::AssertStmt(assert) => {124 find_imports(expr, out);125 find_imports(&assert.0, out);125 if let Some(expr) = expr2 {126 if let Some(expr) = &assert.1 {126 find_imports(expr, out);127 find_imports(expr, out);127 }128 }128 }129 }132 ObjBody::ObjComp(_) => todo!(),133 ObjBody::ObjComp(_) => todo!(),133 }134 }134 }135 }135 match &*expr.expr() {136 match &**expr {136 Expr::Import(v) | Expr::ImportStr(v) | Expr::ImportBin(v) => {137 Expr::Import(_, v) => {137 if let Expr::Str(s) = &*v.expr() {138 if let Expr::Str(s) = &***v {138 out.0.push(Import {139 out.0.push(Import {139 path: ResolvePathOwned::Str(s.to_string()),140 path: ResolvePathOwned::Str(s.to_string()),140 expression: matches!(&*expr.expr(), Expr::Import(_)),141 expression: matches!(&**expr, Expr::Import(ImportKind::Normal, _)),141 });142 });142 }143 }143 // Non-string import will fail in runtime144 // Non-string import will fail in runtime146 Expr::Literal(_) | Expr::Str(_) | Expr::Num(_) | Expr::Var(_) => {}147 Expr::Literal(_) | Expr::Str(_) | Expr::Num(_) | Expr::Var(_) => {}147148148 Expr::Arr(arr) => {149 Expr::Arr(arr) => {149 for expr in arr {150 for expr in &**arr {150 find_imports(expr, out);151 find_imports(expr, out);151 }152 }152 }153 }159 find_imports(expr, out);160 find_imports(expr, out);160 in_obj(obj, out);161 in_obj(obj, out);161 }162 }162 Expr::BinaryOp(a, _, b) => {163 Expr::BinaryOp(binop) => {163 find_imports(a, out);164 find_imports(&binop.lhs, out);164 find_imports(b, out);165 find_imports(&binop.rhs, out);165 }166 }166 Expr::AssertExpr(AssertStmt(expr, expr2), then) => {167 Expr::AssertExpr(assert) => {168 let AssertExpr {169 assert: AssertStmt(expr, expr2),170 rest,171 } = &**assert;167 find_imports(expr, out);172 find_imports(expr, out);168 if let Some(expr) = expr2 {173 if let Some(expr) = expr2 {169 find_imports(expr, out);174 find_imports(expr, out);170 }175 }171 find_imports(then, out);176 find_imports(rest, out);172 }177 }173 Expr::LocalExpr(specs, expr) => {178 Expr::LocalExpr(specs, expr) => {174 in_bind(specs, out);179 in_bind(specs, out);175 find_imports(expr, out);180 find_imports(expr, out);188 in_params(params, out);193 in_params(params, out);189 find_imports(expr, out);194 find_imports(expr, out);190 }195 }191 Expr::IfElse {196 Expr::IfElse(if_else) => {197 let IfElse {192 cond: IfSpecData(expr),198 cond: IfSpecData(expr),193 cond_then,199 cond_then,194 cond_else,200 cond_else,195 } => {201 } = &**if_else;196 find_imports(expr, out);202 find_imports(expr, out);197 find_imports(cond_then, out);203 find_imports(cond_then, out);198 if let Some(expr) = cond_else {204 if let Some(expr) = cond_else {199 find_imports(expr, out);205 find_imports(expr, out);200 }206 }201 }207 }202 Expr::Slice(expr, SliceDesc { start, end, step }) => {208 Expr::Slice(slice) => {209 let Slice {210 value,211 slice: SliceDesc { start, end, step },212 } = &**slice;203 find_imports(expr, out);213 find_imports(value, out);204 if let Some(expr) = start {214 if let Some(expr) = start {205 find_imports(expr, out);215 find_imports(expr, out);206 }216 }210 if let Some(expr) = step {220 if let Some(expr) = step {211 find_imports(expr, out);221 find_imports(expr, out);212 }222 }213 }223 }214 Expr::UnaryOp(_, expr) | Expr::ErrorStmt(expr) => {224 Expr::UnaryOp(_, expr) | Expr::ErrorStmt(expr) => {215 find_imports(expr, out);225 find_imports(expr, out);216 }226 }315 let source = Source::new(path.clone(), code.clone());325 let source = Source::new(path.clone(), code.clone());316 // If failed - then skip import326 // If failed - then skip import317 file.parsed =327 file.parsed = jrsonnet_parser::parse(&code, &ParserSettings { source })328 .map(Rc::new)318 jrsonnet_parser::parse(&code, &ParserSettings { source }).ok();329 .ok();319 if let Some(parsed) = &file.parsed {330 if let Some(parsed) = &file.parsed {320 let mut imports = FoundImports(vec![]);331 let mut imports = FoundImports(vec![]);crates/jrsonnet-evaluator/src/error.rsdiffbeforeafterboth4 fmt::{Debug, Display},4 fmt::{Debug, Display},5};5};667use jrsonnet_gcmodule::Trace;7use jrsonnet_gcmodule::{Acyclic, Trace};8use jrsonnet_interner::IStr;8use jrsonnet_interner::IStr;9use jrsonnet_parser::{BinaryOpType, LocExpr, Source, SourcePath, Span, UnaryOpType};9use jrsonnet_parser::{BinaryOpType, Source, SourcePath, Span, Spanned, UnaryOpType};10use jrsonnet_types::ValType;10use jrsonnet_types::ValType;11use thiserror::Error;11use thiserror::Error;1212324pub trait ErrorSource {324pub trait ErrorSource {325 fn to_location(self) -> Option<Span>;325 fn to_location(self) -> Option<Span>;326}326}327impl ErrorSource for &LocExpr {327impl<T: Acyclic> ErrorSource for &Spanned<T> {328 fn to_location(self) -> Option<Span> {328 fn to_location(self) -> Option<Span> {329 Some(self.span())329 Some(self.span())330 }330 }crates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth4use jrsonnet_interner::IStr;4use jrsonnet_interner::IStr;5use jrsonnet_parser::{5use jrsonnet_parser::{6 ArgsDesc, AssertStmt, BinaryOpType, BindSpec, CompSpec, Expr, FieldMember, FieldName,6 ArgsDesc, AssertStmt, BinaryOpType, BindSpec, CompSpec, Expr, FieldMember, FieldName,7 ForSpecData, IfSpecData, LiteralType, LocExpr, Member, ObjBody, ParamsDesc,7 ForSpecData, IfSpecData, ImportKind, LiteralType, Member, ObjBody, ParamsDesc, Spanned,8};8};9use jrsonnet_types::ValType;9use jrsonnet_types::ValType;10use rustc_hash::FxHashMap;10use rustc_hash::FxHashMap;46 stacker::maybe_grow(RED_ZONE, STACK_PER_RECURSION, f)46 stacker::maybe_grow(RED_ZONE, STACK_PER_RECURSION, f)47}47}484849pub fn evaluate_trivial(expr: &LocExpr) -> Option<Val> {49pub fn evaluate_trivial(expr: &Spanned<Expr>) -> Option<Val> {50 fn is_trivial(expr: &LocExpr) -> bool {50 fn is_trivial(expr: &Spanned<Expr>) -> bool {51 match expr.expr() {51 match &**expr {52 Expr::Str(_)52 Expr::Str(_)53 | Expr::Num(_)53 | Expr::Num(_)54 | Expr::Literal(LiteralType::False | LiteralType::True | LiteralType::Null) => true,54 | Expr::Literal(LiteralType::False | LiteralType::True | LiteralType::Null) => true,55 Expr::Arr(a) => a.iter().all(is_trivial),55 Expr::Arr(a) => a.iter().all(is_trivial),56 _ => false,56 _ => false,57 }57 }58 }58 }59 Some(match expr.expr() {59 Some(match &**expr {60 Expr::Str(s) => Val::string(s.clone()),60 Expr::Str(s) => Val::string(s.clone()),61 Expr::Num(n) => {61 Expr::Num(n) => {62 Val::Num(NumValue::new(*n).expect("parser will not allow non-finite values"))62 Val::Num(NumValue::new(*n).expect("parser will not allow non-finite values"))79 })79 })80}80}818182pub fn evaluate_method(ctx: Context, name: IStr, params: ParamsDesc, body: LocExpr) -> Val {82pub fn evaluate_method(83 ctx: Context,84 name: IStr,85 params: ParamsDesc,86 body: Rc<Spanned<Expr>>,87) -> Val {83 Val::Func(FuncVal::Normal(Cc::new(FuncDesc {88 Val::Func(FuncVal::Normal(Cc::new(FuncDesc {84 name,89 name,215 #[derive(Trace)]220 #[derive(Trace)]216 struct UnboundValue<B: Trace> {221 struct UnboundValue<B: Trace> {217 uctx: B,222 uctx: B,218 value: LocExpr,223 value: Rc<Spanned<Expr>>,219 name: IStr,224 name: IStr,220 }225 }221 impl<B: Unbound<Bound = Context>> Unbound for UnboundValue<B> {226 impl<B: Unbound<Bound = Context>> Unbound for UnboundValue<B> {245 #[derive(Trace)]250 #[derive(Trace)]246 struct UnboundMethod<B: Trace> {251 struct UnboundMethod<B: Trace> {247 uctx: B,252 uctx: B,248 value: LocExpr,253 value: Rc<Spanned<Expr>>,249 params: ParamsDesc,254 params: ParamsDesc,250 name: IStr,255 name: IStr,251 }256 }301 #[derive(Trace)]306 #[derive(Trace)]302 struct ObjectAssert<B: Trace> {307 struct ObjectAssert<B: Trace> {303 uctx: B,308 uctx: B,304 assert: AssertStmt,309 assert: Rc<AssertStmt>,305 }310 }306 impl<B: Unbound<Bound = Context>> ObjectAssertion for ObjectAssert<B> {311 impl<B: Unbound<Bound = Context>> ObjectAssertion for ObjectAssert<B> {307 fn run(&self, sup_this: SupThis) -> Result<()> {312 fn run(&self, sup_this: SupThis) -> Result<()> {347352348pub fn evaluate_apply(353pub fn evaluate_apply(349 ctx: Context,354 ctx: Context,350 value: &LocExpr,355 value: &Spanned<Expr>,351 args: &ArgsDesc,356 args: &ArgsDesc,352 loc: CallLocation<'_>,357 loc: CallLocation<'_>,353 tailstrict: bool,358 tailstrict: bool,389 Ok(())394 Ok(())390}395}391396392pub fn evaluate_named(ctx: Context, expr: &LocExpr, name: IStr) -> Result<Val> {397pub fn evaluate_named(ctx: Context, expr: &Spanned<Expr>, name: IStr) -> Result<Val> {393 use Expr::*;398 use Expr::*;394 Ok(match expr.expr() {399 Ok(match &**expr {395 Function(params, body) => evaluate_method(ctx, name, params.clone(), body.clone()),400 Function(params, body) => evaluate_method(ctx, name, params.clone(), body.clone()),396 _ => evaluate(ctx, expr)?,401 _ => evaluate(ctx, expr)?,397 })402 })398}403}399404400#[allow(clippy::too_many_lines)]405#[allow(clippy::too_many_lines)]401pub fn evaluate(ctx: Context, expr: &LocExpr) -> Result<Val> {406pub fn evaluate(ctx: Context, expr: &Spanned<Expr>) -> Result<Val> {402 use Expr::*;407 use Expr::*;403408404 if let Some(trivial) = evaluate_trivial(expr) {409 if let Some(trivial) = evaluate_trivial(expr) {405 return Ok(trivial);410 return Ok(trivial);406 }411 }407 let loc = expr.span();412 let loc = expr.span();408 Ok(match expr.expr() {413 Ok(match &**expr {409 Literal(LiteralType::This) => Val::Obj(ctx.try_this()?),414 Literal(LiteralType::This) => Val::Obj(ctx.try_this()?),410 Literal(LiteralType::Super) => Val::Obj(ctx.try_sup_this()?.standalone_super()?),415 Literal(LiteralType::Super) => Val::Obj(ctx.try_sup_this()?.standalone_super()?),411 Literal(LiteralType::Dollar) => Val::Obj(ctx.try_dollar()?),416 Literal(LiteralType::Dollar) => Val::Obj(ctx.try_dollar()?),420 // Note that other jsonnet implementations will fail on `if value in (super)` expression,425 // Note that other jsonnet implementations will fail on `if value in (super)` expression,421 // because the standalone super literal is not supported, that is because in other426 // because the standalone super literal is not supported, that is because in other422 // implementations `in super` treated differently from `in smth_else`.427 // implementations `in super` treated differently from `in smth_else`.423 BinaryOp(field, BinaryOpType::In, e)428 BinaryOp(bin)424 if matches!(e.expr(), Expr::Literal(LiteralType::Super)) =>429 if matches!(&*bin.rhs, Expr::Literal(LiteralType::Super))430 && bin.op == BinaryOpType::In =>425 {431 {426 let sup_this = ctx.try_sup_this()?;432 let sup_this = ctx.try_sup_this()?;427 // In jsonnet, "field" in e is eager, LHS expression is always executed regardless of super existence.433 // In jsonnet, "field" in e is eager, LHS expression is always executed regardless of super existence.428 // In jrsonnet, however, this wasn't true, this was kept here for compatibility.434 // In jrsonnet, however, this wasn't true, this was kept here for compatibility.429 if !sup_this.has_super() {435 if !sup_this.has_super() {430 return Ok(Val::Bool(false));436 return Ok(Val::Bool(false));431 }437 }432 let field = evaluate(ctx, field)?;438 let field = evaluate(ctx, &bin.lhs)?;433 Val::Bool(sup_this.field_in_super(field.to_string()?))439 Val::Bool(sup_this.field_in_super(field.to_string()?))434 }440 }435 BinaryOp(v1, o, v2) => evaluate_binary_op_special(ctx, v1, *o, v2)?,441 BinaryOp(bin) => evaluate_binary_op_special(ctx, &bin.lhs, bin.op, &bin.rhs)?,436 UnaryOp(o, v) => evaluate_unary_op(*o, &evaluate(ctx, v)?)?,442 UnaryOp(o, v) => evaluate_unary_op(*o, &evaluate(ctx, v)?)?,437 Var(name) => in_frame(443 Var(name) => in_frame(438 CallLocation::new(&loc),444 CallLocation::new(&loc),441 )?,447 )?,442 Index { indexable, parts } => ensure_sufficient_stack(|| {448 Index { indexable, parts } => ensure_sufficient_stack(|| {443 let mut parts = parts.iter();449 let mut parts = parts.iter();444 let mut indexable = if matches!(indexable.expr(), Expr::Literal(LiteralType::Super)) {450 let mut indexable = if matches!(&***indexable, Expr::Literal(LiteralType::Super)) {445 let part = parts.next().expect("at least part should exist");451 let part = parts.next().expect("at least part should exist");446 // sup_this existence check might also be skipped here for null-coalesce...452 // sup_this existence check might also be skipped here for null-coalesce...447 // But I believe this might cause errors.453 // But I believe this might cause errors.574 Arr(items) => {580 Arr(items) => {575 if items.is_empty() {581 if items.is_empty() {576 Val::Arr(ArrValue::empty())582 Val::Arr(ArrValue::empty())577 } else if items.len() == 1 {583 } else {578 let item = items[0].clone();579 Val::Arr(ArrValue::lazy(vec![Thunk!(move || evaluate(ctx, &item))]))580 } else {581 Val::Arr(ArrValue::expr(ctx, items.iter().cloned()))584 Val::Arr(ArrValue::expr(ctx, items.clone()))582 }585 }583 }586 }584 ArrComp(expr, comp_specs) => {587 ArrComp(expr, comp_specs) => {601 Function(params, body) => {604 Function(params, body) => {602 evaluate_method(ctx, "anonymous".into(), params.clone(), body.clone())605 evaluate_method(ctx, "anonymous".into(), params.clone(), body.clone())603 }606 }604 AssertExpr(assert, returned) => {607 AssertExpr(assert) => {605 evaluate_assert(ctx.clone(), assert)?;608 evaluate_assert(ctx.clone(), &assert.assert)?;606 evaluate(ctx, returned)?609 evaluate(ctx, &assert.rest)?607 }610 }608 ErrorStmt(e) => in_frame(611 ErrorStmt(e) => in_frame(609 CallLocation::new(&loc),612 CallLocation::new(&loc),610 || "error statement".to_owned(),613 || "error statement".to_owned(),611 || bail!(RuntimeError(evaluate(ctx, e)?.to_string()?,)),614 || bail!(RuntimeError(evaluate(ctx, e)?.to_string()?,)),612 )?,615 )?,613 IfElse {616 IfElse (if_else)614 cond,617 // {615 cond_then,618 // cond,616 cond_else,619 // cond_then,620 // cond_else,621 // }617 } => {622 => {618 if in_frame(623 if in_frame(619 CallLocation::new(&loc),624 CallLocation::new(&loc),620 || "if condition".to_owned(),625 || "if condition".to_owned(),621 || bool::from_untyped(evaluate(ctx.clone(), &cond.0)?),626 || bool::from_untyped(evaluate(ctx.clone(), &if_else.cond.0)?),622 )? {627 )? {623 evaluate(ctx, cond_then)?628 evaluate(ctx, &if_else.cond_then)?624 } else {629 } else {625 match cond_else {630 match &if_else.cond_else {626 Some(v) => evaluate(ctx, v)?,631 Some(v) => evaluate(ctx, v)?,627 None => Val::Null,632 None => Val::Null,628 }633 }629 }634 }630 }635 }631 Slice(value, desc) => {636 Slice(slice) => {632 fn parse_idx<T: Typed>(637 fn parse_idx<T: Typed>(633 loc: CallLocation<'_>,638 loc: CallLocation<'_>,634 ctx: Context,639 ctx: Context,635 expr: Option<&LocExpr>,640 expr: Option<&Spanned<Expr>>,636 desc: &'static str,641 desc: &'static str,637 ) -> Result<Option<T>> {642 ) -> Result<Option<T>> {638 if let Some(value) = expr {643 if let Some(value) = expr {646 }651 }647 }652 }648653649 let indexable = evaluate(ctx.clone(), value)?;654 let indexable = evaluate(ctx.clone(), &slice.value)?;650 let loc = CallLocation::new(&loc);655 let loc = CallLocation::new(&loc);651656652 let start = parse_idx(loc, ctx.clone(), desc.start.as_ref(), "start")?;657 let start = parse_idx(loc, ctx.clone(), slice.slice.start.as_ref(), "start")?;653 let end = parse_idx(loc, ctx.clone(), desc.end.as_ref(), "end")?;658 let end = parse_idx(loc, ctx.clone(), slice.slice.end.as_ref(), "end")?;654 let step = parse_idx(loc, ctx, desc.step.as_ref(), "step")?;659 let step = parse_idx(loc, ctx, slice.slice.step.as_ref(), "step")?;655660656 IndexableVal::into_untyped(indexable.into_indexable()?.slice(start, end, step)?)?661 IndexableVal::into_untyped(indexable.into_indexable()?.slice(start, end, step)?)?657 }662 }658 i @ (Import(path) | ImportStr(path) | ImportBin(path)) => {663 Import(kind, path) => {659 let Expr::Str(path) = &path.expr() else {664 let Expr::Str(path) = &***path else {660 bail!("computed imports are not supported")665 bail!("computed imports are not supported")661 };666 };662 let tmp = loc.clone().0;667 let tmp = loc.clone().0;663 with_state(|s| {668 with_state(|s| {664 let resolved_path = s.resolve_from(tmp.source_path(), path)?;669 let resolved_path = s.resolve_from(tmp.source_path(), path)?;665 Ok(match i {670 Ok(match kind {666 Import(_) => in_frame(671 ImportKind::Normal => in_frame(667 CallLocation::new(&loc),672 CallLocation::new(&loc),668 || format!("import {:?}", path.clone()),673 || format!("import {:?}", path.clone()),669 || s.import_resolved(resolved_path),674 || s.import_resolved(resolved_path),670 )?,675 )?,671 ImportStr(_) => Val::string(s.import_resolved_str(resolved_path)?),676 ImportKind::Str => Val::string(s.import_resolved_str(resolved_path)?),672 ImportBin(_) => {677 ImportKind::Bin => {673 Val::Arr(ArrValue::bytes(s.import_resolved_bin(resolved_path)?))678 Val::Arr(ArrValue::bytes(s.import_resolved_bin(resolved_path)?))674 }679 }675 _ => unreachable!(),676 }) as Result<Val>680 }) as Result<Val>677 })?681 })?678 }682 }crates/jrsonnet-evaluator/src/evaluate/operator.rsdiffbeforeafterboth1use std::cmp::Ordering;1use std::cmp::Ordering;223use jrsonnet_parser::{BinaryOpType, LocExpr, UnaryOpType};3use jrsonnet_parser::{BinaryOpType, Expr, Spanned, UnaryOpType};445use crate::{5use crate::{6 arr::ArrValue,6 arr::ArrValue,147147148pub fn evaluate_binary_op_special(148pub fn evaluate_binary_op_special(149 ctx: Context,149 ctx: Context,150 a: &LocExpr,150 a: &Spanned<Expr>,151 op: BinaryOpType,151 op: BinaryOpType,152 b: &LocExpr,152 b: &Spanned<Expr>,153) -> Result<Val> {153) -> Result<Val> {154 use BinaryOpType::*;154 use BinaryOpType::*;155 use Val::*;155 use Val::*;crates/jrsonnet-evaluator/src/function/arglike.rsdiffbeforeafterboth1use std::collections::HashMap;1use std::collections::HashMap;2use std::rc::Rc;233use jrsonnet_gcmodule::Trace;4use jrsonnet_gcmodule::Trace;4use jrsonnet_interner::IStr;5use jrsonnet_interner::IStr;5use jrsonnet_parser::{ArgsDesc, LocExpr, SourceFifo, SourcePath};6use jrsonnet_parser::{ArgsDesc, Expr, SourceFifo, SourcePath, Spanned};677use crate::{evaluate, typed::Typed, with_state, Context, Result, Thunk, Val};8use crate::{evaluate, typed::Typed, with_state, Context, Result, Thunk, Val};8913 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>>;14 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>>;14}15}151616impl ArgLike for &LocExpr {17impl ArgLike for &Rc<Spanned<Expr>> {17 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {18 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {18 Ok(if tailstrict {19 Ok(if tailstrict {19 Thunk::evaluated(evaluate(ctx, self)?)20 Thunk::evaluated(evaluate(ctx, self)?)crates/jrsonnet-evaluator/src/function/mod.rsdiffbeforeafterboth1use std::fmt::Debug;1use std::{fmt::Debug, rc::Rc};223pub use arglike::{ArgLike, ArgsLike, TlaArg};3pub use arglike::{ArgLike, ArgsLike, TlaArg};4use jrsonnet_gcmodule::{Cc, Trace};4use jrsonnet_gcmodule::{Cc, Trace};5use jrsonnet_interner::IStr;5use jrsonnet_interner::IStr;6pub use jrsonnet_macros::builtin;6pub use jrsonnet_macros::builtin;7use jrsonnet_parser::{Destruct, Expr, LocExpr, ParamsDesc, Span};7use jrsonnet_parser::{Destruct, Expr, ParamsDesc, Span, Spanned};889use self::{9use self::{10 arglike::OptionalContext,10 arglike::OptionalContext,66 /// Function parameter definition66 /// Function parameter definition67 pub params: ParamsDesc,67 pub params: ParamsDesc,68 /// Function body68 /// Function body69 pub body: LocExpr,69 pub body: Rc<Spanned<Expr>>,70}70}71impl FuncDesc {71impl FuncDesc {72 /// Create body context, but fill arguments without defaults with lazy error72 /// Create body context, but fill arguments without defaults with lazy error240 #[cfg(feature = "exp-destruct")]240 #[cfg(feature = "exp-destruct")]241 _ => return false,241 _ => return false,242 };242 };243 desc.body.expr() == &Expr::Var(id.clone())243 **desc.body == Expr::Var(id.clone())244 }244 }245 _ => false,245 _ => false,246 }246 }crates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth45#[doc(hidden)]45#[doc(hidden)]46pub use jrsonnet_macros;46pub use jrsonnet_macros;47pub use jrsonnet_parser as parser;47pub use jrsonnet_parser as parser;48use jrsonnet_parser::{LocExpr, ParserSettings, Source, SourcePath};48use jrsonnet_parser::{Expr, ParserSettings, Source, SourcePath, Spanned};49pub use obj::*;49pub use obj::*;50pub use rustc_hash;50pub use rustc_hash;51use rustc_hash::FxHashMap;51use rustc_hash::FxHashMap;186struct FileData {186struct FileData {187 string: Option<IStr>,187 string: Option<IStr>,188 bytes: Option<IBytes>,188 bytes: Option<IBytes>,189 parsed: Option<LocExpr>,189 parsed: Option<Rc<Spanned<Expr>>>,190 evaluated: Option<Val>,190 evaluated: Option<Val>,191191192 evaluating: bool,192 evaluating: bool,350 source: file_name.clone(),350 source: file_name.clone(),351 },351 },352 )352 )353 .map(Rc::new)353 .map_err(|e| ImportSyntaxError {354 .map_err(|e| ImportSyntaxError {354 path: file_name.clone(),355 path: file_name.clone(),355 error: Box::new(e),356 error: Box::new(e),crates/jrsonnet-parser/Cargo.tomldiffbeforeafterboth202021peg.workspace = true21peg.workspace = true2223[dev-dependencies]24insta.workspace = true2225crates/jrsonnet-parser/src/expr.rsdiffbeforeafterboth14 /// {fixed: 2}14 /// {fixed: 2}15 Fixed(IStr),15 Fixed(IStr),16 /// {["dyn"+"amic"]: 3}16 /// {["dyn"+"amic"]: 3}17 Dyn(LocExpr),17 Dyn(Spanned<Expr>),18}18}191920#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]20#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]34 }34 }35}35}363637#[derive(Clone, Debug, PartialEq, Acyclic)]37#[derive(Debug, PartialEq, Acyclic)]38pub struct AssertStmt(pub LocExpr, pub Option<LocExpr>);38pub struct AssertStmt(pub Spanned<Expr>, pub Option<Spanned<Expr>>);393940#[derive(Debug, PartialEq, Acyclic)]40#[derive(Debug, PartialEq, Acyclic)]41pub struct FieldMember {41pub struct FieldMember {42 pub name: FieldName,42 pub name: FieldName,43 pub plus: bool,43 pub plus: bool,44 pub params: Option<ParamsDesc>,44 pub params: Option<ParamsDesc>,45 pub visibility: Visibility,45 pub visibility: Visibility,46 pub value: LocExpr,46 pub value: Rc<Spanned<Expr>>,47}47}484849#[derive(Debug, PartialEq, Acyclic)]49#[derive(Debug, PartialEq, Acyclic)]50pub enum Member {50pub enum Member {51 Field(FieldMember),51 Field(FieldMember),52 BindStmt(BindSpec),52 BindStmt(BindSpec),53 AssertStmt(AssertStmt),53 AssertStmt(Rc<AssertStmt>),54}54}555556#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]56#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]147147148/// name, default value148/// name, default value149#[derive(Debug, PartialEq, Acyclic)]149#[derive(Debug, PartialEq, Acyclic)]150pub struct Param(pub Destruct, pub Option<LocExpr>);150pub struct Param(pub Destruct, pub Option<Rc<Spanned<Expr>>>);151151152/// Defined function parameters152/// Defined function parameters153#[derive(Debug, Clone, PartialEq, Acyclic)]153#[derive(Debug, Clone, PartialEq, Acyclic)]162162163#[derive(Debug, PartialEq, Acyclic)]163#[derive(Debug, PartialEq, Acyclic)]164pub struct ArgsDesc {164pub struct ArgsDesc {165 pub unnamed: Vec<LocExpr>,165 pub unnamed: Vec<Rc<Spanned<Expr>>>,166 pub named: Vec<(IStr, LocExpr)>,166 pub named: Vec<(IStr, Rc<Spanned<Expr>>)>,167}167}168impl ArgsDesc {168impl ArgsDesc {169 pub fn new(unnamed: Vec<LocExpr>, named: Vec<(IStr, LocExpr)>) -> Self {169 pub fn new(unnamed: Vec<Rc<Spanned<Expr>>>, named: Vec<(IStr, Rc<Spanned<Expr>>)>) -> Self {170 Self { unnamed, named }170 Self { unnamed, named }171 }171 }172}172}192 },192 },193 #[cfg(feature = "exp-destruct")]193 #[cfg(feature = "exp-destruct")]194 Object {194 Object {195 fields: Vec<(IStr, Option<Destruct>, Option<LocExpr>)>,195 fields: Vec<(IStr, Option<Destruct>, Option<Spanned<Expr>>)>,196 rest: Option<DestructRest>,196 rest: Option<DestructRest>,197 },197 },198}198}244pub enum BindSpec {244pub enum BindSpec {245 Field {245 Field {246 into: Destruct,246 into: Destruct,247 value: LocExpr,247 value: Rc<Spanned<Expr>>,248 },248 },249 Function {249 Function {250 name: IStr,250 name: IStr,251 params: ParamsDesc,251 params: ParamsDesc,252 value: LocExpr,252 value: Rc<Spanned<Expr>>,253 },253 },254}254}255impl BindSpec {255impl BindSpec {262}262}263263264#[derive(Debug, PartialEq, Acyclic)]264#[derive(Debug, PartialEq, Acyclic)]265pub struct IfSpecData(pub LocExpr);265pub struct IfSpecData(pub Spanned<Expr>);266266267#[derive(Debug, PartialEq, Acyclic)]267#[derive(Debug, PartialEq, Acyclic)]268pub struct ForSpecData(pub Destruct, pub LocExpr);268pub struct ForSpecData(pub Destruct, pub Spanned<Expr>);269269270#[derive(Debug, PartialEq, Acyclic)]270#[derive(Debug, PartialEq, Acyclic)]271pub enum CompSpec {271pub enum CompSpec {276#[derive(Debug, PartialEq, Acyclic)]276#[derive(Debug, PartialEq, Acyclic)]277pub struct ObjComp {277pub struct ObjComp {278 pub pre_locals: Vec<BindSpec>,278 pub pre_locals: Vec<BindSpec>,279 pub field: FieldMember,279 pub field: Rc<FieldMember>,280 pub post_locals: Vec<BindSpec>,280 pub post_locals: Vec<BindSpec>,281 pub compspecs: Vec<CompSpec>,281 pub compspecs: Vec<CompSpec>,282}282}299299300#[derive(Debug, PartialEq, Acyclic)]300#[derive(Debug, PartialEq, Acyclic)]301pub struct SliceDesc {301pub struct SliceDesc {302 pub start: Option<LocExpr>,302 pub start: Option<Spanned<Expr>>,303 pub end: Option<LocExpr>,303 pub end: Option<Spanned<Expr>>,304 pub step: Option<LocExpr>,304 pub step: Option<Spanned<Expr>>,305}305}306307#[derive(Debug, PartialEq, Acyclic)]308pub struct AssertExpr {309 pub assert: AssertStmt,310 pub rest: Spanned<Expr>,311}312313#[derive(Debug, PartialEq, Acyclic)]314pub struct BinaryOp {315 pub lhs: Spanned<Expr>,316 pub op: BinaryOpType,317 pub rhs: Spanned<Expr>,318}319320#[derive(Debug, PartialEq, Acyclic)]321pub enum ImportKind {322 Normal,323 Str,324 Bin,325}326327#[derive(Debug, PartialEq, Acyclic)]328pub struct IfElse {329 pub cond: IfSpecData,330 pub cond_then: Spanned<Expr>,331 pub cond_else: Option<Spanned<Expr>>,332}333334#[derive(Debug, PartialEq, Acyclic)]335pub struct Slice {336 pub value: Spanned<Expr>,337 pub slice: SliceDesc,338}306339307/// Syntax base340/// Syntax base308#[derive(Debug, PartialEq, Acyclic)]341#[derive(Debug, PartialEq, Acyclic)]317 Var(IStr),350 Var(IStr),318351319 /// Array of expressions: [1, 2, "Hello"]352 /// Array of expressions: [1, 2, "Hello"]320 Arr(Vec<LocExpr>),353 Arr(Rc<Vec<Spanned<Expr>>>),321 /// Array comprehension:354 /// Array comprehension:322 /// ```jsonnet355 /// ```jsonnet323 /// ingredients: [356 /// ingredients: [329 /// ]362 /// ]330 /// ],363 /// ],331 /// ```364 /// ```332 ArrComp(LocExpr, Vec<CompSpec>),365 ArrComp(Rc<Spanned<Expr>>, Vec<CompSpec>),333366334 /// Object: {a: 2}367 /// Object: {a: 2}335 Obj(ObjBody),368 Obj(ObjBody),336 /// Object extension: var1 {b: 2}369 /// Object extension: var1 {b: 2}337 ObjExtend(LocExpr, ObjBody),370 ObjExtend(Rc<Spanned<Expr>>, ObjBody),338371339 /// -2372 /// -2340 UnaryOp(UnaryOpType, LocExpr),373 UnaryOp(UnaryOpType, Box<Spanned<Expr>>),341 /// 2 - 2374 /// 2 - 2342 BinaryOp(LocExpr, BinaryOpType, LocExpr),375 BinaryOp(Box<BinaryOp>),343 /// assert 2 == 2 : "Math is broken"376 /// assert 2 == 2 : "Math is broken"344 AssertExpr(AssertStmt, LocExpr),377 AssertExpr(Rc<AssertExpr>),345 /// local a = 2; { b: a }378 /// local a = 2; { b: a }346 LocalExpr(Vec<BindSpec>, LocExpr),379 LocalExpr(Vec<BindSpec>, Box<Spanned<Expr>>),347380348 /// import "hello"381 /// import* "hello"349 Import(LocExpr),382 Import(ImportKind, Box<Spanned<Expr>>),350 /// importStr "file.txt"351 ImportStr(LocExpr),352 /// importBin "file.txt"353 ImportBin(LocExpr),354 /// error "I'm broken"383 /// error "I'm broken"355 ErrorStmt(LocExpr),384 ErrorStmt(Box<Spanned<Expr>>),356 /// a(b, c)385 /// a(b, c)357 Apply(LocExpr, ArgsDesc, bool),386 Apply(Box<Spanned<Expr>>, ArgsDesc, bool),358 /// a[b], a.b, a?.b387 /// a[b], a.b, a?.b359 Index {388 Index {360 indexable: LocExpr,389 indexable: Box<Spanned<Expr>>,361 parts: Vec<IndexPart>,390 parts: Vec<IndexPart>,362 },391 },363 /// function(x) x392 /// function(x) x364 Function(ParamsDesc, LocExpr),393 Function(ParamsDesc, Rc<Spanned<Expr>>),365 /// if true == false then 1 else 2394 /// if true == false then 1 else 2366 IfElse {395 IfElse(Box<IfElse>),367 cond: IfSpecData,368 cond_then: LocExpr,369 cond_else: Option<LocExpr>,370 },371 Slice(LocExpr, SliceDesc),396 Slice(Box<Slice>),372}397}373398374#[derive(Debug, PartialEq, Acyclic)]399#[derive(Debug, PartialEq, Acyclic)]375pub struct IndexPart {400pub struct IndexPart {376 pub value: LocExpr,401 pub value: Spanned<Expr>,377 #[cfg(feature = "exp-null-coaelse")]402 #[cfg(feature = "exp-null-coaelse")]378 pub null_coaelse: bool,403 pub null_coaelse: bool,379}404}396 }421 }397}422}398423399/// Holds AST expression and its location in source file400#[derive(Clone, PartialEq, Acyclic)]424#[derive(Clone, PartialEq, Acyclic)]401pub struct LocExpr(Rc<(Expr, Span)>);425pub struct Spanned<T: Acyclic>(T, Span);426impl<T: Acyclic> Deref for Spanned<T> {427 type Target = T;428 fn deref(&self) -> &Self::Target {429 &self.0430 }431}402impl LocExpr {432impl<T: Acyclic> Spanned<T> {433 #[inline]403 pub fn new(expr: Expr, span: Span) -> Self {434 pub fn new(v: T, s: Span) -> Self {404 Self(Rc::new((expr, span)))435 Self(v, s)405 }436 }406 #[inline]437 #[inline]407 pub fn span(&self) -> Span {438 pub fn span(&self) -> Span {408 self.0 .1.clone()439 self.1.clone()409 }440 }410 #[inline]411 pub fn expr(&self) -> &Expr {412 &self.0 .0413 }414}441}415416static_assertions::assert_eq_size!(LocExpr, usize);417442418impl Debug for LocExpr {443impl<T: Debug + Acyclic> Debug for Spanned<T> {419 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {444 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {420 let expr = self.expr();445 let expr = &**self;421 if f.alternate() {446 if f.alternate() {422 write!(f, "{:#?}", expr)?;447 write!(f, "{:#?}", expr)?;423 } else {448 } else {crates/jrsonnet-parser/src/lib.rsdiffbeforeafterboth222223macro_rules! expr_bin {23macro_rules! expr_bin {24 ($a:ident $op:ident $b:ident) => {24 ($a:ident $op:ident $b:ident) => {25 Expr::BinaryOp($a, $op, $b)25 Expr::BinaryOp(Box::new(BinaryOp {26 lhs: $a,27 op: $op,28 rhs: $b,29 }))26 };30 };27}31}28macro_rules! expr_un {32macro_rules! expr_un {29 ($op:ident $a:ident) => {33 ($op:ident $a:ident) => {30 Expr::UnaryOp($op, $a)34 Expr::UnaryOp($op, Box::new($a))31 };35 };32}36}333764 rule keyword(id: &'static str) -> ()68 rule keyword(id: &'static str) -> ()65 = ##parse_string_literal(id) end_of_ident()69 = ##parse_string_literal(id) end_of_ident()667067 pub rule param(s: &ParserSettings) -> expr::Param = name:destruct(s) expr:(_ "=" _ expr:expr(s){expr})? { expr::Param(name, expr) }71 pub rule param(s: &ParserSettings) -> expr::Param = name:destruct(s) expr:(_ "=" _ expr:expr(s){expr})? { expr::Param(name, expr.map(Rc::new)) }68 pub rule params(s: &ParserSettings) -> expr::ParamsDesc72 pub rule params(s: &ParserSettings) -> expr::ParamsDesc69 = params:param(s) ** comma() comma()? { expr::ParamsDesc(Rc::new(params)) }73 = params:param(s) ** comma() comma()? { expr::ParamsDesc(Rc::new(params)) }70 / { expr::ParamsDesc(Rc::new(Vec::new())) }74 / { expr::ParamsDesc(Rc::new(Vec::new())) }717572 pub rule arg(s: &ParserSettings) -> (Option<IStr>, LocExpr)76 pub rule arg(s: &ParserSettings) -> (Option<IStr>, Rc<Spanned<Expr>>)73 = name:(quiet! { (s:id() _ "=" !['='] _ {s})? } / expected!("<argument name>")) expr:expr(s) {(name, expr)}77 = name:(quiet! { (s:id() _ "=" !['='] _ {s})? } / expected!("<argument name>")) expr:expr(s) {(name, Rc::new(expr))}747875 pub rule args(s: &ParserSettings) -> expr::ArgsDesc79 pub rule args(s: &ParserSettings) -> expr::ArgsDesc76 = args:arg(s)**comma() comma()? {?80 = args:arg(s)**comma() comma()? {?135 / obj:destruct_object(s) {obj}139 / obj:destruct_object(s) {obj}136140137 pub rule bind(s: &ParserSettings) -> expr::BindSpec141 pub rule bind(s: &ParserSettings) -> expr::BindSpec138 = into:destruct(s) _ "=" _ expr:expr(s) {expr::BindSpec::Field{into, value: expr}}142 = into:destruct(s) _ "=" _ expr:expr(s) {expr::BindSpec::Field{into, value: Rc::new(expr)}}139 / name:id() _ "(" _ params:params(s) _ ")" _ "=" _ expr:expr(s) {expr::BindSpec::Function{name, params, value: expr}}143 / name:id() _ "(" _ params:params(s) _ ")" _ "=" _ expr:expr(s) {expr::BindSpec::Function{name, params, value: Rc::new(expr)}}140144141 pub rule assertion(s: &ParserSettings) -> expr::AssertStmt145 pub rule assertion(s: &ParserSettings) -> expr::AssertStmt142 = keyword("assert") _ cond:expr(s) msg:(_ ":" _ e:expr(s) {e})? { expr::AssertStmt(cond, msg) }146 = keyword("assert") _ cond:expr(s) msg:(_ ":" _ e:expr(s) {e})? { expr::AssertStmt(cond, msg) }190 plus: plus.is_some(),194 plus: plus.is_some(),191 params: None,195 params: None,192 visibility,196 visibility,193 value,197 value: Rc::new(value),194 }}198 }}195 / name:field_name(s) _ "(" _ params:params(s) _ ")" _ visibility:visibility() _ value:expr(s) {expr::FieldMember{199 / name:field_name(s) _ "(" _ params:params(s) _ ")" _ visibility:visibility() _ value:expr(s) {expr::FieldMember{196 name,200 name,197 plus: false,201 plus: false,198 params: Some(params),202 params: Some(params),199 visibility,203 visibility,200 value,204 value: Rc::new(value),201 }}205 }}202 pub rule obj_local(s: &ParserSettings) -> BindSpec206 pub rule obj_local(s: &ParserSettings) -> BindSpec203 = keyword("local") _ bind:bind(s) {bind}207 = keyword("local") _ bind:bind(s) {bind}204 pub rule member(s: &ParserSettings) -> expr::Member208 pub rule member(s: &ParserSettings) -> expr::Member205 = bind:obj_local(s) {expr::Member::BindStmt(bind)}209 = bind:obj_local(s) {expr::Member::BindStmt(bind)}206 / assertion:assertion(s) {expr::Member::AssertStmt(assertion)}210 / assertion:assertion(s) {expr::Member::AssertStmt(Rc::new(assertion))}207 / field:field(s) {expr::Member::Field(field)}211 / field:field(s) {expr::Member::Field(field)}208 pub rule objinside(s: &ParserSettings) -> expr::ObjBody212 pub rule objinside(s: &ParserSettings) -> expr::ObjBody209 = pre_locals:(b: obj_local(s) comma() {b})* &"[" field:field(s) post_locals:(comma() b:obj_local(s) {b})* _ ("," _)? forspec:forspec(s) others:(_ rest:compspec(s) {rest})? {213 = pre_locals:(b: obj_local(s) comma() {b})* &"[" field:field(s) post_locals:(comma() b:obj_local(s) {b})* _ ("," _)? forspec:forspec(s) others:(_ rest:compspec(s) {rest})? {210 let mut compspecs = vec![CompSpec::ForSpec(forspec)];214 let mut compspecs = vec![CompSpec::ForSpec(forspec)];211 compspecs.extend(others.unwrap_or_default());215 compspecs.extend(others.unwrap_or_default());212 expr::ObjBody::ObjComp(expr::ObjComp{216 expr::ObjBody::ObjComp(expr::ObjComp{213 pre_locals,217 pre_locals,214 field,218 field: Rc::new(field),215 post_locals,219 post_locals,216 compspecs,220 compspecs,217 })221 })224 pub rule compspec(s: &ParserSettings) -> Vec<expr::CompSpec>228 pub rule compspec(s: &ParserSettings) -> Vec<expr::CompSpec>225 = s:(i:ifspec(s) { expr::CompSpec::IfSpec(i) } / f:forspec(s) {expr::CompSpec::ForSpec(f)} ) ** _ {s}229 = s:(i:ifspec(s) { expr::CompSpec::IfSpec(i) } / f:forspec(s) {expr::CompSpec::ForSpec(f)} ) ** _ {s}226 pub rule local_expr(s: &ParserSettings) -> Expr230 pub rule local_expr(s: &ParserSettings) -> Expr227 = keyword("local") _ binds:bind(s) ** comma() (_ ",")? _ ";" _ expr:expr(s) { Expr::LocalExpr(binds, expr) }231 = keyword("local") _ binds:bind(s) ** comma() (_ ",")? _ ";" _ expr:expr(s) { Expr::LocalExpr(binds, Box::new(expr)) }228 pub rule string_expr(s: &ParserSettings) -> Expr232 pub rule string_expr(s: &ParserSettings) -> Expr229 = s:string() {Expr::Str(s.into())}233 = s:string() {Expr::Str(s.into())}230 pub rule obj_expr(s: &ParserSettings) -> Expr234 pub rule obj_expr(s: &ParserSettings) -> Expr231 = "{" _ body:objinside(s) _ "}" {Expr::Obj(body)}235 = "{" _ body:objinside(s) _ "}" {Expr::Obj(body)}232 pub rule array_expr(s: &ParserSettings) -> Expr236 pub rule array_expr(s: &ParserSettings) -> Expr233 = "[" _ elems:(expr(s) ** comma()) _ comma()? "]" {Expr::Arr(elems)}237 = "[" _ elems:(expr(s) ** comma()) _ comma()? "]" {Expr::Arr(Rc::new(elems))}234 pub rule array_comp_expr(s: &ParserSettings) -> Expr238 pub rule array_comp_expr(s: &ParserSettings) -> Expr235 = "[" _ expr:expr(s) _ comma()? _ forspec:forspec(s) _ others:(others: compspec(s) _ {others})? "]" {239 = "[" _ expr:expr(s) _ comma()? _ forspec:forspec(s) _ others:(others: compspec(s) _ {others})? "]" {236 let mut specs = vec![CompSpec::ForSpec(forspec)];240 let mut specs = vec![CompSpec::ForSpec(forspec)];237 specs.extend(others.unwrap_or_default());241 specs.extend(others.unwrap_or_default());238 Expr::ArrComp(expr, specs)242 Expr::ArrComp(Rc::new(expr), specs)239 }243 }240 pub rule number_expr(s: &ParserSettings) -> Expr244 pub rule number_expr(s: &ParserSettings) -> Expr241 = n:number() {? if n.is_finite() {245 = n:number() {? if n.is_finite() {245 }}249 }}246 pub rule var_expr(s: &ParserSettings) -> Expr250 pub rule var_expr(s: &ParserSettings) -> Expr247 = n:id() { expr::Expr::Var(n) }251 = n:id() { expr::Expr::Var(n) }248 pub rule id_loc(s: &ParserSettings) -> LocExpr252 pub rule id_loc(s: &ParserSettings) -> Spanned<Expr>249 = a:position!() n:id() b:position!() { LocExpr::new(expr::Expr::Str(n), Span(s.source.clone(), a as u32,b as u32)) }253 = a:position!() n:id() b:position!() { Spanned::new(expr::Expr::Str(n), Span(s.source.clone(), a as u32,b as u32)) }250 pub rule if_then_else_expr(s: &ParserSettings) -> Expr254 pub rule if_then_else_expr(s: &ParserSettings) -> Expr251 = cond:ifspec(s) _ keyword("then") _ cond_then:expr(s) cond_else:(_ keyword("else") _ e:expr(s) {e})? {Expr::IfElse{255 = cond:ifspec(s) _ keyword("then") _ cond_then:expr(s) cond_else:(_ keyword("else") _ e:expr(s) {e})? {Expr::IfElse(Box::new(IfElse{252 cond,256 cond,253 cond_then,257 cond_then,254 cond_else,258 cond_else,255 }}259 }))}256260257 pub rule literal(s: &ParserSettings) -> Expr261 pub rule literal(s: &ParserSettings) -> Expr258 = v:(262 = v:(264 / keyword("super") {LiteralType::Super}268 / keyword("super") {LiteralType::Super}265 ) {Expr::Literal(v)}269 ) {Expr::Literal(v)}270271 rule import_kind() -> ImportKind272 = keyword("importstr") { ImportKind::Str }273 / keyword("importbin") { ImportKind::Bin }274 / keyword("import") { ImportKind::Normal }266275267 pub rule expr_basic(s: &ParserSettings) -> Expr276 pub rule expr_basic(s: &ParserSettings) -> Expr268 = literal(s)277 = literal(s)273 / array_expr(s)282 / array_expr(s)274 / array_comp_expr(s)283 / array_comp_expr(s)275284276 / keyword("importstr") _ path:expr(s) {Expr::ImportStr(path)}285 / kind:import_kind() _ path:expr(s) {Expr::Import(kind, Box::new(path))}277 / keyword("importbin") _ path:expr(s) {Expr::ImportBin(path)}278 / keyword("import") _ path:expr(s) {Expr::Import(path)}279286280 / var_expr(s)287 / var_expr(s)281 / local_expr(s)288 / local_expr(s)282 / if_then_else_expr(s)289 / if_then_else_expr(s)283290284 / keyword("function") _ "(" _ params:params(s) _ ")" _ expr:expr(s) {Expr::Function(params, expr)}291 / keyword("function") _ "(" _ params:params(s) _ ")" _ expr:expr(s) {Expr::Function(params, Rc::new(expr))}285 / assertion:assertion(s) _ ";" _ expr:expr(s) { Expr::AssertExpr(assertion, expr) }292 / assert:assertion(s) _ ";" _ rest:expr(s) { Expr::AssertExpr(Rc::new(AssertExpr{293 assert, rest294 })) }286295287 / keyword("error") _ expr:expr(s) { Expr::ErrorStmt(expr) }296 / keyword("error") _ expr:expr(s) { Expr::ErrorStmt(Box::new(expr)) }288297289 rule slice_part(s: &ParserSettings) -> Option<LocExpr>298 rule slice_part(s: &ParserSettings) -> Option<Spanned<Expr>>290 = _ e:(e:expr(s) _{e})? {e}299 = _ e:(e:expr(s) _{e})? {e}291 pub rule slice_desc(s: &ParserSettings) -> SliceDesc300 pub rule slice_desc(s: &ParserSettings) -> SliceDesc292 = start:slice_part(s) ":" pair:(end:slice_part(s) step:(":" e:slice_part(s){e})? {(end, step.flatten())})? {301 = start:slice_part(s) ":" pair:(end:slice_part(s) step:(":" e:slice_part(s){e})? {(end, step.flatten())})? {311 }320 }312 use BinaryOpType::*;321 use BinaryOpType::*;313 use UnaryOpType::*;322 use UnaryOpType::*;314 rule expr(s: &ParserSettings) -> LocExpr323 rule expr(s: &ParserSettings) -> Spanned<Expr>315 = precedence! {324 = precedence! {316 "(" _ e:expr(s) _ ")" {e}325 "(" _ e:expr(s) _ ")" {e}317 start:position!() v:@ end:position!() { LocExpr::new(v, Span(s.source.clone(), start as u32, end as u32)) }326 start:position!() v:@ end:position!() { Spanned::new(v, Span(s.source.clone(), start as u32, end as u32)) }318 --327 --319 a:(@) _ binop(<"||">) _ b:@ {expr_bin!(a Or b)}328 a:(@) _ binop(<"||">) _ b:@ {expr_bin!(a Or b)}320 a:(@) _ binop(<"??">) _ ensure_null_coaelse() b:@ {329 a:(@) _ binop(<"??">) _ ensure_null_coaelse() b:@ {354 unaryop(<"!">) _ b:@ {expr_un!(Not b)}363 unaryop(<"!">) _ b:@ {expr_un!(Not b)}355 unaryop(<"~">) _ b:@ {expr_un!(BitNot b)}364 unaryop(<"~">) _ b:@ {expr_un!(BitNot b)}356 --365 --357 a:(@) _ "[" _ e:slice_desc(s) _ "]" {Expr::Slice(a, e)}366 value:(@) _ "[" _ slice:slice_desc(s) _ "]" {Expr::Slice(Box::new(Slice{value, slice}))}358 indexable:(@) _ parts:index_part(s)+ {Expr::Index{indexable, parts}}367 indexable:(@) _ parts:index_part(s)+ {Expr::Index{indexable: Box::new(indexable), parts}}359 a:(@) _ "(" _ args:args(s) _ ")" ts:(_ keyword("tailstrict"))? {Expr::Apply(a, args, ts.is_some())}368 a:(@) _ "(" _ args:args(s) _ ")" ts:(_ keyword("tailstrict"))? {Expr::Apply(Box::new(a), args, ts.is_some())}360 a:(@) _ "{" _ body:objinside(s) _ "}" {Expr::ObjExtend(a, body)}369 a:(@) _ "{" _ body:objinside(s) _ "}" {Expr::ObjExtend(Rc::new(a), body)}361 --370 --362 e:expr_basic(s) {e}371 e:expr_basic(s) {e}363 }372 }373 null_coaelse: n.is_some(),382 null_coaelse: n.is_some(),374 }}383 }}375384376 pub rule jsonnet(s: &ParserSettings) -> LocExpr = _ e:expr(s) _ {e}385 pub rule jsonnet(s: &ParserSettings) -> Spanned<Expr> = _ e:expr(s) _ {e}377 }386 }378}387}379388380pub type ParseError = peg::error::ParseError<peg::str::LineCol>;389pub type ParseError = peg::error::ParseError<peg::str::LineCol>;381pub fn parse(str: &str, settings: &ParserSettings) -> Result<LocExpr, ParseError> {390pub fn parse(str: &str, settings: &ParserSettings) -> Result<Spanned<Expr>, ParseError> {382 jsonnet_parser::jsonnet(str, settings)391 jsonnet_parser::jsonnet(str, settings)383}392}384/// Used for importstr values393/// Used for importstr values385pub fn string_to_expr(str: IStr, settings: &ParserSettings) -> LocExpr {394pub fn string_to_expr(str: IStr, settings: &ParserSettings) -> Spanned<Expr> {386 let len = str.len();395 let len = str.len();387 LocExpr::new(Expr::Str(str), Span(settings.source.clone(), 0, len as u32))396 Spanned::new(Expr::Str(str), Span(settings.source.clone(), 0, len as u32))388}397}389398390#[cfg(test)]399#[cfg(test)]391pub mod tests {400pub mod tests {392 use jrsonnet_interner::IStr;401 use insta::assert_snapshot;393 use BinaryOpType::*;402 use jrsonnet_interner::IStr;394403395 use super::{expr::*, parse};404 use super::parse;396 use crate::{source::Source, ParserSettings};405 use crate::{source::Source, ParserSettings};397406398 macro_rules! parse {399 ($s:expr) => {407 fn parsep(s: &str) -> String {400 parse(408 let v = parse(401 $s,409 s,402 &ParserSettings {410 &ParserSettings {403 source: Source::new_virtual("<test>".into(), IStr::empty()),411 source: Source::new_virtual("<test>".into(), IStr::empty()),404 },412 },405 )413 )406 .unwrap()414 .unwrap();415 format!("{v:#?}")407 };416 }408 }409417410 macro_rules! el {418 macro_rules! parse {411 ($expr:expr, $from:expr, $to:expr$(,)?) => {419 ($s:expr) => {412 LocExpr::new(420 assert_snapshot!(parsep($s));413 $expr,414 Span(415 Source::new_virtual("<test>".into(), IStr::empty()),416 $from,417 $to,418 ),419 )420 };421 };421 }422 }422423423 #[test]424 #[test]424 fn multiline_string() {425 fn multiline_string() {425 assert_eq!(426 parse!("|||\n Hello world!\n a\n|||"),426 parse!("|||\n Hello world!\n a\n|||");427 el!(Expr::Str("Hello world!\n a\n".into()), 0, 31),428 );429 assert_eq!(430 parse!("|||\n Hello world!\n a\n|||"),427 parse!("|||\n Hello world!\n a\n|||");431 el!(Expr::Str("Hello world!\n a\n".into()), 0, 27),432 );433 assert_eq!(434 parse!("|||\n\t\tHello world!\n\t\t\ta\n|||"),428 parse!("|||\n\t\tHello world!\n\t\t\ta\n|||");435 el!(Expr::Str("Hello world!\n\ta\n".into()), 0, 27),436 );437 assert_eq!(438 parse!("|||\n Hello world!\n a\n |||"),429 parse!("|||\n Hello world!\n a\n |||");439 el!(Expr::Str("Hello world!\n a\n".into()), 0, 30),440 );441 }430 }442431443 #[test]432 #[test]451440452 #[test]441 #[test]453 fn string_escaping() {442 fn string_escaping() {454 assert_eq!(455 parse!(r#""Hello, \"world\"!""#),443 parse!(r#""Hello, \"world\"!""#);456 el!(Expr::Str(r#"Hello, "world"!"#.into()), 0, 19),457 );458 assert_eq!(459 parse!(r#"'Hello \'world\'!'"#),444 parse!(r#"'Hello \'world\'!'"#);460 el!(Expr::Str("Hello 'world'!".into()), 0, 18),461 );462 assert_eq!(parse!(r#"'\\\\'"#), el!(Expr::Str("\\\\".into()), 0, 6));445 parse!(r#"'\\\\'"#);463 }446 }464447465 #[test]448 #[test]466 fn string_unescaping() {449 fn string_unescaping() {467 assert_eq!(468 parse!(r#""Hello\nWorld""#),450 parse!(r#""Hello\nWorld""#);469 el!(Expr::Str("Hello\nWorld".into()), 0, 14),470 );471 }451 }472452473 #[test]453 #[test]474 fn string_verbantim() {454 fn string_verbantim() {475 assert_eq!(476 parse!(r#"@"Hello\n""World""""#),455 parse!(r#"@"Hello\n""World""""#);477 el!(Expr::Str("Hello\\n\"World\"".into()), 0, 19),478 );479 }456 }480457481 #[test]458 #[test]482 fn imports() {459 fn imports() {483 assert_eq!(484 parse!("import \"hello\""),460 parse!("import \"hello\"");485 el!(Expr::Import(el!(Expr::Str("hello".into()), 7, 14)), 0, 14),486 );487 assert_eq!(488 parse!("importstr \"garnish.txt\""),461 parse!("importstr \"garnish.txt\"");489 el!(490 Expr::ImportStr(el!(Expr::Str("garnish.txt".into()), 10, 23)),491 0,492 23493 )494 );495 assert_eq!(496 parse!("importbin \"garnish.bin\""),462 parse!("importbin \"garnish.bin\"");497 el!(498 Expr::ImportBin(el!(Expr::Str("garnish.bin".into()), 10, 23)),499 0,500 23501 )502 );503 }463 }504464505 #[test]465 #[test]506 fn empty_object() {466 fn empty_object() {507 assert_eq!(508 parse!("{}"),467 parse!("{}");509 el!(Expr::Obj(ObjBody::MemberList(vec![])), 0, 2)510 );511 }468 }512469513 #[test]470 #[test]514 fn basic_math() {471 fn basic_math() {515 assert_eq!(472 parse!("2+2*2");516 parse!("2+2*2"),517 el!(518 Expr::BinaryOp(519 el!(Expr::Num(2.0), 0, 1),520 Add,521 el!(522 Expr::BinaryOp(el!(Expr::Num(2.0), 2, 3), Mul, el!(Expr::Num(2.0), 4, 5)),523 2,524 5525 )526 ),527 0,528 5529 )530 );531 }532533 #[test]534 fn basic_math_with_indents() {535 assert_eq!(536 parse!("2 + 2 * 2 "),473 parse!("2 + 2 * 2 ");537 el!(538 Expr::BinaryOp(539 el!(Expr::Num(2.0), 0, 1),540 Add,541 el!(542 Expr::BinaryOp(el!(Expr::Num(2.0), 7, 8), Mul, el!(Expr::Num(2.0), 13, 14),),543 7,544 14545 ),546 ),547 0,548 14549 )550 );551 }552553 #[test]554 fn basic_math_parened() {555 assert_eq!(556 parse!("2+(2+2*2)"),474 parse!("2+(2+2*2)");557 el!(558 Expr::BinaryOp(559 el!(Expr::Num(2.0), 0, 1),560 Add,561 el!(562 Expr::BinaryOp(563 el!(Expr::Num(2.0), 3, 4),564 Add,565 el!(566 Expr::BinaryOp(567 el!(Expr::Num(2.0), 5, 6),568 Mul,569 el!(Expr::Num(2.0), 7, 8),570 ),571 5,572 8573 ),574 ),575 3,576 8577 ),578 ),579 0,580 9581 )582 );583 }584585 /// Comments should not affect parsing586 #[test]587 fn comments() {588 assert_eq!(589 parse!("2//comment\n+//comment\n3/*test*/*/*test*/4"),475 parse!("2//comment\n+//comment\n3/*test*/*/*test*/4");590 el!(476 }591 Expr::BinaryOp(592 el!(Expr::Num(2.0), 0, 1),593 Add,594 el!(595 Expr::BinaryOp(596 el!(Expr::Num(3.0), 22, 23),597 Mul,598 el!(Expr::Num(4.0), 40, 41)599 ),600 22,601 41602 )603 ),604 0,605 41606 )607 );608 }609477610 #[test]478 #[test]611 fn suffix() {479 fn suffix() {612 // assert_eq!(parse!("std.test"), el!(Expr::Num(2.2)));480 parse!("std.test");613 // assert_eq!(parse!("std(2)"), el!(Expr::Num(2.2)));481 parse!("std(2)");614 // assert_eq!(parse!("std.test(2)"), el!(Expr::Num(2.2)));482 parse!("std.test(2)");615 // assert_eq!(parse!("a[b]"), el!(Expr::Num(2.2)))483 parse!("a[b]");616 }484 }617485618 #[test]486 #[test]619 fn array_comp() {487 fn array_comp() {620 use Expr::*;621 /*622 `ArrComp(Apply(Index(Var("std") from "test.jsonnet":1-4, Var("deepJoin") from "test.jsonnet":5-13) from "test.jsonnet":1-13, ArgsDesc { unnamed: [Var("x") from "test.jsonnet":14-15], named: [] }, false) from "test.jsonnet":1-16, [ForSpec(ForSpecData("x", Var("arr") from "test.jsonnet":26-29))]) from "test.jsonnet":0-30`,623 `ArrComp(Apply(Index(Var("std") from "test.jsonnet":1-4, Str("deepJoin") from "test.jsonnet":5-13) from "test.jsonnet":1-13, ArgsDesc { unnamed: [Var("x") from "test.jsonnet":14-15], named: [] }, false) from "test.jsonnet":1-16, [ForSpec(ForSpecData("x", Var("arr") from "test.jsonnet":26-29))]) from "test.jsonnet":0-30`624 */625 assert_eq!(626 parse!("[std.deepJoin(x) for x in arr]"),488 parse!("[std.deepJoin(x) for x in arr]");627 el!(628 ArrComp(629 el!(630 Apply(631 el!(632 Index {633 indexable: el!(Var("std".into()), 1, 4),634 parts: vec![IndexPart {635 value: el!(Str("deepJoin".into()), 5, 13),636 #[cfg(feature = "exp-null-coaelse")]637 null_coaelse: false,638 }],639 },640 1,641 13642 ),643 ArgsDesc::new(vec![el!(Var("x".into()), 14, 15)], vec![]),644 false,645 ),646 1,647 16648 ),649 vec![CompSpec::ForSpec(ForSpecData(650 Destruct::Full("x".into()),651 el!(Var("arr".into()), 26, 29)652 ))]653 ),654 0,655 30656 ),657 )658 }489 }659490660 #[test]491 #[test]661 fn reserved() {492 fn reserved() {662 use Expr::*;663 assert_eq!(parse!("null"), el!(Literal(LiteralType::Null), 0, 4));493 parse!("null");664 assert_eq!(parse!("nulla"), el!(Var("nulla".into()), 0, 5));494 parse!("nulla");665 }495 }666496667 #[test]497 #[test]670 }500 }671501672 #[test]502 #[test]673 fn infix_precedence() {503 fn infix_precedence() {674 use Expr::*;675 assert_eq!(676 parse!("!a && !b"),677 el!(678 BinaryOp(679 el!(UnaryOp(UnaryOpType::Not, el!(Var("a".into()), 1, 2)), 0, 2),680 And,681 el!(UnaryOp(UnaryOpType::Not, el!(Var("b".into()), 7, 8)), 6, 8)682 ),683 0,684 8685 )686 );687 }688689 #[test]690 fn infix_precedence_division() {691 use Expr::*;504 parse!("!a && !b");692 assert_eq!(693 parse!("!a / !b"),505 parse!("!a / !b");694 el!(695 BinaryOp(696 el!(UnaryOp(UnaryOpType::Not, el!(Var("a".into()), 1, 2)), 0, 2),697 Div,698 el!(UnaryOp(UnaryOpType::Not, el!(Var("b".into()), 6, 7)), 5, 7)699 ),700 0,701 7702 )703 );704 }506 }705507706 #[test]508 #[test]707 fn double_negation() {509 fn double_negation() {708 use Expr::*;709 assert_eq!(710 parse!("!!a"),510 parse!("!!a");711 el!(712 UnaryOp(713 UnaryOpType::Not,714 el!(UnaryOp(UnaryOpType::Not, el!(Var("a".into()), 2, 3)), 1, 3)715 ),716 0,717 3718 )719 )720 }511 }721512722 #[test]513 #[test]723 fn array_test_error() {514 fn array_test_error() {724 parse!("[a for a in b if c for e in f]");515 parse!("[a for a in b if c for e in f]");725 // ^^^^ failed code726 }516 }727517728 #[test]518 #[test]741531742 #[test]532 #[test]743 fn add_location_info_to_all_sub_expressions() {533 fn add_location_info_to_all_sub_expressions() {744 use Expr::*;745746 let file_name = Source::new_virtual("<test>".into(), IStr::empty());747 let expr = parse(534 parse!("{} { local x = 1, x: x } + {}");748 "{} { local x = 1, x: x } + {}",749 &ParserSettings { source: file_name },750 )751 .unwrap();752 assert_eq!(753 expr,754 el!(755 BinaryOp(756 el!(757 ObjExtend(758 el!(Obj(ObjBody::MemberList(vec![])), 0, 2),759 ObjBody::MemberList(vec![760 Member::BindStmt(BindSpec::Field {761 into: Destruct::Full("x".into()),762 value: el!(Num(1.0), 15, 16)763 }),764 Member::Field(FieldMember {765 name: FieldName::Fixed("x".into()),766 plus: false,767 params: None,768 visibility: Visibility::Normal,769 value: el!(Var("x".into()), 21, 22),770 })771 ])772 ),773 0,774 24775 ),776 BinaryOpType::Add,777 el!(Obj(ObjBody::MemberList(vec![])), 27, 29),778 ),779 0,780 29781 ),782 );783 }535 }784}536}785537crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__add_location_info_to_all_sub_expressions.snapdiffbeforeafterbothno changes
crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__array_comp.snapdiffbeforeafterbothno changes
crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__array_test_error.snapdiffbeforeafterbothno changes
crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__basic_math-2.snapdiffbeforeafterbothno changes
crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__basic_math-3.snapdiffbeforeafterbothno changes
crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__basic_math-4.snapdiffbeforeafterbothno changes
crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__basic_math.snapdiffbeforeafterbothno changes
crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__default_param_before_nondefault.snapdiffbeforeafterbothno changes
crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__double_negation.snapdiffbeforeafterbothno changes
crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__empty_object.snapdiffbeforeafterbothno changes
crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__imports-2.snapdiffbeforeafterbothno changes
crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__imports-3.snapdiffbeforeafterbothno changes
crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__imports.snapdiffbeforeafterbothno changes
crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__infix_precedence-2.snapdiffbeforeafterbothno changes
crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__infix_precedence.snapdiffbeforeafterbothno changes
crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__missing_newline_between_comment_and_eof.snapdiffbeforeafterbothno changes
crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__multiline_string-2.snapdiffbeforeafterbothno changes
crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__multiline_string-3.snapdiffbeforeafterbothno changes
crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__multiline_string-4.snapdiffbeforeafterbothno changes
crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__multiline_string.snapdiffbeforeafterbothno changes
crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__multiple_args_buf.snapdiffbeforeafterbothno changes
crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__reserved-2.snapdiffbeforeafterbothno changes
crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__reserved.snapdiffbeforeafterbothno changes
crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__slice-2.snapdiffbeforeafterbothno changes
crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__slice-3.snapdiffbeforeafterbothno changes
crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__slice-4.snapdiffbeforeafterbothno changes
crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__slice-5.snapdiffbeforeafterbothno changes
crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__slice.snapdiffbeforeafterbothno changes
crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__string_escaping-2.snapdiffbeforeafterbothno changes
crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__string_escaping-3.snapdiffbeforeafterbothno changes
crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__string_escaping.snapdiffbeforeafterbothno changes
crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__string_unescaping.snapdiffbeforeafterbothno changes
crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__string_verbantim.snapdiffbeforeafterbothno changes
crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__suffix-2.snapdiffbeforeafterbothno changes
crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__suffix-3.snapdiffbeforeafterbothno changes
crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__suffix-4.snapdiffbeforeafterbothno changes
crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__suffix.snapdiffbeforeafterbothno changes
crates/jrsonnet-parser/src/source.rsdiffbeforeafterboth79/// search location is applicable79/// search location is applicable80///80///81/// Resolver may also return custom implementations of this trait, for example it may return http url in case of remotely loaded files81/// Resolver may also return custom implementations of this trait, for example it may return http url in case of remotely loaded files82#[derive(Eq, Debug, Clone, Acyclic)]82#[derive(Eq, Clone, Acyclic)]83pub struct SourcePath(Rc<dyn SourcePathT>);83pub struct SourcePath(Rc<dyn SourcePathT>);84impl SourcePath {84impl SourcePath {85 pub fn new(inner: impl SourcePathT) -> Self {85 pub fn new(inner: impl SourcePathT) -> Self {111 write!(f, "{}", self.0)111 write!(f, "{}", self.0)112 }112 }113}113}114impl Debug for SourcePath {115 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {116 write!(f, "{:?}", self.0)117 }118}114impl Default for SourcePath {119impl Default for SourcePath {115 fn default() -> Self {120 fn default() -> Self {116 Self(Rc::new(SourceDefault))121 Self(Rc::new(SourceDefault))213///218///214/// It is used for --ext-code=.../--tla-code=.../standard library source code by default,219/// It is used for --ext-code=.../--tla-code=.../standard library source code by default,215/// and user can construct arbitrary values by hand, without asking import resolver220/// and user can construct arbitrary values by hand, without asking import resolver216#[derive(Acyclic, Hash, PartialEq, Eq, Debug, Clone)]221#[derive(Acyclic, Hash, PartialEq, Eq, Clone)]217pub struct SourceVirtual(pub IStr);222pub struct SourceVirtual(pub IStr);218impl Display for SourceVirtual {223impl Display for SourceVirtual {219 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {224 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {220 write!(f, "{}", self.0)225 write!(f, "virtual:{}", self.0)221 }226 }222}227}228impl fmt::Debug for SourceVirtual {229 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {230 write!(f, "virtual:{}", self.0)231 }232}223impl SourcePathT for SourceVirtual {233impl SourcePathT for SourceVirtual {224 fn is_default(&self) -> bool {234 fn is_default(&self) -> bool {225 true235 true263273264/// Either real file, or virtual274/// Either real file, or virtual265/// Hash of FileName always have same value as raw Path, to make it possible to use with raw_entry_mut275/// Hash of FileName always have same value as raw Path, to make it possible to use with raw_entry_mut266#[derive(Clone, PartialEq, Eq, Debug, Acyclic)]276#[derive(Clone, PartialEq, Eq, Acyclic)]267pub struct Source(pub Rc<(SourcePath, IStr)>);277pub struct Source(pub Rc<(SourcePath, IStr)>);268278269impl Source {279impl Source {290 location_to_offset(&self.0 .1, line, column)300 location_to_offset(&self.0 .1, line, column)291 }301 }292}302}303impl fmt::Debug for Source {304 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {305 write!(f, "{:?}", self.0 .0)306 }307}293308