git.delta.rocks / jrsonnet / refs/commits / ce2d8d503b4a

difftreelog

Merge pull request #19 from CertainLach/std-intrinsic

Yaroslav Bulyukin2020-10-20parents: #7e00c7d #0a096fe.patch.diff
in: master
Prevent changing meaning of std in desugared expressions

7 files changed

modifiedcrates/jrsonnet-evaluator/src/builtin/mod.rsdiffbeforeafterboth
20pub fn call_builtin(20pub fn call_builtin(
21 context: Context,21 context: Context,
22 loc: &Option<ExprLocation>,22 loc: &Option<ExprLocation>,
23 ns: &str,
24 name: &str,23 name: &str,
25 args: &ArgsDesc,24 args: &ArgsDesc,
26) -> Result<Val> {25) -> Result<Val> {
27 Ok(match (ns, name as &str) {26 Ok(match name as &str {
28 // arr/string/function27 // arr/string/function
29 ("std", "length") => parse_args!(context, "std.length", args, 1, [28 "length" => parse_args!(context, "std.length", args, 1, [
30 0, x: [Val::Str|Val::Arr|Val::Obj], vec![ValType::Str, ValType::Arr, ValType::Obj];29 0, x: [Val::Str|Val::Arr|Val::Obj], vec![ValType::Str, ValType::Arr, ValType::Obj];
31 ], {30 ], {
32 Ok(match x {31 Ok(match x {
42 })41 })
43 })?,42 })?,
44 // any43 // any
45 ("std", "type") => parse_args!(context, "std.type", args, 1, [44 "type" => parse_args!(context, "std.type", args, 1, [
46 0, x, vec![];45 0, x, vec![];
47 ], {46 ], {
48 Ok(Val::Str(x.value_type()?.name().into()))47 Ok(Val::Str(x.value_type()?.name().into()))
49 })?,48 })?,
50 // length, idx=>any49 // length, idx=>any
51 ("std", "makeArray") => parse_args!(context, "std.makeArray", args, 2, [50 "makeArray" => parse_args!(context, "std.makeArray", args, 2, [
52 0, sz: [Val::Num]!!Val::Num, vec![ValType::Num];51 0, sz: [Val::Num]!!Val::Num, vec![ValType::Num];
53 1, func: [Val::Func]!!Val::Func, vec![ValType::Func];52 1, func: [Val::Func]!!Val::Func, vec![ValType::Func];
54 ], {53 ], {
65 Ok(Val::Arr(Rc::new(out)))64 Ok(Val::Arr(Rc::new(out)))
66 })?,65 })?,
67 // string66 // string
68 ("std", "codepoint") => parse_args!(context, "std.codepoint", args, 1, [67 "codepoint" => parse_args!(context, "std.codepoint", args, 1, [
69 0, str: [Val::Str]!!Val::Str, vec![ValType::Str];68 0, str: [Val::Str]!!Val::Str, vec![ValType::Str];
70 ], {69 ], {
71 assert!(70 assert!(
75 Ok(Val::Num(str.chars().take(1).next().unwrap() as u32 as f64))74 Ok(Val::Num(str.chars().take(1).next().unwrap() as u32 as f64))
76 })?,75 })?,
77 // object, includeHidden76 // object, includeHidden
78 ("std", "objectFieldsEx") => parse_args!(context, "std.objectFieldsEx",args, 2, [77 "objectFieldsEx" => parse_args!(context, "std.objectFieldsEx",args, 2, [
79 0, obj: [Val::Obj]!!Val::Obj, vec![ValType::Obj];78 0, obj: [Val::Obj]!!Val::Obj, vec![ValType::Obj];
80 1, inc_hidden: [Val::Bool]!!Val::Bool, vec![ValType::Bool];79 1, inc_hidden: [Val::Bool]!!Val::Bool, vec![ValType::Bool];
81 ], {80 ], {
88 Ok(Val::Arr(Rc::new(out.into_iter().map(Val::Str).collect())))87 Ok(Val::Arr(Rc::new(out.into_iter().map(Val::Str).collect())))
89 })?,88 })?,
90 // object, field, includeHidden89 // object, field, includeHidden
91 ("std", "objectHasEx") => parse_args!(context, "std.objectHasEx", args, 3, [90 "objectHasEx" => parse_args!(context, "std.objectHasEx", args, 3, [
92 0, obj: [Val::Obj]!!Val::Obj, vec![ValType::Obj];91 0, obj: [Val::Obj]!!Val::Obj, vec![ValType::Obj];
93 1, f: [Val::Str]!!Val::Str, vec![ValType::Str];92 1, f: [Val::Str]!!Val::Str, vec![ValType::Str];
94 2, inc_hidden: [Val::Bool]!!Val::Bool, vec![ValType::Bool];93 2, inc_hidden: [Val::Bool]!!Val::Bool, vec![ValType::Bool];
100 .any(|(k, _v)| *k == *f),99 .any(|(k, _v)| *k == *f),
101 ))100 ))
102 })?,101 })?,
103 ("std", "primitiveEquals") => parse_args!(context, "std.primitiveEquals", args, 2, [102 "primitiveEquals" => parse_args!(context, "std.primitiveEquals", args, 2, [
104 0, a, vec![];103 0, a, vec![];
105 1, b, vec![];104 1, b, vec![];
106 ], {105 ], {
107 Ok(Val::Bool(primitive_equals(&a, &b)?))106 Ok(Val::Bool(primitive_equals(&a, &b)?))
108 })?,107 })?,
109 // faster108 // faster
110 ("std", "equals") => parse_args!(context, "std.equals", args, 2, [109 "equals" => parse_args!(context, "std.equals", args, 2, [
111 0, a, vec![];110 0, a, vec![];
112 1, b, vec![];111 1, b, vec![];
113 ], {112 ], {
114 Ok(Val::Bool(equals(&a, &b)?))113 Ok(Val::Bool(equals(&a, &b)?))
115 })?,114 })?,
116 ("std", "modulo") => parse_args!(context, "std.modulo", args, 2, [115 "modulo" => parse_args!(context, "std.modulo", args, 2, [
117 0, a: [Val::Num]!!Val::Num, vec![ValType::Num];116 0, a: [Val::Num]!!Val::Num, vec![ValType::Num];
118 1, b: [Val::Num]!!Val::Num, vec![ValType::Num];117 1, b: [Val::Num]!!Val::Num, vec![ValType::Num];
119 ], {118 ], {
120 Ok(Val::Num(a % b))119 Ok(Val::Num(a % b))
121 })?,120 })?,
122 ("std", "floor") => parse_args!(context, "std.floor", args, 1, [121 "floor" => parse_args!(context, "std.floor", args, 1, [
123 0, x: [Val::Num]!!Val::Num, vec![ValType::Num];122 0, x: [Val::Num]!!Val::Num, vec![ValType::Num];
124 ], {123 ], {
125 Ok(Val::Num(x.floor()))124 Ok(Val::Num(x.floor()))
126 })?,125 })?,
127 ("std", "log") => parse_args!(context, "std.log", args, 2, [126 "log" => parse_args!(context, "std.log", args, 2, [
128 0, n: [Val::Num]!!Val::Num, vec![ValType::Num];127 0, n: [Val::Num]!!Val::Num, vec![ValType::Num];
129 ], {128 ], {
130 Ok(Val::Num(n.ln()))129 Ok(Val::Num(n.ln()))
131 })?,130 })?,
132 ("std", "trace") => parse_args!(context, "std.trace", args, 2, [131 "trace" => parse_args!(context, "std.trace", args, 2, [
133 0, str: [Val::Str]!!Val::Str, vec![ValType::Str];132 0, str: [Val::Str]!!Val::Str, vec![ValType::Str];
134 1, rest, vec![];133 1, rest, vec![];
135 ], {134 ], {
143 eprintln!(" {}", str);142 eprintln!(" {}", str);
144 Ok(rest)143 Ok(rest)
145 })?,144 })?,
146 ("std", "pow") => parse_args!(context, "std.modulo", args, 2, [145 "pow" => parse_args!(context, "std.modulo", args, 2, [
147 0, x: [Val::Num]!!Val::Num, vec![ValType::Num];146 0, x: [Val::Num]!!Val::Num, vec![ValType::Num];
148 1, n: [Val::Num]!!Val::Num, vec![ValType::Num];147 1, n: [Val::Num]!!Val::Num, vec![ValType::Num];
149 ], {148 ], {
150 Ok(Val::Num(x.powf(n)))149 Ok(Val::Num(x.powf(n)))
151 })?,150 })?,
152 ("std", "extVar") => parse_args!(context, "std.extVar", args, 1, [151 "extVar" => parse_args!(context, "std.extVar", args, 1, [
153 0, x: [Val::Str]!!Val::Str, vec![ValType::Str];152 0, x: [Val::Str]!!Val::Str, vec![ValType::Str];
154 ], {153 ], {
155 Ok(with_state(|s| s.settings().ext_vars.get(&x).cloned()).ok_or_else(154 Ok(with_state(|s| s.settings().ext_vars.get(&x).cloned()).ok_or_else(
156 || UndefinedExternalVariable(x),155 || UndefinedExternalVariable(x),
157 )?)156 )?)
158 })?,157 })?,
159 ("std", "native") => parse_args!(context, "std.native", args, 1, [158 "native" => parse_args!(context, "std.native", args, 1, [
160 0, x: [Val::Str]!!Val::Str, vec![ValType::Str];159 0, x: [Val::Str]!!Val::Str, vec![ValType::Str];
161 ], {160 ], {
162 Ok(with_state(|s| s.settings().ext_natives.get(&x).cloned()).map(|v| Val::Func(Rc::new(FuncVal::NativeExt(x.clone(), v)))).ok_or_else(161 Ok(with_state(|s| s.settings().ext_natives.get(&x).cloned()).map(|v| Val::Func(Rc::new(FuncVal::NativeExt(x.clone(), v)))).ok_or_else(
163 || UndefinedExternalFunction(x),162 || UndefinedExternalFunction(x),
164 )?)163 )?)
165 })?,164 })?,
166 ("std", "filter") => parse_args!(context, "std.filter", args, 2, [165 "filter" => parse_args!(context, "std.filter", args, 2, [
167 0, func: [Val::Func]!!Val::Func, vec![ValType::Func];166 0, func: [Val::Func]!!Val::Func, vec![ValType::Func];
168 1, arr: [Val::Arr]!!Val::Arr, vec![ValType::Arr];167 1, arr: [Val::Arr]!!Val::Arr, vec![ValType::Arr];
169 ], {168 ], {
181 )))180 )))
182 })?,181 })?,
183 // faster182 // faster
184 ("std", "foldl") => parse_args!(context, "std.foldl", args, 3, [183 "foldl" => parse_args!(context, "std.foldl", args, 3, [
185 0, func: [Val::Func]!!Val::Func, vec![ValType::Func];184 0, func: [Val::Func]!!Val::Func, vec![ValType::Func];
186 1, arr: [Val::Arr]!!Val::Arr, vec![ValType::Arr];185 1, arr: [Val::Arr]!!Val::Arr, vec![ValType::Arr];
187 2, init, vec![];186 2, init, vec![];
193 Ok(acc)192 Ok(acc)
194 })?,193 })?,
195 // faster194 // faster
196 ("std", "foldr") => parse_args!(context, "std.foldr", args, 3, [195 "foldr" => parse_args!(context, "std.foldr", args, 3, [
197 0, func: [Val::Func]!!Val::Func, vec![ValType::Func];196 0, func: [Val::Func]!!Val::Func, vec![ValType::Func];
198 1, arr: [Val::Arr]!!Val::Arr, vec![ValType::Arr];197 1, arr: [Val::Arr]!!Val::Arr, vec![ValType::Arr];
199 2, init, vec![];198 2, init, vec![];
206 })?,205 })?,
207 // faster206 // faster
208 #[allow(non_snake_case)]207 #[allow(non_snake_case)]
209 ("std", "sortImpl") => parse_args!(context, "std.sort", args, 2, [208 "sortImpl" => parse_args!(context, "std.sort", args, 2, [
210 0, arr: [Val::Arr]!!Val::Arr, vec![ValType::Arr];209 0, arr: [Val::Arr]!!Val::Arr, vec![ValType::Arr];
211 1, keyF: [Val::Func]!!Val::Func, vec![ValType::Func];210 1, keyF: [Val::Func]!!Val::Func, vec![ValType::Func];
212 ], {211 ], {
216 Ok(Val::Arr(sort::sort(context, arr, &keyF)?))215 Ok(Val::Arr(sort::sort(context, arr, &keyF)?))
217 })?,216 })?,
218 // faster217 // faster
219 ("std", "format") => parse_args!(context, "std.format", args, 2, [218 "format" => parse_args!(context, "std.format", args, 2, [
220 0, str: [Val::Str]!!Val::Str, vec![ValType::Str];219 0, str: [Val::Str]!!Val::Str, vec![ValType::Str];
221 1, vals, vec![]220 1, vals, vec![]
222 ], {221 ], {
229 })228 })
230 })?,229 })?,
231 // faster230 // faster
232 ("std", "range") => parse_args!(context, "std.range", args, 2, [231 "range" => parse_args!(context, "std.range", args, 2, [
233 0, from: [Val::Num]!!Val::Num, vec![ValType::Num];232 0, from: [Val::Num]!!Val::Num, vec![ValType::Num];
234 1, to: [Val::Num]!!Val::Num, vec![ValType::Num];233 1, to: [Val::Num]!!Val::Num, vec![ValType::Num];
235 ], {234 ], {
239 }238 }
240 Ok(Val::Arr(Rc::new(out)))239 Ok(Val::Arr(Rc::new(out)))
241 })?,240 })?,
242 ("std", "char") => parse_args!(context, "std.char", args, 1, [241 "char" => parse_args!(context, "std.char", args, 1, [
243 0, n: [Val::Num]!!Val::Num, vec![ValType::Num];242 0, n: [Val::Num]!!Val::Num, vec![ValType::Num];
244 ], {243 ], {
245 let mut out = String::new();244 let mut out = String::new();
248 )?);247 )?);
249 Ok(Val::Str(out.into()))248 Ok(Val::Str(out.into()))
250 })?,249 })?,
251 ("std", "encodeUTF8") => parse_args!(context, "std.encodeUtf8", args, 1, [250 "encodeUTF8" => parse_args!(context, "std.encodeUtf8", args, 1, [
252 0, str: [Val::Str]!!Val::Str, vec![ValType::Str];251 0, str: [Val::Str]!!Val::Str, vec![ValType::Str];
253 ], {252 ], {
254 Ok(Val::Arr(Rc::new(str.bytes().map(|b| Val::Num(b as f64)).collect())))253 Ok(Val::Arr(Rc::new(str.bytes().map(|b| Val::Num(b as f64)).collect())))
255 })?,254 })?,
256 ("std", "md5") => parse_args!(context, "std.md5", args, 1, [255 "md5" => parse_args!(context, "std.md5", args, 1, [
257 0, str: [Val::Str]!!Val::Str, vec![ValType::Str];256 0, str: [Val::Str]!!Val::Str, vec![ValType::Str];
258 ], {257 ], {
259 Ok(Val::Str(format!("{:x}", md5::compute(&str.as_bytes())).into()))258 Ok(Val::Str(format!("{:x}", md5::compute(&str.as_bytes())).into()))
260 })?,259 })?,
261 // faster260 // faster
262 ("std", "base64") => parse_args!(context, "std.base64", args, 1, [261 "base64" => parse_args!(context, "std.base64", args, 1, [
263 0, input: [Val::Str | Val::Arr], vec![ValType::Arr, ValType::Str];262 0, input: [Val::Str | Val::Arr], vec![ValType::Arr, ValType::Str];
264 ], {263 ], {
265 Ok(Val::Str(match input {264 Ok(Val::Str(match input {
275 }))274 }))
276 })?,275 })?,
277 // faster276 // faster
278 ("std", "join") => parse_args!(context, "std.join", args, 2, [277 "join" => parse_args!(context, "std.join", args, 2, [
279 0, sep: [Val::Str|Val::Arr], vec![ValType::Str, ValType::Arr];278 0, sep: [Val::Str|Val::Arr], vec![ValType::Str, ValType::Arr];
280 1, arr: [Val::Arr]!!Val::Arr, vec![ValType::Arr];279 1, arr: [Val::Arr]!!Val::Arr, vec![ValType::Arr];
281 ], {280 ], {
322 })321 })
323 })?,322 })?,
324 // Faster323 // Faster
325 ("std", "escapeStringJson") => parse_args!(context, "std.escapeStringJson", args, 1, [324 "escapeStringJson" => parse_args!(context, "std.escapeStringJson", args, 1, [
326 0, str_: [Val::Str]!!Val::Str, vec![ValType::Str];325 0, str_: [Val::Str]!!Val::Str, vec![ValType::Str];
327 ], {326 ], {
328 Ok(Val::Str(escape_string_json(&str_).into()))327 Ok(Val::Str(escape_string_json(&str_).into()))
329 })?,328 })?,
330 // Faster329 // Faster
331 ("std", "manifestJsonEx") => parse_args!(context, "std.manifestJsonEx", args, 2, [330 "manifestJsonEx" => parse_args!(context, "std.manifestJsonEx", args, 2, [
332 0, value, vec![];331 0, value, vec![];
333 1, indent: [Val::Str]!!Val::Str, vec![ValType::Str];332 1, indent: [Val::Str]!!Val::Str, vec![ValType::Str];
334 ], {333 ], {
338 })?.into()))337 })?.into()))
339 })?,338 })?,
340 // Faster339 // Faster
341 ("std", "reverse") => parse_args!(context, "std.reverse", args, 1, [340 "reverse" => parse_args!(context, "std.reverse", args, 1, [
342 0, arr: [Val::Arr]!!Val::Arr, vec![ValType::Arr];341 0, arr: [Val::Arr]!!Val::Arr, vec![ValType::Arr];
343 ], {342 ], {
344 let mut marr = arr;343 let mut marr = arr;
345 Rc::make_mut(&mut marr).reverse();344 Rc::make_mut(&mut marr).reverse();
346 Ok(Val::Arr(marr))345 Ok(Val::Arr(marr))
347 })?,346 })?,
348 ("std", "id") => parse_args!(context, "std.id", args, 1, [347 "id" => parse_args!(context, "std.id", args, 1, [
349 0, v, vec![];348 0, v, vec![];
350 ], {349 ], {
351 Ok(v)350 Ok(v)
352 })?,351 })?,
353 (ns, name) => throw!(IntrinsicNotFound(ns.into(), name.into())),352 name => throw!(IntrinsicNotFound(name.into())),
354 })353 })
355}354}
356355
modifiedcrates/jrsonnet-evaluator/src/error.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/error.rs
+++ b/crates/jrsonnet-evaluator/src/error.rs
@@ -8,8 +8,8 @@
 
 #[derive(Error, Debug, Clone)]
 pub enum Error {
-	#[error("intrinsic not found: {0}.{1}")]
-	IntrinsicNotFound(Rc<str>, Rc<str>),
+	#[error("intrinsic not found: {0}")]
+	IntrinsicNotFound(Rc<str>),
 	#[error("argument reordering in intrisics not supported yet")]
 	IntrinsicArgumentReorderingIsNotSupportedYet,
 
modifiedcrates/jrsonnet-evaluator/src/evaluate.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/evaluate.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate.rs
@@ -466,10 +466,8 @@
 						|| {
 							if let Some(v) = v.get(s.clone())? {
 								Ok(v.unwrap_if_lazy()?)
-							} else if let Some(Val::Str(n)) =
-								v.get("__intrinsic_namespace__".into())?
-							{
-								Ok(Val::Func(Rc::new(FuncVal::Intrinsic(n, s))))
+							} else if v.get("__intrinsic_namespace__".into())?.is_some() {
+								Ok(Val::Func(Rc::new(FuncVal::Intrinsic(s))))
 							} else {
 								throw!(NoSuchField(s))
 							}
@@ -558,6 +556,7 @@
 		Function(params, body) => {
 			evaluate_method(context, "anonymous".into(), params.clone(), body.clone())
 		}
+		Intrinsic(name) => Val::Func(Rc::new(FuncVal::Intrinsic(name.clone()))),
 		AssertExpr(AssertStmt(value, msg), returned) => {
 			let assertion_result = push(
 				&value.1,
modifiedcrates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/lib.rs
+++ b/crates/jrsonnet-evaluator/src/lib.rs
@@ -893,4 +893,12 @@
 		)?;
 		Ok(())
 	}
+
+	#[test]
+	fn constant_intrinsic() -> crate::error::Result<()> {
+		assert_eval!(
+			"local std2 = std; local std = std2 { primitiveEquals(a, b):: false }; 1 == 1"
+		);
+		Ok(())
+	}
 }
modifiedcrates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/val.rs
+++ b/crates/jrsonnet-evaluator/src/val.rs
@@ -76,7 +76,7 @@
 	/// Plain function implemented in jsonnet
 	Normal(FuncDesc),
 	/// Standard library function
-	Intrinsic(Rc<str>, Rc<str>),
+	Intrinsic(Rc<str>),
 	/// Library functions implemented in native
 	NativeExt(Rc<str>, Rc<NativeCallback>),
 }
