diff options
Diffstat (limited to '')
-rw-r--r-- | matrix-lang/src/compiler.rs (renamed from matrix/src/compiler.rs) | 160 |
1 files changed, 76 insertions, 84 deletions
diff --git a/matrix/src/compiler.rs b/matrix-lang/src/compiler.rs index 6b6a94b..95c6ccf 100644 --- a/matrix/src/compiler.rs +++ b/matrix-lang/src/compiler.rs @@ -1,14 +1,14 @@ -use std::{fmt::Display, rc::Rc, cell::RefCell}; -use crate::{ast::{Expr, ExprData, AstName}, chunk::{Function, Instruction, InnerFunction}, chunk::{Chunk, self}, value::Value, Result, lex::Position}; +use crate::prelude::*; use Instruction as I; use Value as V; use ExprData as E; pub type NamesTable = Rc<RefCell<Vec<Rc<str>>>>; +pub type GlobalsTable = Rc<RefCell<Vec<Global>>>; pub struct CompilerBuilder<'c> { - globals: NamesTable, + globals: GlobalsTable, names: NamesTable, repl: bool, debug: bool, @@ -39,7 +39,7 @@ impl<'c> CompilerBuilder<'c> { self } - pub fn globals(mut self, globals: NamesTable) -> Self { + pub fn globals(mut self, globals: GlobalsTable) -> Self { self.globals = globals; self } @@ -81,9 +81,9 @@ pub struct Compiler<'c> { name: Rc<str>, parent: Option<&'c Compiler<'c>>, - locals: Vec<Rc<Local>>, - globals: Rc<RefCell<Vec<Rc<str>>>>, - names: Rc<RefCell<Vec<Rc<str>>>>, + locals: Vec<Local>, + globals: GlobalsTable, + names: NamesTable, root_is_block: bool, @@ -97,50 +97,25 @@ pub struct Compiler<'c> { debug: bool, } +#[derive(Clone)] struct Local { name: Rc<str>, idx: usize, - scope: usize -} - -#[derive(Debug, Clone)] -pub enum InnerError { - Undefined(Rc<str>), - Redefined(Rc<str>), - InvAssign(Expr), - InvContinue, - InvBreak, - NotImplemented(&'static str), -} - -#[derive(Debug, Clone)] -pub struct Error { - pos: Position, - err: InnerError, + scope: usize, + is_const: bool, } -impl std::error::Error for self::Error {} - -impl Display for self::Error { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - use InnerError as E; - write!(f, "parse failed at {}:{}, ", self.pos.row, self.pos.col)?; - match &self.err { - E::Undefined(name) => write!(f, "value {name} is undefined"), - E::Redefined(name) => write!(f, "cannot redefine {name} in the same scope"), - E::InvAssign(expr) => write!(f, "cannot assign to {expr:?}"), - E::InvContinue => write!(f, "cannot continue outside a loop"), - E::InvBreak => write!(f, "cannot break outside a loop"), - E::NotImplemented(str) => write!(f, "{str} is not implemented yet") - } - } +#[derive(Clone)] +pub struct Global { + pub name: Rc<str>, + pub idx: usize, + pub is_const: bool, } -fn error<T>(err: InnerError, pos: Position) -> Result<T> { - Err(self::Error { - pos, - err - }.into()) +macro_rules! error { + ($($arg:tt)*) => { + exception!(COMPILE_EXCEPTION, $($arg)*) + }; } impl<'c> Compiler<'c> { @@ -185,35 +160,35 @@ impl<'c> Compiler<'c> { }; } - fn create_local(&mut self, name: Rc<str>) { - let local = Local { name, idx: self.locals.len(), scope: self.scopes.len()}; - self.locals.push(Rc::new(local)); + fn create_local(&mut self, name: Rc<str>, is_const: bool) -> Local { + let local = Local { name, idx: self.locals.len(), scope: self.scopes.len(), is_const }; + self.locals.push(local.clone()); + local } - fn create_global(&mut self, name: Rc<str>) -> usize { - self.globals.borrow_mut().push(name); - let c = self.globals.borrow().len() - 1; - c + fn create_global(&mut self, name: Rc<str>, is_const: bool) -> Global { + let global = Global { name, idx: self.globals.borrow().len(), is_const }; + self.globals.borrow_mut().push(global.clone()); + global } - fn create_local_checked(&mut self, name: Rc<str>, pos: Position) -> Result<()> { + fn create_local_checked(&mut self, name: Rc<str>, is_const: bool, pos: Position) -> Result<Local> { if let Some(local) = self.find_local(&name) { if local.scope == self.scopes.len() { - return error(InnerError::Redefined(name), pos) + return Err(error!("redefined {name}").pos(pos)) } }; - self.create_local(name); - Ok(()) + Ok(self.create_local(name, is_const)) } - fn create_global_checked(&mut self, name: Rc<str>, pos: Position) -> Result<usize> { + fn create_global_checked(&mut self, name: Rc<str>, is_const: bool, pos: Position) -> Result<Global> { if let Some(_) = self.find_global(&name) { - return error(InnerError::Redefined(name).into(), pos) + return Err(error!("redefined {name}").pos(pos)) } - Ok(self.create_global(name)) + Ok(self.create_global(name, is_const)) } - fn find_local(&self, name: &str) -> Option<Rc<Local>> { + fn find_local(&self, name: &str) -> Option<Local> { for local in self.locals.iter().rev() { if local.name.as_ref() == name { return Some(local.clone()) @@ -222,13 +197,13 @@ impl<'c> Compiler<'c> { None } - fn find_global(&self, name: &str) -> Option<usize> { + fn find_global(&self, name: &str) -> Option<Global> { if let Some(parent) = self.parent { return parent.find_global(name) } - for (i, global) in self.globals.borrow().iter().enumerate() { - if global.as_ref() == name { - return Some(i) + for global in self.globals.borrow().iter() { + if global.name.as_ref() == name { + return Some(global.clone()) } } None @@ -294,7 +269,7 @@ impl<'c> Compiler<'c> { let chunk = self.compile_function(name.clone(), params, body)?; let arity = params.len() - if *varadic { 1 } else { 0 }; let fun = Value::Function(Rc::new( - chunk::Function { + Function { name: name.0.clone(), arity, fun: InnerFunction::Compiled(chunk.into()), @@ -304,10 +279,10 @@ impl<'c> Compiler<'c> { self.emit_const(fun, expr.pos); self.emit(I::Dup, expr.pos); if self.can_make_globals() { - let idx = self.create_global_checked(name.0.clone(), name.1)?; - self.emit(I::StoreGlobal(idx as u16), expr.pos); + let global = self.create_global_checked(name.0.clone(), false, name.1)?; + self.emit(I::StoreGlobal(global.idx as u16), expr.pos); } else { - self.create_local_checked(name.0.clone(), name.1)?; + self.create_local_checked(name.0.clone(), false, name.1)?; self.emit(I::CreateLocal, expr.pos); } }, @@ -316,7 +291,7 @@ impl<'c> Compiler<'c> { let chunk = self.compile_function(name.clone(), params, body)?; let arity = params.len() - if *varadic { 1 } else { 0 }; let fun = Value::Function(Rc::new( - chunk::Function { + Function { name: name.0.clone(), arity, fun: InnerFunction::Compiled(chunk.into()), @@ -341,7 +316,7 @@ impl<'c> Compiler<'c> { let jmpidx2 = self.emit_temp(expr.pos); self.re_emit(I::Try(self.cur()), jmpidx); self.begin_scope(); - self.create_local(err.0.clone()); + self.create_local(err.0.clone(), true); self.emit(I::CreateLocal, err.1); self.compile_expr(catch)?; self.end_scope(); @@ -378,7 +353,7 @@ impl<'c> Compiler<'c> { let jumpidx = self.emit_temp(expr.pos); self.loop_top.push((top as usize, self.scopes.len())); self.begin_scope(); - self.create_local(name.0.clone()); + self.create_local(name.0.clone(), true); self.emit(I::CreateLocal, name.1); self.compile_expr(expr)?; self.emit(I::Discard(1), expr.pos); @@ -407,10 +382,21 @@ impl<'c> Compiler<'c> { self.compile_expr(expr)?; self.emit(I::Dup, expr.pos); if self.can_make_globals() { - let global = self.create_global_checked(name.0.clone(), name.1)?; - self.emit(I::StoreGlobal(global as u16), expr.pos); + let global = self.create_global_checked(name.0.clone(), false, name.1)?; + self.emit(I::StoreGlobal(global.idx as u16), expr.pos); + } else { + self.create_local_checked(name.0.clone(), false, name.1)?; + self.emit(I::CreateLocal, expr.pos); + } + }, + E::Const(name, expr) => { + self.compile_expr(expr)?; + self.emit(I::Dup, expr.pos); + if self.can_make_globals() { + let global = self.create_global_checked(name.0.clone(), true, name.1)?; + self.emit(I::StoreGlobal(global.idx as u16), expr.pos); } else { - self.create_local_checked(name.0.clone(), name.1)?; + self.create_local_checked(name.0.clone(), true, name.1)?; self.emit(I::CreateLocal, expr.pos); } }, @@ -420,7 +406,7 @@ impl<'c> Compiler<'c> { self.collapse_scopes(scope); self.emit(I::Jump(top as u16), expr.pos); } else { - return error(InnerError::InvContinue, expr.pos) + return Err(error!("invalid continue outside loop").pos(expr.pos)) } }, E::Break => { @@ -430,7 +416,7 @@ impl<'c> Compiler<'c> { let tmpidx = self.emit_temp(expr.pos); self.loop_bot.push(tmpidx); } else { - return error(InnerError::InvBreak, expr.pos) + return Err(error!("invalid break outside loop").pos(expr.pos)) } }, E::Return(expr) => { @@ -444,9 +430,9 @@ impl<'c> Compiler<'c> { } else if let Some(local) = self.find_local(name) { self.emit(I::LoadLocal(local.idx as u16), expr.pos); } else if let Some(global) = self.find_global(name) { - self.emit(I::LoadGlobal(global as u16), expr.pos); + self.emit(I::LoadGlobal(global.idx as u16), expr.pos); } else { - return error(InnerError::Undefined(name.clone()), expr.pos) + return Err(error!("variable '{name}' is undefined").pos(expr.pos)) }; }, E::Assign(lhs, rhs) => { @@ -455,14 +441,20 @@ impl<'c> Compiler<'c> { match &lhs.data { E::Ident(name) if name.as_ref() != "_" => { if let Some(local) = self.find_local(&name) { + if local.is_const { + return Err(error!("cannot assign to const '{name}'").pos(lhs.pos)) + } self.emit(I::StoreLocal(local.idx as u16), lhs.pos); } else if let Some(global) = self.find_global(&name) { - self.emit(I::StoreGlobal(global as u16), lhs.pos); + if global.is_const { + return Err(error!("cannot assign to const '{name}'").pos(lhs.pos)) + } + self.emit(I::StoreGlobal(global.idx as u16), lhs.pos); } else if self.can_make_globals() { - let global = self.create_global_checked(name.clone(), lhs.pos)?; - self.emit(I::StoreGlobal(global as u16), lhs.pos); + let global = self.create_global_checked(name.clone(), false, lhs.pos)?; + self.emit(I::StoreGlobal(global.idx as u16), lhs.pos); } else { - self.create_local_checked(name.clone(), lhs.pos)?; + self.create_local_checked(name.clone(), false, lhs.pos)?; self.emit(I::CreateLocal, lhs.pos); } }, @@ -478,7 +470,7 @@ impl<'c> Compiler<'c> { let name = self.get_name(ident.0.clone()); self.emit(I::StoreField(name as u16), expr.pos); } - _ => return error(InnerError::InvAssign(*lhs.clone()), lhs.pos) + _ => return Err(error!("assignment to {lhs} is not allowed").pos(lhs.pos)) } } E::UnaryOp(expr, op) => { @@ -554,7 +546,7 @@ impl<'c> Compiler<'c> { fn compile_function(&mut self, name: AstName, params: &Vec<AstName>, body: &Box<Expr>) -> Result<Chunk> { let mut compiler = self.child(name.0); for (name, pos) in params { - compiler.create_local(name.clone()); + compiler.create_local(name.clone(), false); compiler.emit(I::CreateLocal, *pos); } compiler.compile_expr(body)?; @@ -611,7 +603,7 @@ impl<'c> Compiler<'c> { }; if self.loop_bot.len() > 0 { - return error(InnerError::InvBreak, pos) + return Err(error!("invalid break outside loop").pos(pos)) } if self.debug { |