use std::collections::HashMap; use super::errors::CompilerError; use super::parser::{Expression, LiteralPattern, ParsedReid, Pattern, Position, Statement}; type Variable = (HeapID, VariableType); type HeapID = u32; type RegID = u32; #[derive(Debug)] pub enum Command { InitializeVariable(HeapID, VariableType), // Initializes new variable to HeapID at VariableType BeginScope, // Begins new Scope EndScope, // Ends Scope Pop(RegID), // Pop into registery at RegID Push(RegID), // Push out of registery at RegID AssignVariable(HeapID, RegID), // Assign variable from registery at RegID VarToReg(HeapID, RegID), // Bring Variable to registery at RegID StringLit(String), // Bring String Literal to Stack } #[derive(Debug, Copy, Clone)] pub enum VariableType { TypeString, } pub struct Compiler { parsed: ParsedReid, root_scope: Scope, list: Vec, } #[derive(Debug)] pub struct CompiledReid { pub list: Vec, } impl Compiler { pub fn from(parsed: ParsedReid) -> Compiler { Compiler { parsed, root_scope: Scope::default(), list: Vec::new(), } } pub fn compile(mut self) -> Result { self.handle_expression(self.parsed.0.clone())?; Ok(CompiledReid { list: self.list }) } fn handle_expression( &mut self, exp: Expression, ) -> Result, CompilerError> { match exp { Expression::BlockExpr(pos, list) => { self.list.push(Command::BeginScope); self.root_scope.begin_scope(); for statement in list { self.handle_statement(statement)?; } self.root_scope.end_scope(pos)?; self.list.push(Command::EndScope); Ok(None) } Expression::ValueRef(_, val) => match val { Pattern::IdentPattern(pos, ident) => { if let Some(var) = self.root_scope.get(ident.clone()) { self.list.push(Command::VarToReg(var.0, 0)); self.list.push(Command::Push(0)); Ok(Some(var.1)) } else { Err(CompilerError::VariableNotExists(pos, ident)) } } Pattern::LiteralPattern(_, literal) => { let vtype = self.handle_literal(literal)?; Ok(Some(vtype)) } }, } } fn handle_statement( &mut self, statement: Statement, ) -> Result, CompilerError> { match statement { Statement::LetStatement(pos, ident, val) => { let res = self.handle_expression(*val); match res { Ok(vtype) => { if let Some(vtype) = vtype { self.root_scope.add_var(pos, ident.clone(), vtype)?; let var = self.root_scope.get(ident).unwrap(); self.list.push(Command::InitializeVariable(var.0, var.1)); self.list.push(Command::Pop(0)); self.list.push(Command::AssignVariable(var.0, 0)); Ok(None) } else { Err(CompilerError::LetFailed( pos, Box::new(CompilerError::CanNotAssignVoidType), )) } } Err(err) => Err(CompilerError::LetFailed(pos, Box::new(err))), } } Statement::ExprStatement(_, expr) => self.handle_expression(expr), } } fn handle_literal(&mut self, pattern: LiteralPattern) -> Result { match pattern { LiteralPattern::StringLit(string) => self.list.push(Command::StringLit(string)), } Ok(VariableType::TypeString) } } #[derive(Default)] pub struct Scope { counter: HeapID, variables: HashMap, inner_scope: Option>, } impl Scope { fn get(&self, variable: String) -> Option { if let Some(val) = self.variables.get(&variable) { Some(*val) } else if let Some(inner) = &self.inner_scope { if let Some(val) = inner.get(variable) { Some((val.0 + self.counter, val.1)) } else { None } } else { None } } fn add_var( &mut self, pos: Position, variable: String, vtype: VariableType, ) -> Result<(), CompilerError> { if self.variables.contains_key(&variable) { Err(CompilerError::VariableExists(pos, variable)) } else if let Some(inner) = &mut self.inner_scope { inner.add_var(pos, variable, vtype) } else { self.variables.insert(variable, (self.counter, vtype)); self.counter += 1; Ok(()) } } fn begin_scope(&mut self) { if let Some(inner) = &mut self.inner_scope { inner.begin_scope(); } else { self.inner_scope = Some(Box::default()); } } fn end_scope(&mut self, pos: Position) -> Result<(), CompilerError> { if let Some(inner) = &mut self.inner_scope { if inner.inner_scope.is_some() { inner.end_scope(pos)?; } else { self.inner_scope = None; } Ok(()) } else { Err(CompilerError::InvalidScopeExit(pos)) } } }