233 lines
7.5 KiB
Rust
233 lines
7.5 KiB
Rust
use std::collections::hash_map::Entry;
|
|
use std::collections::HashMap;
|
|
use std::num::ParseIntError;
|
|
|
|
use super::errors::CompilerError;
|
|
use super::parser::{Expression, LiteralPattern, ParsedReid, Pattern, Statement};
|
|
use super::vm::{Command, CompiledReid, FuncID, FunctionSignature, HeapID, Position, VariableType};
|
|
|
|
pub type Variable = (HeapID, VariableType);
|
|
|
|
pub struct Compiler {
|
|
parsed: ParsedReid,
|
|
root_scope: Scope,
|
|
list: Vec<Command>,
|
|
}
|
|
|
|
impl Compiler {
|
|
pub fn from(parsed: ParsedReid) -> Compiler {
|
|
Compiler {
|
|
parsed,
|
|
root_scope: Scope::default(),
|
|
list: Vec::new(),
|
|
}
|
|
}
|
|
|
|
pub fn with_builtin_functions<T: Into<Vec<FunctionSignature>>>(mut self, list: T) -> Compiler {
|
|
self.add_builtin_functions(list.into());
|
|
self
|
|
}
|
|
|
|
pub fn compile(mut self) -> Result<CompiledReid, CompilerError> {
|
|
self.handle_expression(self.parsed.0.clone())?;
|
|
Ok(CompiledReid { list: self.list })
|
|
}
|
|
|
|
pub fn add_builtin_functions<T: Into<Vec<FunctionSignature>>>(&mut self, list: T) {
|
|
for func in list.into() {
|
|
self.root_scope.add_builtin_function(func);
|
|
}
|
|
}
|
|
|
|
fn handle_expression(
|
|
&mut self,
|
|
exp: Expression,
|
|
) -> Result<Option<VariableType>, 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::FunctionCall(pos, name, args) => {
|
|
let mut arguments = Vec::new();
|
|
|
|
for expr in args {
|
|
if let Some(vtype) = self.handle_expression(expr)? {
|
|
arguments.push(vtype);
|
|
} else {
|
|
return Err(CompilerError::CanNotAssignVoidType);
|
|
}
|
|
}
|
|
if let Some(func) = self
|
|
.root_scope
|
|
.find_function(&FunctionSignature::new(name.clone(), arguments.clone()))
|
|
{
|
|
self.list.push(Command::FunctionCall(func.0));
|
|
Ok(None)
|
|
} else {
|
|
Err(CompilerError::FunctionNotFound(pos, name, arguments))
|
|
}
|
|
}
|
|
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<Option<VariableType>, 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<VariableType, CompilerError> {
|
|
match pattern {
|
|
LiteralPattern::StringLit(string) => {
|
|
self.list.push(Command::StringLit(string));
|
|
Ok(VariableType::TypeString)
|
|
}
|
|
LiteralPattern::Integer32Lit(string) => {
|
|
self.list.push(Command::I32Lit(Compiler::handle_parseint(
|
|
string.parse::<i32>(),
|
|
)?));
|
|
Ok(VariableType::TypeI32)
|
|
}
|
|
}
|
|
}
|
|
|
|
fn handle_parseint<T>(res: Result<T, ParseIntError>) -> Result<T, CompilerError> {
|
|
match res {
|
|
Ok(i) => Ok(i),
|
|
Err(err) => Err(CompilerError::ParseIntError(err)),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Default)]
|
|
pub struct Scope {
|
|
counter: HeapID,
|
|
variables: HashMap<String, Variable>,
|
|
functions: Vec<FunctionSignature>,
|
|
inner_scope: Option<Box<Scope>>,
|
|
}
|
|
|
|
impl Scope {
|
|
fn get(&self, variable: String) -> Option<Variable> {
|
|
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 find_function(&self, signature: &FunctionSignature) -> Option<(FuncID, &FunctionSignature)> {
|
|
let mut found = None;
|
|
for (idx, func) in self.functions.iter().enumerate() {
|
|
if func == signature {
|
|
found = Some((idx as u16, func));
|
|
}
|
|
}
|
|
found
|
|
}
|
|
|
|
fn add_builtin_function(&mut self, function: FunctionSignature) -> bool {
|
|
if self.find_function(&function).is_some() {
|
|
false
|
|
} else {
|
|
self.functions.push(function);
|
|
true
|
|
}
|
|
}
|
|
|
|
fn add_var(
|
|
&mut self,
|
|
pos: Position,
|
|
variable: String,
|
|
vtype: VariableType,
|
|
) -> Result<(), CompilerError> {
|
|
let entry = self.variables.entry(variable.clone());
|
|
if let Entry::Vacant(e) = entry {
|
|
if let Some(inner) = &mut self.inner_scope {
|
|
inner.add_var(pos, variable, vtype)
|
|
} else {
|
|
e.insert((self.counter, vtype));
|
|
self.counter += 1;
|
|
Ok(())
|
|
}
|
|
} else {
|
|
Err(CompilerError::VariableExists(pos, variable))
|
|
}
|
|
}
|
|
|
|
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))
|
|
}
|
|
}
|
|
}
|