Add arithmeticexpression
This commit is contained in:
parent
ec32e55357
commit
00619f09fd
@ -1,2 +1,3 @@
|
||||
let gotus = "Hello, world!";
|
||||
print(gotus);
|
||||
let number = 2 + 5 * 2 + 5 + 1 * 10 + 1;
|
||||
let text = "" + number;
|
||||
print(text);
|
@ -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<Command>,
|
||||
possible_arit_possib: Vec<ArithmeticOp>,
|
||||
}
|
||||
|
||||
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<Option<VariableType>, 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,
|
||||
|
@ -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<VariableType>),
|
||||
ParseIntError(ParseIntError),
|
||||
ArithmeticExpressionFailed(Position, Box<CompilerError>),
|
||||
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,
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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<Statement>),
|
||||
FunctionCall(Position, Ident, Vec<Expression>),
|
||||
ArithmeticExpression(Position, Box<ArithmeticExpression>),
|
||||
ValueRef(Position, Pattern),
|
||||
}
|
||||
|
||||
impl Expression {
|
||||
pub fn parse(parser: &mut Parser) -> Result<Expression, SyntaxError> {
|
||||
pub fn parse(parser: &mut Parser, allow_arithmetic: bool) -> Result<Expression, SyntaxError> {
|
||||
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,7 +101,100 @@ 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<ArithmeticExpression, SyntaxError> {
|
||||
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<String>)> = 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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<Value> {
|
||||
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<Value> {
|
||||
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<Value> {
|
||||
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)]
|
||||
|
@ -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);
|
||||
self.registry[regid as usize] = Some(self.pop_stack()?);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(RuntimePanic::StackUnderflow)
|
||||
}
|
||||
}
|
||||
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<Value, RuntimePanic> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user