implemented more nodes
This commit is contained in:
parent
c5a0180f04
commit
b7834b5244
|
@ -2,7 +2,7 @@ use std::io::{self, StdoutLock, Write, stdout};
|
||||||
|
|
||||||
use libopenbirch::environment::Environment;
|
use libopenbirch::environment::Environment;
|
||||||
use libopenbirch::node::Node;
|
use libopenbirch::node::Node;
|
||||||
use libopenbirch::parser::{Lexer, Parser};
|
use libopenbirch::parser::{Lexer, Parser, ParserError};
|
||||||
#[cfg(feature = "async")]
|
#[cfg(feature = "async")]
|
||||||
use termion::AsyncReader;
|
use termion::AsyncReader;
|
||||||
use termion::color;
|
use termion::color;
|
||||||
|
@ -133,8 +133,13 @@ impl Input {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_err(i: usize, exp: String) {
|
fn print_err(i: usize, len: usize, exp: String) {
|
||||||
println!("\r{}{}^", " ".repeat(i + 2), color::Fg(color::Yellow));
|
println!(
|
||||||
|
"\r{}{}{}",
|
||||||
|
" ".repeat(i + 3 - len),
|
||||||
|
color::Fg(color::Yellow),
|
||||||
|
"^".repeat(len)
|
||||||
|
);
|
||||||
println!(
|
println!(
|
||||||
"\r{}{}{}",
|
"\r{}{}{}",
|
||||||
color::Fg(color::Red),
|
color::Fg(color::Red),
|
||||||
|
@ -154,7 +159,7 @@ fn main() -> Result<(), io::Error> {
|
||||||
|
|
||||||
if tokens_result.is_err() {
|
if tokens_result.is_err() {
|
||||||
match tokens_result.err().unwrap() {
|
match tokens_result.err().unwrap() {
|
||||||
libopenbirch::parser::LexerError::UnexpectedChar(i, exp) => print_err(i, exp),
|
libopenbirch::parser::LexerError::UnexpectedChar(i, exp) => print_err(i, 1, exp),
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -163,7 +168,7 @@ fn main() -> Result<(), io::Error> {
|
||||||
input.disable_raw();
|
input.disable_raw();
|
||||||
|
|
||||||
let tokens = tokens_result.unwrap();
|
let tokens = tokens_result.unwrap();
|
||||||
let mut parser = Parser::new(tokens);
|
let mut parser = Parser::new(tokens, &mut env);
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
input.enable_raw();
|
input.enable_raw();
|
||||||
|
@ -172,10 +177,10 @@ fn main() -> Result<(), io::Error> {
|
||||||
Ok(nodes) => nodes,
|
Ok(nodes) => nodes,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
match err {
|
match err {
|
||||||
libopenbirch::parser::ParserError::UnexpectedEndOfTokens(exp) => {
|
ParserError::UnexpectedEndOfTokens(exp) => print_err(source.len(), 1, exp),
|
||||||
print_err(source.len(), exp)
|
ParserError::UnexpectedToken(i, len, exp)
|
||||||
}
|
| ParserError::Unimplemented(i, len, exp) => print_err(i, len, exp),
|
||||||
libopenbirch::parser::ParserError::UnexpectedToken(i, exp) => print_err(i, exp),
|
ParserError::UnexpectedNode(i, exp) => print_err(i, 1, exp),
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -186,8 +191,8 @@ fn main() -> Result<(), io::Error> {
|
||||||
for node in nodes {
|
for node in nodes {
|
||||||
let evaluated = node.evaluate(&mut env);
|
let evaluated = node.evaluate(&mut env);
|
||||||
match evaluated {
|
match evaluated {
|
||||||
Ok(result) => println!("\r\t{}", result.as_string(None)),
|
Ok(result) => println!("\r\t{}", result.as_string(Some(&env))),
|
||||||
Err(exp) => print_err(0, exp),
|
Err(exp) => print_err(0, 1, exp),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,4 +3,51 @@ use std::{collections::HashMap, rc::Rc};
|
||||||
use crate::node::NodeEnum;
|
use crate::node::NodeEnum;
|
||||||
|
|
||||||
pub type EnvironmentInternalSymbolKey = u16;
|
pub type EnvironmentInternalSymbolKey = u16;
|
||||||
pub type Environment = HashMap<EnvironmentInternalSymbolKey, Rc<NodeEnum>>;
|
// pub type Environment = HashMap<EnvironmentInternalSymbolKey, Rc<NodeEnum>>;
|
||||||
|
|
||||||
|
pub struct Environment {
|
||||||
|
map: HashMap<EnvironmentInternalSymbolKey, Rc<NodeEnum>>,
|
||||||
|
|
||||||
|
symbol_to_id: HashMap<String, EnvironmentInternalSymbolKey>,
|
||||||
|
id_to_symbol: HashMap<EnvironmentInternalSymbolKey, String>,
|
||||||
|
unique_keys: EnvironmentInternalSymbolKey
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Environment {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
map: HashMap::new(),
|
||||||
|
|
||||||
|
symbol_to_id: HashMap::new(),
|
||||||
|
id_to_symbol: HashMap::new(),
|
||||||
|
unique_keys: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self, key: &EnvironmentInternalSymbolKey) -> Option<&Rc<NodeEnum>> {
|
||||||
|
self.map.get(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert(&mut self, key: EnvironmentInternalSymbolKey, value: Rc<NodeEnum>) {
|
||||||
|
self.map.insert(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn str_to_id(&self, value: &String) -> Option<&EnvironmentInternalSymbolKey> {
|
||||||
|
self.symbol_to_id.get(value)
|
||||||
|
}
|
||||||
|
pub fn id_to_str(&self, value: &EnvironmentInternalSymbolKey) -> Option<&String> {
|
||||||
|
self.id_to_symbol.get(value)
|
||||||
|
}
|
||||||
|
pub fn insert_str_to_id(&mut self, key: String, value: EnvironmentInternalSymbolKey) {
|
||||||
|
self.symbol_to_id.insert(key.clone(), value);
|
||||||
|
self.id_to_symbol.insert(value, key);
|
||||||
|
}
|
||||||
|
pub fn insert_id_to_str(&mut self, key: EnvironmentInternalSymbolKey, value: String) {
|
||||||
|
self.id_to_symbol.insert(key, value.clone());
|
||||||
|
self.symbol_to_id.insert(value, key);
|
||||||
|
}
|
||||||
|
pub fn get_new_id(&mut self) -> EnvironmentInternalSymbolKey {
|
||||||
|
self.unique_keys += 1;
|
||||||
|
self.unique_keys
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -14,10 +14,26 @@ impl Node for Add {
|
||||||
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()) {
|
||||||
|
// Zero rule
|
||||||
|
(NodeEnum::Constant(zero), _) if zero.get_value() == 0. => Ok(evaluated_right),
|
||||||
|
(_, NodeEnum::Constant(zero)) if zero.get_value() == 0. => Ok(evaluated_left),
|
||||||
|
|
||||||
|
// Constant + Constant = Constant
|
||||||
(NodeEnum::Constant(a), NodeEnum::Constant(b)) => {
|
(NodeEnum::Constant(a), NodeEnum::Constant(b)) => {
|
||||||
Ok(Rc::new(Constant::new(a.get_value() + b.get_value()).into()))
|
Ok(Rc::new(Constant::new(a.get_value() + b.get_value()).into()))
|
||||||
}
|
}
|
||||||
_ => Err(format!("Invalid Add operation: {:?}", self)),
|
|
||||||
|
// Symbol + Constant we just return the same
|
||||||
|
(NodeEnum::Symbol(_), NodeEnum::Constant(_)) => {
|
||||||
|
Ok(Rc::new(Add::new(evaluated_left, evaluated_right).into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constant + Symbol we switch them around so the constant is last
|
||||||
|
(NodeEnum::Constant(_), NodeEnum::Symbol(_)) => {
|
||||||
|
Ok(Rc::new(Add::new(evaluated_right, evaluated_left).into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => Ok(Rc::new(Add::new(evaluated_left, evaluated_right).into())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,10 +58,7 @@ impl Node for Add {
|
||||||
|
|
||||||
impl Add {
|
impl Add {
|
||||||
pub fn new(left: Rc<NodeEnum>, right: Rc<NodeEnum>) -> Self {
|
pub fn new(left: Rc<NodeEnum>, right: Rc<NodeEnum>) -> Self {
|
||||||
Self {
|
Self { left, right }
|
||||||
left,
|
|
||||||
right,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_left(&self) -> Rc<NodeEnum> {
|
pub fn get_left(&self) -> Rc<NodeEnum> {
|
||||||
|
|
|
@ -11,8 +11,17 @@ pub struct Assign {
|
||||||
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>, String> {
|
||||||
if let NodeEnum::Symbol(symbol) = self.left.as_ref() {
|
if let NodeEnum::Symbol(symbol) = self.left.as_ref() {
|
||||||
env.insert(symbol.get_value(), self.right.clone());
|
let name = env
|
||||||
Ok(Empty::EMPTY.clone())
|
.id_to_str(&symbol.get_value())
|
||||||
|
.expect("Unknown symbol")
|
||||||
|
.clone();
|
||||||
|
let right = self.right.evaluate(env)?;
|
||||||
|
|
||||||
|
env.insert(symbol.get_value(), right.clone());
|
||||||
|
Ok(Empty::new(format!(
|
||||||
|
"{name} := {}",
|
||||||
|
right.as_string(Some(env))
|
||||||
|
)))
|
||||||
} else {
|
} else {
|
||||||
Err(format!(
|
Err(format!(
|
||||||
"Cannot assign to a {}",
|
"Cannot assign to a {}",
|
||||||
|
@ -35,6 +44,10 @@ impl Node for Assign {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Assign {
|
impl Assign {
|
||||||
|
pub fn new(left: Rc<NodeEnum>, right: Rc<NodeEnum>) -> Self {
|
||||||
|
Self { left, right }
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_left(&self) -> Rc<NodeEnum> {
|
pub fn get_left(&self) -> Rc<NodeEnum> {
|
||||||
self.left.clone()
|
self.left.clone()
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ use super::{Node, NodeEnum, Precedence, symbol::Symbol};
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||||
pub struct Call {
|
pub struct Call {
|
||||||
function: Rc<NodeEnum>,
|
function: Rc<NodeEnum>,
|
||||||
arguments: Vec<Rc<NodeEnum>>,
|
arguments: Rc<NodeEnum>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Node for Call {
|
impl Node for Call {
|
||||||
|
@ -23,29 +23,34 @@ impl Node for Call {
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let arguments = if let NodeEnum::Set(set) = self.arguments.as_ref() {
|
||||||
|
set.get_values()
|
||||||
|
} else {
|
||||||
|
panic!(
|
||||||
|
"This shoulnd not be possible, but call constructed with arguments of type that is not set"
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
// Check if argument counts match
|
// Check if argument counts match
|
||||||
let fargs = func.get_arguments();
|
let fargs = func.get_arguments();
|
||||||
if fargs.len() != self.arguments.len() {
|
if fargs.len() != arguments.len() {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
"Error calling function. Expected {} arguments, but got {}",
|
"Error calling function. Expected {} arguments, but got {}",
|
||||||
func.get_arguments().len(),
|
func.get_arguments().len(),
|
||||||
self.arguments.len()
|
arguments.len()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call function body with arguments
|
// Call function body with arguments
|
||||||
match func.get_body() {
|
match func.get_body() {
|
||||||
// Pass arguments to native function
|
// Pass arguments to native function
|
||||||
FunctionType::Native(_name, native_function) => native_function(&self.arguments),
|
FunctionType::Native(_name, native_function) => native_function(arguments),
|
||||||
FunctionType::UserFunction(node_enum) => {
|
FunctionType::UserFunction(node_enum) => {
|
||||||
// TODO: Push scope
|
// TODO: Push scope
|
||||||
// Define variables
|
// Define variables
|
||||||
fargs
|
fargs.iter().zip(arguments).for_each(|(symbol, value)| {
|
||||||
.iter()
|
env.insert(symbol.get_value(), value.clone());
|
||||||
.zip(&self.arguments)
|
});
|
||||||
.for_each(|(symbol, value)| {
|
|
||||||
env.insert(symbol.get_value(), value.clone());
|
|
||||||
});
|
|
||||||
let ev = node_enum.evaluate(env);
|
let ev = node_enum.evaluate(env);
|
||||||
// TODO: Pop scope
|
// TODO: Pop scope
|
||||||
// Return evaluated return value for function
|
// Return evaluated return value for function
|
||||||
|
@ -55,12 +60,7 @@ impl Node for Call {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_string(&self, env: Option<&Environment>) -> String {
|
fn as_string(&self, env: Option<&Environment>) -> String {
|
||||||
let arguments = self
|
let arguments = self.arguments.as_string(env);
|
||||||
.arguments
|
|
||||||
.iter()
|
|
||||||
.map(|x| x.as_string(env))
|
|
||||||
.reduce(|a, b| a + ", " + &b)
|
|
||||||
.unwrap();
|
|
||||||
format!("{}({})", self.function.as_string(env), arguments)
|
format!("{}({})", self.function.as_string(env), arguments)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,3 +68,15 @@ impl Node for Call {
|
||||||
Precedence::Call
|
Precedence::Call
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Call {
|
||||||
|
pub fn new(function: Rc<NodeEnum>, arguments: Rc<NodeEnum>) -> Rc<NodeEnum> {
|
||||||
|
Rc::new(
|
||||||
|
Self {
|
||||||
|
function,
|
||||||
|
arguments,
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -9,6 +9,12 @@ pub struct Constant {
|
||||||
value: ConstantValue,
|
value: ConstantValue,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<ConstantValue> for Constant {
|
||||||
|
fn from(value: ConstantValue) -> Self {
|
||||||
|
Self::new(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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>, String> {
|
||||||
Ok(Rc::new(self.clone().into()))
|
Ok(Rc::new(self.clone().into()))
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use super::{Node, NodeEnum, Precedence, constant::Constant};
|
use super::{constant::Constant, set::Set, Node, NodeEnum, Precedence};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||||
pub struct Divide {
|
pub struct Divide {
|
||||||
|
@ -14,10 +14,55 @@ impl Node for Divide {
|
||||||
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
|
||||||
|
(_, NodeEnum::Constant(zero)) if zero.get_value() == 0. => {
|
||||||
|
Err("Division by Zero".into())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zero rule
|
||||||
|
(NodeEnum::Constant(zero), _) if zero.get_value() == 0. => {
|
||||||
|
Ok(evaluated_left)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constant + Constant = Constant
|
||||||
(NodeEnum::Constant(a), NodeEnum::Constant(b)) => {
|
(NodeEnum::Constant(a), NodeEnum::Constant(b)) => {
|
||||||
Ok(Rc::new(Constant::new(a.get_value() / b.get_value()).into()))
|
Ok(Rc::new(Constant::new(a.get_value() / b.get_value()).into()))
|
||||||
}
|
}
|
||||||
_ => Err(format!("Invalid Divide operation: {:?}", self)),
|
// Symbol + Constant we just return the same
|
||||||
|
(NodeEnum::Symbol(_), NodeEnum::Constant(_)) => {
|
||||||
|
Ok(Rc::new(Divide::new(evaluated_left, evaluated_right).into()))
|
||||||
|
}
|
||||||
|
// Constant + Symbol we switch them around so the constant is last
|
||||||
|
(NodeEnum::Constant(_), NodeEnum::Symbol(_)) => {
|
||||||
|
Ok(Rc::new(Divide::new(evaluated_right, evaluated_left).into()))
|
||||||
|
}
|
||||||
|
// Divide a set with a constant
|
||||||
|
(NodeEnum::Set(s), NodeEnum::Constant(c)) => {
|
||||||
|
let old_values = s.get_values();
|
||||||
|
let mut values = Vec::with_capacity(old_values.len());
|
||||||
|
let c: Rc<NodeEnum> = Rc::new(c.clone().into());
|
||||||
|
|
||||||
|
for value in old_values.iter() {
|
||||||
|
let new_value = Divide::new(c.clone(), value.clone());
|
||||||
|
values.push(new_value.evaluate(env)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Set::new(values))
|
||||||
|
}
|
||||||
|
// Divide a set with a symbol
|
||||||
|
(NodeEnum::Set(s), NodeEnum::Symbol(c)) => {
|
||||||
|
let old_values = s.get_values();
|
||||||
|
let mut values = Vec::with_capacity(old_values.len());
|
||||||
|
let c: Rc<NodeEnum> = Rc::new(c.clone().into());
|
||||||
|
|
||||||
|
for value in old_values.iter() {
|
||||||
|
let new_value = Divide::new(c.clone(), value.clone());
|
||||||
|
values.push(new_value.evaluate(env)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Set::new(values))
|
||||||
|
}
|
||||||
|
_ => Ok(Rc::new(Divide::new(evaluated_left, evaluated_right).into())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,10 +87,7 @@ impl Node for Divide {
|
||||||
|
|
||||||
impl Divide {
|
impl Divide {
|
||||||
pub fn new(left: Rc<NodeEnum>, right: Rc<NodeEnum>) -> Self {
|
pub fn new(left: Rc<NodeEnum>, right: Rc<NodeEnum>) -> Self {
|
||||||
Self {
|
Self { left, right }
|
||||||
left,
|
|
||||||
right
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_left(&self) -> Rc<NodeEnum> {
|
pub fn get_left(&self) -> Rc<NodeEnum> {
|
||||||
|
|
|
@ -3,14 +3,20 @@ use std::{rc::Rc, sync::LazyLock};
|
||||||
use super::{Environment, Node, NodeEnum, Precedence};
|
use super::{Environment, Node, NodeEnum, Precedence};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||||
pub struct Empty;
|
pub struct Empty {
|
||||||
|
message: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
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>, String> {
|
||||||
Ok(Empty::EMPTY.clone())
|
Ok(Empty::EMPTY.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_string(&self, _: Option<&Environment>) -> String {
|
fn as_string(&self, _: Option<&Environment>) -> String {
|
||||||
String::from("{{#VOID}}")
|
match &self.message {
|
||||||
|
Some(m) => m.clone(),
|
||||||
|
None => String::from("{{#VOID}}"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn precedence(&self) -> Precedence {
|
fn precedence(&self) -> Precedence {
|
||||||
|
@ -19,5 +25,15 @@ impl Node for Empty {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Empty {
|
impl Empty {
|
||||||
pub const EMPTY: LazyLock<Rc<NodeEnum>> = LazyLock::new(|| Rc::new(Empty{}.into()));
|
pub const EMPTY: LazyLock<Rc<NodeEnum>> =
|
||||||
|
LazyLock::new(|| Rc::new(Empty { message: None }.into()));
|
||||||
|
|
||||||
|
pub fn new(message: impl Into<String>) -> Rc<NodeEnum> {
|
||||||
|
Rc::new(
|
||||||
|
Self {
|
||||||
|
message: Some(message.into()),
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
39
src/lib/node/equals.rs
Normal file
39
src/lib/node/equals.rs
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use super::{Environment, Node, NodeEnum, Precedence, if_else::Bool};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||||
|
pub struct Equals {
|
||||||
|
left: Rc<NodeEnum>,
|
||||||
|
right: Rc<NodeEnum>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Node for Equals {
|
||||||
|
fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, String> {
|
||||||
|
let left = self.left.evaluate(env)?;
|
||||||
|
let right = self.right.evaluate(env)?;
|
||||||
|
|
||||||
|
match left == right {
|
||||||
|
true => Ok(Rc::new(Bool::True.into())),
|
||||||
|
false => Ok(Rc::new(Bool::False.into())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_string(&self, env: Option<&Environment>) -> String {
|
||||||
|
format!(
|
||||||
|
"({}={})",
|
||||||
|
self.left.as_string(env),
|
||||||
|
self.right.as_string(env)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn precedence(&self) -> Precedence {
|
||||||
|
Precedence::Primary
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Equals {
|
||||||
|
pub fn new(left: Rc<NodeEnum>, right: Rc<NodeEnum>) -> Self {
|
||||||
|
Self { left, right }
|
||||||
|
}
|
||||||
|
}
|
|
@ -30,7 +30,7 @@ impl Node for Function {
|
||||||
let args = self
|
let args = self
|
||||||
.arguments
|
.arguments
|
||||||
.iter()
|
.iter()
|
||||||
.map(|x| Node::as_string(x, None))
|
.map(|x| Node::as_string(x, env))
|
||||||
.reduce(|acc, e| format!("{acc}, {e}"))
|
.reduce(|acc, e| format!("{acc}, {e}"))
|
||||||
.unwrap_or("()".to_owned());
|
.unwrap_or("()".to_owned());
|
||||||
|
|
||||||
|
@ -46,10 +46,15 @@ impl Node for Function {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Function {
|
impl Function {
|
||||||
// TODO: Implement new.
|
pub fn new(t: FunctionType, args: Vec<Symbol>) -> Rc<NodeEnum> {
|
||||||
// pub fn new(t: FunctionType, ) -> Self {
|
Rc::new(
|
||||||
//
|
Self {
|
||||||
// }
|
function: t,
|
||||||
|
arguments: args,
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_body(&self) -> &FunctionType {
|
pub fn get_body(&self) -> &FunctionType {
|
||||||
&self.function
|
&self.function
|
||||||
|
|
|
@ -12,6 +12,8 @@ use if_else::{Bool, IfElse};
|
||||||
use multiply::Multiply;
|
use multiply::Multiply;
|
||||||
use subtract::Subtract;
|
use subtract::Subtract;
|
||||||
use symbol::Symbol;
|
use symbol::Symbol;
|
||||||
|
use equals::Equals;
|
||||||
|
use set::Set;
|
||||||
|
|
||||||
use crate::environment::Environment;
|
use crate::environment::Environment;
|
||||||
|
|
||||||
|
@ -21,12 +23,14 @@ pub mod divide;
|
||||||
pub mod multiply;
|
pub mod multiply;
|
||||||
pub mod subtract;
|
pub mod subtract;
|
||||||
pub mod symbol;
|
pub mod symbol;
|
||||||
mod node_ref;
|
pub mod node_ref;
|
||||||
mod assign;
|
pub mod assign;
|
||||||
mod empty;
|
pub mod empty;
|
||||||
mod function;
|
pub mod function;
|
||||||
mod call;
|
pub mod call;
|
||||||
mod if_else;
|
pub mod if_else;
|
||||||
|
pub mod equals;
|
||||||
|
pub mod set;
|
||||||
|
|
||||||
#[enum_dispatch]
|
#[enum_dispatch]
|
||||||
#[enum_dispatch(Debug, Clone, PartialEq, PartialOrd, ToString)]
|
#[enum_dispatch(Debug, Clone, PartialEq, PartialOrd, ToString)]
|
||||||
|
@ -50,6 +54,14 @@ pub enum NodeEnum {
|
||||||
Bool,
|
Bool,
|
||||||
IfElse,
|
IfElse,
|
||||||
|
|
||||||
|
Set,
|
||||||
|
|
||||||
|
Equals,
|
||||||
|
// Greater,
|
||||||
|
// GreaterEquals,
|
||||||
|
// Less,
|
||||||
|
// LessEquals
|
||||||
|
|
||||||
// Logical operators
|
// Logical operators
|
||||||
// In,
|
// In,
|
||||||
// Where,
|
// Where,
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use super::{Node, NodeEnum, Precedence, constant::Constant};
|
use crate::environment::Environment;
|
||||||
|
|
||||||
|
use super::{Node, NodeEnum, Precedence, constant::Constant, set::Set};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||||
pub struct Multiply {
|
pub struct Multiply {
|
||||||
|
@ -14,10 +16,70 @@ impl Node for Multiply {
|
||||||
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()) {
|
||||||
|
// Zero rule
|
||||||
|
(NodeEnum::Constant(zero), _) | (_, NodeEnum::Constant(zero))
|
||||||
|
if zero.get_value() == 0. =>
|
||||||
|
{
|
||||||
|
Ok(Rc::new(Constant::new(0.).into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constant + Constant = Constant
|
||||||
(NodeEnum::Constant(a), NodeEnum::Constant(b)) => {
|
(NodeEnum::Constant(a), NodeEnum::Constant(b)) => {
|
||||||
Ok(Rc::new(Constant::new(a.get_value() * b.get_value()).into()))
|
Ok(Rc::new(Constant::new(a.get_value() * b.get_value()).into()))
|
||||||
}
|
}
|
||||||
_ => Err(format!("Invalid Multiply operation: {:?}", self)),
|
|
||||||
|
// Symbol + Constant we just return the same
|
||||||
|
(NodeEnum::Symbol(_), NodeEnum::Constant(_)) => Ok(Rc::new(
|
||||||
|
Multiply::new(evaluated_right, evaluated_left).into(),
|
||||||
|
)),
|
||||||
|
|
||||||
|
// Constant + Symbol we switch them around so the constant is last
|
||||||
|
(NodeEnum::Constant(_), NodeEnum::Symbol(_)) => Ok(Rc::new(
|
||||||
|
Multiply::new(evaluated_left, evaluated_right).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 mut values = Vec::with_capacity(old_values.len());
|
||||||
|
let c: Rc<NodeEnum> = Rc::new(c.clone().into());
|
||||||
|
|
||||||
|
for value in old_values.iter() {
|
||||||
|
let new_value = Multiply::new(c.clone(), value.clone());
|
||||||
|
values.push(new_value.evaluate(env)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Set::new(values))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiply a set with a constant
|
||||||
|
(NodeEnum::Set(s), NodeEnum::Symbol(c)) | (NodeEnum::Symbol(c), NodeEnum::Set(s)) => {
|
||||||
|
let old_values = s.get_values();
|
||||||
|
let mut values = Vec::with_capacity(old_values.len());
|
||||||
|
let c: Rc<NodeEnum> = Rc::new(c.clone().into());
|
||||||
|
|
||||||
|
for value in old_values.iter() {
|
||||||
|
let new_value = Multiply::new(c.clone(), value.clone());
|
||||||
|
values.push(new_value.evaluate(env)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Set::new(values))
|
||||||
|
}
|
||||||
|
|
||||||
|
(NodeEnum::Constant(c), NodeEnum::Multiply(m))
|
||||||
|
| (NodeEnum::Multiply(m), NodeEnum::Constant(c)) => {
|
||||||
|
Self::collapse_nested_multiply(c, m, env)?.evaluate(env)
|
||||||
|
}
|
||||||
|
|
||||||
|
// (NodeEnum::Multiply(m1), NodeEnum::Multiply(m2)) => {
|
||||||
|
// Self::move_constants_to_left(evaluated_left.clone(), evaluated_right.clone())
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Default to returning with left and right evaluated
|
||||||
|
_ => Ok(Rc::new(
|
||||||
|
Multiply::new(evaluated_left, evaluated_right).into(),
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,13 +103,79 @@ impl Node for Multiply {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Multiply {
|
impl Multiply {
|
||||||
pub fn new(left: Rc<NodeEnum>, right: Rc<NodeEnum>) -> Self {
|
fn collapse_nested_multiply(
|
||||||
Self {
|
constant: &Constant,
|
||||||
left,
|
multiply: &Multiply,
|
||||||
right
|
env: &mut Environment,
|
||||||
|
) -> Result<Rc<NodeEnum>, String> {
|
||||||
|
match (multiply.left.as_ref(), multiply.right.as_ref()) {
|
||||||
|
(NodeEnum::Constant(c2), _) => {
|
||||||
|
let new_const = Constant::new(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(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(),
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Multiply {
|
||||||
|
pub fn new(left: Rc<NodeEnum>, right: Rc<NodeEnum>) -> Self {
|
||||||
|
Self { left, right }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_rc(left: Rc<NodeEnum>, right: Rc<NodeEnum>) -> Rc<NodeEnum> {
|
||||||
|
Rc::new(Self::new(left, right).into())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_left(&self) -> Rc<NodeEnum> {
|
pub fn get_left(&self) -> Rc<NodeEnum> {
|
||||||
self.left.clone()
|
self.left.clone()
|
||||||
}
|
}
|
||||||
|
|
49
src/lib/node/set.rs
Normal file
49
src/lib/node/set.rs
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use super::{Environment, Node, NodeEnum, Precedence};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||||
|
pub struct Set {
|
||||||
|
values: Vec<Rc<NodeEnum>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Node for Set {
|
||||||
|
fn evaluate(&self, env: &mut super::Environment) -> Result<Rc<NodeEnum>, String> {
|
||||||
|
let mut values = Vec::with_capacity(self.values.len());
|
||||||
|
|
||||||
|
for value in self.values.iter() {
|
||||||
|
values.push(value.evaluate(env)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self::new(values))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_string(&self, env: Option<&Environment>) -> String {
|
||||||
|
format!(
|
||||||
|
"({})",
|
||||||
|
self.values
|
||||||
|
.iter()
|
||||||
|
.map(|x| x.as_string(env))
|
||||||
|
.reduce(|a, b| a + ", " + &b)
|
||||||
|
.unwrap()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn precedence(&self) -> Precedence {
|
||||||
|
Precedence::Primary
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Set {
|
||||||
|
pub fn new(values: Vec<Rc<NodeEnum>>) -> Rc<NodeEnum> {
|
||||||
|
Rc::new(Self { values }.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_values(&self) -> &Vec<Rc<NodeEnum>> {
|
||||||
|
&self.values
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_value(&mut self, values: Vec<Rc<NodeEnum>>) {
|
||||||
|
self.values = values;
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,10 +14,25 @@ impl Node for Subtract {
|
||||||
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()) {
|
||||||
|
// Zero rule
|
||||||
|
(NodeEnum::Constant(zero), _) if zero.get_value() == 0. => Ok(evaluated_right),
|
||||||
|
(_, NodeEnum::Constant(zero)) if zero.get_value() == 0. => Ok(evaluated_left),
|
||||||
|
|
||||||
|
// Constant + Constant = Constant
|
||||||
(NodeEnum::Constant(a), NodeEnum::Constant(b)) => {
|
(NodeEnum::Constant(a), NodeEnum::Constant(b)) => {
|
||||||
Ok(Rc::new(Constant::new(a.get_value() - b.get_value()).into()))
|
Ok(Rc::new(Constant::new(a.get_value() - b.get_value()).into()))
|
||||||
}
|
}
|
||||||
_ => Err(format!("Invalid Add operation: {:?}", self)),
|
// Symbol + Constant we just return the same
|
||||||
|
(NodeEnum::Symbol(_), NodeEnum::Constant(_)) => {
|
||||||
|
Ok(Rc::new(Subtract::new(evaluated_left, evaluated_right).into()))
|
||||||
|
}
|
||||||
|
// Constant + Symbol we switch them around so the constant is last
|
||||||
|
(NodeEnum::Constant(_), NodeEnum::Symbol(_)) => {
|
||||||
|
Ok(Rc::new(Subtract::new(evaluated_right, evaluated_left).into()))
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
Ok(Rc::new(Subtract::new(evaluated_left, evaluated_right).into()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,20 +28,12 @@ impl Node for Symbol {
|
||||||
if let Some(value) = env.get(&self.value) {
|
if let Some(value) = env.get(&self.value) {
|
||||||
value.as_string(Some(env))
|
value.as_string(Some(env))
|
||||||
} else {
|
} else {
|
||||||
Symbol::ID_TO_STR_MAP
|
env.id_to_str(&self.value)
|
||||||
.lock()
|
.cloned()
|
||||||
.unwrap()
|
.unwrap_or(format!("{{#SYMBOL {}}}", self.value))
|
||||||
.get(&self.value)
|
|
||||||
.unwrap_or(&format!("{{#SYMBOL {}}}", self.value))
|
|
||||||
.clone()
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Symbol::ID_TO_STR_MAP
|
format!("{{#SYMBOL {}}}", self.value)
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.get(&self.value)
|
|
||||||
.unwrap_or(&format!("{{#SYMBOL {}}}", self.value))
|
|
||||||
.clone()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,32 +43,17 @@ impl Node for Symbol {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Symbol {
|
impl Symbol {
|
||||||
const STR_TO_ID_MAP: LazyLock<Mutex<HashMap<String, EnvironmentInternalSymbolKey>>> =
|
|
||||||
LazyLock::new(|| HashMap::new().into());
|
|
||||||
const ID_TO_STR_MAP: LazyLock<Mutex<HashMap<EnvironmentInternalSymbolKey, String>>> =
|
|
||||||
LazyLock::new(|| HashMap::new().into());
|
|
||||||
|
|
||||||
pub fn new(value: EnvironmentInternalSymbolKey) -> Self {
|
pub fn new(value: EnvironmentInternalSymbolKey) -> Self {
|
||||||
Self { value }
|
Self { value }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_from_str(str: impl Into<String>) -> Self {
|
pub fn new_from_str(str: impl Into<String>, env: &mut Environment) -> Self {
|
||||||
let str = str.into();
|
let str = str.into();
|
||||||
if let Some(value) = Symbol::STR_TO_ID_MAP.lock().unwrap().get(str.as_str()) {
|
if let Some(value) = env.str_to_id(&str) {
|
||||||
Self::new(value.clone())
|
Self::new(value.clone())
|
||||||
} else {
|
} else {
|
||||||
let id = Symbol::STR_TO_ID_MAP
|
let id = env.get_new_id();
|
||||||
.lock()
|
env.insert_str_to_id(str.clone(), id);
|
||||||
.unwrap()
|
|
||||||
.len()
|
|
||||||
.try_into()
|
|
||||||
.unwrap();
|
|
||||||
Symbol::STR_TO_ID_MAP
|
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.insert(str.clone(), id);
|
|
||||||
Symbol::ID_TO_STR_MAP.lock().unwrap().insert(id, str);
|
|
||||||
|
|
||||||
Self::new(id)
|
Self::new(id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,29 +1,45 @@
|
||||||
use std::{collections::HashMap, iter::Peekable, rc::Rc, slice::Iter, vec::IntoIter};
|
use std::{collections::HashMap, iter::Peekable, rc::Rc, slice::Iter, str::Chars, vec::IntoIter};
|
||||||
|
|
||||||
use crate::node::{
|
use crate::{
|
||||||
NodeEnum,
|
environment::Environment,
|
||||||
add::Add,
|
node::{
|
||||||
constant::{Constant, ConstantValue},
|
NodeEnum,
|
||||||
divide::Divide,
|
add::Add,
|
||||||
multiply::Multiply,
|
assign::Assign,
|
||||||
subtract::Subtract,
|
call::Call,
|
||||||
|
constant::{Constant, ConstantValue},
|
||||||
|
divide::Divide,
|
||||||
|
equals::Equals,
|
||||||
|
function::{Function, FunctionType},
|
||||||
|
multiply::Multiply,
|
||||||
|
set::Set,
|
||||||
|
subtract::Subtract,
|
||||||
|
symbol::Symbol,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Token(usize, TokenType);
|
pub struct Token(usize, TokenType);
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum TokenType {
|
pub enum TokenType {
|
||||||
// Space,
|
// Space,
|
||||||
Number(ConstantValue),
|
Number(ConstantValue),
|
||||||
|
Identifier(String),
|
||||||
|
|
||||||
Plus,
|
Plus,
|
||||||
Minus,
|
Minus,
|
||||||
Star,
|
Star,
|
||||||
Slash,
|
Slash,
|
||||||
|
|
||||||
|
Equals,
|
||||||
|
|
||||||
|
ColonEquals,
|
||||||
|
LeftArrow,
|
||||||
|
|
||||||
RParen,
|
RParen,
|
||||||
LParen,
|
LParen,
|
||||||
|
Comma,
|
||||||
|
|
||||||
If,
|
If,
|
||||||
Then,
|
Then,
|
||||||
|
@ -31,8 +47,35 @@ pub enum TokenType {
|
||||||
End,
|
End,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TokenType {
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
match self {
|
||||||
|
TokenType::Number(n) => n.to_string().len(),
|
||||||
|
TokenType::Identifier(s) => s.len(),
|
||||||
|
|
||||||
|
TokenType::Plus => 1,
|
||||||
|
TokenType::Minus => 1,
|
||||||
|
TokenType::Star => 1,
|
||||||
|
TokenType::Slash => 1,
|
||||||
|
TokenType::Equals => 1,
|
||||||
|
|
||||||
|
TokenType::ColonEquals => 2,
|
||||||
|
TokenType::LeftArrow => 2,
|
||||||
|
|
||||||
|
TokenType::RParen => 1,
|
||||||
|
TokenType::LParen => 1,
|
||||||
|
TokenType::Comma => 1,
|
||||||
|
|
||||||
|
TokenType::If => 2,
|
||||||
|
TokenType::Then => 4,
|
||||||
|
TokenType::Else => 4,
|
||||||
|
TokenType::End => 3,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Lexer<'a> {
|
pub struct Lexer<'a> {
|
||||||
source: &'a String,
|
source: Peekable<Chars<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -42,40 +85,41 @@ pub enum LexerError {
|
||||||
|
|
||||||
impl<'a> Lexer<'a> {
|
impl<'a> Lexer<'a> {
|
||||||
pub fn new(source: &'a String) -> Self {
|
pub fn new(source: &'a String) -> Self {
|
||||||
Self { source }
|
Self {
|
||||||
|
source: source.chars().peekable(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lex(&'a mut self) -> Result<Vec<Token>, LexerError> {
|
pub fn lex(&'a mut self) -> Result<Vec<Token>, LexerError> {
|
||||||
let mut src = self.source.chars().peekable();
|
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
let mut tokens = vec![];
|
let mut tokens = vec![];
|
||||||
|
|
||||||
while let Some(c) = src.next() {
|
while let Some(c) = self.source.next() {
|
||||||
match c {
|
match c {
|
||||||
// Collapse spaces into a single Space token
|
// Collapse spaces into a single Space token
|
||||||
' ' => {
|
' ' => {
|
||||||
while src.peek() == Some(&' ') {
|
while self.source.peek() == Some(&' ') {
|
||||||
src.next();
|
self.source.next();
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
// tokens.push(Token(i, TokenType::Space));
|
// tokens.push(Token(i, TokenType::Space));
|
||||||
}
|
}
|
||||||
// Comments with //
|
// Comments with //
|
||||||
'/' if src.peek() == Some(&'/') => {
|
'/' if self.source.peek() == Some(&'/') => {
|
||||||
while src.next() != Some('\n') {
|
while self.source.next() != Some('\n') {
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Numbers with decimal points
|
// Numbers with decimal points
|
||||||
'0'..'9' | '.' => {
|
'0'..='9' | '.' => {
|
||||||
let mut digit = String::from(c);
|
let mut digit = String::from(c);
|
||||||
loop {
|
loop {
|
||||||
let d = src.peek();
|
let d = self.source.peek();
|
||||||
let mut has_decimal = c == '.';
|
let mut has_decimal = c == '.';
|
||||||
match d {
|
match d {
|
||||||
Some('0'..'9') => {
|
Some('0'..='9') => {
|
||||||
digit.push(*d.unwrap());
|
digit.push(*d.unwrap());
|
||||||
src.next();
|
self.source.next();
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
#[allow(unused_assignments)] // For some reason it thinks has_decimal
|
#[allow(unused_assignments)] // For some reason it thinks has_decimal
|
||||||
|
@ -101,14 +145,33 @@ impl<'a> Lexer<'a> {
|
||||||
tokens.push(Token(i, TokenType::Number(number)));
|
tokens.push(Token(i, TokenType::Number(number)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LeftArrow (->)
|
||||||
|
'-' if self.source.peek() == Some(&'>') => {
|
||||||
|
self.source.next();
|
||||||
|
i += 1;
|
||||||
|
tokens.push(Token(i, TokenType::LeftArrow));
|
||||||
|
}
|
||||||
|
|
||||||
'+' => tokens.push(Token(i, TokenType::Plus)),
|
'+' => tokens.push(Token(i, TokenType::Plus)),
|
||||||
'-' => tokens.push(Token(i, TokenType::Minus)),
|
'-' => tokens.push(Token(i, TokenType::Minus)),
|
||||||
'*' => tokens.push(Token(i, TokenType::Star)),
|
'*' => tokens.push(Token(i, TokenType::Star)),
|
||||||
'/' => tokens.push(Token(i, TokenType::Slash)),
|
'/' => tokens.push(Token(i, TokenType::Slash)),
|
||||||
|
'=' => tokens.push(Token(i, TokenType::Equals)),
|
||||||
|
',' => tokens.push(Token(i, TokenType::Comma)),
|
||||||
|
|
||||||
|
':' if self.source.peek() == Some(&'=') => {
|
||||||
|
self.source.next();
|
||||||
|
i += 1;
|
||||||
|
tokens.push(Token(i, TokenType::ColonEquals));
|
||||||
|
}
|
||||||
|
|
||||||
'(' => tokens.push(Token(i, TokenType::LParen)),
|
'(' => tokens.push(Token(i, TokenType::LParen)),
|
||||||
')' => tokens.push(Token(i, TokenType::RParen)),
|
')' => tokens.push(Token(i, TokenType::RParen)),
|
||||||
|
|
||||||
|
_ if c.is_alphabetic() || c == '_' => {
|
||||||
|
tokens.push(self.lex_identifier(&mut i, c)?);
|
||||||
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
return Err(LexerError::UnexpectedChar(
|
return Err(LexerError::UnexpectedChar(
|
||||||
i,
|
i,
|
||||||
|
@ -121,26 +184,57 @@ impl<'a> Lexer<'a> {
|
||||||
|
|
||||||
Ok(tokens)
|
Ok(tokens)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn lex_identifier<'b>(&'b mut self, i: &mut usize, c: char) -> Result<Token, LexerError> {
|
||||||
|
let mut identifier = c.to_string();
|
||||||
|
|
||||||
|
while let Some(c) = self.source.peek() {
|
||||||
|
if c.is_alphanumeric() || c == &'_' || c == &'\'' {
|
||||||
|
identifier.push(*c);
|
||||||
|
self.source.next();
|
||||||
|
*i += 1;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Token(
|
||||||
|
*i,
|
||||||
|
match identifier.to_lowercase().as_str() {
|
||||||
|
"if" => TokenType::If,
|
||||||
|
"then" => TokenType::Then,
|
||||||
|
"else" => TokenType::Else,
|
||||||
|
"end" => TokenType::End,
|
||||||
|
_ => TokenType::Identifier(identifier),
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum ParserError {
|
pub enum ParserError {
|
||||||
UnexpectedEndOfTokens(String),
|
UnexpectedEndOfTokens(String),
|
||||||
UnexpectedToken(usize, String),
|
UnexpectedToken(usize, usize, String),
|
||||||
|
Unimplemented(usize, usize, String),
|
||||||
|
UnexpectedNode(usize, String),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Recursive descent parser
|
/// Recursive descent parser
|
||||||
pub struct Parser {
|
pub struct Parser<'a> {
|
||||||
tokens: Peekable<IntoIter<Token>>,
|
tokens: Peekable<IntoIter<Token>>,
|
||||||
|
environment: &'a mut Environment,
|
||||||
|
previous: Option<&'a Token>,
|
||||||
}
|
}
|
||||||
|
|
||||||
type Tokens<'a> = Peekable<Iter<'a, Token>>;
|
type Tokens<'a> = Peekable<Iter<'a, Token>>;
|
||||||
|
|
||||||
impl Parser {
|
impl<'a> Parser<'a> {
|
||||||
pub fn new(tokens: Vec<Token>) -> Self {
|
pub fn new(tokens: Vec<Token>, env: &'a mut Environment) -> Self {
|
||||||
// #[cfg(debug_assertions)]
|
// #[cfg(debug_assertions)]
|
||||||
// println!("\r{tokens:#?}");
|
// println!("\r{tokens:?}");
|
||||||
Self {
|
Self {
|
||||||
tokens: tokens.into_iter().peekable(),
|
tokens: tokens.into_iter().peekable(),
|
||||||
|
environment: env,
|
||||||
|
previous: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,13 +249,61 @@ impl Parser {
|
||||||
Ok(expressions)
|
Ok(expressions)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn matchType<'b>(&'b mut self, t: TokenType) -> bool {
|
||||||
|
if let Some(Token(_, token_type)) = self.tokens.peek() {
|
||||||
|
if *token_type == t {
|
||||||
|
self.tokens.next();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn matchOrErr(&mut self, t: TokenType) -> Result<bool, ParserError> {
|
||||||
|
let (i, tt) = if let Some(Token(i, tt)) = self.tokens.peek() {
|
||||||
|
(*i, tt.clone())
|
||||||
|
} else {
|
||||||
|
return Err(ParserError::UnexpectedEndOfTokens(format!(
|
||||||
|
"Expected {t:?} but found nothing instead"
|
||||||
|
)));
|
||||||
|
};
|
||||||
|
|
||||||
|
if self.matchType(t.clone()) {
|
||||||
|
Ok(true)
|
||||||
|
} else {
|
||||||
|
Err(ParserError::UnexpectedToken(
|
||||||
|
i,
|
||||||
|
tt.len(),
|
||||||
|
format!("Expected {t:?} but found {tt:?} instead"),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn expression(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
fn expression(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
||||||
self.equality()
|
self.assignment()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assignment(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
||||||
|
let expr = self.equality();
|
||||||
|
|
||||||
|
if let Some(Token(_, TokenType::ColonEquals)) = self.tokens.peek() {
|
||||||
|
self.tokens.next();
|
||||||
|
return Ok(Rc::new(Assign::new(expr?, self.equality()?).into()));
|
||||||
|
}
|
||||||
|
|
||||||
|
expr
|
||||||
}
|
}
|
||||||
|
|
||||||
fn equality(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
fn equality(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
||||||
// TODO: Implement equality
|
// TODO: Implement equality
|
||||||
self.comparison()
|
let expr = self.comparison();
|
||||||
|
if self.matchType(TokenType::Equals) {
|
||||||
|
return Ok(Rc::new(Equals::new(expr?, self.equality()?).into()));
|
||||||
|
}
|
||||||
|
expr
|
||||||
}
|
}
|
||||||
|
|
||||||
fn comparison(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
fn comparison(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
||||||
|
@ -171,8 +313,7 @@ impl Parser {
|
||||||
|
|
||||||
fn term(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
fn term(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
||||||
let expr = self.factor()?;
|
let expr = self.factor()?;
|
||||||
if let Some(Token(_, TokenType::Plus)) = self.tokens.peek() {
|
if self.matchType(TokenType::Plus) {
|
||||||
self.tokens.next();
|
|
||||||
Ok(Rc::new(Add::new(expr, self.comparison()?).into()))
|
Ok(Rc::new(Add::new(expr, self.comparison()?).into()))
|
||||||
} else if let Some(Token(_, TokenType::Minus)) = self.tokens.peek() {
|
} else if let Some(Token(_, TokenType::Minus)) = self.tokens.peek() {
|
||||||
self.tokens.next();
|
self.tokens.next();
|
||||||
|
@ -204,11 +345,83 @@ impl Parser {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
fn call(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
||||||
self.function()
|
let mut expr = self.function();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let (i, t) = if let Some(Token(i, x)) = self.tokens.peek() {
|
||||||
|
(*i, x.clone())
|
||||||
|
} else {
|
||||||
|
return expr;
|
||||||
|
};
|
||||||
|
|
||||||
|
if t == TokenType::LParen {
|
||||||
|
let potential_parameters = self.primary()?;
|
||||||
|
let parameters = if let NodeEnum::Set(set) = potential_parameters.as_ref() {
|
||||||
|
potential_parameters
|
||||||
|
} else {
|
||||||
|
// return Err(ParserError::UnexpectedNode(
|
||||||
|
// i,
|
||||||
|
// format!("Expected a Set here, but got a {potential_parameters:?}"),
|
||||||
|
// ));
|
||||||
|
Set::new(vec![potential_parameters])
|
||||||
|
};
|
||||||
|
|
||||||
|
expr = Ok(Call::new(expr?, parameters));
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expr
|
||||||
}
|
}
|
||||||
|
|
||||||
fn function(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
fn function(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
||||||
self.primary()
|
let error_loc = if let Some(Token(i, _)) = self.tokens.peek() {
|
||||||
|
*i
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
let expr = self.primary()?;
|
||||||
|
|
||||||
|
if self.matchType(TokenType::LeftArrow) {
|
||||||
|
let right = self.equality()?;
|
||||||
|
match expr.clone().as_ref() {
|
||||||
|
NodeEnum::Symbol(symbol) => {
|
||||||
|
return Ok(Function::new(
|
||||||
|
FunctionType::UserFunction(right),
|
||||||
|
vec![symbol.clone()],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
NodeEnum::Set(set) => {
|
||||||
|
let mut symbols = vec![];
|
||||||
|
for (i, value) in set.get_values().into_iter().enumerate() {
|
||||||
|
match value.as_ref() {
|
||||||
|
_ => {
|
||||||
|
return Err(ParserError::UnexpectedNode(
|
||||||
|
error_loc,
|
||||||
|
format!(
|
||||||
|
"Expected set of Identifiers, but argument #{i} is a {value:?}"
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeEnum::Symbol(symbol) => symbols.push(symbol.clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(Function::new(FunctionType::UserFunction(right), symbols));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(ParserError::UnexpectedNode(
|
||||||
|
error_loc,
|
||||||
|
format!("Expected Set, got {:?}", expr),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn primary(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
fn primary(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
|
||||||
|
@ -222,8 +435,73 @@ impl Parser {
|
||||||
|
|
||||||
match token {
|
match token {
|
||||||
TokenType::Number(value) => Ok(Rc::new(Constant::new(value).into())),
|
TokenType::Number(value) => Ok(Rc::new(Constant::new(value).into())),
|
||||||
|
TokenType::Identifier(string) => Ok(Rc::new(
|
||||||
|
Symbol::new_from_str(string, self.environment).into(),
|
||||||
|
)),
|
||||||
|
TokenType::LParen => {
|
||||||
|
let expr = self.expression()?;
|
||||||
|
let (i, t) = if let Some(Token(i, x)) = self.tokens.peek() {
|
||||||
|
(i, x)
|
||||||
|
} else {
|
||||||
|
return Err(ParserError::UnexpectedEndOfTokens(
|
||||||
|
"Unclosed right parenthesis".into(),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
|
match t {
|
||||||
|
TokenType::RParen => {
|
||||||
|
self.tokens.next();
|
||||||
|
Ok(expr)
|
||||||
|
}
|
||||||
|
TokenType::Comma => {
|
||||||
|
let mut values = vec![expr];
|
||||||
|
while {
|
||||||
|
if let Some(Token(_, TokenType::RParen)) = self.tokens.peek() {
|
||||||
|
self.tokens.next();
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
} {
|
||||||
|
let (i, token) = if let Some(Token(i, x)) = self.tokens.peek() {
|
||||||
|
(i, x)
|
||||||
|
} else {
|
||||||
|
return Err(ParserError::UnexpectedEndOfTokens(
|
||||||
|
"Expected comma here".into(),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
|
if *token == TokenType::Comma {
|
||||||
|
self.tokens.next();
|
||||||
|
} else {
|
||||||
|
return Err(ParserError::UnexpectedToken(
|
||||||
|
*i,
|
||||||
|
token.len(),
|
||||||
|
format!("Expected comma here, but got {token:?}"),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
values.push(self.equality()?);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Set::new(values))
|
||||||
|
}
|
||||||
|
_ => Err(ParserError::Unimplemented(
|
||||||
|
*i,
|
||||||
|
t.len(),
|
||||||
|
format!("Expected either a comma or a right parenthesis here. Got {t:?}"),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
|
||||||
|
// if t != TokenType::RParen {
|
||||||
|
// Err(ParserError::UnexpectedToken(i, t.len(), format!("")))
|
||||||
|
// } else {
|
||||||
|
// Ok(expr)
|
||||||
|
// }
|
||||||
|
}
|
||||||
_ => Err(ParserError::UnexpectedToken(
|
_ => Err(ParserError::UnexpectedToken(
|
||||||
i,
|
i,
|
||||||
|
token.len(),
|
||||||
format!("Unexpected token {token:?}"),
|
format!("Unexpected token {token:?}"),
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue