From 9b267d56d7881bdc98915ff740bf83daac39f15a Mon Sep 17 00:00:00 2001 From: Лач Date: Sat, 16 May 2020 14:13:45 +0000 Subject: [PATCH] feat(evaluator): create evaluator crate BREAKING CHANGE: rename Expr internals to not match Expr variants --- --- 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 = [ --- a/Cargo.toml +++ b/Cargo.toml @@ -1,2 +1,5 @@ [workspace] -members = ["crates/jsonnet-parser"] +members = [ + "crates/jsonnet-parser", + "crates/jsonnet-evaluator", +] --- /dev/null +++ b/crates/jsonnet-evaluator/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "jsonnet-evaluator" +version = "0.1.0" +authors = ["Лач "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +jsonnet-parser = { path = "../jsonnet-parser" } --- /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()), + ); + } +} --- a/crates/jsonnet-parser/src/expr.rs +++ b/crates/jsonnet-parser/src/expr.rs @@ -43,7 +43,7 @@ } #[derive(Debug, Clone, PartialEq)] -pub enum UnaryOp { +pub enum UnaryOpType { Plus, Minus, BitNot, @@ -51,7 +51,7 @@ } #[derive(Debug, Clone, PartialEq)] -pub enum BinaryOp { +pub enum BinaryOpType { Mul, Div, Mod, @@ -129,10 +129,14 @@ } #[derive(Debug, Clone, PartialEq)] -pub enum Literal { +pub enum ValueType { Null, True, False, +} + +#[derive(Debug, Clone, PartialEq)] +pub enum LiteralType { This, Super, Dollar, @@ -141,8 +145,9 @@ /// Syntax base #[derive(Debug, Clone, PartialEq)] pub enum Expr { + Value(ValueType), /// Plain value: null/true/false - Literal(Literal), + Literal(LiteralType), /// String value: "hello" Str(String), @@ -177,8 +182,8 @@ Params(Params), Args(Args), - UnaryOp(UnaryOp, Box), - BinaryOp(Box, BinaryOp, Box), + UnaryOp(UnaryOpType, Box), + BinaryOp(Box, BinaryOpType, Box), AssertExpr(AssertStmt, Box), LocalExpr(Vec, Box), --- 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)) )) ) -- gitstuff