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

difftreelog

fix(evaluator) missing intrinsics for slice, mod

Yaroslav Bolyukin2021-01-06parent: #7c1d01a.patch.diff
in: master
Fixes #30

3 files changed

modifiedcrates/jrsonnet-evaluator/build.rsdiffbeforeafterboth
after · crates/jrsonnet-evaluator/build.rs
1use bincode::serialize;2use jrsonnet_parser::{3	parse, Expr, FieldMember, FieldName, LocExpr, Member, ObjBody, ParserSettings,4};5use jrsonnet_stdlib::STDLIB_STR;6use std::{7	env,8	fs::File,9	io::Write,10	path::{Path, PathBuf},11	rc::Rc,12};13use structdump::CodegenResult;1415fn main() {16	let parsed = parse(17		STDLIB_STR,18		&ParserSettings {19			file_name: Rc::new(PathBuf::from("std.jsonnet")),20			loc_data: true,21		},22	)23	.expect("parse");2425	let parsed = if cfg!(feature = "faster") {26		let LocExpr(expr, location) = parsed;27		LocExpr(28			Rc::new(match Rc::try_unwrap(expr).unwrap() {29				Expr::Obj(ObjBody::MemberList(members)) => Expr::Obj(ObjBody::MemberList(30					members31						.into_iter()32						.filter(|p| {33							!matches!(34								p,35								Member::Field(FieldMember {36									name: FieldName::Fixed(name),37									..38								})39								if **name == *"join" || **name == *"manifestJsonEx" ||40								**name == *"escapeStringJson" || **name == *"equals" ||41								**name == *"base64" || **name == *"foldl" || **name == *"foldr" ||42								**name == *"sortImpl" || **name == *"format" || **name == *"range" ||43								**name == *"reverse" || **name == *"slice" || **name == *"mod"44							)45						})46						.collect(),47				)),48				_ => panic!("std value should be object"),49			}),50			location,51		)52	} else {53		parsed54	};55	{56		let mut codegen = CodegenResult::default();57		let code = codegen.codegen(&parsed);5859		let out_dir = env::var("OUT_DIR").unwrap();60		let dest_path = Path::new(&out_dir).join("stdlib.rs");61		let mut f = File::create(&dest_path).unwrap();62		f.write_all(&code.as_bytes()).unwrap();63	}64	{65		let out_dir = env::var("OUT_DIR").unwrap();66		let dest_path = Path::new(&out_dir).join("stdlib.bincode");67		let mut f = File::create(&dest_path).unwrap();68		f.write_all(&serialize(&parsed).unwrap()).unwrap();69	}70}
modifiedcrates/jrsonnet-evaluator/src/builtin/mod.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/builtin/mod.rs
+++ b/crates/jrsonnet-evaluator/src/builtin/mod.rs
@@ -16,6 +16,20 @@
 pub mod manifest;
 pub mod sort;
 
+fn std_format(str: Rc<str>, vals: Val) -> Result<Val> {
+	push(
+		&Some(ExprLocation(Rc::from(PathBuf::from("std.jsonnet")), 0, 0)),
+		|| format!("std.format of {}", str),
+		|| {
+			Ok(match vals {
+				Val::Arr(vals) => Val::Str(format_arr(&str, &vals)?.into()),
+				Val::Obj(obj) => Val::Str(format_obj(&str, &obj)?.into()),
+				o => Val::Str(format_arr(&str, &[o])?.into()),
+			})
+		},
+	)
+}
+
 #[allow(clippy::cognitive_complexity)]
 pub fn call_builtin(
 	context: Context,
@@ -99,6 +113,43 @@
 					.any(|(k, _v)| *k == *f),
 			))
 		})?,
+
+		// faster
+		"slice" => parse_args!(context, "slice", args, 4, [
+			0, indexable: [Val::Str | Val::Arr], vec![ValType::Str, ValType::Arr];
+			1, index, vec![ValType::Num, ValType::Null];
+			2, end, vec![ValType::Num, ValType::Null];
+			3, step, vec![ValType::Num, ValType::Null];
+		], {
+			let index = match index {
+				Val::Num(v) => v as usize,
+				Val::Null => 0,
+				_ => unreachable!(),
+			};
+			let end = match end {
+				Val::Num(v) => v as usize,
+				Val::Null => match &indexable {
+					Val::Str(s) => s.chars().count(),
+					Val::Arr(v) => v.len(),
+					_ => unreachable!()
+				},
+				_ => unreachable!()
+			};
+			let step = match step {
+				Val::Num(v) => v as usize,
+				Val::Null => 1,
+				_ => unreachable!()
+			};
+			match &indexable {
+				Val::Str(s) => {
+					Ok(Val::Str((s.chars().skip(index).take(end-index).step_by(step).collect::<String>()).into()))
+				}
+				Val::Arr(arr) => {
+					Ok(Val::Arr((arr.iter().skip(index).take(end-index).step_by(step).cloned().collect::<Vec<Val>>()).into()))
+				}
+				_ => unreachable!()
+			}
+		})?,
 		"primitiveEquals" => parse_args!(context, "std.primitiveEquals", args, 2, [
 			0, a, vec![];
 			1, b, vec![];
@@ -112,6 +163,16 @@
 		], {
 			Ok(Val::Bool(equals(&a, &b)?))
 		})?,
+		"mod" => parse_args!(context, "std.mod", args, 2, [
+			0, a: [Val::Num | Val::Str], vec![ValType::Num, ValType::Str];
+			1, b, vec![];
+		], {
+			match (a, b) {
+				(Val::Num(a), Val::Num(b)) => Ok(Val::Num(a % b)),
+				(Val::Str(str), vals) => std_format(str, vals),
+				(a, b) => throw!(BinaryOperatorDoesNotOperateOnValues(jrsonnet_parser::BinaryOpType::Mod, a.value_type()?, b.value_type()?))
+			}
+		})?,
 		"modulo" => parse_args!(context, "std.modulo", args, 2, [
 			0, a: [Val::Num]!!Val::Num, vec![ValType::Num];
 			1, b: [Val::Num]!!Val::Num, vec![ValType::Num];
@@ -219,13 +280,7 @@
 			0, str: [Val::Str]!!Val::Str, vec![ValType::Str];
 			1, vals, vec![]
 		], {
-			push(&Some(ExprLocation(Rc::from(PathBuf::from("std.jsonnet")), 0, 0)), ||format!("std.format of {}", str), ||{
-				Ok(match vals {
-					Val::Arr(vals) => Val::Str(format_arr(&str, &vals)?.into()),
-					Val::Obj(obj) => Val::Str(format_obj(&str, &obj)?.into()),
-					o => Val::Str(format_arr(&str, &[o])?.into()),
-				})
-			})
+			std_format(str, vals)
 		})?,
 		// faster
 		"range" => parse_args!(context, "std.range", args, 2, [
modifiedcrates/jrsonnet-parser/src/expr.rsdiffbeforeafterboth
--- a/crates/jrsonnet-parser/src/expr.rs
+++ b/crates/jrsonnet-parser/src/expr.rs
@@ -97,6 +97,8 @@
 	Mul,
 	Div,
 
+	Mod,
+
 	Add,
 	Sub,
 
@@ -124,6 +126,7 @@
 			match self {
 				Mul => "*",
 				Div => "/",
+				Mod => "%",
 				Add => "+",
 				Sub => "-",
 				Lhs => "<<",