did some grinding off camera
This commit is contained in:
parent
cd758a7fce
commit
f6909e5e23
206
README.md
Normal file
206
README.md
Normal 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`
|
196
src/cli-repl.rs
196
src/cli-repl.rs
|
@ -1,6 +1,7 @@
|
|||
use std::f64;
|
||||
use std::io::{self, StdoutLock, Write, stdout};
|
||||
use std::fs::File;
|
||||
use std::io::{self, Read, StdoutLock, Write, stdout};
|
||||
use std::rc::Rc;
|
||||
use std::{env, f64};
|
||||
|
||||
use libopenbirch::environment::{Environment, EnvironmentInternalSymbolKey};
|
||||
use libopenbirch::node::call::Call;
|
||||
|
@ -8,7 +9,7 @@ use libopenbirch::node::constant::Constant;
|
|||
use libopenbirch::node::empty::Empty;
|
||||
use libopenbirch::node::set::Set;
|
||||
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 termion::color;
|
||||
use termion::event::Key;
|
||||
|
@ -73,7 +74,9 @@ impl Input {
|
|||
return Err(io::Error::from(io::ErrorKind::Interrupted));
|
||||
}
|
||||
|
||||
if self.buffer.trim().len() > 0 {
|
||||
self.history.insert(0, self.buffer.clone());
|
||||
}
|
||||
let r = self.buffer.clone();
|
||||
self.buffer.clear();
|
||||
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 {
|
||||
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(""))
|
||||
}
|
||||
|
||||
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 {
|
||||
if let NodeEnum::StringNode(string) = arg.as_ref() {
|
||||
if let Some(id) = env.str_to_id(string.get_value()) {
|
||||
env.undefine(*id);
|
||||
}
|
||||
} else {
|
||||
return Err(format!(
|
||||
return Err(Error::MismatchedType(format!(
|
||||
"Expected strings, but one of the arguments was a {}",
|
||||
arg.type_str()
|
||||
));
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -228,7 +231,7 @@ fn unset(args: &Vec<Rc<NodeEnum>>, env: &mut Environment) -> Result<Rc<NodeEnum>
|
|||
fn get_float_precision(
|
||||
args: &Vec<Rc<NodeEnum>>,
|
||||
env: &mut Environment,
|
||||
) -> Result<Rc<NodeEnum>, String> {
|
||||
) -> Result<Rc<NodeEnum>, Error> {
|
||||
match args.len() {
|
||||
0 => Ok(Rc::new(
|
||||
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()))
|
||||
} else {
|
||||
Err(format!(
|
||||
Err(Error::MismatchedType(format!(
|
||||
"Expected argument of type Constant, but got {}",
|
||||
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(
|
||||
args: &Vec<Rc<NodeEnum>>,
|
||||
env: &mut Environment,
|
||||
) -> Result<Rc<NodeEnum>, String> {
|
||||
) -> Result<Rc<NodeEnum>, Error> {
|
||||
if args.len() != 1 {
|
||||
Err(format!("Expected 1 arguments, got {}", args.len()))?
|
||||
Err(Error::ArgumentCount(1, args.len()))?
|
||||
}
|
||||
|
||||
let arg = args.first().unwrap();
|
||||
|
@ -263,10 +269,10 @@ fn set_float_precision(
|
|||
let precision: u64 = if let NodeEnum::Constant(value) = arg.as_ref() {
|
||||
value.get_value().to_u32_saturating().unwrap().into()
|
||||
} else {
|
||||
Err(format!(
|
||||
Err(Error::MismatchedType(format!(
|
||||
"Expected argument of type Constant, but got {}",
|
||||
arg.type_str()
|
||||
))?
|
||||
)))?
|
||||
};
|
||||
|
||||
env.set_float_precision(precision);
|
||||
|
@ -274,28 +280,28 @@ fn set_float_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 {
|
||||
Err(format!("Expected 2 argument but got {}", args.len()))?
|
||||
Err(Error::ArgumentCount(2, args.len()))?
|
||||
}
|
||||
|
||||
let arg = args.first().unwrap();
|
||||
let func = match arg.as_ref() {
|
||||
NodeEnum::Function(_) | NodeEnum::Closure(_) => arg,
|
||||
_ => Err(format!(
|
||||
_ => Err(Error::MismatchedType(format!(
|
||||
"Argument 1 expected a Function but got {}",
|
||||
arg.type_str()
|
||||
))?,
|
||||
)))?,
|
||||
};
|
||||
|
||||
let arg = args.get(1).unwrap().as_ref();
|
||||
let set = if let NodeEnum::Set(set) = arg {
|
||||
set.get_values()
|
||||
} else {
|
||||
return Err(format!(
|
||||
return Err(Error::MismatchedType(format!(
|
||||
"Argument 1 expected a Set but got {}",
|
||||
arg.type_str()
|
||||
))?;
|
||||
)))?;
|
||||
};
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
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 {
|
||||
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() {
|
||||
set.get_values()
|
||||
} else {
|
||||
return Err(format!(
|
||||
return Err(Error::MismatchedType(format!(
|
||||
"Argument 1 expected Set but got {}",
|
||||
args.first().unwrap().type_str()
|
||||
));
|
||||
)));
|
||||
};
|
||||
|
||||
let idx = if let NodeEnum::Constant(c) = args.get(1).unwrap().as_ref() {
|
||||
if let Some(u) = c.get_value().to_u32_saturating() {
|
||||
u as usize
|
||||
} else {
|
||||
return Err(
|
||||
return Err(Error::ConversionError(
|
||||
"Error occured while trying to convert second argument to integer".to_owned(),
|
||||
);
|
||||
));
|
||||
}
|
||||
} 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) {
|
||||
return Ok(v.clone());
|
||||
}
|
||||
|
||||
return Err(format!(
|
||||
"Index was out of bounds for Set of length {}",
|
||||
set.len()
|
||||
));
|
||||
return Err(Error::IndexOutOfBounds(set.len(), idx));
|
||||
}
|
||||
|
||||
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 {
|
||||
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() {
|
||||
set.get_values()
|
||||
} 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(
|
||||
|
@ -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 {
|
||||
Err(format!("Expected 1 argument but got {}", args.len()))?
|
||||
Err(Error::ArgumentCount(1, args.len()))?
|
||||
}
|
||||
|
||||
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]))
|
||||
}
|
||||
|
||||
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 {
|
||||
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() {
|
||||
set.get_values()
|
||||
} else {
|
||||
return Err(format!(
|
||||
return Err(Error::MismatchedType(format!(
|
||||
"Expected a Set but got a {}",
|
||||
args.first().unwrap().type_str()
|
||||
));
|
||||
)));
|
||||
};
|
||||
|
||||
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)]))
|
||||
}
|
||||
|
||||
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 {
|
||||
return Err(format!("Expected 1-2 argument but got {}", args.len()));
|
||||
return Err(Error::ArgumentCount(2, args.len()));
|
||||
}
|
||||
|
||||
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() {
|
||||
symbol.get_value()
|
||||
} else {
|
||||
return Err(format!(
|
||||
return Err(Error::MismatchedType(format!(
|
||||
"Argument 2 is expected to be a Symbol but got a {}",
|
||||
args.get(1).unwrap().type_str()
|
||||
));
|
||||
)));
|
||||
};
|
||||
|
||||
todo!()
|
||||
|
@ -429,31 +457,7 @@ fn diff_internally(
|
|||
todo!()
|
||||
}
|
||||
|
||||
fn main() -> Result<(), io::Error> {
|
||||
let mut input = Input::new();
|
||||
|
||||
let mut env = Environment::new();
|
||||
|
||||
env.set_float_precision(128);
|
||||
|
||||
env.define_native_function("print", print);
|
||||
env.define_native_function("unset", unset);
|
||||
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);
|
||||
|
||||
env.define(
|
||||
"pi",
|
||||
Rc::new(Constant::new_from_float(std::f64::consts::PI, &env).into()),
|
||||
);
|
||||
|
||||
while let Some(source) = input.get()? {
|
||||
input.disable_raw()?;
|
||||
|
||||
fn evaluate(source: &String, mut env: &mut Environment, verbose: bool) {
|
||||
let mut lexer = Lexer::new(&source);
|
||||
let tokens_result = lexer.lex();
|
||||
|
||||
|
@ -461,7 +465,7 @@ fn main() -> Result<(), io::Error> {
|
|||
match tokens_result.err().unwrap() {
|
||||
LexerError::UnexpectedChar(i, exp) => print_err(i, 1, exp),
|
||||
}
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
|
||||
let tokens = tokens_result.unwrap();
|
||||
|
@ -478,7 +482,7 @@ fn main() -> Result<(), io::Error> {
|
|||
print_err(i, 1, exp)
|
||||
}
|
||||
}
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -487,10 +491,54 @@ fn main() -> Result<(), io::Error> {
|
|||
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),
|
||||
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();
|
||||
|
||||
env.set_float_precision(128);
|
||||
|
||||
env.define_native_function("print", print);
|
||||
env.define_native_function("unset", unset);
|
||||
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);
|
||||
env.define_native_function("mult_equals", mult_equal);
|
||||
|
||||
env.define(
|
||||
"pi",
|
||||
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()? {
|
||||
input.disable_raw()?;
|
||||
|
||||
evaluate(&source, &mut env, true);
|
||||
|
||||
input.enable_raw()?;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::{collections::HashMap, rc::Rc};
|
||||
|
||||
use crate::node::{
|
||||
NodeEnum,
|
||||
Error, NodeEnum,
|
||||
function::{Function, FunctionType, NativeFunctionType},
|
||||
};
|
||||
|
||||
|
@ -90,11 +90,11 @@ impl Environment {
|
|||
self.enable_closures
|
||||
}
|
||||
|
||||
pub fn push_stack(&mut self) -> Result<(), String> {
|
||||
if self.stack_depth == self.max_stack_depth {
|
||||
self.unwind_stack();
|
||||
return Err("Max Stack depth exceeded".to_owned());
|
||||
}
|
||||
pub fn push_stack(&mut self) -> Result<(), Error> {
|
||||
// if self.stack_depth == self.max_stack_depth {
|
||||
// // self.unwind_stack();
|
||||
// return Err("Max Stack depth exceeded".to_owned());
|
||||
// }
|
||||
|
||||
self.stack_depth += 1;
|
||||
self.stack_sizes.push(Scope {
|
||||
|
@ -107,9 +107,9 @@ impl Environment {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn pop_stack(&mut self) -> Result<(), String> {
|
||||
pub fn pop_stack(&mut self) -> Result<(), Error> {
|
||||
if self.stack_depth == 0 {
|
||||
return Err("Trying to pop empty stack".to_owned());
|
||||
return Err(Error::StackUnderflow);
|
||||
}
|
||||
|
||||
self.stack_depth -= 1;
|
||||
|
@ -126,15 +126,20 @@ impl Environment {
|
|||
}
|
||||
|
||||
fn unwind_stack(&mut self) {
|
||||
for scope in &self.stack_sizes {
|
||||
for _ in 0..scope.stack_len {
|
||||
self.map.remove(&self.stack.pop().unwrap());
|
||||
}
|
||||
}
|
||||
// for scope in &self.stack_sizes {
|
||||
// for _ in 0..scope.stack_len {
|
||||
// self.map.remove(&self.stack.pop().unwrap());
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// self.stack_sizes = vec![];
|
||||
// self.stack_shadows = vec![];
|
||||
// self.stack_depth = 0;
|
||||
|
||||
self.stack_sizes = vec![];
|
||||
self.stack_shadows = vec![];
|
||||
self.stack_depth = 0;
|
||||
let depth = self.stack_depth - 1;
|
||||
for _ in 0..depth {
|
||||
let _ = self.pop_stack();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn define(&mut self, name: impl Into<String>, value: Rc<NodeEnum>) {
|
||||
|
@ -174,8 +179,13 @@ impl Environment {
|
|||
self.stack.get(start..len).unwrap()
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, key: EnvironmentInternalSymbolKey, value: Rc<NodeEnum>) {
|
||||
if self.stack_depth != 0 {
|
||||
pub fn insert(
|
||||
&mut self,
|
||||
key: EnvironmentInternalSymbolKey,
|
||||
value: Rc<NodeEnum>,
|
||||
dont_shadow: bool,
|
||||
) {
|
||||
if self.stack_depth != 0 && !dont_shadow {
|
||||
let mut shadow = false;
|
||||
if self.map.get(&key).is_some() {
|
||||
if !self.get_current_scope().contains(&key) {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use std::rc::Rc;
|
||||
use std::{cmp::Ordering, rc::Rc};
|
||||
|
||||
use rug::Float;
|
||||
|
||||
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)]
|
||||
|
@ -13,7 +13,7 @@ pub struct 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_right = self.right.evaluate(env)?;
|
||||
|
||||
|
@ -51,17 +51,79 @@ impl Node for Add {
|
|||
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())),
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
} else {
|
||||
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))
|
||||
} else {
|
||||
self.right.as_string(env)
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
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)]
|
||||
pub struct Assign {
|
||||
left: Rc<NodeEnum>,
|
||||
right: Rc<NodeEnum>,
|
||||
shadow: bool,
|
||||
}
|
||||
|
||||
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() {
|
||||
NodeEnum::Symbol(symbol) => {
|
||||
let name = env
|
||||
|
@ -18,9 +19,10 @@ impl Node for Assign {
|
|||
.clone();
|
||||
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!(
|
||||
"{name} := {}",
|
||||
"{name} {} {}",
|
||||
if self.shadow { ":=" } else { "<-" },
|
||||
right.as_string(Some(env))
|
||||
)))
|
||||
}
|
||||
|
@ -30,7 +32,7 @@ impl Node for Assign {
|
|||
let values = set.get_values();
|
||||
|
||||
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());
|
||||
|
@ -38,7 +40,10 @@ impl Node for Assign {
|
|||
if let NodeEnum::Symbol(symbol) = node.as_ref() {
|
||||
symbols.push(symbol);
|
||||
} 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() {
|
||||
let values = set.get_values();
|
||||
if values.len() != symbols.len() {
|
||||
return Err(format!(
|
||||
"Expected rhs with {} elements but got {}",
|
||||
return Err(Error::SetAssignmentCountMismatch(
|
||||
symbols.len(),
|
||||
values.len()
|
||||
values.len(),
|
||||
));
|
||||
}
|
||||
|
||||
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!(
|
||||
"[{}] := {}",
|
||||
"[{}] {} {}",
|
||||
if self.shadow { ":=" } else { "<-" },
|
||||
symbols
|
||||
.iter()
|
||||
.map(|x| env.id_to_str(&x.get_value()).unwrap().clone())
|
||||
|
@ -69,18 +74,25 @@ impl Node for Assign {
|
|||
right.as_string(Some(env))
|
||||
)))
|
||||
} 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 {
|
||||
format!(
|
||||
"{} := {}",
|
||||
"{} {} {}",
|
||||
self.left.as_string(env),
|
||||
if self.shadow { ":=" } else { "<-" },
|
||||
self.right.as_string(env)
|
||||
)
|
||||
}
|
||||
|
@ -91,8 +103,12 @@ impl Node for Assign {
|
|||
}
|
||||
|
||||
impl Assign {
|
||||
pub fn new(left: Rc<NodeEnum>, right: Rc<NodeEnum>) -> Self {
|
||||
Self { left, right }
|
||||
pub fn new(left: Rc<NodeEnum>, right: Rc<NodeEnum>, shadow: bool) -> Self {
|
||||
Self {
|
||||
left,
|
||||
right,
|
||||
shadow,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_left(&self) -> Rc<NodeEnum> {
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::{
|
|||
node::{closure::Closure, function::FunctionType},
|
||||
};
|
||||
|
||||
use super::{Node, NodeEnum, Precedence};
|
||||
use super::{Error, Node, NodeEnum, Precedence};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
pub struct Call {
|
||||
|
@ -14,7 +14,7 @@ pub struct 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() {
|
||||
return Ok(Rc::new(self.clone().into()));
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ impl Node for Call {
|
|||
NodeEnum::Function(func) => func,
|
||||
NodeEnum::Closure(closure) => {
|
||||
for (k, v) in closure.get_captured_variables() {
|
||||
env.insert(*k, v.clone());
|
||||
env.insert(*k, v.clone(), false);
|
||||
}
|
||||
closure.get_function()
|
||||
}
|
||||
|
@ -56,15 +56,11 @@ impl Node for Call {
|
|||
FunctionType::Native(_name, native_function) => native_function(&arguments, env),
|
||||
FunctionType::UserFunction(body, fargs) => {
|
||||
if fargs.len() != arguments.len() {
|
||||
return Err(format!(
|
||||
"Error calling function. Expected {} arguments, but got {}",
|
||||
fargs.len(),
|
||||
arguments.len()
|
||||
));
|
||||
return Err(Error::ArgumentCount(fargs.len(), arguments.len()));
|
||||
}
|
||||
// Define variables
|
||||
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);
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::rc::Rc;
|
|||
|
||||
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)]
|
||||
pub struct Closure {
|
||||
|
@ -11,7 +11,7 @@ pub struct 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()))
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::rc::Rc;
|
|||
|
||||
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)]
|
||||
pub struct Greater {
|
||||
|
@ -29,7 +29,7 @@ pub struct LessEquals {
|
|||
}
|
||||
|
||||
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)?;
|
||||
for e in &self.right {
|
||||
let e = e.evaluate(env)?;
|
||||
|
@ -66,7 +66,7 @@ impl Node for Greater {
|
|||
}
|
||||
|
||||
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)?;
|
||||
for e in &self.right {
|
||||
let e = e.evaluate(env)?;
|
||||
|
@ -103,14 +103,14 @@ impl Node for Less {
|
|||
}
|
||||
|
||||
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)?;
|
||||
for e in &self.right {
|
||||
let e = e.evaluate(env)?;
|
||||
let evaluation = expr.partial_cmp(&e);
|
||||
match evaluation {
|
||||
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()));
|
||||
}
|
||||
|
@ -142,14 +142,14 @@ impl Node for GreaterEquals {
|
|||
}
|
||||
|
||||
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)?;
|
||||
for e in &self.right {
|
||||
let e = e.evaluate(env)?;
|
||||
let evaluation = expr.partial_cmp(&e);
|
||||
match evaluation {
|
||||
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()));
|
||||
}
|
||||
|
@ -185,7 +185,7 @@ impl Greater {
|
|||
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![];
|
||||
for value in self.right.iter() {
|
||||
arguments.push(value.evaluate(env)?);
|
||||
|
@ -199,7 +199,7 @@ impl Less {
|
|||
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![];
|
||||
for value in self.right.iter() {
|
||||
arguments.push(value.evaluate(env)?);
|
||||
|
@ -213,7 +213,7 @@ impl LessEquals {
|
|||
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![];
|
||||
for value in self.right.iter() {
|
||||
arguments.push(value.evaluate(env)?);
|
||||
|
@ -227,7 +227,7 @@ impl GreaterEquals {
|
|||
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![];
|
||||
for value in self.right.iter() {
|
||||
arguments.push(value.evaluate(env)?);
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::rc::Rc;
|
|||
|
||||
use rug::Float;
|
||||
|
||||
use super::{Environment, Node, Precedence};
|
||||
use super::{Environment, Error, Node, Precedence};
|
||||
|
||||
pub type ConstantValue = Float;
|
||||
|
||||
|
@ -18,7 +18,7 @@ impl From<ConstantValue> 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()))
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::rc::Rc;
|
|||
|
||||
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)]
|
||||
pub struct Divide {
|
||||
|
@ -11,14 +11,14 @@ pub struct 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_right = self.right.evaluate(env)?;
|
||||
|
||||
match (evaluated_left.as_ref(), evaluated_right.as_ref()) {
|
||||
// Error if dividing by zero
|
||||
(_, NodeEnum::Constant(zero)) if zero.get_value() == &0.0 => {
|
||||
Err("Division by Zero".into())
|
||||
Err(Error::DivideByZero)
|
||||
}
|
||||
|
||||
(_, _) if evaluated_left == evaluated_right => {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::{rc::Rc, sync::LazyLock};
|
||||
|
||||
use super::{Environment, Node, NodeEnum, Precedence};
|
||||
use super::{Environment, Error, Node, NodeEnum, Precedence};
|
||||
|
||||
#[derive(Debug, Clone, PartialOrd)]
|
||||
pub struct Empty {
|
||||
|
@ -15,7 +15,7 @@ impl PartialEq for Empty {
|
|||
impl Eq 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())
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
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)]
|
||||
pub struct Equals {
|
||||
|
@ -9,7 +9,7 @@ pub struct 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)?;
|
||||
|
||||
for expr in &self.right {
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::rc::Rc;
|
|||
|
||||
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)]
|
||||
pub struct Exponent {
|
||||
|
@ -11,7 +11,7 @@ pub struct 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_right = self.right.evaluate(env)?;
|
||||
|
||||
|
|
|
@ -2,10 +2,10 @@ use std::rc::Rc;
|
|||
|
||||
use crate::environment::Environment;
|
||||
|
||||
use super::{symbol::Symbol, Node, NodeEnum, Precedence};
|
||||
use super::{symbol::Symbol, Error, Node, NodeEnum, Precedence};
|
||||
|
||||
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)]
|
||||
pub enum FunctionType {
|
||||
|
@ -19,7 +19,7 @@ pub struct 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(
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::rc::Rc;
|
|||
|
||||
use crate::node::empty::Empty;
|
||||
|
||||
use super::{Environment, Node, NodeEnum, Precedence};
|
||||
use super::{Environment, Error, Node, NodeEnum, Precedence};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||
pub enum Bool {
|
||||
|
@ -10,8 +10,14 @@ pub enum Bool {
|
|||
False,
|
||||
}
|
||||
|
||||
impl From<bool> for Bool {
|
||||
fn from(value: bool) -> Self {
|
||||
if value { Self::True } else { Self::False }
|
||||
}
|
||||
}
|
||||
|
||||
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()))
|
||||
}
|
||||
|
||||
|
@ -43,22 +49,22 @@ pub struct 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 = if let NodeEnum::Bool(bool) = condition_evaluated.as_ref() {
|
||||
bool
|
||||
} else {
|
||||
return Err(format!(
|
||||
return Err(Error::MismatchedType(format!(
|
||||
"Cannot evaluate {} to a bool",
|
||||
condition_evaluated.as_string(Some(env))
|
||||
));
|
||||
)));
|
||||
};
|
||||
|
||||
fn evaluate_block(
|
||||
block: &Vec<Rc<NodeEnum>>,
|
||||
env: &mut Environment,
|
||||
) -> Result<Rc<NodeEnum>, String> {
|
||||
) -> Result<Rc<NodeEnum>, Error> {
|
||||
env.push_stack()?;
|
||||
let ret = if let Some((last, to_evaluate)) = block.split_last() {
|
||||
for expr in to_evaluate {
|
||||
|
@ -89,8 +95,8 @@ impl Node for IfElse {
|
|||
self.true_branch
|
||||
.iter()
|
||||
.map(|x| x.as_string(env))
|
||||
.reduce(|a, b| a + " " + &b)
|
||||
.unwrap()
|
||||
.reduce(|a, b| a + "; " + &b)
|
||||
.unwrap_or("".to_owned())
|
||||
.as_str(),
|
||||
match &self.else_branch {
|
||||
ElseBranchEnum::ElseIf(if_else) => if_else.as_string(env),
|
||||
|
@ -100,7 +106,7 @@ impl Node for IfElse {
|
|||
.iter()
|
||||
.map(|x| x.as_string(env))
|
||||
.reduce(|a, b| a + "\n" + &b)
|
||||
.unwrap()
|
||||
.unwrap_or("".to_owned())
|
||||
+ " end",
|
||||
ElseBranchEnum::None => " end".to_owned(),
|
||||
}
|
||||
|
|
78
src/lib/node/loop.rs
Normal file
78
src/lib/node/loop.rs
Normal 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())
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@ use std::{fmt::Display, rc::Rc};
|
|||
use add::Add;
|
||||
use assign::Assign;
|
||||
use call::Call;
|
||||
use closure::Closure;
|
||||
use comparison::{Greater, GreaterEquals, Less, LessEquals};
|
||||
use constant::Constant;
|
||||
use divide::Divide;
|
||||
|
@ -12,18 +13,20 @@ use equals::Equals;
|
|||
use exponent::Exponent;
|
||||
use function::Function;
|
||||
use if_else::{Bool, IfElse};
|
||||
use r#loop::{Break, Loop};
|
||||
use multiply::Multiply;
|
||||
use range::Range;
|
||||
use set::Set;
|
||||
use string_node::StringNode;
|
||||
use subtract::Subtract;
|
||||
use symbol::Symbol;
|
||||
use string_node::StringNode;
|
||||
use closure::Closure;
|
||||
|
||||
use crate::environment::Environment;
|
||||
|
||||
pub mod add;
|
||||
pub mod assign;
|
||||
pub mod call;
|
||||
pub mod closure;
|
||||
pub mod comparison;
|
||||
pub mod constant;
|
||||
pub mod divide;
|
||||
|
@ -32,13 +35,14 @@ pub mod equals;
|
|||
pub mod exponent;
|
||||
pub mod function;
|
||||
pub mod if_else;
|
||||
pub mod r#loop;
|
||||
pub mod range;
|
||||
pub mod multiply;
|
||||
pub mod node_ref;
|
||||
pub mod set;
|
||||
pub mod string_node;
|
||||
pub mod subtract;
|
||||
pub mod symbol;
|
||||
pub mod string_node;
|
||||
pub mod closure;
|
||||
|
||||
#[enum_dispatch]
|
||||
#[enum_dispatch(Debug, Clone, PartialEq, PartialOrd, ToString)]
|
||||
|
@ -58,13 +62,17 @@ pub enum NodeEnum {
|
|||
Assign,
|
||||
Empty,
|
||||
Function,
|
||||
Closure, // IMPLEMENT THIS SO CURRYING WORKS
|
||||
Closure,
|
||||
Call,
|
||||
|
||||
Loop,
|
||||
Break,
|
||||
|
||||
Bool,
|
||||
IfElse,
|
||||
|
||||
Set,
|
||||
Range,
|
||||
|
||||
Equals,
|
||||
Greater,
|
||||
|
@ -93,9 +101,59 @@ pub enum Precedence {
|
|||
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)]
|
||||
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 precedence(&self) -> Precedence;
|
||||
}
|
||||
|
@ -153,6 +211,7 @@ impl PartialOrd for NodeEnum {
|
|||
less_equals1.partial_cmp(less_equals2)
|
||||
}
|
||||
|
||||
// (a,b) => a.partial_cmp(b)
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -181,7 +240,11 @@ impl NodeEnum {
|
|||
NodeEnum::Greater(_) => "Greater",
|
||||
NodeEnum::GreaterEquals(_) => "Greater Equals",
|
||||
NodeEnum::Less(_) => "Less",
|
||||
NodeEnum::LessEquals(_) => "Less Equals"
|
||||
}.to_owned()
|
||||
NodeEnum::LessEquals(_) => "Less Equals",
|
||||
NodeEnum::Loop(_) => "Loop",
|
||||
NodeEnum::Break(_) => "Break",
|
||||
NodeEnum::Range(_) => "Range",
|
||||
}
|
||||
.to_owned()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
use std::rc::Rc;
|
||||
use std::{cmp::Ordering, ops::Mul, rc::Rc};
|
||||
|
||||
use rug::Float;
|
||||
|
||||
use crate::environment::Environment;
|
||||
|
||||
use super::{
|
||||
Node, NodeEnum, Precedence, add::Add, constant::Constant, divide::Divide, set::Set,
|
||||
subtract::Subtract,
|
||||
add::Add, constant::Constant, divide::Divide, set::Set, subtract::Subtract, Error, Node, NodeEnum, Precedence
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||
|
@ -16,7 +15,7 @@ pub struct 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_right = self.right.evaluate(env)?;
|
||||
|
||||
|
@ -29,51 +28,38 @@ impl Node for Multiply {
|
|||
}
|
||||
|
||||
// Identity rule
|
||||
(NodeEnum::Constant(one), _) if one.get_value() == &0.0 => Ok(evaluated_right),
|
||||
(_, NodeEnum::Constant(one)) if one.get_value() == &0.0 => Ok(evaluated_left),
|
||||
(x, NodeEnum::Constant(one)) | (NodeEnum::Constant(one), x)
|
||||
if one.get_value() == &1.0 =>
|
||||
{
|
||||
Ok(Rc::new(x.clone()))
|
||||
}
|
||||
|
||||
// Multiply into parenthesis (add)
|
||||
(_, NodeEnum::Add(add)) => Ok(Add::new_rc(
|
||||
Self::new_rc(evaluated_left.clone(), add.get_left()).evaluate(env)?,
|
||||
Self::new_rc(evaluated_left, 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)?,
|
||||
(NodeEnum::Add(add), x) | (x, NodeEnum::Add(add)) => Ok(Add::new_rc(
|
||||
Multiply::new_rc(Rc::new(x.clone()), add.get_left()).evaluate(env)?,
|
||||
Multiply::new_rc(Rc::new(x.clone()), add.get_right()).evaluate(env)?,
|
||||
)),
|
||||
|
||||
// Multiply into parenthesis (sub)
|
||||
(_, NodeEnum::Subtract(sub)) => Ok(Subtract::new_rc(
|
||||
Self::new_rc(evaluated_left.clone(), sub.get_left()).evaluate(env)?,
|
||||
Self::new_rc(evaluated_left, 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)?,
|
||||
(NodeEnum::Subtract(sub), x) | (x, NodeEnum::Subtract(sub)) => Ok(Subtract::new_rc(
|
||||
Multiply::new_rc(Rc::new(x.clone()), sub.get_left()).evaluate(env)?,
|
||||
Multiply::new_rc(Rc::new(x.clone()), sub.get_right()).evaluate(env)?,
|
||||
)),
|
||||
|
||||
// Multiply fraction
|
||||
(NodeEnum::Divide(div), _) => Ok(Divide::new_rc(
|
||||
Self::new_rc(evaluated_right, 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)?,
|
||||
(x, NodeEnum::Divide(div)) | (NodeEnum::Divide(div), x) => Ok(Divide::new_rc(
|
||||
Self::new_rc(Rc::new(x.clone()), div.get_left()).evaluate(env)?,
|
||||
div.get_right(),
|
||||
)),
|
||||
|
||||
// 0.5*n -> n/2
|
||||
(NodeEnum::Constant(c), _) if c.get_value() == &0.5 => Divide::new(
|
||||
evaluated_right,
|
||||
(x, NodeEnum::Constant(c)) | (NodeEnum::Constant(c), x) if c.get_value() == &0.5 => {
|
||||
Divide::new(
|
||||
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(
|
||||
evaluated_left,
|
||||
Rc::new(Constant::new_from_float(2, &env).into()),
|
||||
)
|
||||
.evaluate(env),
|
||||
.evaluate(env)
|
||||
}
|
||||
|
||||
// Constant * Constant = Constant
|
||||
(NodeEnum::Constant(a), NodeEnum::Constant(b)) => {
|
||||
|
@ -83,18 +69,11 @@ impl Node for Multiply {
|
|||
)))))
|
||||
}
|
||||
|
||||
// Move constant infront of symbols
|
||||
(NodeEnum::Symbol(_), NodeEnum::Constant(_))
|
||||
| (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)) => {
|
||||
// Multiply into sets
|
||||
(NodeEnum::Set(s), c) | (c, NodeEnum::Set(s)) => {
|
||||
let old_values = s.get_values();
|
||||
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() {
|
||||
let new_value = Multiply::new(c.clone(), value.clone());
|
||||
|
@ -104,28 +83,76 @@ impl Node for Multiply {
|
|||
Ok(Set::new(values))
|
||||
}
|
||||
|
||||
// Multiply a set with a constant
|
||||
(NodeEnum::Set(s), NodeEnum::Symbol(c)) | (NodeEnum::Symbol(c), NodeEnum::Set(s)) => {
|
||||
let old_values = s.get_values();
|
||||
let mut values = Vec::with_capacity(old_values.len());
|
||||
let c: Rc<NodeEnum> = Rc::new(c.clone().into());
|
||||
|
||||
for value in old_values.iter() {
|
||||
let new_value = Multiply::new(c.clone(), value.clone());
|
||||
values.push(new_value.evaluate(env)?);
|
||||
(NodeEnum::Symbol(s1), NodeEnum::Symbol(s2)) => {
|
||||
if s1 > s2 {
|
||||
Ok(Self::new_rc(evaluated_left, evaluated_right))
|
||||
} else {
|
||||
Ok(Self::new_rc(evaluated_right, evaluated_left))
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Set::new(values))
|
||||
// At least one of the nodes is a nested multiply
|
||||
(NodeEnum::Multiply(m), o) | (o, NodeEnum::Multiply(m)) => {
|
||||
// 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());
|
||||
|
||||
loop {
|
||||
match c.as_ref() {
|
||||
NodeEnum::Multiply(m) => {
|
||||
queue.push(m.get_left());
|
||||
queue.push(m.get_right());
|
||||
}
|
||||
_ => {
|
||||
aggregate.push(c.clone());
|
||||
}
|
||||
}
|
||||
|
||||
// (NodeEnum::Constant(c), NodeEnum::Multiply(m))
|
||||
// | (NodeEnum::Multiply(m), NodeEnum::Constant(c)) => {
|
||||
// Self::collapse_nested_multiply(c, m, env)?.evaluate(env)
|
||||
// }
|
||||
if !queue.is_empty() {
|
||||
c = queue.pop().unwrap();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// (NodeEnum::Multiply(m1), NodeEnum::Multiply(m2)) => {
|
||||
// Self::move_constants_to_left(evaluated_left.clone(), evaluated_right.clone())
|
||||
// }
|
||||
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
|
||||
_ => Ok(Rc::new(
|
||||
|
@ -135,12 +162,16 @@ impl Node for Multiply {
|
|||
}
|
||||
|
||||
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))
|
||||
} else {
|
||||
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))
|
||||
} else {
|
||||
self.right.as_string(env)
|
||||
|
@ -154,76 +185,14 @@ impl Node for Multiply {
|
|||
}
|
||||
|
||||
impl Multiply {
|
||||
fn collapse_nested_multiply(
|
||||
constant: &Constant,
|
||||
multiply: &Multiply,
|
||||
env: &mut Environment,
|
||||
) -> 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(),
|
||||
)),
|
||||
pub fn symbols_match(&self, other: &Multiply) -> bool {
|
||||
if let NodeEnum::Constant(_) = self.left.as_ref() {
|
||||
if let NodeEnum::Constant(_) = other.left.as_ref() {
|
||||
return self.right.eq(&other.right);
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
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)),
|
||||
}
|
||||
self.eq(other)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::rc::Rc;
|
||||
|
||||
use super::{Environment, Node, NodeEnum, Precedence};
|
||||
use super::{Environment, Error, Node, NodeEnum, Precedence};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
pub struct NodeRef {
|
||||
|
@ -8,7 +8,7 @@ pub struct 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)
|
||||
}
|
||||
|
||||
|
|
43
src/lib/node/range.rs
Normal file
43
src/lib/node/range.rs
Normal 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())
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
use std::rc::Rc;
|
||||
|
||||
use super::{Environment, Node, NodeEnum, Precedence};
|
||||
use super::{Environment, Error, Node, NodeEnum, Precedence, constant::Constant};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||
pub struct Set {
|
||||
|
@ -8,9 +8,22 @@ pub struct 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());
|
||||
|
||||
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() {
|
||||
values.push(value.evaluate(env)?);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::rc::Rc;
|
||||
|
||||
use super::{Environment, Node, NodeEnum, Precedence};
|
||||
use super::{Environment, Error, Node, NodeEnum, Precedence};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||
pub struct StringNode {
|
||||
|
@ -14,7 +14,7 @@ impl From<String> 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()))
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::rc::Rc;
|
|||
|
||||
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)]
|
||||
pub struct Subtract {
|
||||
|
@ -11,7 +11,7 @@ pub struct 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_right = self.right.evaluate(env)?;
|
||||
|
||||
|
@ -36,51 +36,60 @@ impl Node for Subtract {
|
|||
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)) => {
|
||||
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(),
|
||||
)),
|
||||
if m1.symbols_match(m2) {
|
||||
return Ok(Multiply::new_rc(
|
||||
Subtract::new_rc(m1.get_left(), m2.get_left()).evaluate(env)?,
|
||||
m1.get_right(),
|
||||
));
|
||||
}
|
||||
Ok(Subtract::new_rc(evaluated_left, evaluated_right))
|
||||
}
|
||||
|
||||
_ => {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::rc::Rc;
|
||||
|
||||
use super::{Environment, Node, NodeEnum, Precedence};
|
||||
use super::{Environment, Error, Node, NodeEnum, Precedence};
|
||||
use crate::environment::EnvironmentInternalSymbolKey;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
|
@ -9,7 +9,7 @@ pub struct 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) {
|
||||
// TODO: Detect cyclic references and make sure they get
|
||||
// deleted at some point
|
||||
|
@ -60,7 +60,15 @@ impl Symbol {
|
|||
}
|
||||
|
||||
impl PartialOrd for Symbol {
|
||||
fn partial_cmp(&self, _other: &Self) -> Option<std::cmp::Ordering> {
|
||||
None
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,9 @@ use crate::{
|
|||
exponent::Exponent,
|
||||
function::{Function, FunctionType},
|
||||
if_else::{Bool, ElseBranchEnum, IfElse},
|
||||
r#loop::{Break, Loop},
|
||||
multiply::Multiply,
|
||||
range::Range,
|
||||
set::Set,
|
||||
string_node::StringNode,
|
||||
subtract::Subtract,
|
||||
|
@ -39,6 +41,8 @@ pub enum TokenType {
|
|||
Identifier(String),
|
||||
String(String),
|
||||
|
||||
DoubleDot,
|
||||
|
||||
Plus,
|
||||
Minus,
|
||||
Star,
|
||||
|
@ -53,6 +57,7 @@ pub enum TokenType {
|
|||
|
||||
ColonEquals,
|
||||
LeftArrow,
|
||||
RightArrow,
|
||||
|
||||
RParen,
|
||||
LParen,
|
||||
|
@ -66,6 +71,10 @@ pub enum TokenType {
|
|||
Else,
|
||||
End,
|
||||
|
||||
Loop,
|
||||
Block,
|
||||
Break,
|
||||
|
||||
True,
|
||||
False,
|
||||
|
||||
|
@ -78,6 +87,8 @@ impl TokenType {
|
|||
TokenType::Number(n) => n.to_string().len(),
|
||||
TokenType::Identifier(s) | TokenType::String(s) => s.len(),
|
||||
|
||||
TokenType::DoubleDot => 2,
|
||||
|
||||
TokenType::Plus => 1,
|
||||
TokenType::Minus => 1,
|
||||
TokenType::Star => 1,
|
||||
|
@ -92,6 +103,7 @@ impl TokenType {
|
|||
|
||||
TokenType::ColonEquals => 2,
|
||||
TokenType::LeftArrow => 2,
|
||||
TokenType::RightArrow => 2,
|
||||
|
||||
TokenType::RParen => 1,
|
||||
TokenType::LParen => 1,
|
||||
|
@ -105,6 +117,10 @@ impl TokenType {
|
|||
TokenType::Else => 4,
|
||||
TokenType::End => 3,
|
||||
|
||||
TokenType::Loop => 4,
|
||||
TokenType::Block => 5,
|
||||
TokenType::Break => 5,
|
||||
|
||||
TokenType::True => 4,
|
||||
TokenType::False => 5,
|
||||
|
||||
|
@ -149,19 +165,38 @@ impl<'a> Lexer<'a> {
|
|||
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' | '.' => {
|
||||
let mut digit = String::from(c);
|
||||
let mut digits = String::from(c);
|
||||
let mut has_decimal = c == '.';
|
||||
let mut push = true;
|
||||
loop {
|
||||
let d = self.source.peek();
|
||||
match d {
|
||||
Some('0'..='9') => {
|
||||
digit.push(*d.unwrap());
|
||||
self.source.next();
|
||||
digits.push(self.source.next().unwrap());
|
||||
i += 1;
|
||||
}
|
||||
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 {
|
||||
return Err(LexerError::UnexpectedChar(
|
||||
i + 1,
|
||||
|
@ -169,8 +204,7 @@ impl<'a> Lexer<'a> {
|
|||
));
|
||||
}
|
||||
|
||||
digit.push(*d.unwrap());
|
||||
self.source.next();
|
||||
digits.push(current.unwrap());
|
||||
i += 1;
|
||||
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;
|
||||
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(&'=') => {
|
||||
self.source.next();
|
||||
|
@ -261,10 +294,14 @@ impl<'a> Lexer<'a> {
|
|||
tokens.push(self.lex_identifier(&mut i, c)?);
|
||||
}
|
||||
|
||||
'\n' => {
|
||||
continue;
|
||||
}
|
||||
|
||||
_ => {
|
||||
return Err(LexerError::UnexpectedChar(
|
||||
i,
|
||||
format!("Unexpected char {}", c),
|
||||
format!("Unexpected char {c} ({c:?})"),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -295,6 +332,10 @@ impl<'a> Lexer<'a> {
|
|||
"else" => TokenType::Else,
|
||||
"end" => TokenType::End,
|
||||
|
||||
"loop" => TokenType::Loop,
|
||||
"block" => TokenType::Block,
|
||||
"break" => TokenType::Break,
|
||||
|
||||
"true" => TokenType::True,
|
||||
"false" => TokenType::False,
|
||||
|
||||
|
@ -411,7 +452,9 @@ impl<'a> Parser<'a> {
|
|||
let expr = self.equality()?;
|
||||
|
||||
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)
|
||||
|
@ -472,28 +515,25 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
fn term(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
||||
let expr = self.factor()?;
|
||||
let mut expr = self.factor()?;
|
||||
loop {
|
||||
if self.match_type(TokenType::Plus) {
|
||||
Ok(Rc::new(Add::new(expr, self.comparison()?).into()))
|
||||
} else if let Some(Token(_, TokenType::Minus)) = self.tokens.peek() {
|
||||
self.consume();
|
||||
Ok(Rc::new(Subtract::new(expr, self.comparison()?).into()))
|
||||
} else {
|
||||
Ok(expr)
|
||||
let right = self.factor()?;
|
||||
expr = Add::new_rc(expr, right);
|
||||
continue;
|
||||
} else if self.match_type(TokenType::Minus) {
|
||||
let right = self.factor()?;
|
||||
expr = Subtract::new_rc(expr, right);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Ok(expr)
|
||||
}
|
||||
|
||||
fn factor(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
||||
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 {
|
||||
if self.match_type(TokenType::Star) {
|
||||
|
@ -508,6 +548,23 @@ impl<'a> Parser<'a> {
|
|||
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)
|
||||
}
|
||||
|
||||
|
@ -603,6 +660,7 @@ impl<'a> Parser<'a> {
|
|||
Assign::new(
|
||||
expr,
|
||||
Function::new(FunctionType::UserFunction(body, arguments)),
|
||||
true,
|
||||
)
|
||||
.into(),
|
||||
));
|
||||
|
@ -700,6 +758,7 @@ impl<'a> Parser<'a> {
|
|||
));
|
||||
}
|
||||
expressions.push(self.expression()?);
|
||||
let _ = self.match_type(TokenType::Terminator);
|
||||
}
|
||||
|
||||
ElseBranchEnum::Block(expressions)
|
||||
|
@ -712,6 +771,19 @@ impl<'a> Parser<'a> {
|
|||
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()
|
||||
}
|
||||
|
||||
|
@ -754,7 +826,39 @@ impl<'a> Parser<'a> {
|
|||
|
||||
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> {
|
||||
|
@ -784,6 +888,8 @@ impl<'a> Parser<'a> {
|
|||
TokenType::True => Ok(Rc::new(Bool::True.into())),
|
||||
TokenType::False => Ok(Rc::new(Bool::False.into())),
|
||||
|
||||
TokenType::Break => Ok(Rc::new(Break.into())),
|
||||
|
||||
TokenType::String(s) => Ok(StringNode::new(s)),
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
33
test.txt
Normal file
33
test.txt
Normal 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))
|
Loading…
Reference in a new issue