difftreelog
refactor(ir) flatten obj member
in: master
7 files changed
crates/jrsonnet-evaluator/src/async_import.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/async_import.rs
+++ b/crates/jrsonnet-evaluator/src/async_import.rs
@@ -4,7 +4,7 @@
use jrsonnet_gcmodule::Acyclic;
use jrsonnet_parser::{
ArgsDesc, AssertExpr, AssertStmt, BindSpec, CompSpec, Destruct, Expr, FieldMember, FieldName,
- ForSpecData, IfElse, IfSpecData, ImportKind, Member, ObjBody, Param, ParamsDesc,
+ ForSpecData, IfElse, IfSpecData, ImportKind, ObjBody, Param, ParamsDesc,
ParserSettings, Slice, SliceDesc, Source, SourcePath, Spanned,
};
use rustc_hash::FxHashMap;
@@ -102,31 +102,30 @@
}
fn in_obj(obj: &ObjBody, out: &mut FoundImports) {
match obj {
- ObjBody::MemberList(v) => {
- for member in v {
- match member {
- Member::Field(FieldMember {
- name,
- params,
- value,
- ..
- }) => {
- match name {
- FieldName::Fixed(_) => {}
- FieldName::Dyn(expr) => find_imports(expr, out),
- }
- if let Some(params) = params {
- in_params(params, out);
- }
- find_imports(value, out);
- }
- Member::BindStmt(_) => todo!(),
- Member::AssertStmt(assert) => {
- find_imports(&assert.0, out);
- if let Some(expr) = &assert.1 {
- find_imports(expr, out);
- }
- }
+ ObjBody::MemberList(obj) => {
+ for FieldMember {
+ name,
+ params,
+ value,
+ ..
+ } in &obj.fields
+ {
+ match name {
+ FieldName::Fixed(_) => {}
+ FieldName::Dyn(expr) => find_imports(expr, out),
+ }
+ if let Some(params) = params {
+ in_params(params, out);
+ }
+ find_imports(value, out);
+ }
+ for _ in &*obj.locals {
+ todo!()
+ }
+ for assert in &*obj.asserts {
+ find_imports(&assert.0, out);
+ if let Some(expr) = &assert.1 {
+ find_imports(expr, out);
}
}
}
crates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/evaluate/mod.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate/mod.rs
@@ -4,7 +4,7 @@
use jrsonnet_interner::IStr;
use jrsonnet_parser::{
ArgsDesc, AssertStmt, BinaryOpType, BindSpec, CompSpec, Expr, FieldMember, FieldName,
- ForSpecData, IfSpecData, ImportKind, LiteralType, Member, ObjBody, ParamsDesc, Spanned,
+ ForSpecData, IfSpecData, ImportKind, LiteralType, ObjBody, ObjMembers, ParamsDesc, Spanned,
};
use jrsonnet_types::ValType;
use rustc_hash::FxHashMap;
@@ -282,48 +282,38 @@
}
#[allow(clippy::too_many_lines)]
-pub fn evaluate_member_list_object(ctx: Context, members: &[Member]) -> Result<ObjValue> {
+pub fn evaluate_member_list_object(ctx: Context, members: &ObjMembers) -> Result<ObjValue> {
let mut builder = ObjValueBuilder::new();
- let locals = Rc::new(
- members
- .iter()
- .filter_map(|m| match m {
- Member::BindStmt(bind) => Some(bind.clone()),
- _ => None,
- })
- .collect::<Vec<_>>(),
- );
+ let locals = members.locals.clone();
// We have single context for all fields, so we can cache binds
let uctx = CachedUnbound::new(evaluate_object_locals(ctx.clone(), locals));
- for member in members {
- match member {
- Member::Field(field) => {
- evaluate_field_member(&mut builder, ctx.clone(), uctx.clone(), field)?;
- }
- Member::AssertStmt(stmt) => {
- #[derive(Trace)]
- struct ObjectAssert<B: Trace> {
- uctx: B,
- assert: Rc<AssertStmt>,
+ for field in &members.fields {
+ evaluate_field_member(&mut builder, ctx.clone(), uctx.clone(), &field)?;
+ }
+
+ if !members.asserts.is_empty() {
+ #[derive(Trace)]
+ struct ObjectAssert<B: Trace> {
+ uctx: B,
+ asserts: Rc<Vec<AssertStmt>>,
+ }
+ impl<B: Unbound<Bound = Context>> ObjectAssertion for ObjectAssert<B> {
+ fn run(&self, sup_this: SupThis) -> Result<()> {
+ let ctx = self.uctx.bind(sup_this)?;
+ for assert in &*self.asserts {
+ evaluate_assert(ctx.clone(), &assert)?;
}
- impl<B: Unbound<Bound = Context>> ObjectAssertion for ObjectAssert<B> {
- fn run(&self, sup_this: SupThis) -> Result<()> {
- let ctx = self.uctx.bind(sup_this)?;
- evaluate_assert(ctx, &self.assert)
- }
- }
- builder.assert(ObjectAssert {
- uctx: uctx.clone(),
- assert: stmt.clone(),
- });
- }
- Member::BindStmt(_) => {
- // Already handled
+ Ok(())
}
}
+ builder.assert(ObjectAssert {
+ uctx: uctx.clone(),
+ asserts: members.asserts.clone(),
+ });
}
+
Ok(builder.build())
}
@@ -332,13 +322,7 @@
ObjBody::MemberList(members) => evaluate_member_list_object(ctx, members)?,
ObjBody::ObjComp(obj) => {
let mut builder = ObjValueBuilder::new();
- let locals = Rc::new(
- obj.pre_locals
- .iter()
- .chain(obj.post_locals.iter())
- .cloned()
- .collect::<Vec<_>>(),
- );
+ let locals = obj.locals.clone();
evaluate_comp(ctx, &obj.compspecs, &mut |ctx| {
let uctx = evaluate_object_locals(ctx.clone(), locals.clone());
crates/jrsonnet-parser/src/expr.rsdiffbeforeafterboth1use std::{2 fmt::{self, Debug, Display},3 ops::Deref,4 rc::Rc,5};67use jrsonnet_gcmodule::Acyclic;8use jrsonnet_interner::IStr;910use crate::source::Source;1112#[derive(Debug, PartialEq, Acyclic)]13pub enum FieldName {14 /// {fixed: 2}15 Fixed(IStr),16 /// {["dyn"+"amic"]: 3}17 Dyn(Spanned<Expr>),18}1920#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]21#[repr(u8)]22pub enum Visibility {23 /// :24 Normal,25 /// ::26 Hidden,27 /// :::28 Unhide,29}3031impl Visibility {32 pub fn is_visible(&self) -> bool {33 matches!(self, Self::Normal | Self::Unhide)34 }35}3637#[derive(Debug, PartialEq, Acyclic)]38pub struct AssertStmt(pub Spanned<Expr>, pub Option<Spanned<Expr>>);3940#[derive(Debug, PartialEq, Acyclic)]41pub struct FieldMember {42 pub name: FieldName,43 pub plus: bool,44 pub params: Option<ParamsDesc>,45 pub visibility: Visibility,46 pub value: Rc<Spanned<Expr>>,47}4849#[derive(Debug, PartialEq, Acyclic)]50pub enum Member {51 Field(FieldMember),52 BindStmt(BindSpec),53 AssertStmt(Rc<AssertStmt>),54}5556#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]57pub enum UnaryOpType {58 Plus,59 Minus,60 BitNot,61 Not,62}6364impl Display for UnaryOpType {65 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {66 use UnaryOpType::*;67 write!(68 f,69 "{}",70 match self {71 Plus => "+",72 Minus => "-",73 BitNot => "~",74 Not => "!",75 }76 )77 }78}7980#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]81pub enum BinaryOpType {82 Mul,83 Div,8485 /// Implemented as intrinsic, put here for completeness86 Mod,8788 Add,89 Sub,9091 Lhs,92 Rhs,9394 Lt,95 Gt,96 Lte,97 Gte,9899 BitAnd,100 BitOr,101 BitXor,102103 Eq,104 Neq,105106 And,107 Or,108 #[cfg(feature = "exp-null-coaelse")]109 NullCoaelse,110111 // Equialent to std.objectHasEx(a, b, true)112 In,113}114115impl Display for BinaryOpType {116 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {117 use BinaryOpType::*;118 write!(119 f,120 "{}",121 match self {122 Mul => "*",123 Div => "/",124 Mod => "%",125 Add => "+",126 Sub => "-",127 Lhs => "<<",128 Rhs => ">>",129 Lt => "<",130 Gt => ">",131 Lte => "<=",132 Gte => ">=",133 BitAnd => "&",134 BitOr => "|",135 BitXor => "^",136 Eq => "==",137 Neq => "!=",138 And => "&&",139 Or => "||",140 In => "in",141 #[cfg(feature = "exp-null-coaelse")]142 NullCoaelse => "??",143 }144 )145 }146}147148/// name, default value149#[derive(Debug, PartialEq, Acyclic)]150pub struct Param(pub Destruct, pub Option<Rc<Spanned<Expr>>>);151152/// Defined function parameters153#[derive(Debug, Clone, PartialEq, Acyclic)]154pub struct ParamsDesc(pub Rc<Vec<Param>>);155156impl Deref for ParamsDesc {157 type Target = Vec<Param>;158 fn deref(&self) -> &Self::Target {159 &self.0160 }161}162163#[derive(Debug, PartialEq, Acyclic)]164pub struct ArgsDesc {165 pub unnamed: Vec<Rc<Spanned<Expr>>>,166 pub named: Vec<(IStr, Rc<Spanned<Expr>>)>,167}168impl ArgsDesc {169 pub fn new(unnamed: Vec<Rc<Spanned<Expr>>>, named: Vec<(IStr, Rc<Spanned<Expr>>)>) -> Self {170 Self { unnamed, named }171 }172}173174#[derive(Debug, Clone, PartialEq, Eq, Acyclic)]175pub enum DestructRest {176 /// ...rest177 Keep(IStr),178 /// ...179 Drop,180}181182#[derive(Debug, Clone, PartialEq, Acyclic)]183pub enum Destruct {184 Full(IStr),185 #[cfg(feature = "exp-destruct")]186 Skip,187 #[cfg(feature = "exp-destruct")]188 Array {189 start: Vec<Destruct>,190 rest: Option<DestructRest>,191 end: Vec<Destruct>,192 },193 #[cfg(feature = "exp-destruct")]194 Object {195 fields: Vec<(IStr, Option<Destruct>, Option<Spanned<Expr>>)>,196 rest: Option<DestructRest>,197 },198}199impl Destruct {200 /// Name of destructure, used for function parameter names201 pub fn name(&self) -> Option<IStr> {202 match self {203 Self::Full(name) => Some(name.clone()),204 #[cfg(feature = "exp-destruct")]205 _ => None,206 }207 }208 pub fn capacity_hint(&self) -> usize {209 #[cfg(feature = "exp-destruct")]210 fn cap_rest(rest: &Option<DestructRest>) -> usize {211 match rest {212 Some(DestructRest::Keep(_)) => 1,213 Some(DestructRest::Drop) => 0,214 None => 0,215 }216 }217 match self {218 Self::Full(_) => 1,219 #[cfg(feature = "exp-destruct")]220 Self::Skip => 0,221 #[cfg(feature = "exp-destruct")]222 Self::Array { start, rest, end } => {223 start.iter().map(Destruct::capacity_hint).sum::<usize>()224 + end.iter().map(Destruct::capacity_hint).sum::<usize>()225 + cap_rest(rest)226 }227 #[cfg(feature = "exp-destruct")]228 Self::Object { fields, rest } => {229 let mut out = 0;230 for (_, into, _) in fields {231 match into {232 Some(v) => out += v.capacity_hint(),233 // Field is destructured to default name234 None => out += 1,235 }236 }237 out + cap_rest(rest)238 }239 }240 }241}242243#[derive(Debug, Clone, PartialEq, Acyclic)]244pub enum BindSpec {245 Field {246 into: Destruct,247 value: Rc<Spanned<Expr>>,248 },249 Function {250 name: IStr,251 params: ParamsDesc,252 value: Rc<Spanned<Expr>>,253 },254}255impl BindSpec {256 pub fn capacity_hint(&self) -> usize {257 match self {258 BindSpec::Field { into, .. } => into.capacity_hint(),259 BindSpec::Function { .. } => 1,260 }261 }262}263264#[derive(Debug, PartialEq, Acyclic)]265pub struct IfSpecData(pub Spanned<Expr>);266267#[derive(Debug, PartialEq, Acyclic)]268pub struct ForSpecData(pub Destruct, pub Spanned<Expr>);269270#[derive(Debug, PartialEq, Acyclic)]271pub enum CompSpec {272 IfSpec(IfSpecData),273 ForSpec(ForSpecData),274}275276#[derive(Debug, PartialEq, Acyclic)]277pub struct ObjComp {278 pub pre_locals: Vec<BindSpec>,279 pub field: Rc<FieldMember>,280 pub post_locals: Vec<BindSpec>,281 pub compspecs: Vec<CompSpec>,282}283284#[derive(Debug, PartialEq, Acyclic)]285pub enum ObjBody {286 MemberList(Vec<Member>),287 ObjComp(ObjComp),288}289290#[derive(Debug, PartialEq, Eq, Clone, Copy, Acyclic)]291pub enum LiteralType {292 This,293 Super,294 Dollar,295 Null,296 True,297 False,298}299300#[derive(Debug, PartialEq, Acyclic)]301pub struct SliceDesc {302 pub start: Option<Spanned<Expr>>,303 pub end: Option<Spanned<Expr>>,304 pub step: Option<Spanned<Expr>>,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}339340/// Syntax base341#[derive(Debug, PartialEq, Acyclic)]342pub enum Expr {343 Literal(LiteralType),344345 /// String value: "hello"346 Str(IStr),347 /// Number: 1, 2.0, 2e+20348 Num(f64),349 /// Variable name: test350 Var(IStr),351352 /// Array of expressions: [1, 2, "Hello"]353 Arr(Rc<Vec<Spanned<Expr>>>),354 /// Array comprehension:355 /// ```jsonnet356 /// ingredients: [357 /// { kind: kind, qty: 4 / 3 }358 /// for kind in [359 /// 'Honey Syrup',360 /// 'Lemon Juice',361 /// 'Farmers Gin',362 /// ]363 /// ],364 /// ```365 ArrComp(Rc<Spanned<Expr>>, Vec<CompSpec>),366367 /// Object: {a: 2}368 Obj(ObjBody),369 /// Object extension: var1 {b: 2}370 ObjExtend(Rc<Spanned<Expr>>, ObjBody),371372 /// -2373 UnaryOp(UnaryOpType, Box<Spanned<Expr>>),374 /// 2 - 2375 BinaryOp(Box<BinaryOp>),376 /// assert 2 == 2 : "Math is broken"377 AssertExpr(Rc<AssertExpr>),378 /// local a = 2; { b: a }379 LocalExpr(Vec<BindSpec>, Box<Spanned<Expr>>),380381 /// import* "hello"382 Import(ImportKind, Box<Spanned<Expr>>),383 /// error "I'm broken"384 ErrorStmt(Box<Spanned<Expr>>),385 /// a(b, c)386 Apply(Box<Spanned<Expr>>, ArgsDesc, bool),387 /// a[b], a.b, a?.b388 Index {389 indexable: Box<Spanned<Expr>>,390 parts: Vec<IndexPart>,391 },392 /// function(x) x393 Function(ParamsDesc, Rc<Spanned<Expr>>),394 /// if true == false then 1 else 2395 IfElse(Box<IfElse>),396 Slice(Box<Slice>),397}398399#[derive(Debug, PartialEq, Acyclic)]400pub struct IndexPart {401 pub value: Spanned<Expr>,402 #[cfg(feature = "exp-null-coaelse")]403 pub null_coaelse: bool,404}405406/// file, begin offset, end offset407#[derive(Clone, PartialEq, Eq, Acyclic)]408#[repr(C)]409pub struct Span(pub Source, pub u32, pub u32);410impl Span {411 pub fn belongs_to(&self, other: &Span) -> bool {412 other.0 == self.0 && other.1 <= self.1 && other.2 >= self.2413 }414}415416static_assertions::assert_eq_size!(Span, (usize, usize));417418impl Debug for Span {419 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {420 write!(f, "{:?}:{:?}-{:?}", self.0, self.1, self.2)421 }422}423424#[derive(Clone, PartialEq, Acyclic)]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}432impl<T: Acyclic> Spanned<T> {433 #[inline]434 pub fn new(v: T, s: Span) -> Self {435 Self(v, s)436 }437 #[inline]438 pub fn span(&self) -> Span {439 self.1.clone()440 }441}442443impl<T: Debug + Acyclic> Debug for Spanned<T> {444 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {445 let expr = &**self;446 if f.alternate() {447 write!(f, "{:#?}", expr)?;448 } else {449 write!(f, "{:?}", expr)?;450 }451 write!(f, " from {:?}", self.span())?;452 Ok(())453 }454}1use std::{2 fmt::{self, Debug, Display},3 ops::Deref,4 rc::Rc,5};67use jrsonnet_gcmodule::Acyclic;8use jrsonnet_interner::IStr;910use crate::source::Source;1112#[derive(Debug, PartialEq, Acyclic)]13pub enum FieldName {14 /// {fixed: 2}15 Fixed(IStr),16 /// {["dyn"+"amic"]: 3}17 Dyn(Spanned<Expr>),18}1920#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]21#[repr(u8)]22pub enum Visibility {23 /// :24 Normal,25 /// ::26 Hidden,27 /// :::28 Unhide,29}3031impl Visibility {32 pub fn is_visible(&self) -> bool {33 matches!(self, Self::Normal | Self::Unhide)34 }35}3637#[derive(Debug, PartialEq, Acyclic)]38pub struct AssertStmt(pub Spanned<Expr>, pub Option<Spanned<Expr>>);3940#[derive(Debug, PartialEq, Acyclic)]41pub struct FieldMember {42 pub name: FieldName,43 pub plus: bool,44 pub params: Option<ParamsDesc>,45 pub visibility: Visibility,46 pub value: Rc<Spanned<Expr>>,47}4849#[derive(Debug, PartialEq, Acyclic)]50pub(crate) enum Member {51 Field(FieldMember),52 BindStmt(BindSpec),53 AssertStmt(AssertStmt),54}5556#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]57pub enum UnaryOpType {58 Plus,59 Minus,60 BitNot,61 Not,62}6364impl Display for UnaryOpType {65 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {66 use UnaryOpType::*;67 write!(68 f,69 "{}",70 match self {71 Plus => "+",72 Minus => "-",73 BitNot => "~",74 Not => "!",75 }76 )77 }78}7980#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]81pub enum BinaryOpType {82 Mul,83 Div,8485 /// Implemented as intrinsic, put here for completeness86 Mod,8788 Add,89 Sub,9091 Lhs,92 Rhs,9394 Lt,95 Gt,96 Lte,97 Gte,9899 BitAnd,100 BitOr,101 BitXor,102103 Eq,104 Neq,105106 And,107 Or,108 #[cfg(feature = "exp-null-coaelse")]109 NullCoaelse,110111 // Equialent to std.objectHasEx(a, b, true)112 In,113}114115impl Display for BinaryOpType {116 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {117 use BinaryOpType::*;118 write!(119 f,120 "{}",121 match self {122 Mul => "*",123 Div => "/",124 Mod => "%",125 Add => "+",126 Sub => "-",127 Lhs => "<<",128 Rhs => ">>",129 Lt => "<",130 Gt => ">",131 Lte => "<=",132 Gte => ">=",133 BitAnd => "&",134 BitOr => "|",135 BitXor => "^",136 Eq => "==",137 Neq => "!=",138 And => "&&",139 Or => "||",140 In => "in",141 #[cfg(feature = "exp-null-coaelse")]142 NullCoaelse => "??",143 }144 )145 }146}147148/// name, default value149#[derive(Debug, PartialEq, Acyclic)]150pub struct Param(pub Destruct, pub Option<Rc<Spanned<Expr>>>);151152/// Defined function parameters153#[derive(Debug, Clone, PartialEq, Acyclic)]154pub struct ParamsDesc(pub Rc<Vec<Param>>);155156impl Deref for ParamsDesc {157 type Target = Vec<Param>;158 fn deref(&self) -> &Self::Target {159 &self.0160 }161}162163#[derive(Debug, PartialEq, Acyclic)]164pub struct ArgsDesc {165 pub unnamed: Vec<Rc<Spanned<Expr>>>,166 pub named: Vec<(IStr, Rc<Spanned<Expr>>)>,167}168impl ArgsDesc {169 pub fn new(unnamed: Vec<Rc<Spanned<Expr>>>, named: Vec<(IStr, Rc<Spanned<Expr>>)>) -> Self {170 Self { unnamed, named }171 }172}173174#[derive(Debug, Clone, PartialEq, Eq, Acyclic)]175pub enum DestructRest {176 /// ...rest177 Keep(IStr),178 /// ...179 Drop,180}181182#[derive(Debug, Clone, PartialEq, Acyclic)]183pub enum Destruct {184 Full(IStr),185 #[cfg(feature = "exp-destruct")]186 Skip,187 #[cfg(feature = "exp-destruct")]188 Array {189 start: Vec<Destruct>,190 rest: Option<DestructRest>,191 end: Vec<Destruct>,192 },193 #[cfg(feature = "exp-destruct")]194 Object {195 fields: Vec<(IStr, Option<Destruct>, Option<Spanned<Expr>>)>,196 rest: Option<DestructRest>,197 },198}199impl Destruct {200 /// Name of destructure, used for function parameter names201 pub fn name(&self) -> Option<IStr> {202 match self {203 Self::Full(name) => Some(name.clone()),204 #[cfg(feature = "exp-destruct")]205 _ => None,206 }207 }208 pub fn capacity_hint(&self) -> usize {209 #[cfg(feature = "exp-destruct")]210 fn cap_rest(rest: &Option<DestructRest>) -> usize {211 match rest {212 Some(DestructRest::Keep(_)) => 1,213 Some(DestructRest::Drop) => 0,214 None => 0,215 }216 }217 match self {218 Self::Full(_) => 1,219 #[cfg(feature = "exp-destruct")]220 Self::Skip => 0,221 #[cfg(feature = "exp-destruct")]222 Self::Array { start, rest, end } => {223 start.iter().map(Destruct::capacity_hint).sum::<usize>()224 + end.iter().map(Destruct::capacity_hint).sum::<usize>()225 + cap_rest(rest)226 }227 #[cfg(feature = "exp-destruct")]228 Self::Object { fields, rest } => {229 let mut out = 0;230 for (_, into, _) in fields {231 match into {232 Some(v) => out += v.capacity_hint(),233 // Field is destructured to default name234 None => out += 1,235 }236 }237 out + cap_rest(rest)238 }239 }240 }241}242243#[derive(Debug, PartialEq, Acyclic)]244pub enum BindSpec {245 Field {246 into: Destruct,247 value: Rc<Spanned<Expr>>,248 },249 Function {250 name: IStr,251 params: ParamsDesc,252 value: Rc<Spanned<Expr>>,253 },254}255impl BindSpec {256 pub fn capacity_hint(&self) -> usize {257 match self {258 BindSpec::Field { into, .. } => into.capacity_hint(),259 BindSpec::Function { .. } => 1,260 }261 }262}263264#[derive(Debug, PartialEq, Acyclic)]265pub struct IfSpecData(pub Spanned<Expr>);266267#[derive(Debug, PartialEq, Acyclic)]268pub struct ForSpecData(pub Destruct, pub Spanned<Expr>);269270#[derive(Debug, PartialEq, Acyclic)]271pub enum CompSpec {272 IfSpec(IfSpecData),273 ForSpec(ForSpecData),274}275276#[derive(Debug, PartialEq, Acyclic)]277pub struct ObjComp {278 pub locals: Rc<Vec<BindSpec>>,279 pub field: Rc<FieldMember>,280 pub compspecs: Vec<CompSpec>,281}282283#[derive(Debug, PartialEq, Acyclic)]284pub struct ObjMembers {285 pub locals: Rc<Vec<BindSpec>>,286 pub asserts: Rc<Vec<AssertStmt>>,287 pub fields: Vec<FieldMember>,288}289290#[derive(Debug, PartialEq, Acyclic)]291pub enum ObjBody {292 MemberList(ObjMembers),293 ObjComp(ObjComp),294}295296#[derive(Debug, PartialEq, Eq, Clone, Copy, Acyclic)]297pub enum LiteralType {298 This,299 Super,300 Dollar,301 Null,302 True,303 False,304}305306#[derive(Debug, PartialEq, Acyclic)]307pub struct SliceDesc {308 pub start: Option<Spanned<Expr>>,309 pub end: Option<Spanned<Expr>>,310 pub step: Option<Spanned<Expr>>,311}312313#[derive(Debug, PartialEq, Acyclic)]314pub struct AssertExpr {315 pub assert: AssertStmt,316 pub rest: Spanned<Expr>,317}318319#[derive(Debug, PartialEq, Acyclic)]320pub struct BinaryOp {321 pub lhs: Spanned<Expr>,322 pub op: BinaryOpType,323 pub rhs: Spanned<Expr>,324}325326#[derive(Debug, PartialEq, Acyclic)]327pub enum ImportKind {328 Normal,329 Str,330 Bin,331}332333#[derive(Debug, PartialEq, Acyclic)]334pub struct IfElse {335 pub cond: IfSpecData,336 pub cond_then: Spanned<Expr>,337 pub cond_else: Option<Spanned<Expr>>,338}339340#[derive(Debug, PartialEq, Acyclic)]341pub struct Slice {342 pub value: Spanned<Expr>,343 pub slice: SliceDesc,344}345346/// Syntax base347#[derive(Debug, PartialEq, Acyclic)]348pub enum Expr {349 Literal(LiteralType),350351 /// String value: "hello"352 Str(IStr),353 /// Number: 1, 2.0, 2e+20354 Num(f64),355 /// Variable name: test356 Var(IStr),357358 /// Array of expressions: [1, 2, "Hello"]359 Arr(Rc<Vec<Spanned<Expr>>>),360 /// Array comprehension:361 /// ```jsonnet362 /// ingredients: [363 /// { kind: kind, qty: 4 / 3 }364 /// for kind in [365 /// 'Honey Syrup',366 /// 'Lemon Juice',367 /// 'Farmers Gin',368 /// ]369 /// ],370 /// ```371 ArrComp(Rc<Spanned<Expr>>, Vec<CompSpec>),372373 /// Object: {a: 2}374 Obj(ObjBody),375 /// Object extension: var1 {b: 2}376 ObjExtend(Rc<Spanned<Expr>>, ObjBody),377378 /// -2379 UnaryOp(UnaryOpType, Box<Spanned<Expr>>),380 /// 2 - 2381 BinaryOp(Box<BinaryOp>),382 /// assert 2 == 2 : "Math is broken"383 AssertExpr(Rc<AssertExpr>),384 /// local a = 2; { b: a }385 LocalExpr(Vec<BindSpec>, Box<Spanned<Expr>>),386387 /// import* "hello"388 Import(ImportKind, Box<Spanned<Expr>>),389 /// error "I'm broken"390 ErrorStmt(Box<Spanned<Expr>>),391 /// a(b, c)392 Apply(Box<Spanned<Expr>>, ArgsDesc, bool),393 /// a[b], a.b, a?.b394 Index {395 indexable: Box<Spanned<Expr>>,396 parts: Vec<IndexPart>,397 },398 /// function(x) x399 Function(ParamsDesc, Rc<Spanned<Expr>>),400 /// if true == false then 1 else 2401 IfElse(Box<IfElse>),402 Slice(Box<Slice>),403}404405#[derive(Debug, PartialEq, Acyclic)]406pub struct IndexPart {407 pub value: Spanned<Expr>,408 #[cfg(feature = "exp-null-coaelse")]409 pub null_coaelse: bool,410}411412/// file, begin offset, end offset413#[derive(Clone, PartialEq, Eq, Acyclic)]414#[repr(C)]415pub struct Span(pub Source, pub u32, pub u32);416impl Span {417 pub fn belongs_to(&self, other: &Span) -> bool {418 other.0 == self.0 && other.1 <= self.1 && other.2 >= self.2419 }420}421422static_assertions::assert_eq_size!(Span, (usize, usize));423424impl Debug for Span {425 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {426 write!(f, "{:?}:{:?}-{:?}", self.0, self.1, self.2)427 }428}429430#[derive(Clone, PartialEq, Acyclic)]431pub struct Spanned<T: Acyclic>(T, Span);432impl<T: Acyclic> Deref for Spanned<T> {433 type Target = T;434 fn deref(&self) -> &Self::Target {435 &self.0436 }437}438impl<T: Acyclic> Spanned<T> {439 #[inline]440 pub fn new(v: T, s: Span) -> Self {441 Self(v, s)442 }443 #[inline]444 pub fn span(&self) -> Span {445 self.1.clone()446 }447}448449impl<T: Debug + Acyclic> Debug for Spanned<T> {450 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {451 let expr = &**self;452 if f.alternate() {453 write!(f, "{:#?}", expr)?;454 } else {455 write!(f, "{:?}", expr)?;456 }457 write!(f, " from {:?}", self.span())?;458 Ok(())459 }460}crates/jrsonnet-parser/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-parser/src/lib.rs
+++ b/crates/jrsonnet-parser/src/lib.rs
@@ -139,8 +139,8 @@
/ obj:destruct_object(s) {obj}
pub rule bind(s: &ParserSettings) -> expr::BindSpec
- = into:destruct(s) _ "=" _ expr:expr(s) {expr::BindSpec::Field{into, value: Rc::new(expr)}}
- / name:id() _ "(" _ params:params(s) _ ")" _ "=" _ expr:expr(s) {expr::BindSpec::Function{name, params, value: Rc::new(expr)}}
+ = into:destruct(s) _ "=" _ value:expr(s) {expr::BindSpec::Field{into, value: Rc::new(value)}}
+ / name:id() _ "(" _ params:params(s) _ ")" _ "=" _ value:expr(s) {expr::BindSpec::Function{name, params, value: Rc::new(value)}}
pub rule assertion(s: &ParserSettings) -> expr::AssertStmt
= keyword("assert") _ cond:expr(s) msg:(_ ":" _ e:expr(s) {e})? { expr::AssertStmt(cond, msg) }
@@ -207,20 +207,35 @@
= keyword("local") _ bind:bind(s) {bind}
pub rule member(s: &ParserSettings) -> expr::Member
= bind:obj_local(s) {expr::Member::BindStmt(bind)}
- / assertion:assertion(s) {expr::Member::AssertStmt(Rc::new(assertion))}
+ / assertion:assertion(s) {expr::Member::AssertStmt(assertion)}
/ field:field(s) {expr::Member::Field(field)}
pub rule objinside(s: &ParserSettings) -> expr::ObjBody
= 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})? {
let mut compspecs = vec![CompSpec::ForSpec(forspec)];
compspecs.extend(others.unwrap_or_default());
+ let mut locals = pre_locals;
+ locals.extend(post_locals);
expr::ObjBody::ObjComp(expr::ObjComp{
- pre_locals,
+ locals: Rc::new(locals),
field: Rc::new(field),
- post_locals,
compspecs,
})
}
- / members:(member(s) ** comma()) comma()? {expr::ObjBody::MemberList(members)}
+ / members:(member(s) ** comma()) comma()? {
+ let mut locals = Vec::new();
+ let mut asserts = Vec::new();
+ let mut fields = Vec::new();
+ for member in members {
+ match member {
+ Member::Field(field_member) => fields.push(field_member),
+ Member::BindStmt(bind_spec) => locals.push(bind_spec),
+ Member::AssertStmt(assert_stmt) => asserts.push(assert_stmt),
+ }
+ }
+ expr::ObjBody::MemberList(ObjMembers {
+ locals: Rc::new(locals), asserts: Rc::new(asserts), fields
+ })
+ }
pub rule ifspec(s: &ParserSettings) -> IfSpecData
= keyword("if") _ expr:expr(s) {IfSpecData(expr)}
pub rule forspec(s: &ParserSettings) -> ForSpecData
crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__add_location_info_to_all_sub_expressions.snapdiffbeforeafterboth--- a/crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__add_location_info_to_all_sub_expressions.snap
+++ b/crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__add_location_info_to_all_sub_expressions.snap
@@ -7,12 +7,16 @@
lhs: ObjExtend(
Obj(
MemberList(
- [],
+ ObjMembers {
+ locals: [],
+ asserts: [],
+ fields: [],
+ },
),
) from virtual:<test>:0-2,
MemberList(
- [
- BindStmt(
+ ObjMembers {
+ locals: [
Field {
into: Full(
"x",
@@ -21,8 +25,9 @@
1.0,
) from virtual:<test>:15-16,
},
- ),
- Field(
+ ],
+ asserts: [],
+ fields: [
FieldMember {
name: Fixed(
"x",
@@ -34,14 +39,18 @@
"x",
) from virtual:<test>:21-22,
},
- ),
- ],
+ ],
+ },
),
) from virtual:<test>:0-24,
op: Add,
rhs: Obj(
MemberList(
- [],
+ ObjMembers {
+ locals: [],
+ asserts: [],
+ fields: [],
+ },
),
) from virtual:<test>:27-29,
},
crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__empty_object.snapdiffbeforeafterboth--- a/crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__empty_object.snap
+++ b/crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__empty_object.snap
@@ -4,6 +4,10 @@
---
Obj(
MemberList(
- [],
+ ObjMembers {
+ locals: [],
+ asserts: [],
+ fields: [],
+ },
),
) from virtual:<test>:0-2
crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__missing_newline_between_comment_and_eof.snapdiffbeforeafterboth--- a/crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__missing_newline_between_comment_and_eof.snap
+++ b/crates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__missing_newline_between_comment_and_eof.snap
@@ -4,8 +4,10 @@
---
Obj(
MemberList(
- [
- Field(
+ ObjMembers {
+ locals: [],
+ asserts: [],
+ fields: [
FieldMember {
name: Fixed(
"a",
@@ -17,7 +19,7 @@
1.0,
) from virtual:<test>:3-4,
},
- ),
- ],
+ ],
+ },
),
) from virtual:<test>:0-5