Add arithmeticexpression

This commit is contained in:
Sofia 2020-07-05 22:20:49 +03:00
parent ec32e55357
commit 00619f09fd
7 changed files with 320 additions and 38 deletions

View File

@ -1,2 +1,3 @@
let gotus = "Hello, world!";
print(gotus);
let number = 2 + 5 * 2 + 5 + 1 * 10 + 1;
let text = "" + number;
print(text);

View File

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

View File

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

View File

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

View File

@ -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,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<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
}
}
#[derive(Debug, Clone)]
pub enum Pattern {
IdentPattern(Position, Ident),

View File

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

View File

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