summaryrefslogtreecommitdiff
path: root/matrix-lang/src/compiler.rs
diff options
context:
space:
mode:
authorFreya Murphy <freya@freyacat.org>2024-02-29 17:04:28 -0500
committerFreya Murphy <freya@freyacat.org>2024-02-29 17:04:28 -0500
commit5d2747e26f51cc2344a6bd95f93457248fdfebd8 (patch)
tree8755b4068166c3854d26817683ce438a771ab319 /matrix-lang/src/compiler.rs
parentmore mat, sys, and os stdlib functions, better matrix printing, other fixes (diff)
downloadmatrix-5d2747e26f51cc2344a6bd95f93457248fdfebd8.tar.gz
matrix-5d2747e26f51cc2344a6bd95f93457248fdfebd8.tar.bz2
matrix-5d2747e26f51cc2344a6bd95f93457248fdfebd8.zip
fin prob
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 {