@@ -85,7 +85,7 @@
 	fn eq(&self, other: &Self) -> bool {
 		match (self, other) {
 			(Self::Normal(a), Self::Normal(b)) => a == b,
-			(Self::Intrinsic(ans, an), Self::Intrinsic(bns, bn)) => ans == bns && an == bn,
+			(Self::Intrinsic(an), Self::Intrinsic(bn)) => an == bn,
 			(Self::NativeExt(an, _), Self::NativeExt(bn, _)) => an == bn,
 			(..) => false,
 		}
@@ -93,12 +93,12 @@
 }
 impl FuncVal {
 	pub fn is_ident(&self) -> bool {
-		matches!(&self, Self::Intrinsic(ns, n) if ns as &str == "std" && n as &str == "id")
+		matches!(&self, Self::Intrinsic(n) if n as &str == "id")
 	}
 	pub fn name(&self) -> Rc<str> {
 		match self {
 			Self::Normal(normal) => normal.name.clone(),
-			Self::Intrinsic(ns, name) => format!("intrinsic.{}.{}", ns, name).into(),
+			Self::Intrinsic(name) => format!("std.{}", name).into(),
 			Self::NativeExt(n, _) => format!("native.{}", n).into(),
 		}
 	}
@@ -120,7 +120,7 @@
 				)?;
 				evaluate(ctx, &func.body)
 			}
