From f9cdd4f3f621ac2bc692207acbc7d2fc9ad67a23 Mon Sep 17 00:00:00 2001 From: Jeremy Wall Date: Tue, 21 Aug 2018 23:05:06 -0500 Subject: [PATCH] BUGFIX: Regression tests for our list operators and bugfixes. --- integration_tests/list_ops_test.ucg | 17 +++++ src/ast/mod.rs | 2 +- src/build/compile_test.rs | 5 ++ src/build/mod.rs | 14 +++- src/parse/mod.rs | 99 ++++++++++------------------- 5 files changed, 68 insertions(+), 69 deletions(-) create mode 100644 integration_tests/list_ops_test.ucg diff --git a/integration_tests/list_ops_test.ucg b/integration_tests/list_ops_test.ucg new file mode 100644 index 0000000..c12ef30 --- /dev/null +++ b/integration_tests/list_ops_test.ucg @@ -0,0 +1,17 @@ +let list1 = [1, 2, 3, 4]; +let list2 = ["foo", "bar", "foo", "bar"]; + +let mapper = macro(item) => { result = item + 1 }; +let filtrator = macro(item) => { + result = select item, NULL, { + foo = item, + }, +}; + +assert |map mapper.result list1 == [2, 3, 4, 5]|; +assert |(map mapper.result [1, 2, 3, 4]) == [2, 3, 4, 5]|; +assert |map mapper.result [1, 2, 3, 4] == [2, 3, 4, 5]|; + +assert |filter filtrator.result list2 == ["foo", "foo"]|; +assert |(filter filtrator.result ["foo", "bar", "foo", "bar"]) == ["foo", "foo"]|; +assert |filter filtrator.result ["foo", "bar", "foo", "bar"] == ["foo", "foo"]|; \ No newline at end of file diff --git a/src/ast/mod.rs b/src/ast/mod.rs index f3c3148..1a1f0ce 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -691,7 +691,7 @@ pub struct ListOpDef { pub typ: ListOpType, pub mac: SelectorDef, pub field: String, - pub target: ListDef, + pub target: Box, pub pos: Position, } diff --git a/src/build/compile_test.rs b/src/build/compile_test.rs index 75dde34..09fa7c3 100644 --- a/src/build/compile_test.rs +++ b/src/build/compile_test.rs @@ -61,3 +61,8 @@ fn test_binary_operator_precedence() { "../../integration_tests/operator_precedence_test.ucg" )); } + +#[test] +fn test_list_operations() { + assert_build(include_str!("../../integration_tests/list_ops_test.ucg")); +} diff --git a/src/build/mod.rs b/src/build/mod.rs index ee15447..467ccba 100644 --- a/src/build/mod.rs +++ b/src/build/mod.rs @@ -1137,12 +1137,22 @@ impl<'a> Builder<'a> { } fn eval_list_op(&self, def: &ListOpDef) -> Result, Box> { - let l = &def.target.elems; + let maybe_list = try!(self.eval_expr(&def.target)); + let l = match maybe_list.as_ref() { + &Val::List(ref elems) => elems, + other => { + return Err(Box::new(error::Error::new( + format!("Expected List as target but got {:?}", other.type_name()), + error::ErrorType::TypeFail, + def.target.pos().clone(), + ))); + } + }; let mac = &def.mac; if let &Val::Macro(ref macdef) = try!(self.lookup_selector(&mac.sel)).as_ref() { let mut out = Vec::new(); for expr in l.iter() { - let argvals = vec![try!(self.eval_expr(expr))]; + let argvals = vec![expr.clone()]; let fields = try!(macdef.eval( self.root.clone(), self.assets.clone(), diff --git a/src/parse/mod.rs b/src/parse/mod.rs index f9c21ab..8e99d39 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -43,7 +43,7 @@ macro_rules! trace_nom { } let result = $rule($i, $($args)* ); if ENABLE_TRACE { - eprintln!("Exiting Rule: {:?}", stringify!($rule)); + eprintln!("Exiting Rule: {:?} with {:?}", stringify!($rule), result); } result } @@ -57,7 +57,7 @@ macro_rules! trace_nom { } let result = call!($i, $rule); if ENABLE_TRACE { - eprintln!("Exiting Rule: {:?}", stringify!($rule)); + eprintln!("Exiting Rule: {:?} with {:?}", stringify!($rule), result); } result } @@ -636,31 +636,7 @@ named!(call_expression, ) ); -fn symbol_or_list(input: TokenIter) -> NomResult { - let sym = do_parse!(input, sym: symbol >> (sym)); - - match sym { - IResult::Incomplete(i) => { - return IResult::Incomplete(i); - } - IResult::Error(_) => match list_value(input) { - IResult::Incomplete(i) => { - return IResult::Incomplete(i); - } - IResult::Error(e) => { - return IResult::Error(e); - } - IResult::Done(i, val) => { - return IResult::Done(i, val); - } - }, - IResult::Done(rest, val) => { - return IResult::Done(rest, val); - } - } -} - -fn tuple_to_list_op(tpl: (Position, Token, Value, Value)) -> ParseResult { +fn tuple_to_list_op(tpl: (Position, Token, Value, Expression)) -> ParseResult { let pos = tpl.0; let t = if &tpl.1.fragment == "map" { ListOpType::Map @@ -683,6 +659,12 @@ fn tuple_to_list_op(tpl: (Position, Token, Value, Value)) -> ParseResult { + if ENABLE_TRACE { + eprintln!( + "tuple_to_list_op had error {}", + "Missing a result field for the macro" + ); + } return Err(error::Error::new( format!("Missing a result field for the macro"), error::ErrorType::IncompleteParsing, @@ -691,6 +673,12 @@ fn tuple_to_list_op(tpl: (Position, Token, Value, Value)) -> ParseResult { if tl.len() < 1 { + if ENABLE_TRACE { + eprintln!( + "tuple_to_list_op had error {}", + "Missing a result field for the macro" + ); + } return Err(error::Error::new( format!("Missing a result field for the macro"), error::ErrorType::IncompleteParsing, @@ -701,20 +689,19 @@ fn tuple_to_list_op(tpl: (Position, Token, Value, Value)) -> ParseResult, pos: pos >> optype: alt!(word!("map") | word!("filter")) >> macroname: trace_nom!(selector_value) >> - list: trace_nom!(symbol_or_list) >> + list: trace_nom!(non_op_expression) >> (pos, optype, macroname, list) ), tuple_to_list_op @@ -785,12 +772,7 @@ named!(let_statement, do_parse!( word!("let") >> pos: pos >> - stmt: add_return_error!( - nom::ErrorKind::Custom( - error::Error::new( - "Invalid syntax for let binding", - error::ErrorType::ParseError, pos)), - trace_nom!(let_stmt_body)) >> + stmt: trace_nom!(let_stmt_body) >> (stmt) ) ); @@ -819,12 +801,7 @@ named!(import_statement, word!("import") >> // past this point we know this is supposed to be an import statement. pos: pos >> - stmt: add_return_error!( - nom::ErrorKind::Custom( - error::Error::new( - "Invalid syntax for import", - error::ErrorType::ParseError, pos)), - trace_nom!(import_stmt_body)) >> + stmt: trace_nom!(import_stmt_body) >> (stmt) ) ); @@ -833,12 +810,7 @@ named!(assert_statement, do_parse!( word!("assert") >> pos: pos >> - tok: add_return_error!( - nom::ErrorKind::Custom( - error::Error::new( - "Invalid syntax for assert", - error::ErrorType::ParseError, pos)), - match_type!(PIPEQUOTE)) >> + tok: match_type!(PIPEQUOTE) >> punct!(";") >> (Statement::Assert(tok.clone())) ) @@ -849,12 +821,7 @@ named!(out_statement, word!("out") >> pos: pos >> typ: match_type!(BAREWORD) >> - expr: add_return_error!( - nom::ErrorKind::Custom( - error::Error::new( - "Invalid syntax for assert", - error::ErrorType::ParseError, pos)), - expression) >> + expr: expression >> punct!(";") >> (Statement::Output(typ.clone(), expr.clone())) )