implemented more nodes

This commit is contained in:
Snorre 2025-02-20 17:15:59 +01:00
parent c5a0180f04
commit b7834b5244
16 changed files with 782 additions and 125 deletions

View file

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

View file

@ -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
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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
View 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 }
}
}

View file

@ -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

View file

@ -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,

View file

@ -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
View 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;
}
}

View file

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

View file

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

View file

@ -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:?}"),
)), )),
} }