-			Self::Intrinsic(ns, name) => call_builtin(call_ctx, loc, ns, name, args),
+			Self::Intrinsic(name) => call_builtin(call_ctx, loc, name, args),
 			Self::NativeExt(_name, handler) => {
 				let args = parse_function_call(call_ctx, None, &handler.params, args, true)?;
 				let mut out_args = Vec::with_capacity(handler.params.len());
@@ -149,7 +149,7 @@
 				)?;
 				evaluate(ctx, &func.body)
 			}
-			Self::Intrinsic(_, _) => todo!(),
+			Self::Intrinsic(_) => todo!(),
 			Self::NativeExt(_, _) => todo!(),
 		}
 	}
@@ -160,7 +160,7 @@
 				let ctx = place_args(call_ctx, Some(func.ctx.clone()), &func.params, args)?;
 				evaluate(ctx, &func.body)
 			}
-			Self::Intrinsic(_, _) => todo!(),
+			Self::Intrinsic(_) => todo!(),
 			Self::NativeExt(_, _) => todo!(),
 		}
 	}
modifiedcrates/jrsonnet-parser/src/expr.rsdiffbeforeafterboth
--- a/crates/jrsonnet-parser/src/expr.rs
+++ b/crates/jrsonnet-parser/src/expr.rs
@@ -311,6 +311,8 @@
 	Index(LocExpr, LocExpr),
 	/// function(x) x
 	Function(ParamsDesc, LocExpr),
