From 160749ae5b1cf8625aa047d55523474d11eb69a7 Mon Sep 17 00:00:00 2001 From: Jeremy Wall Date: Wed, 30 Jan 2019 20:38:17 -0600 Subject: [PATCH] REFACTOR: Remove builtin map and filter. Work in progress. --- .../functional_processing_test.ucg | 111 +++++++++--------- src/ast/mod.rs | 25 +--- src/ast/walk.rs | 16 +-- src/build/mod.rs | 50 +------- src/parse/mod.rs | 45 +------ std/functional.ucg | 13 +- std/schema.ucg | 6 +- 7 files changed, 85 insertions(+), 181 deletions(-) diff --git a/integration_tests/functional_processing_test.ucg b/integration_tests/functional_processing_test.ucg index fef9357..5fbd663 100644 --- a/integration_tests/functional_processing_test.ucg +++ b/integration_tests/functional_processing_test.ucg @@ -1,4 +1,5 @@ // List processing +let map = import "std/functional.ucg".map; let list1 = [1, 2, 3, 4]; let list2 = ["foo", "bar", "foo", "bar"]; @@ -13,8 +14,8 @@ let boolfiltrator = func (item) => item < 5; let identity_list_reducer = func (acc, item) => acc + [item]; assert { - ok = reduce identity_list_reducer, [], list1 == list1, - desc = "reduce identity_list_reducer, [], list1 == list1", + ok = reduce(identity_list_reducer, [], list1) == list1, + desc = "reduce(identity_list_reducer, [], list1) == list1", }; let nested_list = { @@ -22,54 +23,54 @@ let nested_list = { }; assert { - ok = reduce identity_list_reducer, [], (nested_list.list) == list1, - desc = "reduce identity_list_reducer, [], (nested_list.list) == list1", + ok = reduce(identity_list_reducer, [], (nested_list.list)) == list1, + desc = "reduce(identity_list_reducer, [], (nested_list.list)) == list1", }; let list_reducer = func (acc, item) => acc + item; assert { - ok = reduce list_reducer, 0, list1 == 0 + 1 + 2 + 3 + 4, - desc = "reduce list_reducer, 0, list1 == 0 + 1 + 2 + 3 + 4", + ok = reduce(list_reducer, 0, list1) == 0 + 1 + 2 + 3 + 4, + desc = "reduce(list_reducer, 0, list1) == 0 + 1 + 2 + 3 + 4", }; assert { - ok = map mapper, list1 == [2, 3, 4, 5], - desc = "map mapper, list1 == [2, 3, 4, 5]", + ok = map(mapper, list1) == [2, 3, 4, 5], + desc = "map(mapper, list1) == [2, 3, 4, 5]", }; assert { - ok = (map mapper, [1, 2, 3, 4]) == [2, 3, 4, 5], - desc = "(map mapper, [1, 2, 3, 4]) == [2, 3, 4, 5]", + ok = (map(mapper, [1, 2, 3, 4])) == [2, 3, 4, 5], + desc = "(map(mapper, [1, 2, 3, 4])) == [2, 3, 4, 5]", }; assert { - ok = map mapper, [1, 2, 3, 4] == [2, 3, 4, 5], - desc = "map mapper, [1, 2, 3, 4] == [2, 3, 4, 5]", + ok = map(mapper, [1, 2, 3, 4]) == [2, 3, 4, 5], + desc = "map(mapper, [1, 2, 3, 4]) == [2, 3, 4, 5]", }; let s_mapper = func (arg) => arg + ","; assert { - ok = map s_mapper, "foo" == "f,o,o,", + ok = map(s_mapper, "foo") == "f,o,o,", desc = "we can map over each character", }; -assert { - ok = filter filtrator, list2 == ["foo", "foo"], - desc = "filter filtrator, list2 == [\"foo\", \"foo\"]", -}; - -assert { - ok = (filter filtrator, ["foo", "bar", "foo", "bar"]) == ["foo", "foo"], - desc = "(filter filtrator, [\"foo\", \"bar\", \"foo\", \"bar\"]) == [\"foo\", \"foo\"]", -}; -assert { - ok = filter filtrator, ["foo", "bar", "foo", "bar"] == ["foo", "foo"], - desc = "filter filtrator, [\"foo\", \"bar\", \"foo\", \"bar\"] == [\"foo\", \"foo\"]", -}; -assert { - ok = filter boolfiltrator, [1, 2, 3, 4, 5, 6, 7] == [1, 2, 3, 4], - desc = "filter boolfiltrator, [1, 2, 3, 4, 5, 6, 7] == [1, 2, 3, 4]", -}; +//assert { +// ok = filter filtrator, list2 == ["foo", "foo"], +// desc = "filter filtrator, list2 == [\"foo\", \"foo\"]", +//}; +// +//assert { +// ok = (filter filtrator, ["foo", "bar", "foo", "bar"]) == ["foo", "foo"], +// desc = "(filter filtrator, [\"foo\", \"bar\", \"foo\", \"bar\"]) == [\"foo\", \"foo\"]", +//}; +//assert { +// ok = filter filtrator, ["foo", "bar", "foo", "bar"] == ["foo", "foo"], +// desc = "filter filtrator, [\"foo\", \"bar\", \"foo\", \"bar\"] == [\"foo\", \"foo\"]", +//}; +//assert { +// ok = filter boolfiltrator, [1, 2, 3, 4, 5, 6, 7] == [1, 2, 3, 4], +// desc = "filter boolfiltrator, [1, 2, 3, 4, 5, 6, 7] == [1, 2, 3, 4]", +//}; // Tuple processing let test_tpl = { @@ -80,8 +81,8 @@ let test_tpl = { let identity_tpl_mapper = func (name, val) => [name, val]; assert { - ok = map identity_tpl_mapper, test_tpl == test_tpl, - desc = "map identity_tpl_mapper, test_tpl == test_tpl", + ok = map(identity_tpl_mapper, test_tpl) == test_tpl, + desc = "map(identity_tpl_mapper, test_tpl) == test_tpl", }; let tpl_mapper = func (name, val) => select name, [name, val], { @@ -90,8 +91,8 @@ let tpl_mapper = func (name, val) => select name, [name, val], { }; assert { - ok = map tpl_mapper, test_tpl == {foo = "barbar", cute = "pygmy"}, - desc = "map tpl_mapper, test_tpl == {foo = \"barbar\", cute = \"pygmy\"}", + ok = map(tpl_mapper, test_tpl) == {foo = "barbar", cute = "pygmy"}, + desc = "map(tpl_mapper, test_tpl) == {foo = \"barbar\", cute = \"pygmy\"}", }; let identity_tpl_filter = func (name, val) => true; @@ -99,22 +100,22 @@ let identity_tpl_filter = func (name, val) => true; // strip out foo field let tpl_filter = func (name, val) => name != "foo"; -assert { - ok = filter identity_tpl_filter, test_tpl == test_tpl, - desc = "filter identity_tpl_filter, test_tpl == test_tpl", -}; - -assert { - ok = filter tpl_filter, test_tpl == { quux = "baz" }, - desc = "filter tpl_filter, test_tpl == { quux = \"baz\" }", -}; - -let o_str_filter = func (s) => s != "o"; - -assert { - ok = filter o_str_filter, "foobar" == "fbar", - desc = "We can strip out characters", -}; +//assert { +// ok = filter identity_tpl_filter, test_tpl == test_tpl, +// desc = "filter identity_tpl_filter, test_tpl == test_tpl", +//}; +// +//assert { +// ok = filter tpl_filter, test_tpl == { quux = "baz" }, +// desc = "filter tpl_filter, test_tpl == { quux = \"baz\" }", +//}; +// +//let o_str_filter = func (s) => s != "o"; +// +//assert { +// ok = filter o_str_filter, "foobar" == "fbar", +// desc = "We can strip out characters", +//}; let tpl_reducer = func (acc, name, val) => acc{ keys = self.keys + [name], @@ -122,25 +123,25 @@ let tpl_reducer = func (acc, name, val) => acc{ }; assert { - ok = reduce tpl_reducer, {keys = [], vals = []}, test_tpl == {keys = ["foo", "quux"], vals = ["bar", "baz"]}, - desc = "reduce tpl_reducer, {keys = [], vals = []}, test_tpl == {keys = [\"foo\", \"quux\"], vals = [\"bar\", \"baz\"]}", + ok = reduce(tpl_reducer, {keys = [], vals = []}, test_tpl) == {keys = ["foo", "quux"], vals = ["bar", "baz"]}, + desc = "reduce(tpl_reducer, {keys = [], vals = []}, test_tpl) == {keys = [\"foo\", \"quux\"], vals = [\"bar\", \"baz\"]}", }; let str_identity_reducer = func (acc, s) => acc + s; assert { - ok = reduce str_identity_reducer, "", "foo" == "foo", + ok = reduce(str_identity_reducer, "", "foo") == "foo", desc = "identity reducer copies string", }; let char_iter = func (acc, s) => acc + [s]; assert { - ok = reduce char_iter, [], "foo" == ["f", "o", "o"], + ok = reduce(char_iter, [], "foo") == ["f", "o", "o"], desc = "we can split a string into grapheme clusters", }; assert { - ok = reduce (char_iter), [], "foo" == ["f", "o", "o"], + ok = reduce((char_iter), [], "foo") == ["f", "o", "o"], desc = "We can use arbitrary expressions to refer to the macro.", }; \ No newline at end of file diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 061abd3..b1c1fb1 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -489,13 +489,6 @@ pub struct ListDef { pub pos: Position, } -#[derive(Debug, PartialEq, Clone)] -pub enum FuncOpDef { - Reduce(ReduceOpDef), - Map(MapFilterOpDef), - Filter(MapFilterOpDef), -} - #[derive(Debug, PartialEq, Clone)] pub struct ReduceOpDef { pub func: Box, @@ -504,21 +497,9 @@ pub struct ReduceOpDef { pub pos: Position, } -/// MapFilterOpDef implements the list operations in the UCG AST. -#[derive(Debug, PartialEq, Clone)] -pub struct MapFilterOpDef { - pub func: Box, - pub target: Box, - pub pos: Position, -} - -impl FuncOpDef { +impl ReduceOpDef { pub fn pos(&self) -> &Position { - match self { - FuncOpDef::Map(def) => &def.pos, - FuncOpDef::Filter(def) => &def.pos, - FuncOpDef::Reduce(def) => &def.pos, - } + &self.pos } } @@ -635,7 +616,7 @@ pub enum Expression { Call(CallDef), Func(FuncDef), Select(SelectDef), - FuncOp(FuncOpDef), + FuncOp(ReduceOpDef), Module(ModuleDef), // Declarative failure expressions diff --git a/src/ast/walk.rs b/src/ast/walk.rs index 1a00ca2..6bd4a4b 100644 --- a/src/ast/walk.rs +++ b/src/ast/walk.rs @@ -75,18 +75,10 @@ impl<'a> AstWalker<'a> { self.walk_expression(expr); } }, - Expression::FuncOp(ref mut def) => match def { - FuncOpDef::Reduce(ref mut def) => { - self.walk_expression(def.target.as_mut()); - self.walk_expression(def.acc.as_mut()) - } - FuncOpDef::Map(ref mut def) => { - self.walk_expression(def.target.as_mut()); - } - FuncOpDef::Filter(ref mut def) => { - self.walk_expression(def.target.as_mut()); - } - }, + Expression::FuncOp(ref mut def) => { + self.walk_expression(def.target.as_mut()); + self.walk_expression(def.acc.as_mut()); + } Expression::Binary(ref mut def) => { self.walk_expression(def.left.as_mut()); self.walk_expression(def.right.as_mut()); diff --git a/src/build/mod.rs b/src/build/mod.rs index 19e6a22..f38e1bd 100644 --- a/src/build/mod.rs +++ b/src/build/mod.rs @@ -352,7 +352,7 @@ impl<'a> FileBuilder<'a> { fn check_reserved_word(name: &str) -> bool { match name { "self" | "assert" | "true" | "false" | "let" | "import" | "as" | "select" | "func" - | "module" | "env" | "map" | "filter" | "NULL" | "out" | "in" | "is" | "not" => true, + | "module" | "env" | "NULL" | "out" | "in" | "is" | "not" => true, _ => false, } } @@ -1465,40 +1465,6 @@ impl<'a> FileBuilder<'a> { Ok(Rc::new(Val::Str(result))) } - fn eval_functional_processing( - &self, - def: &MapFilterOpDef, - typ: ProcessingOpType, - scope: &Scope, - ) -> Result, Box> { - let maybe_target = self.eval_expr(&def.target, scope)?; - let maybe_mac = self.eval_expr(&def.func, scope)?; - let macdef = match maybe_mac.as_ref() { - &Val::Func(ref macdef) => macdef, - _ => { - return Err(Box::new(error::BuildError::new( - format!("Expected func but got {:?}", def.func), - error::ErrorType::TypeFail, - def.pos.clone(), - ))); - } - }; - return match maybe_target.as_ref() { - &Val::List(ref elems) => self.eval_functional_list_processing(elems, macdef, typ), - &Val::Tuple(ref fs) => self.eval_functional_tuple_processing(fs, macdef, typ), - // TODO(jwall): Strings? - &Val::Str(ref s) => self.eval_functional_string_processing(s, macdef, typ), - other => Err(Box::new(error::BuildError::new( - format!( - "Expected List or Tuple as target but got {:?}", - other.type_name() - ), - error::ErrorType::TypeFail, - def.target.pos().clone(), - ))), - }; - } - fn record_assert_result(&mut self, msg: &str, is_success: bool) { if !is_success { let msg = format!("{} - NOT OK: {}\n", self.assert_collector.counter, msg); @@ -1647,18 +1613,6 @@ impl<'a> FileBuilder<'a> { }; } - fn eval_func_op(&self, def: &FuncOpDef, scope: &Scope) -> Result, Box> { - match def { - FuncOpDef::Filter(ref def) => { - self.eval_functional_processing(def, ProcessingOpType::Filter, scope) - } - FuncOpDef::Map(ref def) => { - self.eval_functional_processing(def, ProcessingOpType::Map, scope) - } - FuncOpDef::Reduce(ref def) => self.eval_reduce_op(def, scope), - } - } - pub fn eval_range(&self, def: &RangeDef, scope: &Scope) -> Result, Box> { let start = self.eval_expr(&def.start, scope)?; let start = match start.as_ref() { @@ -1776,7 +1730,7 @@ impl<'a> FileBuilder<'a> { self.eval_module_def(&mut def_clone, scope) } &Expression::Select(ref def) => self.eval_select(def, scope), - &Expression::FuncOp(ref def) => self.eval_func_op(def, scope), + &Expression::FuncOp(ref def) => self.eval_reduce_op(def, scope), &Expression::Include(ref def) => self.eval_include(def), &Expression::Import(ref def) => self.eval_import(def), &Expression::Fail(ref def) => { diff --git a/src/parse/mod.rs b/src/parse/mod.rs index 82e8576..0332d36 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -574,57 +574,22 @@ make_fn!( do_each!( pos => pos, _ => word!("reduce"), + _ => must!(punct!("(")), func => must!(expression), _ => must!(punct!(",")), acc => must!(trace_parse!(non_op_expression)), _ => must!(punct!(",")), tgt => must!(trace_parse!(non_op_expression)), - (Expression::FuncOp(FuncOpDef::Reduce(ReduceOpDef{ + _ => must!(punct!(")")), + (Expression::FuncOp(ReduceOpDef{ func: Box::new(func), acc: Box::new(acc), target: Box::new(tgt), pos: pos, - }))) + })) ) ); -make_fn!( - map_expression, Expression>, - do_each!( - pos => pos, - _ => word!("map"), - func => must!(expression), - _ => must!(punct!(",")), - list => must!(trace_parse!(non_op_expression)), - (Expression::FuncOp(FuncOpDef::Map(MapFilterOpDef{ - func: Box::new(func), - target: Box::new(list), - pos: pos, - }))) - ) -); - -make_fn!( - filter_expression, Expression>, - do_each!( - pos => pos, - _ => word!("filter"), - func => must!(expression), - _ => must!(punct!(",")), - list => must!(trace_parse!(non_op_expression)), - (Expression::FuncOp(FuncOpDef::Filter(MapFilterOpDef{ - func: Box::new(func), - target: Box::new(list), - pos: pos, - }))) - ) -); - -make_fn!( - func_op_expression, Expression>, - either!(reduce_expression, map_expression, filter_expression) -); - make_fn!( range_expression, Expression>, do_each!( @@ -710,7 +675,7 @@ fn unprefixed_expression(input: SliceIter) -> ParseResult { make_fn!( non_op_expression, Expression>, either!( - trace_parse!(func_op_expression), + trace_parse!(reduce_expression), trace_parse!(func_expression), trace_parse!(import_expression), trace_parse!(not_expression), diff --git a/std/functional.ucg b/std/functional.ucg index 32ef535..47ea4bd 100644 --- a/std/functional.ucg +++ b/std/functional.ucg @@ -14,4 +14,15 @@ let if = module{ }; }; -let identity = func (arg) => arg; \ No newline at end of file +let identity = func (arg) => arg; + +let s = import "std/schema.ucg"; + +let map_list_reducer = func(acc, item) => acc{list = acc.list + [acc.op(item)]}; + +let map_str_reducer = func(acc, item) => acc{str = acc.str + acc.op(item)}; + +let map = func(op, coll) => select s.base_type_of(coll), NULL, { + list = reduce(map_list_reducer, {op=op, list=[]}, coll).list, + str = reduce(map_str_reducer, {op=op, str=""}, coll).str, +}; \ No newline at end of file diff --git a/std/schema.ucg b/std/schema.ucg index 9e80011..36e334d 100644 --- a/std/schema.ucg +++ b/std/schema.ucg @@ -17,7 +17,7 @@ let base_type_reducer = func (acc, f) => select (acc.val is f), f, { }; // Computes the base type of a value. -let base_type_of = func (val) => (reduce base_type_reducer, {val=val, typ="null"}, base_types).typ; +let base_type_of = func (val) => (reduce(base_type_reducer, {val=val, typ="null"}, base_types)).typ; // Turns any schema check module into a compile failure. // The module must export the computed value as the result field. @@ -39,7 +39,7 @@ let any = module { let reducer = func (acc, t) => acc{ ok = acc.ok || (schema.shaped{val=acc.val, shape=t}.result), }; - let any = func (val, types) => reduce reducer, {ok=false, val=val}, types; + let any = func (val, types) => reduce(reducer, {ok=false, val=val}, types); let result = any(mod.val, mod.types).ok; }; @@ -82,7 +82,7 @@ let shaped = module { float = simple_handler(mod.val, mod.shape), bool = simple_handler(mod.val, mod.shape), null = simple_handler(mod.val, mod.shape), - tuple = (reduce tuple_handler, {shape=mod.shape, ok=false}, (mod.val)).ok, + tuple = (reduce(tuple_handler, {shape=mod.shape, ok=false}, (mod.val))).ok, list = simple_handler(mod.val, mod.shape), func = simple_handler(mod.val, mod.shape), module = simple_handler(mod.val, mod.shape),