difftreelog
fix exp-destruct
in: master
7 files changed
crates/jrsonnet-evaluator/src/analyze.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/analyze.rs
+++ b/crates/jrsonnet-evaluator/src/analyze.rs
@@ -425,7 +425,7 @@
/// h = 1 => referenced += [], closures += 0, destructs += 1
/// And the result is
///
- /// ```
+ /// ```rust,ignore
/// Closures {
/// referenced: vec![d, e, f, a, b, c, h]
/// spec_shapes: vec![(3, 3), (4, 3), (0, 1)],
crates/jrsonnet-evaluator/src/evaluate/compspec.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/evaluate/compspec.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate/compspec.rs
@@ -195,7 +195,7 @@
) -> Result<()> {
if idx >= specs.len() {
collector.reserve(guaranteed_reserve);
- return collector.collect(ctx.clone());
+ return collector.collect(ctx);
}
match &specs[idx] {
LCompSpec::If(cond) => {
@@ -239,18 +239,20 @@
)?;
}
}
+ // TODO: Should not be eager? CoW won't work here
#[cfg(feature = "exp-destruct")]
_ => {
for (i, item) in arr.iter().enumerate() {
let item_val = item?;
let mut inner_builder = ContextBuilder::extend(ctx.clone(), 1);
+ let fctx = Pending::new();
destructure::destruct(
destruct,
Thunk::evaluated(item_val),
- None,
+ fctx.clone(),
&mut inner_builder,
);
- let inner_ctx = inner_builder.build();
+ let inner_ctx = inner_builder.build().into_future(fctx);
evaluate_compspecs_eager(
inner_ctx,
specs,
crates/jrsonnet-evaluator/src/evaluate/destructure.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/evaluate/destructure.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate/destructure.rs
@@ -12,7 +12,7 @@
#[allow(dead_code, reason = "not dead in exp-destruct")]
fn destruct_array(
start: &[LDestruct],
- rest: Option<LDestructRest>,
+ rest: Option<&LDestructRest>,
end: &[LDestruct],
value: Thunk<Val>,
@@ -56,7 +56,7 @@
if let Some(crate::analyze::LDestructRest::Keep(id)) = rest {
let full = full.clone();
builder.bind(
- id,
+ *id,
Thunk!(move || {
let full = full.evaluate()?;
let to = full.len() - end_len;
@@ -88,7 +88,7 @@
#[allow(dead_code, reason = "not dead in exp-destruct")]
fn destruct_object(
fields: &[LDestructField],
- rest: Option<LDestructRest>,
+ rest: Option<&LDestructRest>,
value: Thunk<Val>,
fctx: Pending<Context>,
@@ -127,7 +127,7 @@
if let Some(crate::analyze::LDestructRest::Keep(id)) = rest {
let full = full.clone();
builder.bind(
- id,
+ *id,
Thunk!(move || {
let full = full.evaluate()?;
let mut out = ObjValueBuilder::new();
@@ -178,9 +178,13 @@
#[cfg(feature = "exp-destruct")]
LDestruct::Skip => {}
#[cfg(feature = "exp-destruct")]
- LDestruct::Array { start, rest, end } => destruct_array(start, rest, end, value, fctx, builder),
+ LDestruct::Array { start, rest, end } => {
+ destruct_array(start, rest.as_ref(), end, value, fctx, builder)
+ }
#[cfg(feature = "exp-destruct")]
- LDestruct::Object { fields, rest } => destruct_object(fields, rest, value, fctx, builder),
+ LDestruct::Object { fields, rest } => {
+ destruct_object(fields, rest.as_ref(), value, fctx, builder)
+ }
}
}
crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@redeclared_local.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@redeclared_local.jsonnet.snap
+++ b/crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@redeclared_local.jsonnet.snap
@@ -1,7 +1,7 @@
---
source: crates/jrsonnet-evaluator/src/analyze.rs
expression: rendered
-input_file: crates/jrsonnet-evaluator/src/analyze_tests/redeclared_local.jsonnet
+input_file: crates/jrsonnet-evaluator/src/analysis_tests/redeclared_local.jsonnet
---
--- source ---
local x = 1, x = 2; x
@@ -10,7 +10,7 @@
local_dependent_depth: 0
errored: true
--- diagnostics ---
- · ╭── variable redeclared: x
+ · ╭── local is already defined in the current frame: x
1 │ local x = 1, x = 2; x
2 │
--- lir ---
crates/jrsonnet-ir-parser/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-ir-parser/src/lib.rs
+++ b/crates/jrsonnet-ir-parser/src/lib.rs
@@ -381,7 +381,7 @@
None
};
let default = if p.try_eat(T![=]) {
- Some(Rc::new(spanned(p, expr)?))
+ Some(spanned(p, expr)?)
} else {
None
};
@@ -466,8 +466,10 @@
if !p.at(SyntaxKind::IDENT) {
let d = destruct(p)?;
p.eat(T![=])?;
- let value = Rc::new(expr(p)?);
- return Ok(BindSpec::Field { into: d, value });
+ return Ok(BindSpec::Field {
+ into: d,
+ value: expr(p)?,
+ });
}
}
let name_spanned = spanned(p, ident)?;
crates/jrsonnet-ir/src/expr.rsdiffbeforeafterboth1use std::{2 fmt::{self, Debug, Display},3 ops::{Deref, RangeInclusive},4};56use jrsonnet_gcmodule::Acyclic;7use jrsonnet_interner::IStr;89use crate::{10 NumValue,11 function::{FunctionSignature, ParamDefault, ParamName, ParamParse},12 source::Source,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, PartialEq, Eq, Acyclic)]215pub enum DestructRest {216 /// ...rest217 Keep(IStr),218 /// ...219 Drop,220}221222#[derive(Debug, 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<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
@@ -1,5 +1,3 @@
-use std::rc::Rc;
-
use jrsonnet_gcmodule::Acyclic;
use jrsonnet_ir::{
ArgsDesc, AssertExpr, AssertStmt, BinaryOp, BindSpec, CompSpec, Destruct, DestructRest, Expr,
@@ -110,7 +108,7 @@
}
pub rule destruct_object(s: &ParserSettings) -> Destruct
= "{" _
- fields:(name:id() into:(_ ":" _ into:destruct(s) {into})? default:(_ "=" _ v:spanned(<expr(s)>, s) {v})? {(name, into, default.map(Rc::new))})**comma()
+ fields:(name:id() into:(_ ":" _ into:destruct(s) {into})? default:(_ "=" _ v:spanned(<expr(s)>, s) {v})? {(name, into, default)})**comma()
rest:(
comma() rest:destruct_rest()? {rest}
/ comma()? {None}