diff --git a/reid_src/test.reid b/reid_src/test.reid index cdbddb0..5403a71 100644 --- a/reid_src/test.reid +++ b/reid_src/test.reid @@ -1,2 +1,3 @@ -let gotus = "Hello, world!"; -print(gotus); \ No newline at end of file +let number = 2 + 5 * 2 + 5 + 1 * 10 + 1; +let text = "" + number; +print(text); \ No newline at end of file diff --git a/src/compiler.rs b/src/compiler.rs index 981b57a..f7bfe56 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -3,23 +3,42 @@ use std::collections::HashMap; use std::num::ParseIntError; use super::errors::CompilerError; -use super::parser::{Expression, LiteralPattern, ParsedReid, Pattern, Statement}; +use super::parser::{ + ArithmeticExpression, Expression, LiteralPattern, ParsedReid, Pattern, Statement, +}; +use super::vm::VariableType::*; use super::vm::{Command, CompiledReid, FuncID, FunctionSignature, HeapID, Position, VariableType}; pub type Variable = (HeapID, VariableType); +#[derive(Debug, Clone)] +pub enum ArithmeticOp { + Add(VariableType, VariableType, VariableType), + Subtract(VariableType, VariableType, VariableType), + Mult(VariableType, VariableType, VariableType), +} + pub struct Compiler { parsed: ParsedReid, root_scope: Scope, list: Vec, + possible_arit_possib: Vec, } impl Compiler { pub fn from(parsed: ParsedReid) -> Compiler { + let list = vec![ + ArithmeticOp::Add(TypeI32, TypeI32, TypeI32), + ArithmeticOp::Subtract(TypeI32, TypeI32, TypeI32), + ArithmeticOp::Mult(TypeI32, TypeI32, TypeI32), + ArithmeticOp::Add(TypeString, TypeI32, TypeString), + ArithmeticOp::Add(TypeString, TypeString, TypeString), + ]; Compiler { parsed, root_scope: Scope::default(), list: Vec::new(), + possible_arit_possib: list, } } @@ -76,6 +95,9 @@ impl Compiler { Err(CompilerError::FunctionNotFound(pos, name, arguments)) } } + Expression::ArithmeticExpression(pos, val) => { + self.handle_arithmetic_expression(pos, *val) + } Expression::ValueRef(_, val) => match val { Pattern::IdentPattern(pos, ident) => { if let Some(var) = self.root_scope.get(ident.clone()) { @@ -94,6 +116,77 @@ impl Compiler { } } + fn handle_arithmetic_expression( + &mut self, + pos: Position, + exp: ArithmeticExpression, + ) -> Result, CompilerError> { + let (exp1, exp2) = match exp.clone() { + ArithmeticExpression::Add(e1, e2) => (e1, e2), + ArithmeticExpression::Subtract(e1, e2) => (e1, e2), + ArithmeticExpression::Mult(e1, e2) => (e1, e2), + }; + let type1 = self.handle_expression(exp1)?; + let type2 = self.handle_expression(exp2)?; + if let (Some(type1), Some(type2)) = (type1, type2) { + let mut return_type = None; + for op in &self.possible_arit_possib { + match op { + ArithmeticOp::Add(t1, t2, t3) => { + if let ArithmeticExpression::Add(..) = exp { + if (t1 == &type1 && t2 == &type2) || (t2 == &type1 && t1 == &type2) { + return_type = Some(t3); + break; + } + } + } + ArithmeticOp::Subtract(t1, t2, t3) => { + if let ArithmeticExpression::Subtract(..) = exp { + if (t1 == &type1 && t2 == &type2) || (t2 == &type1 && t1 == &type2) { + return_type = Some(t3); + break; + } + } + } + ArithmeticOp::Mult(t1, t2, t3) => { + if let ArithmeticExpression::Mult(..) = exp { + if (t1 == &type1 && t2 == &type2) || (t2 == &type1 && t1 == &type2) { + return_type = Some(t3); + break; + } + } + } + } + } + let (command, error) = match exp { + ArithmeticExpression::Add(..) => { + (Command::Add, ArithmeticOp::Add(type1, type2, TypeI32)) + } + ArithmeticExpression::Subtract(..) => ( + Command::Subtract, + ArithmeticOp::Subtract(type1, type2, TypeI32), + ), + ArithmeticExpression::Mult(..) => { + (Command::Mult, ArithmeticOp::Subtract(type1, type2, TypeI32)) + } + }; + if let Some(t) = return_type { + self.list.push(command); + Ok(Some(*t)) + } else { + Err(CompilerError::ArithmeticExpressionFailed( + pos, + Box::new(CompilerError::InvalidArithmeticOperation(error)), + )) + } + } else { + Err(CompilerError::ArithmeticExpressionFailed( + pos, + Box::new(CompilerError::CanNotAssignVoidType), + )) + } + } + fn handle_statement( &mut self, statement: Statement, diff --git a/src/errors.rs b/src/errors.rs index 916dfc1..f400659 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -5,6 +5,9 @@ use std::io; #[cfg(feature = "compiler")] use std::num::ParseIntError; +#[cfg(feature = "compiler")] +use super::compiler::ArithmeticOp; + #[cfg(feature = "compiler")] use super::vm::Position; use super::vm::VariableType; @@ -113,6 +116,8 @@ pub enum CompilerError { CanNotAssignVoidType, FunctionNotFound(Position, String, Vec), ParseIntError(ParseIntError), + ArithmeticExpressionFailed(Position, Box), + InvalidArithmeticOperation(ArithmeticOp), } #[cfg(feature = "compiler")] @@ -140,6 +145,23 @@ impl Display for CompilerError { pos ), CompilerError::ParseIntError(err) => format!("Failed to parse integer value: {}", err), + CompilerError::ArithmeticExpressionFailed(pos, err) => { + format!("Arithmetic expression failed at {}:\n {}", pos, err) + } + CompilerError::InvalidArithmeticOperation(op) => { + let text = match op { + ArithmeticOp::Add(t1, t2, _) => { + format!("{} + {}", t1.to_string(), t2.to_string()) + } + ArithmeticOp::Subtract(t1, t2, _) => { + format!("{} - {}", t1.to_string(), t2.to_string()) + } + ArithmeticOp::Mult(t1, t2, _) => { + format!("{} * {}", t1.to_string(), t2.to_string()) + } + }; + format!("Invalid arithmetic operation: {}", text) + } }; write!(f, "{}", text) } @@ -175,4 +197,5 @@ pub enum RuntimePanic { ValueNotInitialized, InvalidTypeAssign, InvalidFuncAddress, + AttemptedInvalidArithmeticOperation, } diff --git a/src/file_io.rs b/src/file_io.rs index 013a18d..05abb00 100644 --- a/src/file_io.rs +++ b/src/file_io.rs @@ -80,6 +80,9 @@ impl Command { Command::StringLit(..) => 7, Command::I32Lit(..) => 8, Command::FunctionCall(..) => 9, + Command::Add => 10, + Command::Subtract => 11, + Command::Mult => 12, } } @@ -128,6 +131,9 @@ impl Command { let funcid = u16::from_be_bytes([*iter.next()?, *iter.next()?]); Some(Command::FunctionCall(funcid)) } + 10 => Some(Command::Add), + 11 => Some(Command::Subtract), + 12 => Some(Command::Mult), _ => None, } } @@ -167,6 +173,9 @@ impl Command { let funcid = funcid.to_be_bytes(); list.append(&mut vec![funcid[0], funcid[1]]); } + Command::Add => (), + Command::Subtract => (), + Command::Mult => (), } list } diff --git a/src/parser/parsed_reid.rs b/src/parser/parsed_reid.rs index 51242bd..0d1721b 100644 --- a/src/parser/parsed_reid.rs +++ b/src/parser/parsed_reid.rs @@ -22,7 +22,7 @@ impl Statement { parser .expect_static("=") .get_or(SyntaxError::ExpectedToken(pos, '='))?; - match Expression::parse(parser) { + match Expression::parse(parser, true) { Ok(expr) => { parser .expect_static(";") @@ -32,7 +32,7 @@ impl Statement { Err(err) => Err(SyntaxError::ExpectedExpression(pos, Some(Box::new(err)))), } } else { - match Expression::parse(parser) { + match Expression::parse(parser, true) { Ok(expr) => { let statement = Statement::ExprStatement(pos, expr); parser @@ -50,14 +50,15 @@ impl Statement { pub enum Expression { BlockExpr(Position, Vec), FunctionCall(Position, Ident, Vec), + ArithmeticExpression(Position, Box), ValueRef(Position, Pattern), } impl Expression { - pub fn parse(parser: &mut Parser) -> Result { + pub fn parse(parser: &mut Parser, allow_arithmetic: bool) -> Result { let begin_pos = parser.pos(); - if parser.expect_static("{").get().is_some() { + let first = if parser.expect_static("{").get().is_some() { let mut statement_list = Vec::new(); while { match Statement::parse(parser) { @@ -78,7 +79,7 @@ impl Expression { let name = texts.get(0).unwrap(); let mut arg_list = Vec::new(); while { - match Expression::parse(parser) { + match Expression::parse(parser, true) { Ok(exp) => { arg_list.push(exp); parser.expect_static(",").get().is_some() @@ -100,10 +101,103 @@ impl Expression { Ok(Expression::ValueRef(begin_pos, pattern)) } else { Err(SyntaxError::ExpectedExpression(begin_pos, None)) + }?; + + if allow_arithmetic { + if let Ok(exp) = ArithmeticExpression::parse(first.clone(), parser) { + Ok(Expression::ArithmeticExpression(begin_pos, Box::new(exp))) + } else { + Ok(first) + } + } else { + Ok(first) } } } +#[derive(Debug, Clone)] +pub enum ArithmeticExpression { + Add(Expression, Expression), + Subtract(Expression, Expression), + Mult(Expression, Expression), +} + +impl ArithmeticExpression { + fn parse( + first_exp: Expression, + parser: &mut Parser, + ) -> Result { + let mut list = Vec::new(); + let mut exp = first_exp; + while { + let sign = parser + .expect_static("+") + .get() + .or_else(|| parser.expect_static("-").get()) + .or_else(|| parser.expect_static("*").get()); + if sign.is_some() { + list.push((exp, sign.clone())); + exp = Expression::parse(parser, false)?; + } + sign.is_some() + } {} + list.push((exp, None)); + if list.len() == 1 { + return Err(SyntaxError::Fatal); + } + + // Replace all (expr, "*"), (expr, any) => ((mult_expr, any) + let clone = list.clone(); + let iter = clone.iter().enumerate().rev(); + let mut previous: Option<(Expression, Option)> = None; + for (idx, (exp, sign)) in iter { + if let Some(sign) = sign { + if sign == "*" { + if let Some((exp2, sign2)) = previous { + list.remove(idx + 1); + list.remove(idx); + let expr = Expression::ArithmeticExpression( + parser.pos(), + Box::new(ArithmeticExpression::Mult(exp.clone(), exp2.clone())), + ); + list.insert(idx, (expr, sign2.clone())); + }; + } + } + previous = Some((exp.clone(), sign.clone())); + } + + let mut ret = Err(SyntaxError::Fatal); + while list.len() > 1 { + let (exp2, sign2) = list.remove(1); + let (exp1, sign1) = list.remove(0); + let expr = if let Some(sign1) = sign1 { + match &*sign1 { + "+" => Some(Box::new(ArithmeticExpression::Add(exp1, exp2))), + "-" => Some(Box::new(ArithmeticExpression::Subtract(exp1, exp2))), + _ => None, + } + } else { + return Err(SyntaxError::ExpectedExpression(parser.pos(), None)); + }; + if let Some(expr) = expr { + list.insert( + 0, + (Expression::ArithmeticExpression(parser.pos(), expr), sign2), + ); + } + } + + if let Some(first) = list.get(0) { + if let Expression::ArithmeticExpression(_, expr) = &first.0 { + ret = Ok(*expr.clone()); + } + } + + ret + } +} + #[derive(Debug, Clone)] pub enum Pattern { IdentPattern(Position, Ident), diff --git a/src/vm/compiled.rs b/src/vm/compiled.rs index 41b737d..5dc4bfb 100644 --- a/src/vm/compiled.rs +++ b/src/vm/compiled.rs @@ -1,6 +1,8 @@ use std::fmt; use std::fmt::Display; +use std::ops::{Add, Sub}; + pub type FuncID = u16; pub type HeapID = u16; pub type RegID = u8; @@ -17,6 +19,9 @@ pub enum Command { StringLit(String), // Bring String Literal to Stack I32Lit(i32), // Bring i32 Literal to Stack FunctionCall(FuncID), // Call Function at FuncID + Add, // Add last two items on stack + Subtract, // Subtract last two items on stack + Mult, // Subtract last two items on stack } #[derive(Debug)] @@ -37,6 +42,39 @@ impl Value { Value::I32Val(_) => VariableType::TypeI32, } } + + pub fn add(self, other: Value) -> Option { + match self { + Value::StringVal(string) => match other { + Value::StringVal(string2) => Some(Value::StringVal(string + &string2)), + Value::I32Val(val) => Some(Value::StringVal(string + &val.to_string())), + }, + Value::I32Val(val) => match other { + Value::StringVal(string) => Some(Value::StringVal(val.to_string() + &string)), + Value::I32Val(val2) => Some(Value::I32Val(val + val2)), + }, + } + } + + pub fn sub(self, other: Value) -> Option { + match self { + Value::StringVal(_) => None, + Value::I32Val(val) => match other { + Value::I32Val(val2) => Some(Value::I32Val(val - val2)), + _ => None, + }, + } + } + + pub fn mul(self, other: Value) -> Option { + match self { + Value::StringVal(_) => None, + Value::I32Val(val) => match other { + Value::I32Val(val2) => Some(Value::I32Val(val * val2)), + _ => None, + }, + } + } } #[derive(Debug, Copy, Clone, PartialEq, Eq)] diff --git a/src/vm/mod.rs b/src/vm/mod.rs index f8d81d7..baa39d6 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -73,38 +73,29 @@ impl VirtualMachine { match command { Command::InitializeVariable(heapid, vtype) => { self.heap.insert(heapid, AllocatedVar(vtype, None)); - //dbg!("Initialized new variable to heap", &self.heap); Ok(()) } Command::BeginScope => { self.registry_stack.push(self.registry.clone()); self.registry = Default::default(); - //dbg!("Begun new scope"); Ok(()) } Command::EndScope => { if let Some(reg) = self.registry_stack.pop() { self.registry = reg; - //dbg!("Scope ended"); Ok(()) } else { Err(RuntimePanic::ScopeStackUnderflow) } } Command::Pop(regid) => { - if let Some(val) = self.stack.pop() { - self.registry[regid as usize] = Some(val); - //dbg!("Registry popped", regid, &self.stack, &self.registry); - Ok(()) - } else { - Err(RuntimePanic::StackUnderflow) - } + self.registry[regid as usize] = Some(self.pop_stack()?); + Ok(()) } Command::Push(regid) => { if let Some(reg) = &self.registry[regid as usize] { if self.stack.len() < usize::MAX { self.stack.push(reg.clone()); - //dbg!("Registry pushed", regid, &self.stack); Ok(()) } else { Err(RuntimePanic::StackOverflow) @@ -117,7 +108,6 @@ impl VirtualMachine { if let Some(reg) = &self.registry[regid as usize] { if let Some(var) = self.heap.get_mut(&heapid) { var.try_set(Some(reg.clone()))?; - //dbg!("Variable assigned", heapid, regid, &self.heap); Ok(()) } else { Err(RuntimePanic::InvalidHeapAddress) @@ -130,7 +120,6 @@ impl VirtualMachine { if let Some(var) = self.heap.get(&heapid) { if let Some(val) = &var.1 { self.registry[regid as usize] = Some(val.clone()); - //dbg!("Variable pushed to registry", heapid, regid, &self.registry); Ok(()) } else { Err(RuntimePanic::ValueNotInitialized) @@ -139,23 +128,8 @@ impl VirtualMachine { Err(RuntimePanic::InvalidHeapAddress) } } - Command::StringLit(string) => { - if self.stack.len() < usize::MAX { - self.stack.push(Value::StringVal(string)); - //dbg!("String literal added to stack", string, &self.stack); - Ok(()) - } else { - Err(RuntimePanic::StackOverflow) - } - } - Command::I32Lit(val) => { - if self.stack.len() < usize::MAX { - self.stack.push(Value::I32Val(val)); - Ok(()) - } else { - Err(RuntimePanic::StackOverflow) - } - } + Command::StringLit(string) => self.push_stack(Value::StringVal(string)), + Command::I32Lit(val) => self.push_stack(Value::I32Val(val)), Command::FunctionCall(funcid) => { if self.functions.len() <= funcid as usize { Err(RuntimePanic::InvalidFuncAddress) @@ -176,6 +150,56 @@ impl VirtualMachine { Ok(()) } } + Command::Add => { + let val1 = self.pop_stack()?; + let val2 = self.pop_stack()?; + let res = val2.add(val1); + if let Some(res) = res { + self.push_stack(res); + Ok(()) + } else { + Err(RuntimePanic::AttemptedInvalidArithmeticOperation) + } + } + Command::Subtract => { + let val1 = self.pop_stack()?; + let val2 = self.pop_stack()?; + let res = val2.sub(val1); + if let Some(res) = res { + self.push_stack(res); + Ok(()) + } else { + Err(RuntimePanic::AttemptedInvalidArithmeticOperation) + } + } + Command::Mult => { + let val1 = self.pop_stack()?; + let val2 = self.pop_stack()?; + let res = val2.mul(val1); + if let Some(res) = res { + self.push_stack(res); + Ok(()) + } else { + Err(RuntimePanic::AttemptedInvalidArithmeticOperation) + } + } + } + } + + fn pop_stack(&mut self) -> Result { + if let Some(val) = self.stack.pop() { + Ok(val) + } else { + Err(RuntimePanic::StackUnderflow) + } + } + + fn push_stack(&mut self, val: Value) -> Result<(), RuntimePanic> { + if self.stack.len() < usize::MAX { + self.stack.push(val); + Ok(()) + } else { + Err(RuntimePanic::StackOverflow) } } }