use crate::{
ast::{
ArrayLiteral, BlockStatement, BooleanLiteral, CallExpression,
Expression, ExpressionStatement, FunctionLiteral, Identifier,
IfExpression, IndexExpression, InfixExpression, IntegerLiteral,
LetStatement, PrefixExpression, Program, ReturnStatement, Statement,
StringLiteral,
},
object::{Bool, CompiledFunction, Int, Object, StringObject},
token::Kind,
};
use super::{
errors::CompileError,
instruction::Instruction,
instructions::Instructions,
symbol::{self, Symbol, SymbolTable},
Bytecode,
};
const SUCCESS: Result<bool, CompileError> = Ok(true);
#[derive(Debug, Clone)]
struct Scope {
instructions: Instructions,
}
impl Scope {
pub fn new(instructions: Instructions) -> Self {
Self { instructions }
}
}
#[derive(Debug)]
struct InstructionInfo {
instruction: Instruction,
pos: usize,
}
#[derive(Debug)]
pub struct Compiler {
constants: Vec<Object>,
scopes: Vec<Scope>,
scope_idx: usize,
symbol_table: Option<SymbolTable>,
last_instruction: Option<InstructionInfo>,
}
impl Compiler {
pub fn create() -> Result<Self, CompileError> {
let mut scopes = Vec::new();
match Instructions::create() {
Err(e) => {
return Err(CompileError::CreationFailed(e));
}
Ok(ins) => {
scopes.push(
Scope { instructions: ins },
);
}
}
Ok(Self {
constants: Vec::new(),
scopes,
scope_idx: 0,
symbol_table: Some(SymbolTable::new()),
last_instruction: None,
})
}
pub fn bytecode(self) -> Result<Bytecode, CompileError> {
if self.scope_idx != 0 {
return Err(CompileError::NotFinishedInMain);
}
Ok(Bytecode {
constants: self.constants.clone(),
instructions: self.current_scope().instructions.clone(),
})
}
pub fn compile(&mut self, src: Program) -> Result<bool, CompileError> {
for stm in src.statements {
self.compile_stm(&stm)?;
}
SUCCESS
}
fn compile_stm(&mut self, stm: &Statement) -> Result<bool, CompileError> {
match stm {
Statement::ExpressionStatement(stm) => {
self.compile_expression_stm(stm)
}
Statement::LetStatement(stm) => self.compile_let_stm(stm),
Statement::ReturnStatement(stm) => self.compile_return_stm(stm),
Statement::BlockStatement(stm) => self.compile_block_stm(stm),
}
}
fn compile_exp(&mut self, exp: &Expression) -> Result<bool, CompileError> {
match exp {
Expression::Identifier(exp) => self.compile_identifier_exp(exp),
Expression::IntegerLiteral(lit) => {
self.compile_integer_literal(lit)
}
Expression::BooleanLiteral(lit) => self.compile_bool_literal(lit),
Expression::StringLiteral(lit) => self.compile_string_literal(lit),
Expression::FunctionLiteral(lit) => {
self.compile_function_literal(lit)
}
Expression::ArrayLiteral(lit) => self.compile_array_literal(lit),
Expression::InfixExpression(exp) => self.compile_infix_exp(exp),
Expression::PrefixExpression(exp) => self.compile_prefix_exp(exp),
Expression::IfExpression(exp) => self.compile_if_exp(exp),
Expression::CallExpression(exp) => self.compile_call_exp(exp),
Expression::IndexExpression(exp) => self.compile_index_exp(exp),
}
}
fn compile_expression_stm(
&mut self,
stm: &ExpressionStatement,
) -> Result<bool, CompileError> {
self.compile_exp(stm.expression.as_ref().unwrap())?;
self.emit(Instruction::POP)?;
SUCCESS
}
fn compile_let_stm(
&mut self,
stm: &LetStatement,
) -> Result<bool, CompileError> {
let idx = self
.symbol_table
.as_mut()
.unwrap()
.define(&stm.identifier.value);
self.compile_exp(&stm.value.clone().unwrap())?;
if self.symbol_table.as_ref().unwrap().is_global() {
self.emit(Instruction::DEFGLB { idx })?;
} else {
self.emit(Instruction::DEFLCL { idx })?;
}
SUCCESS
}
fn compile_return_stm(
&mut self,
stm: &ReturnStatement,
) -> Result<bool, CompileError> {
match &stm.value {
Some(exp) => {
self.compile_exp(exp)?;
self.emit(Instruction::RETV)?;
}
None => {
self.emit(Instruction::RETN)?;
}
}
SUCCESS
}
fn compile_block_stm(
&mut self,
stm: &BlockStatement,
) -> Result<bool, CompileError> {
for statement in &stm.statements {
self.compile_stm(statement)?;
}
SUCCESS
}
fn compile_identifier_exp(
&mut self,
exp: &Identifier,
) -> Result<bool, CompileError> {
let rst = self.symbol_table.as_mut().unwrap().resolve(&exp.value);
if rst.is_some() {
let sym = rst.unwrap();
self.load_symbol(&sym)?;
SUCCESS
} else {
Err(CompileError::IdentifierNotFound(exp.clone()))
}
}
fn compile_integer_literal(
&mut self,
lit: &IntegerLiteral,
) -> Result<bool, CompileError> {
let int = Object::Int(Int { value: lit.value });
self.constants.push(int); self.emit(Instruction::CONST {
idx: self.constants.len() - 1,
})?;
SUCCESS
}
fn compile_bool_literal(
&mut self,
lit: &BooleanLiteral,
) -> Result<bool, CompileError> {
let boolean = Object::Bool(Bool { value: lit.value });
self.constants.push(boolean); self.emit(Instruction::CONST {
idx: self.constants.len() - 1,
})?;
SUCCESS
}
fn compile_string_literal(
&mut self,
lit: &StringLiteral,
) -> Result<bool, CompileError> {
let str = Object::String(StringObject {
value: lit.value.clone(),
});
self.constants.push(str);
self.emit(Instruction::CONST {
idx: self.constants.len() - 1,
})?;
SUCCESS
}
fn compile_function_literal(
&mut self,
lit: &FunctionLiteral,
) -> Result<bool, CompileError> {
self.enter_scope()?;
if lit.ident.is_some() {
unsafe {
self.symbol_table
.as_mut()
.unwrap_unchecked()
.define_function_name(&lit.ident.as_ref().unwrap().value);
}
}
for param in &lit.parameters {
self.symbol_table.as_mut().unwrap().define(¶m.value);
}
self.compile_block_stm(&lit.body)?;
if !self.update_last_instruction_if(Instruction::POP, Instruction::RETV)
{
self.emit(Instruction::RETN)?;
}
let free_syms = self.symbol_table.as_ref().unwrap().get_free();
let local_len = self.symbol_table.as_ref().unwrap().len;
let body_scope = self.leave_scope();
for free in free_syms.iter() {
self.load_symbol(free)?;
}
let compiled_function = CompiledFunction {
arg_len: lit.parameters.len(),
local_len,
instructions: body_scope.instructions,
};
self.constants
.push(Object::CompiledFunction(compiled_function));
self.emit(Instruction::CLOSURE {
idx: self.constants.len() - 1,
free: free_syms.len(),
})?;
if lit.ident.is_some() && !lit.is_let_bind {
let idx = self
.symbol_table
.as_mut()
.unwrap()
.define(&lit.ident.as_ref().unwrap().value);
if self.symbol_table.as_ref().unwrap().is_global() {
self.emit(Instruction::DEFGLB { idx })?;
} else {
self.emit(Instruction::DEFLCL { idx })?;
}
}
SUCCESS
}
fn compile_array_literal(
&mut self,
lit: &ArrayLiteral,
) -> Result<bool, CompileError> {
for el in lit.elements.iter() {
self.compile_exp(el)?;
}
self.emit(Instruction::ARRAY {
count: lit.elements.len(),
})?;
SUCCESS
}
fn compile_prefix_exp(
&mut self,
exp: &PrefixExpression,
) -> Result<bool, CompileError> {
self.compile_exp(&exp.right)?;
match exp.token.kind {
Kind::Bang => self.emit(Instruction::BANG)?,
Kind::Minus => self.emit(Instruction::NEG)?,
wrong_token => Err(CompileError::WrongPrefixOperator(wrong_token))?,
};
SUCCESS
}
fn compile_infix_exp(
&mut self,
exp: &InfixExpression,
) -> Result<bool, CompileError> {
self.compile_exp(&exp.right)?;
self.compile_exp(&exp.left)?;
match exp.operator.kind {
Kind::Assign => todo!(),
Kind::Plus => self.emit(Instruction::ADD)?,
Kind::Minus => self.emit(Instruction::SUB)?,
Kind::Product => self.emit(Instruction::PRODUCT)?,
Kind::Divide => self.emit(Instruction::DIVIDE)?,
Kind::Mod => self.emit(Instruction::MOD)?,
Kind::LT => self.emit(Instruction::CLT)?,
Kind::LT_OR_EQ => self.emit(Instruction::CLTE)?,
Kind::GT => self.emit(Instruction::CGT)?,
Kind::GT_OR_EQ => self.emit(Instruction::CGTE)?,
Kind::EQ => self.emit(Instruction::CEQ)?,
Kind::NOT_EQ => self.emit(Instruction::CNEQ)?,
Kind::And => self.emit(Instruction::AND)?,
Kind::Or => self.emit(Instruction::OR)?,
Kind::Bit_And => self.emit(Instruction::BAND)?,
Kind::Bit_Or => self.emit(Instruction::BOR)?,
wrong_token => Err(CompileError::WrongInfixOperator(wrong_token))?,
};
SUCCESS
}
fn compile_if_exp(
&mut self,
exp: &IfExpression,
) -> Result<bool, CompileError> {
self.compile_exp(&exp.condition)?;
let jump_consequence = self.emit(Instruction::JNS { idx: 0 })?;
self.compile_stm(&Statement::BlockStatement(exp.consequence.clone()))?;
self.remove_last_instruction_if(Instruction::POP);
if exp.alternative.is_some() {
let jump_alternative = self.emit(Instruction::JMP { idx: 0 })?;
unsafe {
self.update(
Instruction::JNS {
idx: self.next_offset(),
},
jump_consequence,
);
}
self.compile_stm(&Statement::BlockStatement(
exp.alternative.clone().unwrap(),
))?;
self.remove_last_instruction_if(Instruction::POP);
unsafe {
self.update(
Instruction::JMP {
idx: self.next_offset(),
},
jump_alternative,
);
}
} else {
unsafe {
self.update(
Instruction::JNS {
idx: self.next_offset(),
},
jump_consequence,
);
}
}
SUCCESS
}
fn compile_call_exp(
&mut self,
exp: &CallExpression,
) -> Result<bool, CompileError> {
self.compile_exp(&exp.function)?;
for arg in &exp.arguments {
self.compile_exp(arg)?;
}
self.emit(Instruction::CALL {
arg_len: exp.arguments.len(),
})?;
SUCCESS
}
fn compile_index_exp(
&mut self,
exp: &IndexExpression,
) -> Result<bool, CompileError> {
self.compile_exp(&exp.left)?;
self.compile_exp(&exp.index)?;
self.emit(Instruction::INDEX)?;
SUCCESS
}
fn emit(&mut self, ins: Instruction) -> Result<usize, CompileError> {
let res = self
.current_scope_mut()
.instructions
.add_instruction(ins.clone());
if let Err(e) = res {
return Err(CompileError::InstructionWriteError(e));
}
let pos = res.unwrap();
self.last_instruction = Some(InstructionInfo {
instruction: ins,
pos,
});
Ok(pos)
}
unsafe fn update(&mut self, ins: Instruction, offset: usize) {
self.current_scope_mut()
.instructions
.update_instruction(ins, offset)
}
fn remove_last_instruction(&mut self) {
let new_length = self.last_instruction.as_ref().unwrap().pos;
self.current_scope_mut()
.instructions
.remove_instruction(new_length);
self.last_instruction = None;
}
fn update_last_instruction_if(
&mut self,
ins: Instruction,
with: Instruction,
) -> bool {
if self.last_instruction.as_ref().is_some_and(|ins_info| {
(ins_info.instruction == ins) || (ins_info.instruction == with)
}) {
let pos = self.last_instruction.as_ref().unwrap().pos;
unsafe {
self.update(with.clone(), pos);
}
self.last_instruction = Some(InstructionInfo {
instruction: with,
pos,
});
return true;
}
false
}
fn remove_last_instruction_if(&mut self, ins: Instruction) {
if self
.last_instruction
.as_ref()
.is_some_and(|ins_info| ins_info.instruction == ins)
{
self.remove_last_instruction();
}
}
fn next_offset(&self) -> usize {
self.current_scope().instructions.length()
}
fn enter_scope(&mut self) -> Result<bool, CompileError> {
let inst_rst = Instructions::create();
if inst_rst.is_err() {
unsafe {
return Err(CompileError::ScopeCreateFaild(
inst_rst.unwrap_err_unchecked(),
));
}
}
let new_scope = Scope::new(unsafe { inst_rst.unwrap_unchecked() });
self.scopes.push(new_scope);
self.scope_idx += 1;
self.symbol_table =
Some(SymbolTable::enclose(self.symbol_table.take().unwrap()));
SUCCESS
}
fn leave_scope(&mut self) -> Scope {
self.symbol_table =
Some(self.symbol_table.as_mut().unwrap().get_outer());
self.scope_idx -= 1;
self.scopes.pop().unwrap()
}
fn current_scope(&self) -> &Scope {
&self.scopes[self.scope_idx]
}
fn current_scope_mut(&mut self) -> &mut Scope {
&mut self.scopes[self.scope_idx]
}
fn load_symbol(&mut self, sym: &Symbol) -> Result<bool, CompileError> {
let inst = match sym.scope() {
symbol::Scope::Global => Instruction::GETGLB { idx: sym.index },
symbol::Scope::Local => Instruction::GETLCL { idx: sym.index },
symbol::Scope::Free => Instruction::GETFREE { idx: sym.index },
symbol::Scope::Function => Instruction::GETCUR,
};
self.emit(inst)?;
SUCCESS
}
}