From 8d7ca3d6c19d81367e3c0f13dce08b5739a25063 Mon Sep 17 00:00:00 2001 From: Jeremy Wall Date: Sat, 17 Aug 2019 14:04:02 -0500 Subject: [PATCH] DEV: Maps over lists, strings, and tuples are working --- src/build/opcode/runtime.rs | 80 +++++++++++++++++++++++++------------ src/build/opcode/test.rs | 25 +++++++++++- 2 files changed, 78 insertions(+), 27 deletions(-) diff --git a/src/build/opcode/runtime.rs b/src/build/opcode/runtime.rs index b2e9d68..be563f8 100644 --- a/src/build/opcode/runtime.rs +++ b/src/build/opcode/runtime.rs @@ -21,7 +21,7 @@ use std::rc::Rc; use regex::Regex; use super::environment::Environment; -use super::Value::{C, F, P}; +use super::Value::{C, F, P, S}; use super::VM; use super::{Composite, Error, Hook, Primitive, Value}; use crate::ast::Position; @@ -334,18 +334,6 @@ impl Builtins { } else { return Err(dbg!(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 func ptr from the stack let fptr = if let Some(ptr) = stack.pop() { ptr @@ -359,19 +347,59 @@ impl Builtins { return Err(dbg!(Error {})); }; - let mut result_elems = Vec::new(); - for e in elems.iter() { - // push function argument on the stack. - stack.push(e.clone()); - // call function and push it's result on the stack. - result_elems.push(VM::fcall_impl( - path.as_ref().to_owned(), - f, - stack, - env.clone(), - )?); - } - stack.push(Rc::new(C(List(result_elems)))); + // TODO(jwall): This can also be tuples or strings. + match list.as_ref() { + &C(List(ref elems)) => { + let mut result_elems = Vec::new(); + for e in elems.iter() { + // push function argument on the stack. + stack.push(e.clone()); + // call function and push it's result on the stack. + result_elems.push(VM::fcall_impl( + path.as_ref().to_owned(), + f, + stack, + env.clone(), + )?); + } + stack.push(Rc::new(C(List(result_elems)))); + } + &C(Tuple(ref _flds)) => { + let mut new_fields = Vec::new(); + for (ref name, ref val) in _flds { + stack.push(val.clone()); + stack.push(Rc::new(P(Str(name.clone())))); + let result = VM::fcall_impl(path.as_ref().to_owned(), f, stack, env.clone())?; + if let &C(List(ref fval)) = result.as_ref() { + // we expect them to be a list of exactly 2 items. + if fval.len() != 2 { + return Err(dbg!(Error {})); + } + let name = match fval[0].as_ref() { + &P(Str(ref name)) => name.clone(), + _ => return Err(dbg!(Error {})), + }; + new_fields.push((name, fval[1].clone())); + } + } + stack.push(Rc::new(C(Tuple(dbg!(new_fields))))); + } + &P(Str(ref s)) => { + let mut buf = String::new(); + for c in s.chars() { + stack.push(Rc::new(P(Str(c.to_string())))); + // call function and push it's result on the stack. + let result = VM::fcall_impl(path.as_ref().to_owned(), f, stack, env.clone())?; + if let &P(Str(ref s)) = result.as_ref() { + buf.push_str(s); + } else { + return Err(dbg!(Error {})); + } + } + stack.push(Rc::new(P(Str(buf)))); + } + _ => return Err(dbg!(Error {})), + }; Ok(()) } diff --git a/src/build/opcode/test.rs b/src/build/opcode/test.rs index 73e2abe..4314446 100644 --- a/src/build/opcode/test.rs +++ b/src/build/opcode/test.rs @@ -570,7 +570,6 @@ fn scope_stacks() { } use super::translate; -use crate::ast::{Expression, Position, PositionedItem, Statement, Value as ASTValue}; use crate::iter::OffsetStrIter; use crate::parse::parse; @@ -775,3 +774,27 @@ fn simple_trace() { "TRACE: 1 + 1 = 2 at line: 1 column: 1\n" ); } + +#[test] +fn simple_maps() { + assert_parse_cases![ + "map(func(el) => el, [1,2,3]);" => C(List(vec![ + Rc::new(P(Int(1))), + Rc::new(P(Int(2))), + Rc::new(P(Int(3))), + ])), + "map(func(el) => el + 1, [1,2,3]);" => C(List(vec![ + Rc::new(P(Int(2))), + Rc::new(P(Int(3))), + Rc::new(P(Int(4))), + ])), + "map(func(el) => el, \"foo\");" => P(Str("foo".to_owned())), + "map(func(el) => el + \"-\", \"foo\");" => P(Str("f-o-o-".to_owned())), + "map(func(k, v) => [k, v], {foo = 1});" => C(Tuple(vec![ + ("foo".to_owned(), Rc::new(P(Int(1)))), + ])), + "map(func(k, v) => [k, v + 1], {foo = 1});" => C(Tuple(vec![ + ("foo".to_owned(), Rc::new(P(Int(2)))), + ])), + ]; +}