git.delta.rocks / jrsonnet / refs/commits / 9b267d56d788

difftreelog

feat(evaluator) create evaluator crate BREAKING CHANGE: rename Expr internals to not match Expr variants

Лач2020-05-16parent: #31dfb91.patch.diff
in: master

6 files changed

modifiedCargo.lockdiffbeforeafterboth
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,6 +1,13 @@
 # This file is automatically @generated by Cargo.
 # It is not intended for manual editing.
 [[package]]
+name = "jsonnet-evaluator"
+version = "0.1.0"
+dependencies = [
+ "jsonnet-parser",
+]
+
+[[package]]
 name = "jsonnet-parser"
 version = "0.1.0"
 dependencies = [
modifiedCargo.tomldiffbeforeafterboth
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,2 +1,5 @@
 [workspace]
-members = ["crates/jsonnet-parser"]
+members = [
+	"crates/jsonnet-parser",
+	"crates/jsonnet-evaluator",
+]
addedcrates/jsonnet-evaluator/Cargo.tomldiffbeforeafterboth
--- /dev/null
+++ b/crates/jsonnet-evaluator/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "jsonnet-evaluator"
+version = "0.1.0"
+authors = ["Лач <iam@lach.pw>"]
+edition = "2018"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+jsonnet-parser = { path = "../jsonnet-parser" }
addedcrates/jsonnet-evaluator/src/lib.rsdiffbeforeafterboth
--- /dev/null
+++ b/crates/jsonnet-evaluator/src/lib.rs
@@ -0,0 +1,59 @@
+#![feature(box_syntax, box_patterns)]
+
+use jsonnet_parser::*;
+
+#[derive(Debug, Clone, PartialEq)]
+pub enum Val {
+	Str(String),
+	Num(f64),
+}
+
+pub fn evaluate(expr: &Expr) -> Val {
+	use Expr::*;
+	match expr {
+		Parened(e) => evaluate(e),
+		Str(v) => Val::Str(v.clone()),
+		Num(v) => Val::Num(*v),
+		BinaryOp(v1, o, v2) => match (evaluate(v1), o, evaluate(v2)) {
+			(Val::Str(v1), BinaryOpType::Add, Val::Str(v2)) => Val::Str(v1 + &v2),
+			(Val::Str(v1), BinaryOpType::Mul, Val::Num(v2)) => {
+				Val::Str(v1.repeat(v2 as usize))
+			},
+			(Val::Num(v1), BinaryOpType::Add, Val::Num(v2)) => Val::Num(v1 + v2),
+			(Val::Num(v1), BinaryOpType::Mul, Val::Num(v2)) => Val::Num(v1 * v2),
+			_ => panic!("Can't evaluate binary op: {:?} {:?} {:?}", v1, o, v2),
+		},
+		_ => panic!("Can't evaluate: {:?}", expr),
+	}
+}
+
+#[cfg(test)]
+pub mod tests {
+	use super::{evaluate, Val};
+	use jsonnet_parser::parse;
+	#[test]
+	fn math_evaluation() {
+		assert_eq!(evaluate(&parse("2+2*2").unwrap()), Val::Num(6.0));
+	}
+
+	#[test]
+	fn math_evaluation_with_parened() {
+		assert_eq!(evaluate(&parse("3+(2+2*2)").unwrap()), Val::Num(9.0));
+	}
+
+	#[test]
+	fn string_concat() {
+		assert_eq!(
+			evaluate(&parse("\"Hello\"+\"World\"").unwrap()),
+			Val::Str("HelloWorld".to_owned()),
+		);
+	}
+
+	#[test]
+	fn string_repeat() {
+		assert_eq!(
+			evaluate(&parse("\"Hello\"*3").unwrap()),
+			Val::Str("HelloHelloHello".to_owned()),
+		);
+	}
+}
modifiedcrates/jsonnet-parser/src/expr.rsdiffbeforeafterboth
before · crates/jsonnet-parser/src/expr.rs
1#[derive(Debug, Clone, PartialEq)]2pub enum FieldName {3	/// {fixed: 2}4	Fixed(String),5	/// {["dyn"+"amic"]: 3}6	Dyn(Box<Expr>),7}89#[derive(Debug, Clone, PartialEq)]10pub enum Visibility {11	/// :12	Normal,13	/// ::14	Hidden,15	/// :::16	Unhide,17}1819#[derive(Debug, Clone, PartialEq)]20pub struct AssertStmt(pub Box<Expr>, pub Option<Box<Expr>>);2122#[derive(Debug, Clone, PartialEq)]23pub enum FieldMember {24	Value {25		name: FieldName,26		plus: bool,27		visibility: Visibility,28		value: Expr,29	},30	Function {31		name: FieldName,32		params: Params,33		visibility: Visibility,34		value: Expr,35	},36}3738#[derive(Debug, Clone, PartialEq)]39pub enum Member {40	Field(FieldMember),41	BindStmt(Bind),42	AssertStmt(AssertStmt),43}4445#[derive(Debug, Clone, PartialEq)]46pub enum UnaryOp {47	Plus,48	Minus,49	BitNot,50	Not,51}5253#[derive(Debug, Clone, PartialEq)]54pub enum BinaryOp {55	Mul,56	Div,57	Mod,5859	Add,60	Sub,6162	Lhs,63	Rhs,6465	Lt,66	Gt,67	Lte,68	Gte,6970	In,7172	Eq,73	Ne,7475	BitAnd,76	BitOr,77	And,78	Or,7980	BitXor,81}8283#[derive(Debug, Clone, PartialEq)]84pub enum Param {85	Positional(String),86	Named(String, Box<Expr>),87}8889#[derive(Debug, Clone, PartialEq)]90pub struct Params(pub Vec<Param>);9192#[derive(Debug, Clone, PartialEq)]93pub enum Arg {94	Positional(Box<Expr>),95	Named(String, Box<Expr>),96}9798#[derive(Debug, Clone, PartialEq)]99pub struct Args(pub Vec<Arg>);100101#[derive(Debug, Clone, PartialEq)]102pub enum Bind {103	Value(String, Box<Expr>),104	Function(String, Params, Box<Expr>),105}106107#[derive(Debug, Clone, PartialEq)]108pub struct IfSpec(pub Box<Expr>);109#[derive(Debug, Clone, PartialEq)]110pub struct ForSpec(pub String, pub Vec<IfSpec>);111112#[derive(Debug, Clone, PartialEq)]113pub enum CompSpec {114	IfSpec(IfSpec),115	ForSpec(ForSpec),116}117118#[derive(Debug, Clone, PartialEq)]119pub enum ObjBody {120	MemberList(Vec<Member>),121	ObjComp {122		pre_locals: Vec<Bind>,123		key: Box<Expr>,124		value: Box<Expr>,125		post_locals: Vec<Bind>,126		first: ForSpec,127		rest: Vec<CompSpec>,128	},129}130131#[derive(Debug, Clone, PartialEq)]132pub enum Literal {133	Null,134	True,135	False,136	This,137	Super,138	Dollar,139}140141/// Syntax base142#[derive(Debug, Clone, PartialEq)]143pub enum Expr {144	/// Plain value: null/true/false145	Literal(Literal),146147	/// String value: "hello"148	Str(String),149	/// Number: 1, 2.0, 2e+20150	Num(f64),151	/// Variable name: test152	Var(String),153154	/// Array of expressions: [1, 2, "Hello"]155	Arr(Vec<Expr>),156	/// Array comprehension:157	/// ```jsonnet158	///  ingredients: [159	///    { kind: kind, qty: 4 / 3 }160	///    for kind in [161	///      'Honey Syrup',162	///      'Lemon Juice',163	///      'Farmers Gin',164	///    ]165	///  ],166	/// ```167	ArrComp(Box<Expr>, Vec<ForSpec>),168169	/// Object: {a: 2}170	Obj(ObjBody),171	/// Object extension: var1 {b: 2}172	ObjExtend(Box<Expr>, ObjBody),173174	/// (obj)175	Parened(Box<Expr>),176177	Params(Params),178	Args(Args),179180	UnaryOp(UnaryOp, Box<Expr>),181	BinaryOp(Box<Expr>, BinaryOp, Box<Expr>),182	AssertExpr(AssertStmt, Box<Expr>),183	LocalExpr(Vec<Bind>, Box<Expr>),184185	Bind(Bind),186	Import(String),187	ImportStr(String),188	Error(Box<Expr>),189	Apply(Box<Expr>, Args),190	Select(Box<Expr>, String),191	Index(Box<Expr>, Box<Expr>),192	Slice {193		value: Box<Expr>,194		start: Option<Box<Expr>>,195		end: Option<Box<Expr>>,196		step: Option<Box<Expr>>,197	},198	Function(Params, Box<Expr>),199	IfElse {200		cond: IfSpec,201		cond_then: Box<Expr>,202		cond_else: Option<Box<Expr>>,203	},204	IfSpec(IfSpec),205	ForSpec(ForSpec),206}
modifiedcrates/jsonnet-parser/src/lib.rsdiffbeforeafterboth
--- a/crates/jsonnet-parser/src/lib.rs
+++ b/crates/jsonnet-parser/src/lib.rs
@@ -1,7 +1,7 @@
 use peg::parser;
 
-pub mod expr;
-use expr::{Expr, Literal};
+mod expr;
+pub use expr::*;
 
 enum Suffix {
 	String(String),
@@ -101,10 +101,11 @@
 			cond_else,
 		}}
 		pub rule expr_basic() -> Expr
