diff --git a/src/cli-repl.rs b/src/cli-repl.rs index 86ee31b..2d14046 100644 --- a/src/cli-repl.rs +++ b/src/cli-repl.rs @@ -1,4 +1,3 @@ -use std::f32::consts; use std::f64; use std::io::{self, StdoutLock, Write, stdout}; use std::rc::Rc; @@ -12,7 +11,6 @@ use libopenbirch::node::set::Set; use libopenbirch::node::string_node::StringNode; use libopenbirch::node::{Node, NodeEnum}; use libopenbirch::parser::{Lexer, LexerError, Parser, ParserError}; -use raylib::ease::elastic_in; #[cfg(feature = "async")] use termion::AsyncReader; use termion::color; @@ -382,6 +380,31 @@ fn benchmark(args: &Vec>, env: &mut Environment) -> Result>, env: &mut Environment) -> Result, String> { + if args.len() != 1 { + Err(format!("Expected 1 argument but got {}", args.len()))? + } + + let set = if let NodeEnum::Set(set) = args.first().unwrap().as_ref() { + set.get_values() + } else { + return Err(format!( + "Expected a Set but got a {}", + args.first().unwrap().type_str() + )); + }; + + let head = set.first().cloned().unwrap_or(Set::new(vec![])); + let len = set.len(); + let tail = if len > 1 { + set[1..len].to_vec() + } else { + vec![] + }; + + Ok(Set::new(vec![head, Set::new(tail)])) +} + fn main() -> Result<(), io::Error> { let mut input = Input::new(); @@ -394,6 +417,7 @@ fn main() -> Result<(), io::Error> { env.define_native_function("get_float_precision", get_float_precision); env.define_native_function("set_float_precision", set_float_precision); env.define_native_function("map", map); + env.define_native_function("head", head); env.define_native_function("get", get); env.define_native_function("length", length); env.define_native_function("benchmark", benchmark); diff --git a/src/lib/node/add.rs b/src/lib/node/add.rs index 9349010..462ec1e 100644 --- a/src/lib/node/add.rs +++ b/src/lib/node/add.rs @@ -1,8 +1,11 @@ use std::rc::Rc; +use raylib::ffi::StopAutomationEventRecording; use rug::Float; -use super::{Environment, Node, NodeEnum, Precedence, constant::Constant, set::Set}; +use super::{ + Environment, Node, NodeEnum, Precedence, constant::Constant, set::Set, string_node::StringNode, +}; #[derive(Clone, Debug, PartialEq, PartialOrd)] pub struct Add { @@ -44,6 +47,11 @@ impl Node for Add { Ok(Set::new(values)) } + // Concatenate strings + (NodeEnum::StringNode(s1), NodeEnum::StringNode(s2)) => { + Ok(StringNode::new(s1.get_value().clone() + s2.get_value())) + } + _ => Ok(Rc::new(Add::new(evaluated_left, evaluated_right).into())), } } diff --git a/src/lib/node/assign.rs b/src/lib/node/assign.rs index f2bdc14..962013b 100644 --- a/src/lib/node/assign.rs +++ b/src/lib/node/assign.rs @@ -1,6 +1,6 @@ use std::rc::Rc; -use super::{Environment, Node, NodeEnum, Precedence, empty::Empty}; +use super::{Environment, Node, NodeEnum, Precedence, empty::Empty, symbol}; #[derive(Debug, Clone, PartialEq, PartialOrd)] pub struct Assign { @@ -10,23 +10,70 @@ pub struct Assign { impl Node for Assign { fn evaluate(&self, env: &mut Environment) -> Result, String> { - if let NodeEnum::Symbol(symbol) = self.left.as_ref() { - let name = env - .id_to_str(&symbol.get_value()) - .expect("Unknown symbol") - .clone(); - let right = self.right.evaluate(env)?; + match self.left.as_ref() { + NodeEnum::Symbol(symbol) => { + let name = env + .id_to_str(&symbol.get_value()) + .expect("Unknown symbol") + .clone(); + let right = self.right.evaluate(env)?; - env.insert(symbol.get_value(), right.clone()); - Ok(Empty::new(format!( - "{name} := {}", - right.as_string(Some(env)) - ))) - } else { - Err(format!( - "Cannot assign to a {}", - self.left.as_string(Some(env)) - )) + env.insert(symbol.get_value(), right.clone()); + Ok(Empty::new(format!( + "{name} := {}", + right.as_string(Some(env)) + ))) + } + + NodeEnum::Set(set) => { + // Check if every element of the set is a symbol + let values = set.get_values(); + + if values.len() == 0 { + return Err(format!("Cannot assign to an empty Set")); + } + + let mut symbols = Vec::with_capacity(values.len()); + for node in values { + if let NodeEnum::Symbol(symbol) = node.as_ref() { + symbols.push(symbol); + } else { + return Err(format!("Cannot assign to a {}", node.type_str())); + } + } + + // Evaluate right hand side and check that it is a set of the same size + let right = self.right.evaluate(env)?; + + if let NodeEnum::Set(set) = right.as_ref() { + let values = set.get_values(); + if values.len() != symbols.len() { + return Err(format!( + "Expected rhs with {} elements but got {}", + symbols.len(), + values.len() + )); + } + + for (symbol,value) in symbols.iter().zip(values.into_iter()) { + env.insert(symbol.get_value(), value.clone()); + } + + Ok(Empty::new(format!( + "[{}] := {}", + symbols + .iter() + .map(|x| env.id_to_str(&x.get_value()).unwrap().clone()) + .reduce(|x, acc| format!("{x}, {acc}")) + .unwrap(), + right.as_string(Some(env)) + ))) + } else { + return Err(format!("Cannot unpack {} for assignment", right.type_str())); + } + } + + _ => Err(format!("Cannot assign to a {}", self.left.type_str())), } } diff --git a/src/lib/node/call.rs b/src/lib/node/call.rs index 668d9bf..8f74f8a 100644 --- a/src/lib/node/call.rs +++ b/src/lib/node/call.rs @@ -66,7 +66,14 @@ impl Node for Call { fargs.iter().zip(&arguments).for_each(|(symbol, value)| { env.insert(symbol.get_value(), value.clone()); }); - let ev = body.evaluate(env)?; + let ev = body.evaluate(env); + + if ev.is_err() { + env.pop_stack()?; + return ev; + } + + let ev = ev?; // Return evaluated return value for function Ok(match ev.as_ref() {