destructuring assignment

This commit is contained in:
Snorre 2025-02-24 14:38:54 +01:00
parent bb1b051598
commit 9da6f7d302
4 changed files with 107 additions and 21 deletions

View file

@ -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<Rc<NodeEnum>>, env: &mut Environment) -> Result<Rc<NodeE
Ok(Set::new(vec![time_str, time_const, result]))
}
fn head(args: &Vec<Rc<NodeEnum>>, env: &mut Environment) -> Result<Rc<NodeEnum>, 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);

View file

@ -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())),
}
}

View file

@ -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<Rc<NodeEnum>, 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())),
}
}

View file

@ -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() {