+	/// std.primitiveEquals
+	Intrinsic(Rc<str>),
 	/// if true == false then 1 else 2
 	IfElse {
 		cond: IfSpecData,
modifiedcrates/jrsonnet-parser/src/lib.rsdiffbeforeafterboth
--- a/crates/jrsonnet-parser/src/lib.rs
+++ b/crates/jrsonnet-parser/src/lib.rs
@@ -221,18 +221,12 @@
 				a:(@) _ "&" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::BitAnd, b))}
 				--
 				a:(@) _ "==" _ b:@ {loc_expr_todo!(Expr::Apply(
-					el!(Expr::Index(
-						el!(Expr::Var("std".into())),
-						el!(Expr::Str("equals".into()))
-					)),
+					el!(Expr::Intrinsic("equals".into())),
 					ArgsDesc(vec![Arg(None, a), Arg(None, b)]),
 					true
 				))}
 				a:(@) _ "!=" _ b:@ {loc_expr_todo!(Expr::UnaryOp(UnaryOpType::Not, el!(Expr::Apply(
-					el!(Expr::Index(
-						el!(Expr::Var("std".into())),
-						el!(Expr::Str("equals".into()))
-					)),
+					el!(Expr::Intrinsic("equals".into())),
 					ArgsDesc(vec![Arg(None, a), Arg(None, b)]),
 					true
 				))))}
