difftreelog
feat destruct function arguments
in: master
5 files changed
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(clippy::too_many_lines)]
-fn destruct(
+pub fn destruct(
d: &Destruct,
parent: Thunk<Val>,
new_bindings: &mut GcHashMap<IStr, Thunk<Val>>,
crates/jrsonnet-evaluator/src/function/mod.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/function/mod.rs
+++ b/crates/jrsonnet-evaluator/src/function/mod.rs
@@ -59,7 +59,7 @@
}
impl FuncDesc {
/// Create body context, but fill arguments without defaults with lazy error
- pub fn default_body_context(&self) -> Context {
+ pub fn default_body_context(&self) -> Result<Context> {
parse_default_function_call(self.ctx.clone(), &self.params)
}
crates/jrsonnet-evaluator/src/function/parse.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/function/parse.rs
+++ b/crates/jrsonnet-evaluator/src/function/parse.rs
@@ -7,6 +7,7 @@
builtin::{BuiltinParam, BuiltinParamName},
};
use crate::{
+ destructure::destruct,
error::{Error::*, Result},
evaluate_named,
gc::GcHashMap,
@@ -50,60 +51,77 @@
throw!(TooManyArgsFunctionHas(params.len()))
}
- let mut filled_args = 0;
+ let mut filled_named = 0;
+ let mut filled_positionals = 0;
args.unnamed_iter(s.clone(), ctx.clone(), tailstrict, &mut |id, arg| {
let name = params[id].0.clone();
- passed_args.insert(name, arg);
- filled_args += 1;
+ destruct(&name, arg, &mut passed_args)?;
+ filled_positionals += 1;
Ok(())
})?;
args.named_iter(s, ctx, tailstrict, &mut |name, value| {
// FIXME: O(n) for arg existence check
- if !params.iter().any(|p| &p.0 == name) {
+ if !params.iter().any(|p| p.0.name().as_ref() == Some(name)) {
throw!(UnknownFunctionParameter((name as &str).to_owned()));
}
if passed_args.insert(name.clone(), value).is_some() {
throw!(BindingParameterASecondTime(name.clone()));
}
- filled_args += 1;
+ filled_named += 1;
Ok(())
})?;
- if filled_args < params.len() {
+ if filled_named + filled_positionals < params.len() {
// Some args are unset, but maybe we have defaults for them
// Default values should be created in newly created context
let fctx = Context::new_future();
- let mut defaults = GcHashMap::with_capacity(params.len() - filled_args);
+ let mut defaults =
+ GcHashMap::with_capacity(params.len() - filled_named - filled_positionals);
- for param in params.iter().filter(|p| p.1.is_some()) {
- if passed_args.contains_key(¶m.0.clone()) {
+ for (idx, param) in params.iter().enumerate().filter(|p| p.1 .1.is_some()) {
+ if let Some(name) = param.0.name() {
+ if passed_args.contains_key(&name) {
+ continue;
+ }
+ } else if idx < filled_positionals {
continue;
}
- defaults.insert(
- param.0.clone(),
+ destruct(
+ ¶m.0,
Thunk::new(tb!(EvaluateNamedThunk {
ctx: fctx.clone(),
- name: param.0.clone(),
+ name: param.0.name().unwrap_or_else(|| "<destruct>".into()),
value: param.1.clone().expect("default exists"),
})),
- );
- filled_args += 1;
+ &mut defaults,
+ )?;
+ if param.0.name().is_some() {
+ filled_named += 1;
+ } else {
+ filled_positionals += 1;
+ }
}
- // Some args still wasn't filled
- if filled_args != params.len() {
+ // Some args still weren't filled
+ if filled_named + filled_positionals != params.len() {
for param in params.iter().skip(args.unnamed_len()) {
let mut found = false;
args.named_names(&mut |name| {
- if name == ¶m.0 {
+ if Some(name) == param.0.name().as_ref() {
found = true;
}
});
if !found {
- throw!(FunctionParameterNotBoundInCall(param.0.clone()));
+ throw!(FunctionParameterNotBoundInCall(
+ param
+ .0
+ .clone()
+ .name()
+ .unwrap_or_else(|| "<destruct>".into())
+ ));
}
}
unreachable!();
@@ -189,7 +207,7 @@
/// Creates Context, which has all argument default values applied
/// and with unbound values causing error to be returned
-pub fn parse_default_function_call(body_ctx: Context, params: &ParamsDesc) -> Context {
+pub fn parse_default_function_call(body_ctx: Context, params: &ParamsDesc) -> Result<Context> {
#[derive(Trace)]
struct DependsOnUnbound(IStr);
impl ThunkValue for DependsOnUnbound {
@@ -205,23 +223,27 @@
for param in params.iter() {
if let Some(v) = ¶m.1 {
- bindings.insert(
- param.0.clone(),
+ destruct(
+ ¶m.0.clone(),
Thunk::new(tb!(EvaluateNamedThunk {
ctx: fctx.clone(),
- name: param.0.clone(),
+ name: param.0.name().unwrap_or_else(|| "<destruct>".into()),
value: v.clone(),
})),
- );
+ &mut bindings,
+ )?;
} else {
- bindings.insert(
- param.0.clone(),
- Thunk::new(tb!(DependsOnUnbound(param.0.clone()))),
- );
+ destruct(
+ ¶m.0,
+ Thunk::new(tb!(DependsOnUnbound(
+ param.0.name().unwrap_or_else(|| "<destruct>".into())
+ ))),
+ &mut bindings,
+ )?;
}
}
- body_ctx
+ Ok(body_ctx
.extend(bindings, None, None, None)
- .into_future(fctx)
+ .into_future(fctx))
}
crates/jrsonnet-parser/src/expr.rsdiffbeforeafterboth1use std::{2 fmt::{self, Debug, Display},3 ops::Deref,4 rc::Rc,5};67use gcmodule::Trace;8use jrsonnet_interner::IStr;9#[cfg(feature = "serde")]10use serde::{Deserialize, Serialize};1112use crate::source::Source;1314#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]15#[derive(Debug, PartialEq, Trace)]16pub enum FieldName {17 /// {fixed: 2}18 Fixed(IStr),19 /// {["dyn"+"amic"]: 3}20 Dyn(LocExpr),21}2223#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]24#[derive(Debug, Clone, Copy, PartialEq, Eq, Trace)]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#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]41#[derive(Clone, Debug, PartialEq, Trace)]42pub struct AssertStmt(pub LocExpr, pub Option<LocExpr>);4344#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]45#[derive(Debug, PartialEq, Trace)]46pub struct FieldMember {47 pub name: FieldName,48 pub plus: bool,49 pub params: Option<ParamsDesc>,50 pub visibility: Visibility,51 pub value: LocExpr,52}5354#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]55#[derive(Debug, PartialEq, Trace)]56pub enum Member {57 Field(FieldMember),58 BindStmt(BindSpec),59 AssertStmt(AssertStmt),60}6162#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]63#[derive(Debug, Clone, Copy, PartialEq, Eq, Trace)]64pub enum UnaryOpType {65 Plus,66 Minus,67 BitNot,68 Not,69}7071impl Display for UnaryOpType {72 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {73 use UnaryOpType::*;74 write!(75 f,76 "{}",77 match self {78 Plus => "+",79 Minus => "-",80 BitNot => "~",81 Not => "!",82 }83 )84 }85}8687#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]88#[derive(Debug, Clone, Copy, PartialEq, Eq, Trace)]89pub enum BinaryOpType {90 Mul,91 Div,9293 /// Implemented as intrinsic, put here for completeness94 Mod,9596 Add,97 Sub,9899 Lhs,100 Rhs,101102 Lt,103 Gt,104 Lte,105 Gte,106107 BitAnd,108 BitOr,109 BitXor,110111 Eq,112 Neq,113114 And,115 Or,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 }148 )149 }150}151152/// name, default value153#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]154#[derive(Debug, PartialEq, Trace)]155pub struct Param(pub IStr, pub Option<LocExpr>);156157/// Defined function parameters158#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]159#[derive(Debug, Clone, PartialEq, Trace)]160pub struct ParamsDesc(pub Rc<Vec<Param>>);161162impl Deref for ParamsDesc {163 type Target = Vec<Param>;164 fn deref(&self) -> &Self::Target {165 &self.0166 }167}168169#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]170#[derive(Debug, PartialEq, Trace)]171pub struct ArgsDesc {172 pub unnamed: Vec<LocExpr>,173 pub named: Vec<(IStr, LocExpr)>,174}175impl ArgsDesc {176 pub fn new(unnamed: Vec<LocExpr>, named: Vec<(IStr, LocExpr)>) -> Self {177 Self { unnamed, named }178 }179}180181#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]182#[derive(Debug, Clone, PartialEq, Eq, Trace)]183pub enum DestructRest {184 /// ...rest185 Keep(IStr),186 /// ...187 Drop,188}189190#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]191#[derive(Debug, Clone, PartialEq, Eq, Trace)]192pub enum Destruct {193 Full(IStr),194 #[cfg(feature = "exp-destruct")]195 Skip,196 #[cfg(feature = "exp-destruct")]197 Array {198 start: Vec<Destruct>,199 rest: Option<DestructRest>,200 end: Vec<Destruct>,201 },202 #[cfg(feature = "exp-destruct")]203 Object {204 fields: Vec<(IStr, Option<Destruct>)>,205 rest: Option<DestructRest>,206 },207}208impl Destruct {209 pub fn name(&self) -> Option<IStr> {210 match self {211 Self::Full(name) => Some(name.clone()),212 #[cfg(feature = "exp-destruct")]213 _ => None,214 }215 }216}217218#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]219#[derive(Debug, Clone, PartialEq, Trace)]220pub enum BindSpec {221 Field {222 into: Destruct,223 value: LocExpr,224 },225 Function {226 name: IStr,227 params: ParamsDesc,228 value: LocExpr,229 },230}231232#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]233#[derive(Debug, PartialEq, Trace)]234pub struct IfSpecData(pub LocExpr);235236#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]237#[derive(Debug, PartialEq, Trace)]238pub struct ForSpecData(pub IStr, pub LocExpr);239240#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]241#[derive(Debug, PartialEq, Trace)]242pub enum CompSpec {243 IfSpec(IfSpecData),244 ForSpec(ForSpecData),245}246247#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]248#[derive(Debug, PartialEq, Trace)]249pub struct ObjComp {250 pub pre_locals: Vec<BindSpec>,251 pub key: LocExpr,252 pub plus: bool,253 pub value: LocExpr,254 pub post_locals: Vec<BindSpec>,255 pub compspecs: Vec<CompSpec>,256}257258#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]259#[derive(Debug, PartialEq, Trace)]260pub enum ObjBody {261 MemberList(Vec<Member>),262 ObjComp(ObjComp),263}264265#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]266#[derive(Debug, PartialEq, Eq, Clone, Copy, Trace)]267pub enum LiteralType {268 This,269 Super,270 Dollar,271 Null,272 True,273 False,274}275276#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]277#[derive(Debug, PartialEq, Trace)]278pub struct SliceDesc {279 pub start: Option<LocExpr>,280 pub end: Option<LocExpr>,281 pub step: Option<LocExpr>,282}283284/// Syntax base285#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]286#[derive(Debug, PartialEq, Trace)]287pub enum Expr {288 Literal(LiteralType),289290 /// String value: "hello"291 Str(IStr),292 /// Number: 1, 2.0, 2e+20293 Num(f64),294 /// Variable name: test295 Var(IStr),296297 /// Array of expressions: [1, 2, "Hello"]298 Arr(Vec<LocExpr>),299 /// Array comprehension:300 /// ```jsonnet301 /// ingredients: [302 /// { kind: kind, qty: 4 / 3 }303 /// for kind in [304 /// 'Honey Syrup',305 /// 'Lemon Juice',306 /// 'Farmers Gin',307 /// ]308 /// ],309 /// ```310 ArrComp(LocExpr, Vec<CompSpec>),311312 /// Object: {a: 2}313 Obj(ObjBody),314 /// Object extension: var1 {b: 2}315 ObjExtend(LocExpr, ObjBody),316317 /// (obj)318 Parened(LocExpr),319320 /// -2321 UnaryOp(UnaryOpType, LocExpr),322 /// 2 - 2323 BinaryOp(LocExpr, BinaryOpType, LocExpr),324 /// assert 2 == 2 : "Math is broken"325 AssertExpr(AssertStmt, LocExpr),326 /// local a = 2; { b: a }327 LocalExpr(Vec<BindSpec>, LocExpr),328329 /// import "hello"330 Import(IStr),331 /// importStr "file.txt"332 ImportStr(IStr),333 /// importBin "file.txt"334 ImportBin(IStr),335 /// error "I'm broken"336 ErrorStmt(LocExpr),337 /// a(b, c)338 Apply(LocExpr, ArgsDesc, bool),339 /// a[b]340 Index(LocExpr, LocExpr),341 /// function(x) x342 Function(ParamsDesc, LocExpr),343 /// std.thisFile344 IntrinsicThisFile,345 /// std.id,346 IntrinsicId,347 /// std.primitiveEquals348 Intrinsic(IStr),349 /// if true == false then 1 else 2350 IfElse {351 cond: IfSpecData,352 cond_then: LocExpr,353 cond_else: Option<LocExpr>,354 },355 Slice(LocExpr, SliceDesc),356}357358/// file, begin offset, end offset359#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]360#[derive(Clone, PartialEq, Eq, Trace)]361#[skip_trace]362#[repr(C)]363pub struct ExprLocation(pub Source, pub u32, pub u32);364impl ExprLocation {365 pub fn belongs_to(&self, other: &ExprLocation) -> bool {366 other.0 == self.0 && other.1 <= self.1 && other.2 >= self.2367 }368}369370#[cfg(target_pointer_width = "64")]371static_assertions::assert_eq_size!(ExprLocation, [u8; 16]);372373impl Debug for ExprLocation {374 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {375 write!(f, "{:?}:{:?}-{:?}", self.0, self.1, self.2)376 }377}378379/// Holds AST expression and its location in source file380#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]381#[derive(Clone, PartialEq, Trace)]382pub struct LocExpr(pub Rc<Expr>, pub ExprLocation);383384#[cfg(target_pointer_width = "64")]385static_assertions::assert_eq_size!(LocExpr, [u8; 24]);386387impl Debug for LocExpr {388 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {389 if f.alternate() {390 write!(f, "{:#?}", self.0)?;391 } else {392 write!(f, "{:?}", self.0)?;393 }394 write!(f, " from {:?}", self.1)?;395 Ok(())396 }397}crates/jrsonnet-parser/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-parser/src/lib.rs
+++ b/crates/jrsonnet-parser/src/lib.rs
@@ -59,7 +59,7 @@
rule keyword(id: &'static str) -> ()
= ##parse_string_literal(id) end_of_ident()
- pub rule param(s: &ParserSettings) -> expr::Param = name:id() expr:(_ "=" _ expr:expr(s){expr})? { expr::Param(name, expr) }
+ pub rule param(s: &ParserSettings) -> expr::Param = name:destruct(s) expr:(_ "=" _ expr:expr(s){expr})? { expr::Param(name, expr) }
pub rule params(s: &ParserSettings) -> expr::ParamsDesc
= params:param(s) ** comma() comma()? { expr::ParamsDesc(Rc::new(params)) }
/ { expr::ParamsDesc(Rc::new(Vec::new())) }