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`
|
218
src/cli-repl.rs
218
src/cli-repl.rs
|
@ -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()?;
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)?);
|
||||||
|
|
|
@ -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()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 => {
|
||||||
|
|
|
@ -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())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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)?;
|
||||||
|
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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
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 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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
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 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)?);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
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