-			= "null" {Expr::Literal(Literal::Null)}
-			/ "true" {Expr::Literal(Literal::True)} / "false" {Expr::Literal(Literal::False)}
-			/ "self" {Expr::Literal(Literal::This)} / "$" {Expr::Literal(Literal::Dollar)}
-			/ "super" {Expr::Literal(Literal::Super)}
+			= "null" {Expr::Value(ValueType::Null)}
+			/ "true" {Expr::Value(ValueType::True)} / "false" {Expr::Value(ValueType::False)}
+
+			/ "self" {Expr::Literal(LiteralType::This)} / "$" {Expr::Literal(LiteralType::Dollar)}
+			/ "super" {Expr::Literal(LiteralType::Super)}
 
 			/ string_expr() / number_expr()
 			/ array_expr()
@@ -124,36 +125,36 @@
 
 		rule expr() -> Expr
 			= a:precedence! {
-				a:(@) __() "||" __() b:@ {Expr::BinaryOp(Box::new(a), expr::BinaryOp::Or, Box::new(b))}
+				a:(@) __() "||" __() b:@ {Expr::BinaryOp(Box::new(a), expr::BinaryOpType::Or, Box::new(b))}
 				--
-				a:(@) __() "&&" __() b:@ {Expr::BinaryOp(Box::new(a), expr::BinaryOp::And, Box::new(b))}
+				a:(@) __() "&&" __() b:@ {Expr::BinaryOp(Box::new(a), expr::BinaryOpType::And, Box::new(b))}
 				--
-				a:(@) __() "|" __() b:@ {Expr::BinaryOp(Box::new(a), expr::BinaryOp::BitOr, Box::new(b))}
+				a:(@) __() "|" __() b:@ {Expr::BinaryOp(Box::new(a), expr::BinaryOpType::BitOr, Box::new(b))}
 				--
-				a:@ __() "^" __() b:(@) {Expr::BinaryOp(Box::new(a), expr::BinaryOp::BitXor, Box::new(b))}
+				a:@ __() "^" __() b:(@) {Expr::BinaryOp(Box::new(a), expr::BinaryOpType::BitXor, Box::new(b))}
 				--
-				a:(@) __() "&" __() b:@ {Expr::BinaryOp(Box::new(a), expr::BinaryOp::BitAnd, Box::new(b))}
+				a:(@) __() "&" __() b:@ {Expr::BinaryOp(Box::new(a), expr::BinaryOpType::BitAnd, Box::new(b))}
 				--
-				a:(@) __() "==" __() b:@ {Expr::BinaryOp(Box::new(a), expr::BinaryOp::Eq, Box::new(b))}
-				a:(@) __() "!=" __() b:@ {Expr::BinaryOp(Box::new(a), expr::BinaryOp::Ne, Box::new(b))}
+				a:(@) __() "==" __() b:@ {Expr::BinaryOp(Box::new(a), expr::BinaryOpType::Eq, Box::new(b))}
+				a:(@) __() "!=" __() b:@ {Expr::BinaryOp(Box::new(a), expr::BinaryOpType::Ne, Box::new(b))}
 				--
-				a:(@) __() "<" __() b:@ {Expr::BinaryOp(Box::new(a), expr::BinaryOp::Lt, Box::new(b))}
-				a:(@) __() ">" __() b:@ {Expr::BinaryOp(Box::new(a), expr::BinaryOp::Gt, Box::new(b))}
-				a:(@) __() "<=" __() b:@ {Expr::BinaryOp(Box::new(a), expr::BinaryOp::Lte, Box::new(b))}
-				a:(@) __() ">=" __() b:@ {Expr::BinaryOp(Box::new(a), expr::BinaryOp::Gte, Box::new(b))}
+				a:(@) __() "<" __() b:@ {Expr::BinaryOp(Box::new(a), expr::BinaryOpType::Lt, Box::new(b))}
+				a:(@) __() ">" __() b:@ {Expr::BinaryOp(Box::new(a), expr::BinaryOpType::Gt, Box::new(b))}
+				a:(@) __() "<=" __() b:@ {Expr::BinaryOp(Box::new(a), expr::BinaryOpType::Lte, Box::new(b))}
+				a:(@) __() ">=" __() b:@ {Expr::BinaryOp(Box::new(a), expr::BinaryOpType::Gte, Box::new(b))}
 				--
-				a:(@) __() "<<" __() b:@ {Expr::BinaryOp(Box::new(a), expr::BinaryOp::Lhs, Box::new(b))}
-				a:(@) __() ">>" __() b:@ {Expr::BinaryOp(Box::new(a), expr::BinaryOp::Rhs, Box::new(b))}
+				a:(@) __() "<<" __() b:@ {Expr::BinaryOp(Box::new(a), expr::BinaryOpType::Lhs, Box::new(b))}
+				a:(@) __() ">>" __() b:@ {Expr::BinaryOp(Box::new(a), expr::BinaryOpType::Rhs, Box::new(b))}
 				--
-				a:(@) __() "+" __() b:@ {Expr::BinaryOp(Box::new(a), expr::BinaryOp::Add, Box::new(b))}
-				a:(@) __() "-" __() b:@ {Expr::BinaryOp(Box::new(a), expr::BinaryOp::Sub, Box::new(b))}
+				a:(@) __() "+" __() b:@ {Expr::BinaryOp(Box::new(a), expr::BinaryOpType::Add, Box::new(b))}
+				a:(@) __() "-" __() b:@ {Expr::BinaryOp(Box::new(a), expr::BinaryOpType::Sub, Box::new(b))}
 				--
-				a:(@) __() "*" __() b:@ {Expr::BinaryOp(Box::new(a), expr::BinaryOp::Mul, Box::new(b))}
-				a:(@) __() "/" __() b:@ {Expr::BinaryOp(Box::new(a), expr::BinaryOp::Div, Box::new(b))}
-				a:(@) __() "%" __() b:@ {Expr::BinaryOp(Box::new(a), expr::BinaryOp::Mod, Box::new(b))}
+				a:(@) __() "*" __() b:@ {Expr::BinaryOp(Box::new(a), expr::BinaryOpType::Mul, Box::new(b))}
+				a:(@) __() "/" __() b:@ {Expr::BinaryOp(Box::new(a), expr::BinaryOpType::Div, Box::new(b))}
+				a:(@) __() "%" __() b:@ {Expr::BinaryOp(Box::new(a), expr::BinaryOpType::Mod, Box::new(b))}
 				--
 				e:expr_basic() {e}
-				"(" __() e:expr_basic() __() ")" {Expr::Parened(Box::new(e))}
+				"(" __() e:boxed_expr() __() ")" {Expr::Parened(e)}
 			} suffixes:(__() suffix:expr_suffix() {suffix})* {
 				let mut cur = a;
 				for suffix in suffixes {
@@ -196,10 +197,10 @@
 			parse("2+2*2").unwrap(),
 			Expr::BinaryOp(
 				Box::new(Expr::Num(2.0)),
-				BinaryOp::Add,
+				BinaryOpType::Add,
 				Box::new(Expr::BinaryOp(
 					Box::new(Expr::Num(2.0)),
-					BinaryOp::Mul,
+					BinaryOpType::Mul,
 					Box::new(Expr::Num(2.0))
 				))
 			)