From d09bd13f42bd7243812d72ff4268b4f8382216c6 Mon Sep 17 00:00:00 2001 From: Jeremy Wall Date: Sat, 17 Aug 2019 14:42:56 -0500 Subject: [PATCH] DEV: Reduce works over lists, tuples, and string --- src/build/opcode/runtime.rs | 56 ++++++++++++++++++++++--------------- src/build/opcode/test.rs | 23 +++++++++++++++ src/build/opcode/vm.rs | 20 +++++++++---- 3 files changed, 72 insertions(+), 27 deletions(-) diff --git a/src/build/opcode/runtime.rs b/src/build/opcode/runtime.rs index 15e9629..f706e33 100644 --- a/src/build/opcode/runtime.rs +++ b/src/build/opcode/runtime.rs @@ -539,18 +539,6 @@ impl Builtins { } else { return dbg!(Err(Error {})); }; - // TODO(jwall): This can also be tuples or strings. - let elems = match list.as_ref() { - &C(List(ref elems)) => elems, - &C(Tuple(ref _flds)) => { - unimplemented!("TODO Tuple functional operations"); - } - &P(Str(ref _s)) => { - unimplemented!("TODO String functional operations"); - } - _ => return Err(dbg!(Error {})), - }; - // Get the accumulator from the stack let mut acc = if let Some(acc) = stack.pop() { acc @@ -570,17 +558,41 @@ impl Builtins { return dbg!(Err(Error {})); }; - for e in elems.iter() { - // push function arguments on the stack. - stack.push(e.clone()); - stack.push(acc.clone()); - // call function and push it's result on the stack. - acc = VM::fcall_impl(path.as_ref().to_owned(), f, stack, env.clone())?; - // Check for empty or boolean results and only push e back in - // if they are non empty and true - } + // TODO(jwall): This can also be tuples or strings. + match list.as_ref() { + &C(List(ref elems)) => { + for e in dbg!(elems).iter() { + // push function arguments on the stack. + stack.push(dbg!(e.clone())); + stack.push(dbg!(acc.clone())); + // call function and push it's result on the stack. + acc = VM::fcall_impl(path.as_ref().to_owned(), f, stack, env.clone())?; + } + } + &C(Tuple(ref _flds)) => { + for (ref name, ref val) in _flds.iter() { + // push function arguments on the stack. + stack.push(val.clone()); + stack.push(Rc::new(P(Str(name.clone())))); + stack.push(dbg!(acc.clone())); + // call function and push it's result on the stack. + acc = VM::fcall_impl(path.as_ref().to_owned(), f, stack, env.clone())?; + } + } + &P(Str(ref _s)) => { + for c in _s.chars() { + // push function arguments on the stack. + stack.push(dbg!(Rc::new(P(Str(c.to_string()))))); + stack.push(dbg!(acc.clone())); + // call function and push it's result on the stack. + acc = VM::fcall_impl(path.as_ref().to_owned(), f, stack, env.clone())?; + } + } + _ => return Err(dbg!(Error {})), + }; + // push the acc on the stack as our result - stack.push(acc); + stack.push(dbg!(acc)); Ok(()) } diff --git a/src/build/opcode/test.rs b/src/build/opcode/test.rs index c9486bf..6d52092 100644 --- a/src/build/opcode/test.rs +++ b/src/build/opcode/test.rs @@ -827,3 +827,26 @@ fn simple_filters() { ])), ]; } + +#[test] +fn simple_reduces() { + assert_parse_cases![ + "reduce(func(acc, el) => acc + [el], [], [1,2,3]);" => C(List(vec![ + Rc::new(P(Int(1))), + Rc::new(P(Int(2))), + Rc::new(P(Int(3))), + ])), + "reduce(func(acc, el) => acc + [el+1], [], [1,2,3]);" => C(List(vec![ + Rc::new(P(Int(2))), + Rc::new(P(Int(3))), + Rc::new(P(Int(4))), + ])), + "reduce(func(acc, s) => acc + s, \"\", \"foo\");" => P(Str("foo".to_owned())), + "reduce(func(acc, k, v) => acc + [[k, v]], [], {foo = 1});" => C(List(vec![ + Rc::new(C(List(vec![ + Rc::new(P(Str("foo".to_owned()))), + Rc::new(P(Int(1))), + ]))), + ])), + ]; +} diff --git a/src/build/opcode/vm.rs b/src/build/opcode/vm.rs index 5c65ac9..5bbad74 100644 --- a/src/build/opcode/vm.rs +++ b/src/build/opcode/vm.rs @@ -456,7 +456,7 @@ where let left = self.pop()?; let right = self.pop()?; // Then pushes the result onto the stack. - self.push(Rc::new(P(self.add(&left, &right)?)))?; + self.push(Rc::new(self.add(&left, &right)?))?; Ok(()) } @@ -757,15 +757,25 @@ where }) } - fn add(&self, left: &Value, right: &Value) -> Result { + fn add(&self, left: &Value, right: &Value) -> Result { Ok(match (left, right) { - (P(Int(i)), Value::P(Int(ii))) => Int(i + ii), - (P(Float(f)), Value::P(Float(ff))) => Float(f + ff), + (P(Int(i)), Value::P(Int(ii))) => P(Int(i + ii)), + (P(Float(f)), Value::P(Float(ff))) => P(Float(f + ff)), (P(Str(s)), Value::P(Str(ss))) => { let mut ns = String::new(); ns.push_str(&s); ns.push_str(&ss); - Str(ns) + P(Str(ns)) + } + (C(List(ref left_list)), C(List(ref right_list))) => { + let mut new_list = Vec::with_capacity(left_list.len() + right_list.len()); + for v in left_list.iter() { + new_list.push(v.clone()); + } + for v in right_list.iter() { + new_list.push(v.clone()); + } + C(List(new_list)) } _ => return Err(dbg!(Error {})), })