@@ -242,10 +236,7 @@
 				a:(@) _ "<=" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Lte, b))}
 				a:(@) _ ">=" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Gte, b))}
 				a:(@) _ keyword("in") _ b:@ {loc_expr_todo!(Expr::Apply(
-					el!(Expr::Index(
-						el!(Expr::Var("std".into())),
-						el!(Expr::Str("objectHasEx".into()))
-					)), ArgsDesc(vec![Arg(None, b), Arg(None, a), Arg(None, el!(Expr::Literal(LiteralType::True)))]),
+					el!(Expr::Intrinsic("objectHasEx".into())), ArgsDesc(vec![Arg(None, b), Arg(None, a), Arg(None, el!(Expr::Literal(LiteralType::True)))]),
 					true
 				))}
 				--
@@ -258,10 +249,7 @@
 				a:(@) _ "*" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Mul, b))}
 				a:(@) _ "/" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Div, b))}
 				a:(@) _ "%" _ b:@ {loc_expr_todo!(Expr::Apply(
-					el!(Expr::Index(
-						el!(Expr::Var("std".into())),
-						el!(Expr::Str("mod".into()))
-					)), ArgsDesc(vec![Arg(None, a), Arg(None, b)]),
+					el!(Expr::Intrinsic("mod".into())), ArgsDesc(vec![Arg(None, a), Arg(None, b)]),
 					false
 				))}
 				--
@@ -270,10 +258,7 @@
 						"~" _ b:@ { loc_expr_todo!(Expr::UnaryOp(UnaryOpType::BitNot, b)) }
 				--
 				a:(@) _ "[" _ s:slice_desc(s) _ "]" {loc_expr_todo!(Expr::Apply(
-					el!(Expr::Index(
-						el!(Expr::Var("std".into())),
-						el!(Expr::Str("slice".into())),
-					)),
+					el!(Expr::Intrinsic("slice".into())),
 					ArgsDesc(vec![
 						Arg(None, a),
 						Arg(None, s.start.unwrap_or_else(||el!(Expr::Literal(LiteralType::Null)))),