did some grinding off camera

This commit is contained in:
Snorre 2025-03-20 12:27:27 +01:00
parent cd758a7fce
commit f6909e5e23
26 changed files with 1070 additions and 421 deletions

206
README.md Normal file
View file

@ -0,0 +1,206 @@
# Openbirch Rust
Openbirch rewritten in rust.
Very messy and bad, im gonna start the umpteenth rewrite soon.
# Features
[x] Constants (numbers)
[x] Addition
[x] Subtraction
[x] Multiplication
[x] Division
[x] Arbitrary float precision
[ ] Sets (or lists, arrays, etc)
[x] Definition
[x] Multiplication with constants
[x] Concattenation
[ ] Index operator
[x] Functions
[x] Native functions
[x] User defined functions
[x] Currying
[x] Closures
[x] Calling
[x] Scopes
[x] Shadowing variables
[ ] Ranges
[x] Defining ranges (`1..5` is a range of `[1..5)`)
[ ] Iterating ranges
[x] Evaluating ranges (very hacky, but defining a Set of length 1 with a range expands said range into the set, eg `[1..3]` becomes `[1,2]`)
[ ] Loops
[x] Infinite loops (`loop ... end` block)
[ ] For loops (`for x in y ... end` block)
[x] Break keyword
[ ] Match expression
[x] If expression
[x] If expression
[x] If-else expression
## Wanted
[ ] More concise syntax, i dont like how it is right now
[ ] Fix stack overflow with recursive functions (internally convert to loops)
[ ] Generally implement more
[ ] Implicit multiplication (may not be possible to implement non-ambiguously)
[ ] Differentiation
[ ] Integration
[ ] Better error handling (i was lazy and skimped on errors, bad move)
# Syntax
Every Openbirch program is made up of 0 or more *expressions*.
An expression is anything from a binary operation like `2+2` to function calls `f(x)` and
even assignments `x := 5`.
All expressions return a value. For expressions that "dont" they return an `Empty`, which cant
be used for anything and will error if used in other operations (eg. `2+{Empty}`).
## Definition
Variables can be defined with a `define` expression.
```
x := 5 # define x as 5
print(x+x) # prints 10
```
As openbirch is a symbolic language variables can be used before assignment
```
y := x^2
print(y) # prints x^2
x := 5
print(y) # prints 25
```
### Scopes
Some expressions define a *scope*, where all defined variables inside will be deleted once the scope ends.
Expressions that create a scope include, but are not limited to,
- If-else
- Loop
- Functions
- Closures
If a variable is defined outside a scope it will be *shadowed* inside the scope. What this means
is that inside the scope the variable will have the shadowed value, while outside the scope it
will have the previous value.
```
x := 5 # Global scope
print(x) # prints 5
if true then # Define a new scope
x := 5000 # Shadow the value of x
print(x) # prints 5000
end # Scope ends here
print(x) # prints 5
```
### Assignment
Since you may want to change the value of a variable outside the current scope you can use an `assignment` rather than a definition.
```
x := 5
if true then
x <- 500 # Assign to x rather than defining it and shadowing it
end
print(x) # prints 500
```
## If-else
If expressions are defined as such
```
if {condition} then
# 0 or more statements
end
```
and if-else as
```
if {condition} then
# 0 or more statements
else
{expression}
end
```
Since `if` is an expression the body of the else branch can be another if expression, in which
case only 1 `end` keyword is needed.
```
if {condition} then
# 0 or more statements
else if {condition} then
# 0 or more statements
end
```
Since all expressions evaluate to a value the value of the if expression is the resulting value
of the last statement in the chosen branch, eg.
```
x := if true then
# Evaluate some expressions
2+2
f(x)
y := f(f(x))
# Last expression is returned
5
else
0
end
print(x) # prints 5
```
if a branch is empty then `Empty` is returned.
## Loops
Currently the only type of loop is an infinite loop.
```
loop
# This will repeat forever
end
```
# Running
## Linux
```sh
$ cargo run
```
### Nixos
```sh
$ nix develop
$ cargo run
```
## Windows
idfk, havent used that shit in years, but probably just `cargo run`.
## MacOS
never used, but again probably `cargo run`

View file

@ -1,6 +1,7 @@
use std::f64; use std::fs::File;
use std::io::{self, StdoutLock, Write, stdout}; use std::io::{self, Read, StdoutLock, Write, stdout};
use std::rc::Rc; use std::rc::Rc;
use std::{env, f64};
use libopenbirch::environment::{Environment, EnvironmentInternalSymbolKey}; use libopenbirch::environment::{Environment, EnvironmentInternalSymbolKey};
use libopenbirch::node::call::Call; use libopenbirch::node::call::Call;
@ -8,7 +9,7 @@ use libopenbirch::node::constant::Constant;
use libopenbirch::node::empty::Empty; use libopenbirch::node::empty::Empty;
use libopenbirch::node::set::Set; use libopenbirch::node::set::Set;
use libopenbirch::node::string_node::StringNode; use libopenbirch::node::string_node::StringNode;
use libopenbirch::node::{Node, NodeEnum}; use libopenbirch::node::{Error, Node, NodeEnum};
use libopenbirch::parser::{Lexer, LexerError, Parser, ParserError}; use libopenbirch::parser::{Lexer, LexerError, Parser, ParserError};
use termion::color; use termion::color;
use termion::event::Key; use termion::event::Key;
@ -73,7 +74,9 @@ impl Input {
return Err(io::Error::from(io::ErrorKind::Interrupted)); return Err(io::Error::from(io::ErrorKind::Interrupted));
} }
self.history.insert(0, self.buffer.clone()); if self.buffer.trim().len() > 0 {
self.history.insert(0, self.buffer.clone());
}
let r = self.buffer.clone(); let r = self.buffer.clone();
self.buffer.clear(); self.buffer.clear();
self.current_char = 0; self.current_char = 0;
@ -200,7 +203,7 @@ fn print_err(i: usize, len: usize, exp: String) {
); );
} }
fn print(args: &Vec<Rc<NodeEnum>>, env: &mut Environment) -> Result<Rc<NodeEnum>, String> { fn print(args: &Vec<Rc<NodeEnum>>, env: &mut Environment) -> Result<Rc<NodeEnum>, Error> {
for expr in args { for expr in args {
println!("\r{}", expr.as_string(Some(env))); println!("\r{}", expr.as_string(Some(env)));
} }
@ -208,17 +211,17 @@ fn print(args: &Vec<Rc<NodeEnum>>, env: &mut Environment) -> Result<Rc<NodeEnum>
Ok(Empty::new("")) Ok(Empty::new(""))
} }
fn unset(args: &Vec<Rc<NodeEnum>>, env: &mut Environment) -> Result<Rc<NodeEnum>, String> { fn unset(args: &Vec<Rc<NodeEnum>>, env: &mut Environment) -> Result<Rc<NodeEnum>, Error> {
for arg in args { for arg in args {
if let NodeEnum::StringNode(string) = arg.as_ref() { if let NodeEnum::StringNode(string) = arg.as_ref() {
if let Some(id) = env.str_to_id(string.get_value()) { if let Some(id) = env.str_to_id(string.get_value()) {
env.undefine(*id); env.undefine(*id);
} }
} else { } else {
return Err(format!( return Err(Error::MismatchedType(format!(
"Expected strings, but one of the arguments was a {}", "Expected strings, but one of the arguments was a {}",
arg.type_str() arg.type_str()
)); )));
} }
} }
@ -228,7 +231,7 @@ fn unset(args: &Vec<Rc<NodeEnum>>, env: &mut Environment) -> Result<Rc<NodeEnum>
fn get_float_precision( fn get_float_precision(
args: &Vec<Rc<NodeEnum>>, args: &Vec<Rc<NodeEnum>>,
env: &mut Environment, env: &mut Environment,
) -> Result<Rc<NodeEnum>, String> { ) -> Result<Rc<NodeEnum>, Error> {
match args.len() { match args.len() {
0 => Ok(Rc::new( 0 => Ok(Rc::new(
Constant::new_from_float(env.get_float_precision() as f64, &env).into(), Constant::new_from_float(env.get_float_precision() as f64, &env).into(),
@ -240,22 +243,25 @@ fn get_float_precision(
Ok(Rc::new(Constant::new_from_float(prec, &env).into())) Ok(Rc::new(Constant::new_from_float(prec, &env).into()))
} else { } else {
Err(format!( Err(Error::MismatchedType(format!(
"Expected argument of type Constant, but got {}", "Expected argument of type Constant, but got {}",
arg.type_str() arg.type_str()
)) )))
} }
} }
_ => Err(format!("Expected 0 or 1 arguments, got {}", args.len()))?, _ => Err(Error::Other(format!(
"Expected 0 or 1 arguments, got {}",
args.len()
)))?,
} }
} }
fn set_float_precision( fn set_float_precision(
args: &Vec<Rc<NodeEnum>>, args: &Vec<Rc<NodeEnum>>,
env: &mut Environment, env: &mut Environment,
) -> Result<Rc<NodeEnum>, String> { ) -> Result<Rc<NodeEnum>, Error> {
if args.len() != 1 { if args.len() != 1 {
Err(format!("Expected 1 arguments, got {}", args.len()))? Err(Error::ArgumentCount(1, args.len()))?
} }
let arg = args.first().unwrap(); let arg = args.first().unwrap();
@ -263,10 +269,10 @@ fn set_float_precision(
let precision: u64 = if let NodeEnum::Constant(value) = arg.as_ref() { let precision: u64 = if let NodeEnum::Constant(value) = arg.as_ref() {
value.get_value().to_u32_saturating().unwrap().into() value.get_value().to_u32_saturating().unwrap().into()
} else { } else {
Err(format!( Err(Error::MismatchedType(format!(
"Expected argument of type Constant, but got {}", "Expected argument of type Constant, but got {}",
arg.type_str() arg.type_str()
))? )))?
}; };
env.set_float_precision(precision); env.set_float_precision(precision);
@ -274,28 +280,28 @@ fn set_float_precision(
Ok(Empty::new(format!("Set float precision to {precision}"))) Ok(Empty::new(format!("Set float precision to {precision}")))
} }
fn map(args: &Vec<Rc<NodeEnum>>, env: &mut Environment) -> Result<Rc<NodeEnum>, String> { fn map(args: &Vec<Rc<NodeEnum>>, env: &mut Environment) -> Result<Rc<NodeEnum>, Error> {
if args.len() != 2 { if args.len() != 2 {
Err(format!("Expected 2 argument but got {}", args.len()))? Err(Error::ArgumentCount(2, args.len()))?
} }
let arg = args.first().unwrap(); let arg = args.first().unwrap();
let func = match arg.as_ref() { let func = match arg.as_ref() {
NodeEnum::Function(_) | NodeEnum::Closure(_) => arg, NodeEnum::Function(_) | NodeEnum::Closure(_) => arg,
_ => Err(format!( _ => Err(Error::MismatchedType(format!(
"Argument 1 expected a Function but got {}", "Argument 1 expected a Function but got {}",
arg.type_str() arg.type_str()
))?, )))?,
}; };
let arg = args.get(1).unwrap().as_ref(); let arg = args.get(1).unwrap().as_ref();
let set = if let NodeEnum::Set(set) = arg { let set = if let NodeEnum::Set(set) = arg {
set.get_values() set.get_values()
} else { } else {
return Err(format!( return Err(Error::MismatchedType(format!(
"Argument 1 expected a Set but got {}", "Argument 1 expected a Set but got {}",
arg.type_str() arg.type_str()
))?; )))?;
}; };
let mut out = Vec::with_capacity(set.len()); let mut out = Vec::with_capacity(set.len());
@ -307,51 +313,52 @@ fn map(args: &Vec<Rc<NodeEnum>>, env: &mut Environment) -> Result<Rc<NodeEnum>,
Ok(Set::new(out)) Ok(Set::new(out))
} }
fn get(args: &Vec<Rc<NodeEnum>>, _env: &mut Environment) -> Result<Rc<NodeEnum>, String> { fn get(args: &Vec<Rc<NodeEnum>>, _env: &mut Environment) -> Result<Rc<NodeEnum>, Error> {
if args.len() != 2 { if args.len() != 2 {
Err(format!("Expected 2 argument but got {}", args.len()))? Err(Error::ArgumentCount(2, args.len()))?
} }
let set = if let NodeEnum::Set(set) = args.first().unwrap().as_ref() { let set = if let NodeEnum::Set(set) = args.first().unwrap().as_ref() {
set.get_values() set.get_values()
} else { } else {
return Err(format!( return Err(Error::MismatchedType(format!(
"Argument 1 expected Set but got {}", "Argument 1 expected Set but got {}",
args.first().unwrap().type_str() args.first().unwrap().type_str()
)); )));
}; };
let idx = if let NodeEnum::Constant(c) = args.get(1).unwrap().as_ref() { let idx = if let NodeEnum::Constant(c) = args.get(1).unwrap().as_ref() {
if let Some(u) = c.get_value().to_u32_saturating() { if let Some(u) = c.get_value().to_u32_saturating() {
u as usize u as usize
} else { } else {
return Err( return Err(Error::ConversionError(
"Error occured while trying to convert second argument to integer".to_owned(), "Error occured while trying to convert second argument to integer".to_owned(),
); ));
} }
} else { } else {
return Err("Argument 1 is expected to be a Set".to_owned()); return Err(Error::MismatchedType(
"Argument 1 is expected to be a Set".to_owned(),
));
}; };
if let Some(v) = set.get(idx) { if let Some(v) = set.get(idx) {
return Ok(v.clone()); return Ok(v.clone());
} }
return Err(format!( return Err(Error::IndexOutOfBounds(set.len(), idx));
"Index was out of bounds for Set of length {}",
set.len()
));
} }
fn length(args: &Vec<Rc<NodeEnum>>, env: &mut Environment) -> Result<Rc<NodeEnum>, String> { fn length(args: &Vec<Rc<NodeEnum>>, env: &mut Environment) -> Result<Rc<NodeEnum>, Error> {
if args.len() != 1 { if args.len() != 1 {
Err(format!("Expected 1 argument but got {}", args.len()))? Err(Error::ArgumentCount(1, args.len()))?
} }
let set = if let NodeEnum::Set(set) = args.first().unwrap().as_ref() { let set = if let NodeEnum::Set(set) = args.first().unwrap().as_ref() {
set.get_values() set.get_values()
} else { } else {
return Err("Argument 1 is expected to be a Set".to_owned()); return Err(Error::MismatchedType(
"Argument 1 is expected to be a Set".to_owned(),
));
}; };
Ok(Rc::new( Ok(Rc::new(
@ -359,9 +366,9 @@ fn length(args: &Vec<Rc<NodeEnum>>, env: &mut Environment) -> Result<Rc<NodeEnum
)) ))
} }
fn benchmark(args: &Vec<Rc<NodeEnum>>, env: &mut Environment) -> Result<Rc<NodeEnum>, String> { fn benchmark(args: &Vec<Rc<NodeEnum>>, env: &mut Environment) -> Result<Rc<NodeEnum>, Error> {
if args.len() != 1 { if args.len() != 1 {
Err(format!("Expected 1 argument but got {}", args.len()))? Err(Error::ArgumentCount(1, args.len()))?
} }
use std::time::Instant; use std::time::Instant;
@ -377,18 +384,18 @@ fn benchmark(args: &Vec<Rc<NodeEnum>>, env: &mut Environment) -> Result<Rc<NodeE
Ok(Set::new(vec![time_str, time_const, result])) Ok(Set::new(vec![time_str, time_const, result]))
} }
fn head(args: &Vec<Rc<NodeEnum>>, _env: &mut Environment) -> Result<Rc<NodeEnum>, String> { fn head(args: &Vec<Rc<NodeEnum>>, _env: &mut Environment) -> Result<Rc<NodeEnum>, Error> {
if args.len() != 1 { if args.len() != 1 {
Err(format!("Expected 1 argument but got {}", args.len()))? Err(Error::ArgumentCount(1, args.len()))?
} }
let set = if let NodeEnum::Set(set) = args.first().unwrap().as_ref() { let set = if let NodeEnum::Set(set) = args.first().unwrap().as_ref() {
set.get_values() set.get_values()
} else { } else {
return Err(format!( return Err(Error::MismatchedType(format!(
"Expected a Set but got a {}", "Expected a Set but got a {}",
args.first().unwrap().type_str() args.first().unwrap().type_str()
)); )));
}; };
let head = set.first().cloned().unwrap_or(Set::new(vec![])); let head = set.first().cloned().unwrap_or(Set::new(vec![]));
@ -402,9 +409,30 @@ fn head(args: &Vec<Rc<NodeEnum>>, _env: &mut Environment) -> Result<Rc<NodeEnum>
Ok(Set::new(vec![head, Set::new(tail)])) Ok(Set::new(vec![head, Set::new(tail)]))
} }
fn diff(args: &Vec<Rc<NodeEnum>>, _env: &mut Environment) -> Result<Rc<NodeEnum>, String> { fn mult_equal(args: &Vec<Rc<NodeEnum>>, env: &mut Environment) -> Result<Rc<NodeEnum>, Error> {
let a1 = if let NodeEnum::Multiply(m) = args.get(0).ok_or(Error::ArgumentCount(1, 0))?.as_ref()
{
m
} else {
return Err(Error::MismatchedType(
"Argument 1 is not a multiply".to_owned(),
));
};
let a2 = if let NodeEnum::Multiply(m) = args.get(1).ok_or(Error::ArgumentCount(2, 1))?.as_ref()
{
m
} else {
return Err(Error::MismatchedType(
"Argument 2 is not a multiply".to_owned(),
));
};
Ok(Rc::new(NodeEnum::Bool(a1.symbols_match(a2).into())))
}
fn diff(args: &Vec<Rc<NodeEnum>>, _env: &mut Environment) -> Result<Rc<NodeEnum>, Error> {
if args.len() != 2 { if args.len() != 2 {
return Err(format!("Expected 1-2 argument but got {}", args.len())); return Err(Error::ArgumentCount(2, args.len()));
} }
let expr = args.first().unwrap().clone(); let expr = args.first().unwrap().clone();
@ -412,10 +440,10 @@ fn diff(args: &Vec<Rc<NodeEnum>>, _env: &mut Environment) -> Result<Rc<NodeEnum>
let var = if let NodeEnum::Symbol(symbol) = args.get(1).unwrap().as_ref() { let var = if let NodeEnum::Symbol(symbol) = args.get(1).unwrap().as_ref() {
symbol.get_value() symbol.get_value()
} else { } else {
return Err(format!( return Err(Error::MismatchedType(format!(
"Argument 2 is expected to be a Symbol but got a {}", "Argument 2 is expected to be a Symbol but got a {}",
args.get(1).unwrap().type_str() args.get(1).unwrap().type_str()
)); )));
}; };
todo!() todo!()
@ -429,9 +457,48 @@ fn diff_internally(
todo!() todo!()
} }
fn main() -> Result<(), io::Error> { fn evaluate(source: &String, mut env: &mut Environment, verbose: bool) {
let mut input = Input::new(); let mut lexer = Lexer::new(&source);
let tokens_result = lexer.lex();
if tokens_result.is_err() {
match tokens_result.err().unwrap() {
LexerError::UnexpectedChar(i, exp) => print_err(i, 1, exp),
}
return;
}
let tokens = tokens_result.unwrap();
let mut parser = Parser::new(tokens, &mut env);
let nodes = match parser.parse() {
Ok(nodes) => nodes,
Err(err) => {
match err {
ParserError::UnexpectedEndOfTokens(exp) => print_err(source.len(), 1, exp),
ParserError::UnexpectedToken(i, len, exp)
| ParserError::Unimplemented(i, len, exp) => print_err(i, len, exp),
ParserError::UnexpectedNode(i, exp) | ParserError::NumberParse(i, exp) => {
print_err(i, 1, exp)
}
}
return;
}
};
print!("{}", color::Fg(color::Blue));
for node in nodes {
let evaluated = node.evaluate(&mut env);
match evaluated {
Ok(result) if verbose => println!("\r\t{}", result.as_string(Some(&env))),
Err(exp) => print_err(0, 1, exp.to_string()),
_ => {}
}
}
}
fn main() -> Result<(), io::Error> {
let mut env = Environment::new(); let mut env = Environment::new();
env.set_float_precision(128); env.set_float_precision(128);
@ -445,52 +512,33 @@ fn main() -> Result<(), io::Error> {
env.define_native_function("get", get); env.define_native_function("get", get);
env.define_native_function("length", length); env.define_native_function("length", length);
env.define_native_function("benchmark", benchmark); env.define_native_function("benchmark", benchmark);
env.define_native_function("mult_equals", mult_equal);
env.define( env.define(
"pi", "pi",
Rc::new(Constant::new_from_float(std::f64::consts::PI, &env).into()), Rc::new(Constant::new_from_float(std::f64::consts::PI, &env).into()),
); );
let args: Vec<String> = std::env::args().collect();
if args.len() > 1 {
let file = args.get(1).unwrap();
let mut file = File::open(file)?;
let mut src = String::new();
let _ = file.read_to_string(&mut src);
evaluate(&src, &mut env, false);
return Ok(());
}
let mut input = Input::new();
while let Some(source) = input.get()? { while let Some(source) = input.get()? {
input.disable_raw()?; input.disable_raw()?;
let mut lexer = Lexer::new(&source); evaluate(&source, &mut env, true);
let tokens_result = lexer.lex();
if tokens_result.is_err() {
match tokens_result.err().unwrap() {
LexerError::UnexpectedChar(i, exp) => print_err(i, 1, exp),
}
continue;
}
let tokens = tokens_result.unwrap();
let mut parser = Parser::new(tokens, &mut env);
let nodes = match parser.parse() {
Ok(nodes) => nodes,
Err(err) => {
match err {
ParserError::UnexpectedEndOfTokens(exp) => print_err(source.len(), 1, exp),
ParserError::UnexpectedToken(i, len, exp)
| ParserError::Unimplemented(i, len, exp) => print_err(i, len, exp),
ParserError::UnexpectedNode(i, exp) | ParserError::NumberParse(i, exp) => {
print_err(i, 1, exp)
}
}
continue;
}
};
print!("{}", color::Fg(color::Blue));
for node in nodes {
let evaluated = node.evaluate(&mut env);
match evaluated {
Ok(result) => println!("\r\t{}", result.as_string(Some(&env))),
Err(exp) => print_err(0, 1, exp),
}
}
input.enable_raw()?; input.enable_raw()?;

View file

@ -1,7 +1,7 @@
use std::{collections::HashMap, rc::Rc}; use std::{collections::HashMap, rc::Rc};
use crate::node::{ use crate::node::{
NodeEnum, Error, NodeEnum,
function::{Function, FunctionType, NativeFunctionType}, function::{Function, FunctionType, NativeFunctionType},
}; };
@ -90,11 +90,11 @@ impl Environment {
self.enable_closures self.enable_closures
} }
pub fn push_stack(&mut self) -> Result<(), String> { pub fn push_stack(&mut self) -> Result<(), Error> {
if self.stack_depth == self.max_stack_depth { // if self.stack_depth == self.max_stack_depth {
self.unwind_stack(); // // self.unwind_stack();
return Err("Max Stack depth exceeded".to_owned()); // return Err("Max Stack depth exceeded".to_owned());
} // }
self.stack_depth += 1; self.stack_depth += 1;
self.stack_sizes.push(Scope { self.stack_sizes.push(Scope {
@ -107,9 +107,9 @@ impl Environment {
Ok(()) Ok(())
} }
pub fn pop_stack(&mut self) -> Result<(), String> { pub fn pop_stack(&mut self) -> Result<(), Error> {
if self.stack_depth == 0 { if self.stack_depth == 0 {
return Err("Trying to pop empty stack".to_owned()); return Err(Error::StackUnderflow);
} }
self.stack_depth -= 1; self.stack_depth -= 1;
@ -126,15 +126,20 @@ impl Environment {
} }
fn unwind_stack(&mut self) { fn unwind_stack(&mut self) {
for scope in &self.stack_sizes { // for scope in &self.stack_sizes {
for _ in 0..scope.stack_len { // for _ in 0..scope.stack_len {
self.map.remove(&self.stack.pop().unwrap()); // self.map.remove(&self.stack.pop().unwrap());
} // }
} // }
//
// self.stack_sizes = vec![];
// self.stack_shadows = vec![];
// self.stack_depth = 0;
self.stack_sizes = vec![]; let depth = self.stack_depth - 1;
self.stack_shadows = vec![]; for _ in 0..depth {
self.stack_depth = 0; let _ = self.pop_stack();
}
} }
pub fn define(&mut self, name: impl Into<String>, value: Rc<NodeEnum>) { pub fn define(&mut self, name: impl Into<String>, value: Rc<NodeEnum>) {
@ -174,8 +179,13 @@ impl Environment {
self.stack.get(start..len).unwrap() self.stack.get(start..len).unwrap()
} }
pub fn insert(&mut self, key: EnvironmentInternalSymbolKey, value: Rc<NodeEnum>) { pub fn insert(
if self.stack_depth != 0 { &mut self,
key: EnvironmentInternalSymbolKey,
value: Rc<NodeEnum>,
dont_shadow: bool,
) {
if self.stack_depth != 0 && !dont_shadow {
let mut shadow = false; let mut shadow = false;
if self.map.get(&key).is_some() { if self.map.get(&key).is_some() {
if !self.get_current_scope().contains(&key) { if !self.get_current_scope().contains(&key) {

View file

@ -1,9 +1,9 @@
use std::rc::Rc; use std::{cmp::Ordering, rc::Rc};
use rug::Float; use rug::Float;
use super::{ use super::{
Environment, Node, NodeEnum, Precedence, constant::Constant, set::Set, string_node::StringNode, constant::Constant, set::Set, string_node::StringNode, Environment, Error, Node, NodeEnum, Precedence
}; };
#[derive(Clone, Debug, PartialEq, PartialOrd)] #[derive(Clone, Debug, PartialEq, PartialOrd)]
@ -13,7 +13,7 @@ pub struct Add {
} }
impl Node for Add { impl Node for Add {
fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, String> { fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, Error> {
let evaluated_left = self.left.evaluate(env)?; let evaluated_left = self.left.evaluate(env)?;
let evaluated_right = self.right.evaluate(env)?; let evaluated_right = self.right.evaluate(env)?;
@ -51,17 +51,79 @@ impl Node for Add {
Ok(StringNode::new(s1.get_value().clone() + s2.get_value())) Ok(StringNode::new(s1.get_value().clone() + s2.get_value()))
} }
(NodeEnum::Add(add), o) | (o, NodeEnum::Add(add)) => {
// Aggregate into a single vector for easy sorting
let mut aggregate = vec![];
let mut queue = vec![];
queue.push(Rc::new(o.clone()));
let mut c: Rc<NodeEnum> = Rc::new(add.clone().into());
loop {
match c.as_ref() {
NodeEnum::Add(m) => {
queue.push(m.get_left());
queue.push(m.get_right());
}
_ => {
aggregate.push(c.clone());
}
}
if !queue.is_empty() {
c = queue.pop().unwrap();
} else {
break;
}
}
aggregate.sort_by(|a, b| match (a.as_ref(), b.as_ref()) {
(_, NodeEnum::Constant(_)) => Ordering::Less,
(NodeEnum::Constant(_), _) => Ordering::Greater,
(NodeEnum::Symbol(s1), NodeEnum::Symbol(s2)) => s1.cmp(s2),
_ => a.partial_cmp(b).unwrap_or(Ordering::Equal)
});
let mut constant = Rc::new(Constant::new_from_float(0.0, &env).into());
let mut constanted = false;
while let Some(agr) = aggregate.last() {
if let NodeEnum::Constant(_) = agr.as_ref() {
constanted = true;
constant =
Add::new_rc(constant, aggregate.pop().unwrap());
} else {
break;
}
}
let mut out = aggregate.pop().unwrap();
while let Some(a) = aggregate.pop() {
out = Add::new_rc(out, a);
}
if constanted {
Ok(Add::new_rc(constant.evaluate(env)?, out))
} else {
Ok(out)
}
}
_ => Ok(Rc::new(Add::new(evaluated_left, evaluated_right).into())), _ => Ok(Rc::new(Add::new(evaluated_left, evaluated_right).into())),
} }
} }
fn as_string(&self, env: Option<&Environment>) -> String { fn as_string(&self, env: Option<&Environment>) -> String {
let left_string = if self.left.precedence() <= self.precedence() { let left_string = if let NodeEnum::Add(_) = self.left.as_ref() {
self.left.as_string(env)
} else if self.left.precedence() <= self.precedence() {
format!("({})", self.left.as_string(env)) format!("({})", self.left.as_string(env))
} else { } else {
self.left.as_string(env) self.left.as_string(env)
}; };
let right_string = if self.right.precedence() <= self.precedence() { let right_string = if let NodeEnum::Add(_) = self.right.as_ref() {
self.right.as_string(env)
} else if self.right.precedence() <= self.precedence() {
format!("({})", self.right.as_string(env)) format!("({})", self.right.as_string(env))
} else { } else {
self.right.as_string(env) self.right.as_string(env)

View file

@ -1,15 +1,16 @@
use std::rc::Rc; use std::rc::Rc;
use super::{Environment, Node, NodeEnum, Precedence, empty::Empty}; use super::{Environment, Error, Node, NodeEnum, Precedence, empty::Empty};
#[derive(Debug, Clone, PartialEq, PartialOrd)] #[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct Assign { pub struct Assign {
left: Rc<NodeEnum>, left: Rc<NodeEnum>,
right: Rc<NodeEnum>, right: Rc<NodeEnum>,
shadow: bool,
} }
impl Node for Assign { impl Node for Assign {
fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, String> { fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, Error> {
match self.left.as_ref() { match self.left.as_ref() {
NodeEnum::Symbol(symbol) => { NodeEnum::Symbol(symbol) => {
let name = env let name = env
@ -18,9 +19,10 @@ impl Node for Assign {
.clone(); .clone();
let right = self.right.evaluate(env)?; let right = self.right.evaluate(env)?;
env.insert(symbol.get_value(), right.clone()); env.insert(symbol.get_value(), right.clone(), !self.shadow);
Ok(Empty::new(format!( Ok(Empty::new(format!(
"{name} := {}", "{name} {} {}",
if self.shadow { ":=" } else { "<-" },
right.as_string(Some(env)) right.as_string(Some(env))
))) )))
} }
@ -30,7 +32,7 @@ impl Node for Assign {
let values = set.get_values(); let values = set.get_values();
if values.len() == 0 { if values.len() == 0 {
return Err(format!("Cannot assign to an empty Set")); return Err(Error::EmptySetAssignment);
} }
let mut symbols = Vec::with_capacity(values.len()); let mut symbols = Vec::with_capacity(values.len());
@ -38,7 +40,10 @@ impl Node for Assign {
if let NodeEnum::Symbol(symbol) = node.as_ref() { if let NodeEnum::Symbol(symbol) = node.as_ref() {
symbols.push(symbol); symbols.push(symbol);
} else { } else {
return Err(format!("Cannot assign to a {}", node.type_str())); return Err(Error::IllegalAssignment(format!(
"Cannot assign to a {}",
node.type_str()
)));
} }
} }
@ -48,19 +53,19 @@ impl Node for Assign {
if let NodeEnum::Set(set) = right.as_ref() { if let NodeEnum::Set(set) = right.as_ref() {
let values = set.get_values(); let values = set.get_values();
if values.len() != symbols.len() { if values.len() != symbols.len() {
return Err(format!( return Err(Error::SetAssignmentCountMismatch(
"Expected rhs with {} elements but got {}",
symbols.len(), symbols.len(),
values.len() values.len(),
)); ));
} }
for (symbol,value) in symbols.iter().zip(values.into_iter()) { for (symbol, value) in symbols.iter().zip(values.into_iter()) {
env.insert(symbol.get_value(), value.clone()); env.insert(symbol.get_value(), value.clone(), !self.shadow);
} }
Ok(Empty::new(format!( Ok(Empty::new(format!(
"[{}] := {}", "[{}] {} {}",
if self.shadow { ":=" } else { "<-" },
symbols symbols
.iter() .iter()
.map(|x| env.id_to_str(&x.get_value()).unwrap().clone()) .map(|x| env.id_to_str(&x.get_value()).unwrap().clone())
@ -69,18 +74,25 @@ impl Node for Assign {
right.as_string(Some(env)) right.as_string(Some(env))
))) )))
} else { } else {
return Err(format!("Cannot unpack {} for assignment", right.type_str())); return Err(Error::IllegalRhsAssignment(format!(
"Cannot unpack {} for assignment",
right.type_str()
)));
} }
} }
_ => Err(format!("Cannot assign to a {}", self.left.type_str())), _ => Err(Error::IllegalAssignment(format!(
"Cannot assign to a {}",
self.left.type_str()
))),
} }
} }
fn as_string(&self, env: Option<&Environment>) -> String { fn as_string(&self, env: Option<&Environment>) -> String {
format!( format!(
"{} := {}", "{} {} {}",
self.left.as_string(env), self.left.as_string(env),
if self.shadow { ":=" } else { "<-" },
self.right.as_string(env) self.right.as_string(env)
) )
} }
@ -91,8 +103,12 @@ impl Node for Assign {
} }
impl Assign { impl Assign {
pub fn new(left: Rc<NodeEnum>, right: Rc<NodeEnum>) -> Self { pub fn new(left: Rc<NodeEnum>, right: Rc<NodeEnum>, shadow: bool) -> Self {
Self { left, right } Self {
left,
right,
shadow,
}
} }
pub fn get_left(&self) -> Rc<NodeEnum> { pub fn get_left(&self) -> Rc<NodeEnum> {

View file

@ -5,7 +5,7 @@ use crate::{
node::{closure::Closure, function::FunctionType}, node::{closure::Closure, function::FunctionType},
}; };
use super::{Node, NodeEnum, Precedence}; use super::{Error, Node, NodeEnum, Precedence};
#[derive(Debug, Clone, PartialEq, PartialOrd)] #[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct Call { pub struct Call {
@ -14,7 +14,7 @@ pub struct Call {
} }
impl Node for Call { impl Node for Call {
fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, String> { fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, Error> {
if env.closures_enabled() { if env.closures_enabled() {
return Ok(Rc::new(self.clone().into())); return Ok(Rc::new(self.clone().into()));
} }
@ -33,7 +33,7 @@ impl Node for Call {
NodeEnum::Function(func) => func, NodeEnum::Function(func) => func,
NodeEnum::Closure(closure) => { NodeEnum::Closure(closure) => {
for (k, v) in closure.get_captured_variables() { for (k, v) in closure.get_captured_variables() {
env.insert(*k, v.clone()); env.insert(*k, v.clone(), false);
} }
closure.get_function() closure.get_function()
} }
@ -56,15 +56,11 @@ impl Node for Call {
FunctionType::Native(_name, native_function) => native_function(&arguments, env), FunctionType::Native(_name, native_function) => native_function(&arguments, env),
FunctionType::UserFunction(body, fargs) => { FunctionType::UserFunction(body, fargs) => {
if fargs.len() != arguments.len() { if fargs.len() != arguments.len() {
return Err(format!( return Err(Error::ArgumentCount(fargs.len(), arguments.len()));
"Error calling function. Expected {} arguments, but got {}",
fargs.len(),
arguments.len()
));
} }
// Define variables // Define variables
fargs.iter().zip(&arguments).for_each(|(symbol, value)| { fargs.iter().zip(&arguments).for_each(|(symbol, value)| {
env.insert(symbol.get_value(), value.clone()); env.insert(symbol.get_value(), value.clone(), false);
}); });
let ev = body.evaluate(env); let ev = body.evaluate(env);

View file

@ -2,7 +2,7 @@ use std::rc::Rc;
use crate::environment::{Environment, EnvironmentInternalSymbolKey}; use crate::environment::{Environment, EnvironmentInternalSymbolKey};
use super::{Node, NodeEnum, Precedence, function::Function}; use super::{function::Function, Error, Node, NodeEnum, Precedence};
#[derive(Debug, Clone, PartialEq, PartialOrd)] #[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct Closure { pub struct Closure {
@ -11,7 +11,7 @@ pub struct Closure {
} }
impl Node for Closure { impl Node for Closure {
fn evaluate(&self, _env: &mut Environment) -> Result<Rc<NodeEnum>, String> { fn evaluate(&self, _env: &mut Environment) -> Result<Rc<NodeEnum>, Error> {
Ok(Rc::new(self.clone().into())) Ok(Rc::new(self.clone().into()))
} }

View file

@ -2,7 +2,7 @@ use std::rc::Rc;
use crate::environment::Environment; use crate::environment::Environment;
use super::{Node, NodeEnum, Precedence, if_else::Bool}; use super::{if_else::Bool, Error, Node, NodeEnum, Precedence};
#[derive(Clone, Debug, PartialEq, PartialOrd)] #[derive(Clone, Debug, PartialEq, PartialOrd)]
pub struct Greater { pub struct Greater {
@ -29,7 +29,7 @@ pub struct LessEquals {
} }
impl Node for Greater { impl Node for Greater {
fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, String> { fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, Error> {
let mut expr = self.left.evaluate(env)?; let mut expr = self.left.evaluate(env)?;
for e in &self.right { for e in &self.right {
let e = e.evaluate(env)?; let e = e.evaluate(env)?;
@ -66,7 +66,7 @@ impl Node for Greater {
} }
impl Node for Less { impl Node for Less {
fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, String> { fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, Error> {
let mut expr = self.left.evaluate(env)?; let mut expr = self.left.evaluate(env)?;
for e in &self.right { for e in &self.right {
let e = e.evaluate(env)?; let e = e.evaluate(env)?;
@ -103,14 +103,14 @@ impl Node for Less {
} }
impl Node for GreaterEquals { impl Node for GreaterEquals {
fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, String> { fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, Error> {
let mut expr = self.left.evaluate(env)?; let mut expr = self.left.evaluate(env)?;
for e in &self.right { for e in &self.right {
let e = e.evaluate(env)?; let e = e.evaluate(env)?;
let evaluation = expr.partial_cmp(&e); let evaluation = expr.partial_cmp(&e);
match evaluation { match evaluation {
Some(cmp) Some(cmp)
if cmp != std::cmp::Ordering::Equal || cmp != std::cmp::Ordering::Greater => if cmp != std::cmp::Ordering::Equal && cmp != std::cmp::Ordering::Greater =>
{ {
return Ok(Rc::new(Bool::False.into())); return Ok(Rc::new(Bool::False.into()));
} }
@ -142,14 +142,14 @@ impl Node for GreaterEquals {
} }
impl Node for LessEquals { impl Node for LessEquals {
fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, String> { fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, Error> {
let mut expr = self.left.evaluate(env)?; let mut expr = self.left.evaluate(env)?;
for e in &self.right { for e in &self.right {
let e = e.evaluate(env)?; let e = e.evaluate(env)?;
let evaluation = expr.partial_cmp(&e); let evaluation = expr.partial_cmp(&e);
match evaluation { match evaluation {
Some(cmp) Some(cmp)
if cmp != std::cmp::Ordering::Equal || cmp != std::cmp::Ordering::Less => if cmp != std::cmp::Ordering::Equal && cmp != std::cmp::Ordering::Less =>
{ {
return Ok(Rc::new(Bool::False.into())); return Ok(Rc::new(Bool::False.into()));
} }
@ -185,7 +185,7 @@ impl Greater {
Rc::new(Self { left, right }.into()) Rc::new(Self { left, right }.into())
} }
fn abort(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, String> { fn abort(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, Error> {
let mut arguments = vec![]; let mut arguments = vec![];
for value in self.right.iter() { for value in self.right.iter() {
arguments.push(value.evaluate(env)?); arguments.push(value.evaluate(env)?);
@ -199,7 +199,7 @@ impl Less {
Rc::new(Self { left, right }.into()) Rc::new(Self { left, right }.into())
} }
fn abort(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, String> { fn abort(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, Error> {
let mut arguments = vec![]; let mut arguments = vec![];
for value in self.right.iter() { for value in self.right.iter() {
arguments.push(value.evaluate(env)?); arguments.push(value.evaluate(env)?);
@ -213,7 +213,7 @@ impl LessEquals {
Rc::new(Self { left, right }.into()) Rc::new(Self { left, right }.into())
} }
fn abort(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, String> { fn abort(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, Error> {
let mut arguments = vec![]; let mut arguments = vec![];
for value in self.right.iter() { for value in self.right.iter() {
arguments.push(value.evaluate(env)?); arguments.push(value.evaluate(env)?);
@ -227,7 +227,7 @@ impl GreaterEquals {
Rc::new(Self { left, right }.into()) Rc::new(Self { left, right }.into())
} }
fn abort(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, String> { fn abort(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, Error> {
let mut arguments = vec![]; let mut arguments = vec![];
for value in self.right.iter() { for value in self.right.iter() {
arguments.push(value.evaluate(env)?); arguments.push(value.evaluate(env)?);

View file

@ -2,7 +2,7 @@ use std::rc::Rc;
use rug::Float; use rug::Float;
use super::{Environment, Node, Precedence}; use super::{Environment, Error, Node, Precedence};
pub type ConstantValue = Float; pub type ConstantValue = Float;
@ -18,7 +18,7 @@ impl From<ConstantValue> for Constant {
} }
impl Node for Constant { impl Node for Constant {
fn evaluate(&self, _: &mut super::Environment) -> Result<Rc<super::NodeEnum>, String> { fn evaluate(&self, _: &mut super::Environment) -> Result<Rc<super::NodeEnum>, Error> {
Ok(Rc::new(self.clone().into())) Ok(Rc::new(self.clone().into()))
} }

View file

@ -2,7 +2,7 @@ use std::rc::Rc;
use rug::Float; use rug::Float;
use super::{Node, NodeEnum, Precedence, constant::Constant, set::Set}; use super::{constant::Constant, set::Set, Error, Node, NodeEnum, Precedence};
#[derive(Clone, Debug, PartialEq, PartialOrd)] #[derive(Clone, Debug, PartialEq, PartialOrd)]
pub struct Divide { pub struct Divide {
@ -11,14 +11,14 @@ pub struct Divide {
} }
impl Node for Divide { impl Node for Divide {
fn evaluate(&self, env: &mut super::Environment) -> Result<Rc<super::NodeEnum>, String> { fn evaluate(&self, env: &mut super::Environment) -> Result<Rc<super::NodeEnum>, Error> {
let evaluated_left = self.left.evaluate(env)?; let evaluated_left = self.left.evaluate(env)?;
let evaluated_right = self.right.evaluate(env)?; let evaluated_right = self.right.evaluate(env)?;
match (evaluated_left.as_ref(), evaluated_right.as_ref()) { match (evaluated_left.as_ref(), evaluated_right.as_ref()) {
// Error if dividing by zero // Error if dividing by zero
(_, NodeEnum::Constant(zero)) if zero.get_value() == &0.0 => { (_, NodeEnum::Constant(zero)) if zero.get_value() == &0.0 => {
Err("Division by Zero".into()) Err(Error::DivideByZero)
} }
(_, _) if evaluated_left == evaluated_right => { (_, _) if evaluated_left == evaluated_right => {

View file

@ -1,6 +1,6 @@
use std::{rc::Rc, sync::LazyLock}; use std::{rc::Rc, sync::LazyLock};
use super::{Environment, Node, NodeEnum, Precedence}; use super::{Environment, Error, Node, NodeEnum, Precedence};
#[derive(Debug, Clone, PartialOrd)] #[derive(Debug, Clone, PartialOrd)]
pub struct Empty { pub struct Empty {
@ -15,7 +15,7 @@ impl PartialEq for Empty {
impl Eq for Empty {} impl Eq for Empty {}
impl Node for Empty { impl Node for Empty {
fn evaluate(&self, _: &mut Environment) -> Result<Rc<NodeEnum>, String> { fn evaluate(&self, _: &mut Environment) -> Result<Rc<NodeEnum>, Error> {
Ok(Empty::EMPTY.clone()) Ok(Empty::EMPTY.clone())
} }

View file

@ -1,6 +1,6 @@
use std::rc::Rc; use std::rc::Rc;
use super::{Environment, Node, NodeEnum, Precedence, if_else::Bool}; use super::{if_else::Bool, Environment, Error, Node, NodeEnum, Precedence};
#[derive(Clone, Debug, PartialEq, PartialOrd)] #[derive(Clone, Debug, PartialEq, PartialOrd)]
pub struct Equals { pub struct Equals {
@ -9,7 +9,7 @@ pub struct Equals {
} }
impl Node for Equals { impl Node for Equals {
fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, String> { fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, Error> {
let left = self.left.evaluate(env)?; let left = self.left.evaluate(env)?;
for expr in &self.right { for expr in &self.right {

View file

@ -2,7 +2,7 @@ use std::rc::Rc;
use rug::{Float, ops::Pow}; use rug::{Float, ops::Pow};
use super::{Environment, Node, NodeEnum, Precedence, constant::Constant}; use super::{constant::Constant, Environment, Error, Node, NodeEnum, Precedence};
#[derive(Clone, Debug, PartialEq, PartialOrd)] #[derive(Clone, Debug, PartialEq, PartialOrd)]
pub struct Exponent { pub struct Exponent {
@ -11,7 +11,7 @@ pub struct Exponent {
} }
impl Node for Exponent { impl Node for Exponent {
fn evaluate(&self, env: &mut super::Environment) -> Result<Rc<super::NodeEnum>, String> { fn evaluate(&self, env: &mut super::Environment) -> Result<Rc<super::NodeEnum>, Error> {
let evaluated_left = self.left.evaluate(env)?; let evaluated_left = self.left.evaluate(env)?;
let evaluated_right = self.right.evaluate(env)?; let evaluated_right = self.right.evaluate(env)?;

View file

@ -2,10 +2,10 @@ use std::rc::Rc;
use crate::environment::Environment; use crate::environment::Environment;
use super::{symbol::Symbol, Node, NodeEnum, Precedence}; use super::{symbol::Symbol, Error, Node, NodeEnum, Precedence};
pub type NativeFunctionType = pub type NativeFunctionType =
fn(&Vec<Rc<NodeEnum>>, env: &mut Environment) -> Result<Rc<NodeEnum>, String>; fn(&Vec<Rc<NodeEnum>>, env: &mut Environment) -> Result<Rc<NodeEnum>, Error>;
#[derive(Debug, Clone, PartialEq, PartialOrd)] #[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum FunctionType { pub enum FunctionType {
@ -19,7 +19,7 @@ pub struct Function {
} }
impl Node for Function { impl Node for Function {
fn evaluate(&self, _env: &mut Environment) -> Result<Rc<NodeEnum>, String> { fn evaluate(&self, _env: &mut Environment) -> Result<Rc<NodeEnum>, Error> {
Ok(Rc::new(self.clone().into())) Ok(Rc::new(self.clone().into()))
// Ok(Rc::new( // Ok(Rc::new(

View file

@ -2,7 +2,7 @@ use std::rc::Rc;
use crate::node::empty::Empty; use crate::node::empty::Empty;
use super::{Environment, Node, NodeEnum, Precedence}; use super::{Environment, Error, Node, NodeEnum, Precedence};
#[derive(Clone, Debug, PartialEq, PartialOrd)] #[derive(Clone, Debug, PartialEq, PartialOrd)]
pub enum Bool { pub enum Bool {
@ -10,8 +10,14 @@ pub enum Bool {
False, False,
} }
impl From<bool> for Bool {
fn from(value: bool) -> Self {
if value { Self::True } else { Self::False }
}
}
impl Node for Bool { impl Node for Bool {
fn evaluate(&self, _: &mut Environment) -> Result<Rc<NodeEnum>, String> { fn evaluate(&self, _: &mut Environment) -> Result<Rc<NodeEnum>, Error> {
Ok(Rc::new(self.clone().into())) Ok(Rc::new(self.clone().into()))
} }
@ -43,22 +49,22 @@ pub struct IfElse {
} }
impl Node for IfElse { impl Node for IfElse {
fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, String> { fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, Error> {
let condition_evaluated = self.condition.evaluate(env)?; let condition_evaluated = self.condition.evaluate(env)?;
let condition = if let NodeEnum::Bool(bool) = condition_evaluated.as_ref() { let condition = if let NodeEnum::Bool(bool) = condition_evaluated.as_ref() {
bool bool
} else { } else {
return Err(format!( return Err(Error::MismatchedType(format!(
"Cannot evaluate {} to a bool", "Cannot evaluate {} to a bool",
condition_evaluated.as_string(Some(env)) condition_evaluated.as_string(Some(env))
)); )));
}; };
fn evaluate_block( fn evaluate_block(
block: &Vec<Rc<NodeEnum>>, block: &Vec<Rc<NodeEnum>>,
env: &mut Environment, env: &mut Environment,
) -> Result<Rc<NodeEnum>, String> { ) -> Result<Rc<NodeEnum>, Error> {
env.push_stack()?; env.push_stack()?;
let ret = if let Some((last, to_evaluate)) = block.split_last() { let ret = if let Some((last, to_evaluate)) = block.split_last() {
for expr in to_evaluate { for expr in to_evaluate {
@ -89,8 +95,8 @@ impl Node for IfElse {
self.true_branch self.true_branch
.iter() .iter()
.map(|x| x.as_string(env)) .map(|x| x.as_string(env))
.reduce(|a, b| a + " " + &b) .reduce(|a, b| a + "; " + &b)
.unwrap() .unwrap_or("".to_owned())
.as_str(), .as_str(),
match &self.else_branch { match &self.else_branch {
ElseBranchEnum::ElseIf(if_else) => if_else.as_string(env), ElseBranchEnum::ElseIf(if_else) => if_else.as_string(env),
@ -100,8 +106,8 @@ impl Node for IfElse {
.iter() .iter()
.map(|x| x.as_string(env)) .map(|x| x.as_string(env))
.reduce(|a, b| a + "\n" + &b) .reduce(|a, b| a + "\n" + &b)
.unwrap() .unwrap_or("".to_owned())
+ "end", + " end",
ElseBranchEnum::None => " end".to_owned(), ElseBranchEnum::None => " end".to_owned(),
} }
.as_str() .as_str()

78
src/lib/node/loop.rs Normal file
View file

@ -0,0 +1,78 @@
use std::rc::Rc;
use crate::environment::Environment;
use super::{Error, Node, NodeEnum, Precedence, empty::Empty};
#[derive(Clone, Debug, PartialEq, PartialOrd)]
pub struct Break;
impl Node for Break {
fn evaluate(&self,_: &mut Environment) -> Result<Rc<NodeEnum>,Error> {
return Err(Error::Break);
}
fn as_string(&self,_:Option<&Environment>) -> String {
"break".to_owned()
}
fn precedence(&self) -> Precedence {
Precedence::Primary
}
}
#[derive(Clone, Debug, PartialEq, PartialOrd)]
pub struct Loop {
body: Vec<Rc<NodeEnum>>,
}
impl Node for Loop {
fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, Error> {
let mut break_loop = false;
while !break_loop {
env.push_stack()?;
for statement in self.body.iter() {
let evaluated = statement.evaluate(env);
match evaluated {
Err(Error::Break) => {
break_loop = true;
break;
}
Err(e) => {
env.pop_stack()?;
return Err(e);
}
_ => {}
}
}
env.pop_stack()?;
}
Ok(Empty::new(""))
}
fn as_string(&self, env: Option<&Environment>) -> String {
format!(
"loop {} end",
self.body
.iter()
.map(|x| x.as_string(env))
.reduce(|a, b| a + "; " + &b)
.unwrap()
.as_str()
)
}
fn precedence(&self) -> Precedence {
Precedence::Primary
}
}
impl Loop {
pub fn new(body: Vec<Rc<NodeEnum>>) -> Rc<NodeEnum> {
Rc::new(Self { body }.into())
}
}

View file

@ -3,6 +3,7 @@ use std::{fmt::Display, rc::Rc};
use add::Add; use add::Add;
use assign::Assign; use assign::Assign;
use call::Call; use call::Call;
use closure::Closure;
use comparison::{Greater, GreaterEquals, Less, LessEquals}; use comparison::{Greater, GreaterEquals, Less, LessEquals};
use constant::Constant; use constant::Constant;
use divide::Divide; use divide::Divide;
@ -12,18 +13,20 @@ use equals::Equals;
use exponent::Exponent; use exponent::Exponent;
use function::Function; use function::Function;
use if_else::{Bool, IfElse}; use if_else::{Bool, IfElse};
use r#loop::{Break, Loop};
use multiply::Multiply; use multiply::Multiply;
use range::Range;
use set::Set; use set::Set;
use string_node::StringNode;
use subtract::Subtract; use subtract::Subtract;
use symbol::Symbol; use symbol::Symbol;
use string_node::StringNode;
use closure::Closure;
use crate::environment::Environment; use crate::environment::Environment;
pub mod add; pub mod add;
pub mod assign; pub mod assign;
pub mod call; pub mod call;
pub mod closure;
pub mod comparison; pub mod comparison;
pub mod constant; pub mod constant;
pub mod divide; pub mod divide;
@ -32,13 +35,14 @@ pub mod equals;
pub mod exponent; pub mod exponent;
pub mod function; pub mod function;
pub mod if_else; pub mod if_else;
pub mod r#loop;
pub mod range;
pub mod multiply; pub mod multiply;
pub mod node_ref; pub mod node_ref;
pub mod set; pub mod set;
pub mod string_node;
pub mod subtract; pub mod subtract;
pub mod symbol; pub mod symbol;
pub mod string_node;
pub mod closure;
#[enum_dispatch] #[enum_dispatch]
#[enum_dispatch(Debug, Clone, PartialEq, PartialOrd, ToString)] #[enum_dispatch(Debug, Clone, PartialEq, PartialOrd, ToString)]
@ -58,13 +62,17 @@ pub enum NodeEnum {
Assign, Assign,
Empty, Empty,
Function, Function,
Closure, // IMPLEMENT THIS SO CURRYING WORKS Closure,
Call, Call,
Loop,
Break,
Bool, Bool,
IfElse, IfElse,
Set, Set,
Range,
Equals, Equals,
Greater, Greater,
@ -93,9 +101,59 @@ pub enum Precedence {
Primary, Primary,
} }
pub enum Error {
Break,
StackOverflow,
StackUnderflow,
/// Expected, Got
ArgumentCount(usize, usize),
MismatchedType(String),
ConversionError(String),
IllegalAssignment(String),
IllegalRhsAssignment(String),
EmptySetAssignment,
/// Expected, Got
SetAssignmentCountMismatch(usize, usize),
DivideByZero,
/// Lenght, Index
IndexOutOfBounds(usize, usize),
Other(String),
}
impl ToString for Error {
fn to_string(&self) -> String {
match self {
Error::Break => "Invalid break statement".to_owned(),
Error::StackOverflow => "Stack Overflow".to_owned(),
Error::StackUnderflow => "Stack Underflow".to_owned(),
Error::ArgumentCount(exp, got) => {
format!("Expected {} arguments, but got {}", exp, got)
}
Error::EmptySetAssignment => "Cannot assign to an empty Set".to_owned(),
Error::SetAssignmentCountMismatch(exp, got) => {
format!("Cannot define {} symbols from a Set of {} values", exp, got)
}
Error::DivideByZero => "Division by Zero!".to_owned(),
Error::IndexOutOfBounds(exp, got) => {
format!("Index {} out of bounds for Set of size {}", got, exp)
}
Error::MismatchedType(s)
| Error::ConversionError(s)
| Error::IllegalAssignment(s)
| Error::IllegalRhsAssignment(s)
| Error::Other(s) => s.to_owned(),
}
}
}
#[enum_dispatch(NodeEnum)] #[enum_dispatch(NodeEnum)]
pub trait Node { pub trait Node {
fn evaluate(&self, _: &mut Environment) -> Result<Rc<NodeEnum>, String>; fn evaluate(&self, _: &mut Environment) -> Result<Rc<NodeEnum>, Error>;
fn as_string(&self, _: Option<&Environment>) -> String; fn as_string(&self, _: Option<&Environment>) -> String;
fn precedence(&self) -> Precedence; fn precedence(&self) -> Precedence;
} }
@ -153,6 +211,7 @@ impl PartialOrd for NodeEnum {
less_equals1.partial_cmp(less_equals2) less_equals1.partial_cmp(less_equals2)
} }
// (a,b) => a.partial_cmp(b)
_ => None, _ => None,
} }
} }
@ -165,7 +224,7 @@ impl NodeEnum {
NodeEnum::StringNode(_) => "String", NodeEnum::StringNode(_) => "String",
NodeEnum::Add(_) => "Add", NodeEnum::Add(_) => "Add",
NodeEnum::Subtract(_) => "Subtract", NodeEnum::Subtract(_) => "Subtract",
NodeEnum::Multiply(_) => "Multiply", NodeEnum::Multiply(_) => "Multiply",
NodeEnum::Divide(_) => "Divide", NodeEnum::Divide(_) => "Divide",
NodeEnum::Exponent(_) => "Exponent", NodeEnum::Exponent(_) => "Exponent",
NodeEnum::Symbol(_) => "Symbol", NodeEnum::Symbol(_) => "Symbol",
@ -181,7 +240,11 @@ impl NodeEnum {
NodeEnum::Greater(_) => "Greater", NodeEnum::Greater(_) => "Greater",
NodeEnum::GreaterEquals(_) => "Greater Equals", NodeEnum::GreaterEquals(_) => "Greater Equals",
NodeEnum::Less(_) => "Less", NodeEnum::Less(_) => "Less",
NodeEnum::LessEquals(_) => "Less Equals" NodeEnum::LessEquals(_) => "Less Equals",
}.to_owned() NodeEnum::Loop(_) => "Loop",
NodeEnum::Break(_) => "Break",
NodeEnum::Range(_) => "Range",
}
.to_owned()
} }
} }

View file

@ -1,12 +1,11 @@
use std::rc::Rc; use std::{cmp::Ordering, ops::Mul, rc::Rc};
use rug::Float; use rug::Float;
use crate::environment::Environment; use crate::environment::Environment;
use super::{ use super::{
Node, NodeEnum, Precedence, add::Add, constant::Constant, divide::Divide, set::Set, add::Add, constant::Constant, divide::Divide, set::Set, subtract::Subtract, Error, Node, NodeEnum, Precedence
subtract::Subtract,
}; };
#[derive(Clone, Debug, PartialEq, PartialOrd)] #[derive(Clone, Debug, PartialEq, PartialOrd)]
@ -16,7 +15,7 @@ pub struct Multiply {
} }
impl Node for Multiply { impl Node for Multiply {
fn evaluate(&self, env: &mut super::Environment) -> Result<Rc<super::NodeEnum>, String> { fn evaluate(&self, env: &mut super::Environment) -> Result<Rc<super::NodeEnum>, Error> {
let evaluated_left = self.left.evaluate(env)?; let evaluated_left = self.left.evaluate(env)?;
let evaluated_right = self.right.evaluate(env)?; let evaluated_right = self.right.evaluate(env)?;
@ -29,51 +28,38 @@ impl Node for Multiply {
} }
// Identity rule // Identity rule
(NodeEnum::Constant(one), _) if one.get_value() == &0.0 => Ok(evaluated_right), (x, NodeEnum::Constant(one)) | (NodeEnum::Constant(one), x)
(_, NodeEnum::Constant(one)) if one.get_value() == &0.0 => Ok(evaluated_left), if one.get_value() == &1.0 =>
{
Ok(Rc::new(x.clone()))
}
// Multiply into parenthesis (add) // Multiply into parenthesis (add)
(_, NodeEnum::Add(add)) => Ok(Add::new_rc( (NodeEnum::Add(add), x) | (x, NodeEnum::Add(add)) => Ok(Add::new_rc(
Self::new_rc(evaluated_left.clone(), add.get_left()).evaluate(env)?, Multiply::new_rc(Rc::new(x.clone()), add.get_left()).evaluate(env)?,
Self::new_rc(evaluated_left, add.get_right()).evaluate(env)?, Multiply::new_rc(Rc::new(x.clone()), add.get_right()).evaluate(env)?,
)),
(NodeEnum::Add(add), _) => Ok(Add::new_rc(
Self::new_rc(evaluated_right.clone(), add.get_left()).evaluate(env)?,
Self::new_rc(evaluated_right, add.get_right()).evaluate(env)?,
)), )),
// Multiply into parenthesis (sub) // Multiply into parenthesis (sub)
(_, NodeEnum::Subtract(sub)) => Ok(Subtract::new_rc( (NodeEnum::Subtract(sub), x) | (x, NodeEnum::Subtract(sub)) => Ok(Subtract::new_rc(
Self::new_rc(evaluated_left.clone(), sub.get_left()).evaluate(env)?, Multiply::new_rc(Rc::new(x.clone()), sub.get_left()).evaluate(env)?,
Self::new_rc(evaluated_left, sub.get_right()).evaluate(env)?, Multiply::new_rc(Rc::new(x.clone()), sub.get_right()).evaluate(env)?,
)),
(NodeEnum::Subtract(sub), _) => Ok(Subtract::new_rc(
Self::new_rc(evaluated_right.clone(), sub.get_left()).evaluate(env)?,
Self::new_rc(evaluated_right, sub.get_right()).evaluate(env)?,
)), )),
// Multiply fraction // Multiply fraction
(NodeEnum::Divide(div), _) => Ok(Divide::new_rc( (x, NodeEnum::Divide(div)) | (NodeEnum::Divide(div), x) => Ok(Divide::new_rc(
Self::new_rc(evaluated_right, div.get_left()).evaluate(env)?, Self::new_rc(Rc::new(x.clone()), div.get_left()).evaluate(env)?,
div.get_right(),
)),
(_, NodeEnum::Divide(div)) => Ok(Divide::new_rc(
Self::new_rc(evaluated_left, div.get_left()).evaluate(env)?,
div.get_right(), div.get_right(),
)), )),
// 0.5*n -> n/2 // 0.5*n -> n/2
(NodeEnum::Constant(c), _) if c.get_value() == &0.5 => Divide::new( (x, NodeEnum::Constant(c)) | (NodeEnum::Constant(c), x) if c.get_value() == &0.5 => {
evaluated_right, Divide::new(
Rc::new(Constant::new_from_float(2, &env).into()), Rc::new(x.clone()),
) Rc::new(Constant::new_from_float(2, &env).into()),
.evaluate(env), )
(_, NodeEnum::Constant(c)) if c.get_value() == &0.5 => Divide::new( .evaluate(env)
evaluated_left, }
Rc::new(Constant::new_from_float(2, &env).into()),
)
.evaluate(env),
// Constant * Constant = Constant // Constant * Constant = Constant
(NodeEnum::Constant(a), NodeEnum::Constant(b)) => { (NodeEnum::Constant(a), NodeEnum::Constant(b)) => {
@ -83,18 +69,11 @@ impl Node for Multiply {
))))) )))))
} }
// Move constant infront of symbols // Multiply into sets
(NodeEnum::Symbol(_), NodeEnum::Constant(_)) (NodeEnum::Set(s), c) | (c, NodeEnum::Set(s)) => {
| (NodeEnum::Exponent(_), NodeEnum::Constant(_)) => Ok(Rc::new(
Multiply::new(evaluated_right, evaluated_left).into(),
)),
// Multiply a set with a constant
(NodeEnum::Set(s), NodeEnum::Constant(c))
| (NodeEnum::Constant(c), NodeEnum::Set(s)) => {
let old_values = s.get_values(); let old_values = s.get_values();
let mut values = Vec::with_capacity(old_values.len()); let mut values = Vec::with_capacity(old_values.len());
let c: Rc<NodeEnum> = Rc::new(c.clone().into()); let c: Rc<NodeEnum> = Rc::new(c.clone());
for value in old_values.iter() { for value in old_values.iter() {
let new_value = Multiply::new(c.clone(), value.clone()); let new_value = Multiply::new(c.clone(), value.clone());
@ -104,28 +83,76 @@ impl Node for Multiply {
Ok(Set::new(values)) Ok(Set::new(values))
} }
// Multiply a set with a constant (NodeEnum::Symbol(s1), NodeEnum::Symbol(s2)) => {
(NodeEnum::Set(s), NodeEnum::Symbol(c)) | (NodeEnum::Symbol(c), NodeEnum::Set(s)) => { if s1 > s2 {
let old_values = s.get_values(); Ok(Self::new_rc(evaluated_left, evaluated_right))
let mut values = Vec::with_capacity(old_values.len()); } else {
let c: Rc<NodeEnum> = Rc::new(c.clone().into()); Ok(Self::new_rc(evaluated_right, evaluated_left))
for value in old_values.iter() {
let new_value = Multiply::new(c.clone(), value.clone());
values.push(new_value.evaluate(env)?);
} }
Ok(Set::new(values))
} }
// (NodeEnum::Constant(c), NodeEnum::Multiply(m)) // At least one of the nodes is a nested multiply
// | (NodeEnum::Multiply(m), NodeEnum::Constant(c)) => { (NodeEnum::Multiply(m), o) | (o, NodeEnum::Multiply(m)) => {
// Self::collapse_nested_multiply(c, m, env)?.evaluate(env) // Aggregate into a single vector for easy sorting
// } let mut aggregate = vec![];
let mut queue = vec![];
queue.push(Rc::new(o.clone()));
let mut c: Rc<NodeEnum> = Rc::new(m.clone().into());
// (NodeEnum::Multiply(m1), NodeEnum::Multiply(m2)) => { loop {
// Self::move_constants_to_left(evaluated_left.clone(), evaluated_right.clone()) match c.as_ref() {
// } NodeEnum::Multiply(m) => {
queue.push(m.get_left());
queue.push(m.get_right());
}
_ => {
aggregate.push(c.clone());
}
}
if !queue.is_empty() {
c = queue.pop().unwrap();
} else {
break;
}
}
aggregate.sort_by(|a, b| match (a.as_ref(), b.as_ref()) {
(_, NodeEnum::Constant(_)) => Ordering::Less,
(NodeEnum::Constant(_), _) => Ordering::Greater,
(NodeEnum::Symbol(s1), NodeEnum::Symbol(s2)) => s1.cmp(s2),
_ => a.partial_cmp(b).unwrap_or(Ordering::Equal)
});
let mut constant = Rc::new(Constant::new_from_float(1.0, &env).into());
let mut constanted = false;
while let Some(agr) = aggregate.last() {
if let NodeEnum::Constant(_) = agr.as_ref() {
constanted = true;
constant =
Multiply::new_rc(constant, aggregate.pop().unwrap()).evaluate(env)?;
} else {
break;
}
}
let mut out = aggregate.pop().unwrap();
while let Some(a) = aggregate.pop() {
out = Multiply::new_rc(out, a);
}
if constanted {
Ok(Multiply::new_rc(constant, out))
} else {
Ok(out)
}
}
(_, NodeEnum::Constant(_)) => {
Ok(Multiply::new_rc(evaluated_right, evaluated_left))
}
// Default to returning with left and right evaluated // Default to returning with left and right evaluated
_ => Ok(Rc::new( _ => Ok(Rc::new(
@ -135,12 +162,16 @@ impl Node for Multiply {
} }
fn as_string(&self, env: Option<&super::Environment>) -> String { fn as_string(&self, env: Option<&super::Environment>) -> String {
let left_string = if self.left.precedence() <= self.precedence() { let left_string = if let NodeEnum::Multiply(_) = self.left.as_ref() {
self.left.as_string(env)
} else if self.left.precedence() <= self.precedence() {
format!("({})", self.left.as_string(env)) format!("({})", self.left.as_string(env))
} else { } else {
self.left.as_string(env) self.left.as_string(env)
}; };
let right_string = if self.right.precedence() <= self.precedence() { let right_string = if let NodeEnum::Multiply(_) = self.right.as_ref() {
self.right.as_string(env)
} else if self.right.precedence() <= self.precedence() {
format!("({})", self.right.as_string(env)) format!("({})", self.right.as_string(env))
} else { } else {
self.right.as_string(env) self.right.as_string(env)
@ -154,76 +185,14 @@ impl Node for Multiply {
} }
impl Multiply { impl Multiply {
fn collapse_nested_multiply( pub fn symbols_match(&self, other: &Multiply) -> bool {
constant: &Constant, if let NodeEnum::Constant(_) = self.left.as_ref() {
multiply: &Multiply, if let NodeEnum::Constant(_) = other.left.as_ref() {
env: &mut Environment, return self.right.eq(&other.right);
) -> Result<Rc<NodeEnum>, String> {
match (multiply.left.as_ref(), multiply.right.as_ref()) {
(NodeEnum::Constant(c2), _) => {
let new_const = Constant::new(Float::with_val_64(
env.get_float_precision(),
constant.get_value() * c2.get_value(),
))
.into();
Ok(Rc::new(
Multiply::new(Rc::new(new_const), multiply.right.clone()).into(),
))
} }
(_, NodeEnum::Constant(c2)) => {
let new_const = Constant::new(Float::with_val_64(
env.get_float_precision(),
constant.get_value() * c2.get_value(),
))
.into();
Ok(Rc::new(
Multiply::new(Rc::new(new_const), multiply.right.clone()).into(),
))
}
(_, NodeEnum::Multiply(inner_mul)) => {
let expr = Self::collapse_nested_multiply(constant, inner_mul, env)?;
Ok(Rc::new(Multiply::new(expr, multiply.left.clone()).into()))
}
(NodeEnum::Multiply(inner_mul), _) => {
let expr = Self::collapse_nested_multiply(constant, inner_mul, env)?;
Ok(Rc::new(Multiply::new(expr, multiply.right.clone()).into()))
}
_ => Ok(Rc::new(
Multiply::new(
Rc::new(constant.clone().into()),
Rc::new(multiply.clone().into()),
)
.into(),
)),
} }
}
#[allow(dead_code)] self.eq(other)
fn move_constants_to_left(
left: Rc<NodeEnum>,
right: Rc<NodeEnum>,
) -> Result<Rc<NodeEnum>, String> {
match (left.as_ref(), right.as_ref()) {
// Default cases that returns
(NodeEnum::Constant(_), NodeEnum::Multiply(_))
| (NodeEnum::Symbol(_), NodeEnum::Symbol(_)) => Ok(Self::new_rc(left, right)),
(NodeEnum::Multiply(m), NodeEnum::Constant(_c)) => Ok(Self::new_rc(
right.clone(),
Self::move_constants_to_left(m.left.clone(), m.right.clone())?,
)),
(NodeEnum::Multiply(m1), NodeEnum::Multiply(m2)) => Ok(Self::new_rc(
Self::move_constants_to_left(m1.left.clone(), m1.right.clone())?,
Self::move_constants_to_left(m2.left.clone(), m2.right.clone())?,
)),
_ => Ok(Self::new_rc(left, right)),
}
} }
} }

View file

@ -1,6 +1,6 @@
use std::rc::Rc; use std::rc::Rc;
use super::{Environment, Node, NodeEnum, Precedence}; use super::{Environment, Error, Node, NodeEnum, Precedence};
#[derive(Debug, Clone, PartialEq, PartialOrd)] #[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct NodeRef { pub struct NodeRef {
@ -8,7 +8,7 @@ pub struct NodeRef {
} }
impl Node for NodeRef { impl Node for NodeRef {
fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, String> { fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, Error> {
self.value.evaluate(env) self.value.evaluate(env)
} }

43
src/lib/node/range.rs Normal file
View file

@ -0,0 +1,43 @@
use std::rc::Rc;
use crate::environment::Environment;
use super::{Error, Node, NodeEnum, Precedence, constant::ConstantValue};
#[derive(Clone, Debug, PartialEq, PartialOrd)]
pub struct Range {
pub from: ConstantValue,
pub to: ConstantValue,
}
impl Node for Range {
fn evaluate(&self, _: &mut Environment) -> Result<Rc<NodeEnum>, Error> {
Ok(Rc::new(self.clone().into()))
}
fn as_string(&self, _: Option<&Environment>) -> String {
format!(
"{}..{}",
self.from
.to_string_radix(10, Some(8))
.trim_end_matches('0')
.trim_end_matches('.')
.to_string(),
self.to
.to_string_radix(10, Some(8))
.trim_end_matches('0')
.trim_end_matches('.')
.to_string()
)
}
fn precedence(&self) -> Precedence {
Precedence::Primary
}
}
impl Range {
pub fn new(from: ConstantValue, to: ConstantValue) -> Rc<NodeEnum> {
Rc::new(Self { from, to }.into())
}
}

View file

@ -1,6 +1,6 @@
use std::rc::Rc; use std::rc::Rc;
use super::{Environment, Node, NodeEnum, Precedence}; use super::{Environment, Error, Node, NodeEnum, Precedence, constant::Constant};
#[derive(Clone, Debug, PartialEq, PartialOrd)] #[derive(Clone, Debug, PartialEq, PartialOrd)]
pub struct Set { pub struct Set {
@ -8,9 +8,22 @@ pub struct Set {
} }
impl Node for Set { impl Node for Set {
fn evaluate(&self, env: &mut super::Environment) -> Result<Rc<NodeEnum>, String> { fn evaluate(&self, env: &mut super::Environment) -> Result<Rc<NodeEnum>, Error> {
let mut values = Vec::with_capacity(self.values.len()); let mut values = Vec::with_capacity(self.values.len());
if self.values.len() == 1 {
let evaluated = self.values.first().unwrap().evaluate(env)?;
if let NodeEnum::Range(r) = evaluated.as_ref() {
let mut i = r.from.clone();
while i < r.to {
values.push(Rc::new(Constant::new(i.clone()).into()));
i += 1;
}
return Ok(Self::new(values));
}
}
for value in self.values.iter() { for value in self.values.iter() {
values.push(value.evaluate(env)?); values.push(value.evaluate(env)?);
} }

View file

@ -1,6 +1,6 @@
use std::rc::Rc; use std::rc::Rc;
use super::{Environment, Node, NodeEnum, Precedence}; use super::{Environment, Error, Node, NodeEnum, Precedence};
#[derive(Clone, Debug, PartialEq, PartialOrd)] #[derive(Clone, Debug, PartialEq, PartialOrd)]
pub struct StringNode { pub struct StringNode {
@ -14,7 +14,7 @@ impl From<String> for StringNode {
} }
impl Node for StringNode { impl Node for StringNode {
fn evaluate(&self, _: &mut super::Environment) -> Result<Rc<super::NodeEnum>, String> { fn evaluate(&self, _: &mut super::Environment) -> Result<Rc<super::NodeEnum>, Error> {
Ok(Rc::new(self.clone().into())) Ok(Rc::new(self.clone().into()))
} }

View file

@ -2,7 +2,7 @@ use std::rc::Rc;
use rug::Float; use rug::Float;
use super::{Environment, Node, NodeEnum, Precedence, constant::Constant, multiply::Multiply}; use super::{constant::Constant, multiply::Multiply, Environment, Error, Node, NodeEnum, Precedence};
#[derive(Clone, Debug, PartialEq, PartialOrd)] #[derive(Clone, Debug, PartialEq, PartialOrd)]
pub struct Subtract { pub struct Subtract {
@ -11,7 +11,7 @@ pub struct Subtract {
} }
impl Node for Subtract { impl Node for Subtract {
fn evaluate(&self, env: &mut super::Environment) -> Result<Rc<super::NodeEnum>, String> { fn evaluate(&self, env: &mut super::Environment) -> Result<Rc<super::NodeEnum>, Error> {
let evaluated_left = self.left.evaluate(env)?; let evaluated_left = self.left.evaluate(env)?;
let evaluated_right = self.right.evaluate(env)?; let evaluated_right = self.right.evaluate(env)?;
@ -36,51 +36,60 @@ impl Node for Subtract {
Subtract::new(evaluated_right, evaluated_left).into(), Subtract::new(evaluated_right, evaluated_left).into(),
)), )),
// (NodeEnum::Multiply(m1), NodeEnum::Multiply(m2)) => {
// match (
// (m1.get_left().as_ref(), m1.get_right().as_ref()),
// (m2.get_left().as_ref(), m2.get_right().as_ref()),
// ) {
// ((NodeEnum::Symbol(s1), o1), (NodeEnum::Symbol(s2), o2))
// | ((o1, NodeEnum::Symbol(s1)), (NodeEnum::Symbol(s2), o2))
// | ((NodeEnum::Symbol(s1), o1), (o2, NodeEnum::Symbol(s2)))
// | ((o1, NodeEnum::Symbol(s1)), (o2, NodeEnum::Symbol(s2))) => {
// if s1 == s2 {
// Multiply::new_rc(
// Subtract::new(Rc::new(o1.clone()), Rc::new(o2.clone()))
// .evaluate(env)?,
// Rc::new(s1.clone().into()),
// )
// .evaluate(env)
// } else {
// Ok(Rc::new(
// Subtract::new(evaluated_left, evaluated_right).into(),
// ))
// }
// }
//
// ((NodeEnum::Exponent(e1), o1), (NodeEnum::Exponent(e2), o2))
// | ((o1, NodeEnum::Exponent(e1)), (NodeEnum::Exponent(e2), o2))
// | ((NodeEnum::Exponent(e1), o1), (o2, NodeEnum::Exponent(e2)))
// | ((o1, NodeEnum::Exponent(e1)), (o2, NodeEnum::Exponent(e2))) => {
// if e1 == e2 {
// Multiply::new_rc(
// Subtract::new(Rc::new(o1.clone()), Rc::new(o2.clone()))
// .evaluate(env)?,
// Rc::new(e1.clone().into()),
// )
// .evaluate(env)
// } else {
// Ok(Rc::new(
// Subtract::new(evaluated_left, evaluated_right).into(),
// ))
// }
// }
//
// _ => Ok(Rc::new(
// Subtract::new(evaluated_left, evaluated_right).into(),
// )),
// }
// }
(NodeEnum::Multiply(m1), NodeEnum::Multiply(m2)) => { (NodeEnum::Multiply(m1), NodeEnum::Multiply(m2)) => {
match ( if m1.symbols_match(m2) {
(m1.get_left().as_ref(), m1.get_right().as_ref()), return Ok(Multiply::new_rc(
(m2.get_left().as_ref(), m2.get_right().as_ref()), Subtract::new_rc(m1.get_left(), m2.get_left()).evaluate(env)?,
) { m1.get_right(),
((NodeEnum::Symbol(s1), o1), (NodeEnum::Symbol(s2), o2)) ));
| ((o1, NodeEnum::Symbol(s1)), (NodeEnum::Symbol(s2), o2))
| ((NodeEnum::Symbol(s1), o1), (o2, NodeEnum::Symbol(s2)))
| ((o1, NodeEnum::Symbol(s1)), (o2, NodeEnum::Symbol(s2))) => {
if s1 == s2 {
Multiply::new_rc(
Subtract::new(Rc::new(o1.clone()), Rc::new(o2.clone()))
.evaluate(env)?,
Rc::new(s1.clone().into()),
)
.evaluate(env)
} else {
Ok(Rc::new(
Subtract::new(evaluated_left, evaluated_right).into(),
))
}
}
((NodeEnum::Exponent(e1), o1), (NodeEnum::Exponent(e2), o2))
| ((o1, NodeEnum::Exponent(e1)), (NodeEnum::Exponent(e2), o2))
| ((NodeEnum::Exponent(e1), o1), (o2, NodeEnum::Exponent(e2)))
| ((o1, NodeEnum::Exponent(e1)), (o2, NodeEnum::Exponent(e2))) => {
if e1 == e2 {
Multiply::new_rc(
Subtract::new(Rc::new(o1.clone()), Rc::new(o2.clone()))
.evaluate(env)?,
Rc::new(e1.clone().into()),
)
.evaluate(env)
} else {
Ok(Rc::new(
Subtract::new(evaluated_left, evaluated_right).into(),
))
}
}
_ => Ok(Rc::new(
Subtract::new(evaluated_left, evaluated_right).into(),
)),
} }
Ok(Subtract::new_rc(evaluated_left, evaluated_right))
} }
_ => { _ => {

View file

@ -1,6 +1,6 @@
use std::rc::Rc; use std::rc::Rc;
use super::{Environment, Node, NodeEnum, Precedence}; use super::{Environment, Error, Node, NodeEnum, Precedence};
use crate::environment::EnvironmentInternalSymbolKey; use crate::environment::EnvironmentInternalSymbolKey;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
@ -9,7 +9,7 @@ pub struct Symbol {
} }
impl Node for Symbol { impl Node for Symbol {
fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, String> { fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, Error> {
if let Some(value) = env.get(&self.value) { if let Some(value) = env.get(&self.value) {
// TODO: Detect cyclic references and make sure they get // TODO: Detect cyclic references and make sure they get
// deleted at some point // deleted at some point
@ -60,7 +60,15 @@ impl Symbol {
} }
impl PartialOrd for Symbol { impl PartialOrd for Symbol {
fn partial_cmp(&self, _other: &Self) -> Option<std::cmp::Ordering> { fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
None other.value.partial_cmp(&self.value)
}
}
impl Eq for Symbol {}
impl Ord for Symbol {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
other.value.cmp(&self.value)
} }
} }

View file

@ -21,7 +21,9 @@ use crate::{
exponent::Exponent, exponent::Exponent,
function::{Function, FunctionType}, function::{Function, FunctionType},
if_else::{Bool, ElseBranchEnum, IfElse}, if_else::{Bool, ElseBranchEnum, IfElse},
r#loop::{Break, Loop},
multiply::Multiply, multiply::Multiply,
range::Range,
set::Set, set::Set,
string_node::StringNode, string_node::StringNode,
subtract::Subtract, subtract::Subtract,
@ -39,6 +41,8 @@ pub enum TokenType {
Identifier(String), Identifier(String),
String(String), String(String),
DoubleDot,
Plus, Plus,
Minus, Minus,
Star, Star,
@ -53,6 +57,7 @@ pub enum TokenType {
ColonEquals, ColonEquals,
LeftArrow, LeftArrow,
RightArrow,
RParen, RParen,
LParen, LParen,
@ -66,6 +71,10 @@ pub enum TokenType {
Else, Else,
End, End,
Loop,
Block,
Break,
True, True,
False, False,
@ -78,6 +87,8 @@ impl TokenType {
TokenType::Number(n) => n.to_string().len(), TokenType::Number(n) => n.to_string().len(),
TokenType::Identifier(s) | TokenType::String(s) => s.len(), TokenType::Identifier(s) | TokenType::String(s) => s.len(),
TokenType::DoubleDot => 2,
TokenType::Plus => 1, TokenType::Plus => 1,
TokenType::Minus => 1, TokenType::Minus => 1,
TokenType::Star => 1, TokenType::Star => 1,
@ -92,6 +103,7 @@ impl TokenType {
TokenType::ColonEquals => 2, TokenType::ColonEquals => 2,
TokenType::LeftArrow => 2, TokenType::LeftArrow => 2,
TokenType::RightArrow => 2,
TokenType::RParen => 1, TokenType::RParen => 1,
TokenType::LParen => 1, TokenType::LParen => 1,
@ -105,6 +117,10 @@ impl TokenType {
TokenType::Else => 4, TokenType::Else => 4,
TokenType::End => 3, TokenType::End => 3,
TokenType::Loop => 4,
TokenType::Block => 5,
TokenType::Break => 5,
TokenType::True => 4, TokenType::True => 4,
TokenType::False => 5, TokenType::False => 5,
@ -149,19 +165,38 @@ impl<'a> Lexer<'a> {
i += 1; i += 1;
} }
} }
// Numbers with decimal points // Double period ..
'.' if self.source.peek() == Some(&'.') => {
self.source.next();
i += 1;
tokens.push(Token(i, TokenType::DoubleDot));
}
// Numbers
'0'..='9' | '.' => { '0'..='9' | '.' => {
let mut digit = String::from(c); let mut digits = String::from(c);
let mut has_decimal = c == '.'; let mut has_decimal = c == '.';
let mut push = true;
loop { loop {
let d = self.source.peek(); let d = self.source.peek();
match d { match d {
Some('0'..='9') => { Some('0'..='9') => {
digit.push(*d.unwrap()); digits.push(self.source.next().unwrap());
self.source.next();
i += 1; i += 1;
} }
Some('.') => { Some('.') => {
let current = self.source.next();
if self.source.peek() == Some(&'.') {
// useless clone, TODO: Report this
tokens.push(Token(i, TokenType::Number(digits.clone())));
push = false;
self.source.next();
i += 2;
tokens.push(Token(i, TokenType::DoubleDot));
break;
}
if has_decimal { if has_decimal {
return Err(LexerError::UnexpectedChar( return Err(LexerError::UnexpectedChar(
i + 1, i + 1,
@ -169,8 +204,7 @@ impl<'a> Lexer<'a> {
)); ));
} }
digit.push(*d.unwrap()); digits.push(current.unwrap());
self.source.next();
i += 1; i += 1;
has_decimal = true; has_decimal = true;
} }
@ -179,16 +213,10 @@ impl<'a> Lexer<'a> {
} }
} }
} }
// if let Some(v) = {
// v
// } else {
// return Err(LexerError::NumberParse(
// i,
// format!("Failed to convert {digit} to a number"),
// ));
// };
tokens.push(Token(i, TokenType::Number(digit))); if push {
tokens.push(Token(i, TokenType::Number(digits)));
}
} }
'"' => { '"' => {
@ -221,6 +249,11 @@ impl<'a> Lexer<'a> {
i += 1; i += 1;
tokens.push(Token(i, TokenType::LeftArrow)); tokens.push(Token(i, TokenType::LeftArrow));
} }
'<' if self.source.peek() == Some(&'-') => {
self.source.next();
i += 1;
tokens.push(Token(i, TokenType::RightArrow));
}
'<' if self.source.peek() == Some(&'=') => { '<' if self.source.peek() == Some(&'=') => {
self.source.next(); self.source.next();
@ -261,10 +294,14 @@ impl<'a> Lexer<'a> {
tokens.push(self.lex_identifier(&mut i, c)?); tokens.push(self.lex_identifier(&mut i, c)?);
} }
'\n' => {
continue;
}
_ => { _ => {
return Err(LexerError::UnexpectedChar( return Err(LexerError::UnexpectedChar(
i, i,
format!("Unexpected char {}", c), format!("Unexpected char {c} ({c:?})"),
)); ));
} }
} }
@ -295,6 +332,10 @@ impl<'a> Lexer<'a> {
"else" => TokenType::Else, "else" => TokenType::Else,
"end" => TokenType::End, "end" => TokenType::End,
"loop" => TokenType::Loop,
"block" => TokenType::Block,
"break" => TokenType::Break,
"true" => TokenType::True, "true" => TokenType::True,
"false" => TokenType::False, "false" => TokenType::False,
@ -411,7 +452,9 @@ impl<'a> Parser<'a> {
let expr = self.equality()?; let expr = self.equality()?;
if self.match_type(TokenType::ColonEquals) { if self.match_type(TokenType::ColonEquals) {
return Ok(Rc::new(Assign::new(expr, self.equality()?).into())); return Ok(Rc::new(Assign::new(expr, self.equality()?, true).into()));
} else if self.match_type(TokenType::RightArrow) {
return Ok(Rc::new(Assign::new(expr, self.equality()?, false).into()));
} }
Ok(expr) Ok(expr)
@ -472,28 +515,25 @@ impl<'a> Parser<'a> {
} }
fn term(&mut self) -> Result<Rc<NodeEnum>, ParserError> { fn term(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
let expr = self.factor()?; let mut expr = self.factor()?;
if self.match_type(TokenType::Plus) { loop {
Ok(Rc::new(Add::new(expr, self.comparison()?).into())) if self.match_type(TokenType::Plus) {
} else if let Some(Token(_, TokenType::Minus)) = self.tokens.peek() { let right = self.factor()?;
self.consume(); expr = Add::new_rc(expr, right);
Ok(Rc::new(Subtract::new(expr, self.comparison()?).into())) continue;
} else { } else if self.match_type(TokenType::Minus) {
Ok(expr) let right = self.factor()?;
expr = Subtract::new_rc(expr, right);
continue;
}
break;
} }
Ok(expr)
} }
fn factor(&mut self) -> Result<Rc<NodeEnum>, ParserError> { fn factor(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
let mut expr = self.unary()?; let mut expr = self.unary()?;
// if let Some(Token(_, TokenType::Star)) = self.tokens.peek() {
// self.consume();
// Ok(Rc::new(Multiply::new(expr, self.comparison()?).into()))
// } else if let Some(Token(_, TokenType::Slash)) = self.tokens.peek() {
// self.consume();
// Ok(Rc::new(Divide::new(expr, self.comparison()?).into()))
// } else {
// Ok(expr)
// }
loop { loop {
if self.match_type(TokenType::Star) { if self.match_type(TokenType::Star) {
@ -508,6 +548,23 @@ impl<'a> Parser<'a> {
break; break;
} }
// // Implicit multiplication
// if !self.is_at_end() {
// match self.tokens.peek().unwrap() {
// Token(_, TokenType::Identifier(_)) | Token(_, TokenType::Number(_)) => {
// return Ok(Multiply::new_rc(expr, self.equality()?));
// }
// Token(_, TokenType::LParen) => {
// if let NodeEnum::Symbol(_) = expr.as_ref() {
// return Ok(expr);
// }
//
// return Ok(Multiply::new_rc(expr, self.equality()?));
// }
// _ => {}
// }
// }
Ok(expr) Ok(expr)
} }
@ -603,6 +660,7 @@ impl<'a> Parser<'a> {
Assign::new( Assign::new(
expr, expr,
Function::new(FunctionType::UserFunction(body, arguments)), Function::new(FunctionType::UserFunction(body, arguments)),
true,
) )
.into(), .into(),
)); ));
@ -700,6 +758,7 @@ impl<'a> Parser<'a> {
)); ));
} }
expressions.push(self.expression()?); expressions.push(self.expression()?);
let _ = self.match_type(TokenType::Terminator);
} }
ElseBranchEnum::Block(expressions) ElseBranchEnum::Block(expressions)
@ -712,6 +771,19 @@ impl<'a> Parser<'a> {
return Ok(IfElse::new(condition, expressions, else_branch)); return Ok(IfElse::new(condition, expressions, else_branch));
} }
self.r#loop()
}
fn r#loop(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
if self.match_type(TokenType::Loop) {
let mut body = vec![];
while !self.match_type(TokenType::End) {
body.push(self.expression()?);
let _ = self.match_type(TokenType::Terminator);
}
return Ok(Loop::new(body));
}
self.set() self.set()
} }
@ -754,7 +826,39 @@ impl<'a> Parser<'a> {
return Ok(Set::new(values)); return Ok(Set::new(values));
} }
self.primary() self.range()
}
fn range(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
let exp = self.primary()?;
if self.match_type(TokenType::DoubleDot) {
let to = self.primary()?;
let from = match exp.as_ref() {
NodeEnum::Constant(c) => c.get_value().clone(),
_ => {
return Err(ParserError::UnexpectedNode(
self.previous.as_ref().unwrap().0,
"Expected a Constant here".to_owned(),
));
}
};
let to = match to.as_ref() {
NodeEnum::Constant(c) => c.get_value().clone(),
_ => {
return Err(ParserError::UnexpectedNode(
self.previous.as_ref().unwrap().0,
"Expected a Constant here".to_owned(),
));
}
};
return Ok(Range::new(from, to));
}
Ok(exp)
} }
fn primary(&mut self) -> Result<Rc<NodeEnum>, ParserError> { fn primary(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
@ -784,6 +888,8 @@ impl<'a> Parser<'a> {
TokenType::True => Ok(Rc::new(Bool::True.into())), TokenType::True => Ok(Rc::new(Bool::True.into())),
TokenType::False => Ok(Rc::new(Bool::False.into())), TokenType::False => Ok(Rc::new(Bool::False.into())),
TokenType::Break => Ok(Rc::new(Break.into())),
TokenType::String(s) => Ok(StringNode::new(s)), TokenType::String(s) => Ok(StringNode::new(s)),
TokenType::LParen => { TokenType::LParen => {
@ -814,23 +920,6 @@ impl<'a> Parser<'a> {
)), )),
}; };
// Implicit multiplication
if !self.is_at_end() {
match self.tokens.peek().unwrap() {
Token(_, TokenType::Identifier(_)) | Token(_, TokenType::Number(_)) => {
return Ok(Multiply::new_rc(expr?, self.primary()?));
}
Token(_, TokenType::LParen) if expr.is_ok() => {
if let NodeEnum::Symbol(_) = expr.as_ref().unwrap().as_ref() {
return expr;
}
return Ok(Multiply::new_rc(expr?, self.primary()?));
}
_ => {}
}
}
expr expr
} }
} }

33
test.txt Normal file
View file

@ -0,0 +1,33 @@
zip(x,y) :=
if (length(x) = length(y)) = false then
break
else
out := [];
i := 0;
loop
if i = length(x) then
break
end
out <- out + [[get(x,i), get(y,i)]];
i <- i+1
end;
out
end;
fact'(a,x) :=
block
loop
if x < 1 then
break
end
a <- a*x
x <- x-1
end;
a
end;
fact(x) := fact'(1,x);
print(fact(5))