lang is not expr based

This commit is contained in:
Freya Murphy 2024-02-20 18:58:54 -05:00
parent ef4ada62f8
commit 671301383b
Signed by: freya
GPG key ID: 744AB800E383AE52
6 changed files with 590 additions and 681 deletions

View file

@ -54,7 +54,6 @@ impl<'a> State<'a> {
let compiler = CompilerBuilder::new() let compiler = CompilerBuilder::new()
.repl(repl) .repl(repl)
.debug(args.debug) .debug(args.debug)
.globals(vm.globals())
.build(); .build();
(Self { parser, vm, compiler, repl }, file) (Self { parser, vm, compiler, repl }, file)

View file

@ -36,6 +36,8 @@ pub enum BinaryOp {
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum Expr { pub enum Expr {
NoOp,
Literal(Value), Literal(Value),
Ident(Rc<str>), Ident(Rc<str>),
@ -52,34 +54,24 @@ pub enum Expr {
And(Box<Expr>, Box<Expr>), And(Box<Expr>, Box<Expr>),
Or(Box<Expr>, Box<Expr>), Or(Box<Expr>, Box<Expr>),
}
#[derive(Debug, Clone, PartialEq)] Assign(Box<Expr>, Box<Expr>),
pub enum Assign {
Expr(Expr),
Assign(Expr, Box<Assign>)
}
#[derive(Debug, Clone, PartialEq)] If(Box<Expr>, Box<Expr>, Option<Box<Expr>>),
pub enum Stmt { Function(Rc<str>, Vec<Rc<str>>, Box<Expr>),
NoOp,
If(Expr, Box<Stmt>, Option<Box<Stmt>>),
Function(Rc<str>, Vec<Rc<str>>, Box<Stmt>),
Loop(Box<Stmt>), Loop(Box<Expr>),
While(Expr, Box<Stmt>), While(Box<Expr>, Box<Expr>),
DoWhile(Expr, Box<Stmt>), DoWhile(Box<Expr>, Box<Expr>),
Block(Vec<Stmt>), Block(Vec<Expr>),
Expr(Expr),
Let(Rc<str>, Expr), Let(Rc<str>, Box<Expr>),
Assign(Assign),
Continue, Continue,
Break, Break,
Return(Expr), Return(Box<Expr>),
} }
impl Neg for BinaryOp { impl Neg for BinaryOp {
@ -156,181 +148,156 @@ impl Not for Expr {
} }
} }
fn optimize_expr(expr: Expr) -> Result<Expr> { pub fn optimize(expr: Expr) -> Result<Expr> {
use Expr::*; use Expr as E;
Ok(match expr { Ok(match expr {
UnaryOp(expr, op) => { E::UnaryOp(expr, op) => {
let expr = optimize_expr(*expr)?; let expr = optimize(*expr)?;
match match op { match match op {
self::UnaryOp::Negate => -expr, UnaryOp::Negate => -expr,
self::UnaryOp::Not => !expr, UnaryOp::Not => !expr,
} { } {
Ok(expr) => expr, Ok(expr) => expr,
Err(expr) => UnaryOp(Box::new(expr), op) Err(expr) => E::UnaryOp(Box::new(expr), op)
} }
}, },
BinaryOp(lhs, rhs, op) => { E::BinaryOp(lhs, rhs, op) => {
let lhs = optimize_expr(*lhs)?; let lhs = optimize(*lhs)?;
let rhs = optimize_expr(*rhs)?; let rhs = optimize(*rhs)?;
if let (Literal(l), Literal(r)) = (lhs.clone(), rhs.clone()) { if let (E::Literal(l), E::Literal(r)) = (lhs.clone(), rhs.clone()) {
match Value::binary_op(op, l, r) { match Value::binary_op(op, l, r) {
Err(err) => return Err(err), Err(err) => return Err(err),
Ok(value) => return Ok(Expr::Literal(value)), Ok(value) => return Ok(Expr::Literal(value)),
} }
} }
BinaryOp(Box::new(lhs), Box::new(rhs), op) E::BinaryOp(Box::new(lhs), Box::new(rhs), op)
}, },
FnCall(ident, values) => { E::FnCall(ident, values) => {
FnCall(ident, values E::FnCall(ident, values
.into_iter() .into_iter()
.map(optimize_expr) .map(optimize)
.collect::<Result<Vec<Expr>>>()?) .collect::<Result<Vec<Expr>>>()?)
} }
FieldAccess(key, val) => { E::FieldAccess(key, val) => {
let key = optimize_expr(*key)?; let key = optimize(*key)?;
let val = optimize_expr(*val)?; let val = optimize(*val)?;
FieldAccess(Box::new(key), Box::new(val)) E::FieldAccess(Box::new(key), Box::new(val))
}, },
List(list) => E::List(list) =>
List(list.into_iter() E::List(list.into_iter()
.map(optimize_expr) .map(optimize)
.collect::<Result<Vec<Expr>>>()?), .collect::<Result<Vec<Expr>>>()?),
Matrix(mat) => E::Matrix(mat) =>
Matrix((mat.0, mat.1, E::Matrix((mat.0, mat.1,
mat.2.into_iter().map(optimize_expr) mat.2.into_iter().map(optimize)
.collect::<Result<Vec<Expr>>>()?)), .collect::<Result<Vec<Expr>>>()?)),
Table(table) => E::Table(table) =>
Table(table E::Table(table
.into_iter() .into_iter()
.map(|(k, v)| { .map(|(k, v)| {
let k = optimize_expr(k)?; let k = optimize(k)?;
let v = optimize_expr(v)?; let v = optimize(v)?;
Ok((k, v)) Ok((k, v))
}).collect::<Result<Vec<(Expr, Expr)>>>()?), }).collect::<Result<Vec<(Expr, Expr)>>>()?),
And(lhs, rhs) => { E::And(lhs, rhs) => {
let lhs = optimize_expr(*lhs)?; let lhs = optimize(*lhs)?;
let rhs = optimize_expr(*rhs)?; let rhs = optimize(*rhs)?;
if let (Literal(l), r) = (lhs.clone(), rhs.clone()) { if let (E::Literal(l), r) = (lhs.clone(), rhs.clone()) {
match !!l.clone() { match !!l.clone() {
true => r, true => r,
false => Literal(l), false => E::Literal(l),
} }
} else { } else {
And(Box::new(lhs), Box::new(rhs)) E::And(Box::new(lhs), Box::new(rhs))
} }
}, },
Or(lhs, rhs) => { E::Or(lhs, rhs) => {
let lhs = optimize_expr(*lhs)?; let lhs = optimize(*lhs)?;
let rhs = optimize_expr(*rhs)?; let rhs = optimize(*rhs)?;
if let (Literal(l), r) = (lhs.clone(), rhs.clone()) { if let (E::Literal(l), r) = (lhs.clone(), rhs.clone()) {
match !l.clone() { match !l.clone() {
true => r, true => r,
false => Literal(l), false => E::Literal(l),
} }
} else { } else {
And(Box::new(lhs), Box::new(rhs)) E::And(Box::new(lhs), Box::new(rhs))
} }
}, },
_ => expr E::Block(b) => {
}) let len = b.len();
} let b: Vec<Expr> =
fn optimize_assign(assign: Assign) -> Result<Assign> {
use self::Assign::*;
Ok(match assign {
Expr(expr) => {
let expr = optimize_expr(expr)?;
Expr(expr)
},
Assign(expr, assign) => {
let expr = optimize_expr(expr)?;
let assign = optimize_assign(*assign)?;
Assign(expr, Box::new(assign))
}
})
}
pub fn optimize(stmt: Stmt) -> Result<Stmt> {
use Stmt::*;
Ok(match stmt {
Block(b) => {
let b: Vec<Stmt> =
b.into_iter() b.into_iter()
.map(optimize) .map(optimize)
.collect::<Result<Vec<Stmt>>>()? .collect::<Result<Vec<Expr>>>()?
.into_iter() .into_iter()
.filter(|e| NoOp != *e) .enumerate()
.filter(|(i, e)| {
if let E::Literal(_) = e {
return i + 1 == len
}
E::NoOp != *e
})
.map(|e| e.1)
.collect(); .collect();
if b.is_empty() { if b.is_empty() {
NoOp E::NoOp
} else { } else {
Block(b) E::Block(b)
} }
}, },
If(cond, block, else_block) => { E::If(cond, block, else_block) => {
let cond = optimize_expr(cond)?; let cond = optimize(*cond)?;
let block = optimize(*block)?; let block = optimize(*block)?;
let else_block = else_block.map(|e| optimize(*e)).transpose()?; let else_block = else_block.map(|e| optimize(*e)).transpose()?;
if let self::Expr::Literal(lit) = cond { if let E::Literal(lit) = cond {
if !!lit { if !!lit {
return Ok(block) return Ok(block)
} }
return Ok(else_block.unwrap_or(NoOp)) return Ok(else_block.unwrap_or(E::NoOp))
} }
If(cond, Box::new(block), else_block.map(|e| Box::new(e))) E::If(Box::new(cond), Box::new(block), else_block.map(|e| Box::new(e)))
}, },
While(cond, block) => { E::While(cond, block) => {
let cond = optimize_expr(cond)?; let cond = optimize(*cond)?;
let block = optimize(*block)?; let block = optimize(*block)?;
if let self::Expr::Literal(lit) = cond { if let E::Literal(lit) = cond {
if !!lit { if !!lit {
return Ok(Loop(Box::new(block))) return Ok(E::Loop(Box::new(block)))
} }
return Ok(NoOp) return Ok(E::NoOp)
} }
While(cond, Box::new(block)) E::While(Box::new(cond), Box::new(block))
}, },
DoWhile(cond, block) => { E::DoWhile(block, cond) => {
let cond = optimize_expr(cond)?; let cond = optimize(*cond)?;
let block = optimize(*block)?; let block = optimize(*block)?;
if let self::Expr::Literal(lit) = cond.clone() { if let E::Literal(lit) = cond.clone() {
if !!lit { if !!lit {
return Ok(Loop(Box::new(block))) return Ok(E::Loop(Box::new(block)))
} }
} }
DoWhile(cond, Box::new(block)) E::DoWhile(Box::new(block), Box::new(cond))
} }
Loop(block) => { E::Loop(block) => {
let block = optimize(*block)?; let block = Box::new(optimize(*block)?);
Loop(Box::new(block)) E::Loop(block)
}, },
Function(ident, params, stmt) => { E::Function(ident, params, stmt) => {
let stmt = optimize(*stmt)?; let stmt = Box::new(optimize(*stmt)?);
Function(ident, params, Box::new(stmt)) E::Function(ident, params, stmt)
} }
Expr(expr) => { E::Let(ident, expr) => {
Expr(optimize_expr(expr)?) E::Let(ident, Box::new(optimize(*expr)?))
}, },
Let(ident, expr) => { E::Assign(lhs, rhs) => {
Let(ident, optimize_expr(expr)?) let lhs = Box::new(optimize(*lhs)?);
} let rhs = Box::new(optimize(*rhs)?);
Assign(assign) => { E::Assign(lhs, rhs)
use self::Assign as A;
match assign {
A::Expr(expr) => {
let expr = optimize_expr(expr)?;
Expr(expr)
}, },
A::Assign(lhs, rhs) => { E::Return(expr) => {
let assign = optimize_assign(A::Assign(lhs, rhs))?; E::Return(Box::new(optimize(*expr)?))
Assign(assign)
}, },
} _ => expr
}
Return(expr) => {
Return(optimize_expr(expr)?)
}
_ => stmt
}) })
} }

View file

@ -1,4 +1,4 @@
use crate::{value::Value, ast::{UnaryOp, BinaryOp}, Result}; use crate::{value::Value, ast::{UnaryOp, BinaryOp}};
use std::{fmt::{Debug, Display}, rc::Rc}; use std::{fmt::{Debug, Display}, rc::Rc};
#[derive(Clone)] #[derive(Clone)]
@ -14,10 +14,6 @@ impl Chunk {
code: Vec::new() code: Vec::new()
} }
} }
pub fn from_compiled(_buf: &[u8]) -> Result<Self> {
todo!()
}
} }
impl Debug for Chunk { impl Debug for Chunk {
@ -52,8 +48,11 @@ pub struct Function {
pub enum Instruction { pub enum Instruction {
NoOp, NoOp,
Load(u16), CreateLocal,
Store(u16), LoadLocal(u16),
StoreLocal(u16),
DiscardLocals(u16),
LoadGlobal(u16), LoadGlobal(u16),
StoreGlobal(u16), StoreGlobal(u16),
@ -88,8 +87,10 @@ impl Display for Instruction {
use Instruction::*; use Instruction::*;
match self { match self {
NoOp => write!(f, "noop"), NoOp => write!(f, "noop"),
Load(idx) => write!(f, "load \x1b[33m{idx}\x1b[0m"), CreateLocal => write!(f, "create local"),
Store(idx) => write!(f, "store \x1b[33m{idx}\x1b[0m"), LoadLocal(idx) => write!(f, "load local \x1b[33m{idx}\x1b[0m"),
StoreLocal(idx) => write!(f, "store local \x1b[33m{idx}\x1b[0m"),
DiscardLocals(count) => write!(f, "discard locals \x1b[35m{count}\x1b[0m"),
LoadGlobal(name) => write!(f, "load global \x1b[36m{name}\x1b[0m"), LoadGlobal(name) => write!(f, "load global \x1b[36m{name}\x1b[0m"),
StoreGlobal(name) => write!(f, "store global \x1b[36m{name}\x1b[0m"), StoreGlobal(name) => write!(f, "store global \x1b[36m{name}\x1b[0m"),
Const(idx) => write!(f, "const \x1b[33m{idx}\x1b[0m"), Const(idx) => write!(f, "const \x1b[33m{idx}\x1b[0m"),
@ -98,7 +99,7 @@ impl Display for Instruction {
False => write!(f, "push \x1b[34mfalse\x1b[0m"), False => write!(f, "push \x1b[34mfalse\x1b[0m"),
Nil => write!(f, "push \x1b[34mnil\x1b[0m"), Nil => write!(f, "push \x1b[34mnil\x1b[0m"),
Dup => write!(f, "duplicate"), Dup => write!(f, "duplicate"),
Discard(count) => write!(f, "discard \x1b[33m{count}\x1b[0m"), Discard(count) => write!(f, "discard \x1b[35m{count}\x1b[0m"),
UnaryOp(op) => write!(f, "unary \x1b[32m{op:?}\x1b[0m"), UnaryOp(op) => write!(f, "unary \x1b[32m{op:?}\x1b[0m"),
BinaryOp(op) => write!(f, "binary \x1b[32m{op:?}\x1b[0m"), BinaryOp(op) => write!(f, "binary \x1b[32m{op:?}\x1b[0m"),
NewList(len) => write!(f, "list \x1b[35m{len}\x1b[0m"), NewList(len) => write!(f, "list \x1b[35m{len}\x1b[0m"),

View file

@ -1,10 +1,12 @@
use std::{fmt::Display, rc::Rc, cell::RefCell}; use std::{fmt::Display, rc::Rc, cell::RefCell};
use crate::{ast::{Stmt, Expr, Assign}, chunk::{Function, Instruction}, chunk::{Chunk, self}, value::Value, Result}; use crate::{ast::Expr, chunk::{Function, Instruction}, chunk::{Chunk, self}, value::Value, Result};
pub type Globals = Rc<RefCell<Vec<Rc<str>>>>; use Instruction as I;
use Value as V;
use Expr as E;
pub struct CompilerBuilder<'c> { pub struct CompilerBuilder<'c> {
globals: Globals, globals: Rc<RefCell<Vec<Rc<str>>>>,
repl: bool, repl: bool,
debug: bool, debug: bool,
name: Rc<str>, name: Rc<str>,
@ -33,7 +35,7 @@ impl<'c> CompilerBuilder<'c> {
self self
} }
pub fn globals(mut self, globals: Globals) -> Self { pub fn globals(mut self, globals: Rc<RefCell<Vec<Rc<str>>>>) -> Self {
self.globals = globals; self.globals = globals;
self self
} }
@ -55,7 +57,7 @@ impl<'c> CompilerBuilder<'c> {
globals: self.globals, globals: self.globals,
repl: self.repl, repl: self.repl,
debug: self.debug, debug: self.debug,
scope: 0, scopes: Vec::new(),
locals: Vec::new(), locals: Vec::new(),
chunk: Chunk::new(), chunk: Chunk::new(),
loop_top: Vec::new(), loop_top: Vec::new(),
@ -74,7 +76,7 @@ pub struct Compiler<'c> {
root_is_block: bool, root_is_block: bool,
scope: usize, scopes: Vec<usize>,
chunk: Chunk, chunk: Chunk,
loop_top: Vec<(usize, usize)>, loop_top: Vec<(usize, usize)>,
@ -94,8 +96,10 @@ struct Local {
pub enum Error { pub enum Error {
Undefined(Rc<str>), Undefined(Rc<str>),
Redefined(Rc<str>), Redefined(Rc<str>),
InvAssign(Expr),
InvContinue, InvContinue,
InvBreak, InvBreak,
NotImplemented(&'static str),
} }
impl std::error::Error for self::Error {} impl std::error::Error for self::Error {}
@ -106,8 +110,10 @@ impl Display for self::Error {
match self { match self {
Undefined(name) => write!(f, "value {name} is undefined"), Undefined(name) => write!(f, "value {name} is undefined"),
Redefined(name) => write!(f, "cannot redefine {name} in the same scope"), Redefined(name) => write!(f, "cannot redefine {name} in the same scope"),
InvAssign(expr) => write!(f, "cannot assign to {expr:?}"),
InvContinue => write!(f, "cannot continue outside a loop"), InvContinue => write!(f, "cannot continue outside a loop"),
InvBreak => write!(f, "cannot break outside a loop"), InvBreak => write!(f, "cannot break outside a loop"),
NotImplemented(str) => write!(f, "{str} is not implemented yet")
} }
} }
} }
@ -127,45 +133,34 @@ impl<'c> Compiler<'c> {
if self.root_is_block { if self.root_is_block {
self.root_is_block = false; self.root_is_block = false;
} else { } else {
self.scope += 1; self.scopes.push(self.locals.len())
} }
} }
fn get_scope_start(&self, scope: usize) -> usize { fn collapse_scopes(&mut self, top_scope: usize) {
let mut stack_cutoff = None; let mut cutoff = usize::MAX;
for (i, local) in self.locals.iter().enumerate() { while self.scopes.len() > top_scope {
if local.scope == scope { cutoff = self.scopes.pop().unwrap()
stack_cutoff = Some(i);
break;
} }
} if cutoff < self.locals.len() {
if let Some(cutoff) = stack_cutoff { self.emit(Instruction::DiscardLocals((self.locals.len() - cutoff) as u16));
cutoff self.locals.truncate(cutoff);
} else { };
self.locals.len()
}
}
fn get_scope_diff(&self, scope: usize) -> usize {
let cutoff = self.get_scope_start(scope);
self.locals.len() - cutoff
} }
fn end_scope(&mut self) { fn end_scope(&mut self) {
let cutoff = self.get_scope_start(self.scope); let Some(cutoff) = self.scopes.pop() else {
return;
};
if cutoff < self.locals.len() { if cutoff < self.locals.len() {
self.emit(Instruction::Discard((self.locals.len() - cutoff) as u16)); self.emit(Instruction::DiscardLocals((self.locals.len() - cutoff) as u16));
self.locals.truncate(cutoff); self.locals.truncate(cutoff);
}; };
if self.scope != 0 {
self.scope -= 1;
}
} }
fn create_local(&mut self, name: Rc<str>) -> Rc<Local> { fn create_local(&mut self, name: Rc<str>) {
let local = Local { name, idx: self.locals.len(), scope: self.scope }; let local = Local { name, idx: self.locals.len(), scope: self.scopes.len()};
self.locals.push(Rc::new(local)); self.locals.push(Rc::new(local));
self.locals[self.locals.len() - 1].clone()
} }
fn create_global(&mut self, name: Rc<str>) -> usize { fn create_global(&mut self, name: Rc<str>) -> usize {
@ -174,13 +169,14 @@ impl<'c> Compiler<'c> {
c c
} }
fn create_local_checked(&mut self, name: Rc<str>) -> Result<Rc<Local>> { fn create_local_checked(&mut self, name: Rc<str>) -> Result<()> {
if let Some(local) = self.find_local(&name) { if let Some(local) = self.find_local(&name) {
if local.scope == self.scope { if local.scope == self.scopes.len() {
return Err(Error::Redefined(name).into()) return Err(Error::Redefined(name).into())
} }
}; };
Ok(self.create_local(name)) self.create_local(name);
Ok(())
} }
fn create_global_checked(&mut self, name: Rc<str>) -> Result<usize> { fn create_global_checked(&mut self, name: Rc<str>) -> Result<usize> {
@ -219,16 +215,14 @@ impl<'c> Compiler<'c> {
} }
fn can_make_globals(&self) -> bool { fn can_make_globals(&self) -> bool {
self.repl && self.parent.is_none() && self.scope == 0 self.repl && self.parent.is_none() && self.scopes.len() == 0
} }
fn compile_value(&mut self, val: &Value) { fn compile_value(&mut self, val: &Value) {
use Value::*;
use Instruction as I;
match val { match val {
Nil => self.emit(I::Nil), V::Nil => self.emit(I::Nil),
Bool(b) => if *b { self.emit(I::True) } else { self.emit(I::False) }, V::Bool(b) => if *b { self.emit(I::True) } else { self.emit(I::False) },
Int(i) => { V::Int(i) => {
if let Ok(i) = i16::try_from(*i) { if let Ok(i) = i16::try_from(*i) {
self.emit(I::Int(i)); self.emit(I::Int(i));
} else { } else {
@ -241,65 +235,194 @@ impl<'c> Compiler<'c> {
fn finish_loop(&mut self) {
self.loop_top.pop();
while let Some(tmp) = self.loop_bot.pop() {
self.re_emit(I::Jump(self.cur()), tmp as usize);
}
}
fn compile_expr(&mut self, expr: &Expr) -> Result<()> { fn compile_expr(&mut self, expr: &Expr) -> Result<()> {
use Expr::*;
use Instruction as I;
match expr { match expr {
Literal(val) => self.compile_value(val), E::NoOp => {},
Ident(name) => { E::If(cond, ifb, elseb) => {
self.compile_expr(cond)?;
let jmpidx = self.emit_temp();
self.compile_expr(ifb)?;
self.re_emit(I::JumpFalse(self.cur()), jmpidx);
if let Some(elseb) = elseb {
self.compile_expr(elseb)?;
}
},
E::Function(name, params, body) => {
let chunk = self.compile_function(name.clone(), params, body)?;
let fun = Value::Function(Rc::new(
chunk::Function {
name: name.clone(),
arity: params.len(),
body: chunk
}
));
self.emit_const(fun);
self.emit(I::Dup);
if self.can_make_globals() {
let idx = self.create_global_checked(name.clone())?;
self.emit(I::StoreGlobal(idx as u16));
} else {
self.create_local_checked(name.clone())?;
self.emit(I::CreateLocal);
}
},
E::Loop(expr) => {
let idx = self.cur();
self.loop_top.push((idx as usize, self.scopes.len()));
self.compile_expr(expr)?;
self.emit(I::Discard(1));
self.emit(I::Jump(idx));
self.finish_loop();
self.emit(I::Nil);
},
E::While(cond, expr) => {
let top = self.cur();
self.compile_expr(cond)?;
let jmpidx = self.emit_temp();
self.loop_top.push((top as usize, self.scopes.len()));
self.compile_expr(expr)?;
self.emit(I::Discard(1));
self.emit(I::Jump(top));
self.re_emit(I::JumpFalse(self.cur()), jmpidx);
self.finish_loop();
self.emit(I::Nil);
},
E::DoWhile(expr, cond) => {
let top = self.cur();
self.loop_top.push((top as usize, self.scopes.len()));
self.compile_expr(expr)?;
self.emit(I::Discard(1));
self.compile_expr(cond)?;
self.emit(I::JumpTrue(top));
self.finish_loop();
self.emit(I::Nil);
},
E::Block(block) => {
self.begin_scope();
for (i, expr) in block.iter().enumerate() {
self.compile_expr(expr)?;
if i + 1 != block.len() {
self.emit(I::Discard(1));
}
}
self.end_scope();
},
E::Let(name, expr) => {
self.compile_expr(expr)?;
self.emit(I::Dup);
if self.can_make_globals() {
let global = self.create_global_checked(name.clone())?;
self.emit(I::StoreGlobal(global as u16));
} else {
self.create_local_checked(name.clone())?;
self.emit(I::CreateLocal);
}
},
E::Continue => {
let top = self.loop_top.pop();
if let Some((top, scope)) = top {
self.collapse_scopes(scope);
self.emit(I::Jump(top as u16));
} else {
return Err(Error::InvContinue.into())
}
},
E::Break => {
let top = self.loop_top.pop();
if let Some((_, scope)) = top {
self.collapse_scopes(scope);
let tmpidx = self.emit_temp();
self.loop_bot.push(tmpidx);
} else {
return Err(Error::InvBreak.into())
}
},
E::Return(expr) => {
self.compile_expr(expr)?;
self.emit(I::Return);
},
E::Literal(val) => self.compile_value(val),
E::Ident(name) => {
if let Some(local) = self.find_local(name) { if let Some(local) = self.find_local(name) {
self.emit(I::Load(local.idx as u16)); self.emit(I::LoadLocal(local.idx as u16));
} else if let Some(global) = self.find_global(name) { } else if let Some(global) = self.find_global(name) {
self.emit(I::LoadGlobal(global as u16)); self.emit(I::LoadGlobal(global as u16));
} else { } else {
return Err(Error::Undefined(name.clone()).into()) return Err(self::Error::Undefined(name.clone()).into())
}; };
}, },
UnaryOp(expr, op) => { E::Assign(lhs, rhs) => {
self.compile_expr(rhs)?;
self.emit(I::Dup);
match lhs.as_ref() {
E::Ident(name) => {
if let Some(local) = self.find_local(&name) {
self.emit(I::StoreLocal(local.idx as u16));
} else if let Some(global) = self.find_global(&name) {
self.emit(I::StoreGlobal(global as u16));
} else if self.can_make_globals() {
let global = self.create_global_checked(name.clone())?;
self.emit(I::StoreGlobal(global as u16));
} else {
self.create_local_checked(name.clone())?;
self.emit(I::CreateLocal);
}
},
_ => return Err(self::Error::InvAssign(*lhs.clone()).into())
}
}
E::UnaryOp(expr, op) => {
self.compile_expr(expr)?; self.compile_expr(expr)?;
self.emit(I::UnaryOp(*op)); self.emit(I::UnaryOp(*op));
}, },
BinaryOp(lhs, rhs, op) => { E::BinaryOp(lhs, rhs, op) => {
self.compile_expr(lhs)?; self.compile_expr(lhs)?;
self.compile_expr(rhs)?; self.compile_expr(rhs)?;
self.emit(I::BinaryOp(*op)); self.emit(I::BinaryOp(*op));
}, },
Index(_, _) => todo!("index"), E::Index(_, _) => return Err(self::Error::NotImplemented("indexing").into()),
FnCall(fun, params) => { E::FnCall(fun, params) => {
for expr in params { for expr in params {
self.compile_expr(expr)?; self.compile_expr(expr)?;
} }
self.compile_expr(fun)?; self.compile_expr(fun)?;
self.emit(I::Call(params.len() as u8)); self.emit(I::Call(params.len() as u8));
}, },
FieldAccess(_, _) => todo!("field access"), E::FieldAccess(_, _) => return Err(self::Error::NotImplemented("filed access").into()),
List(list) => { E::List(list) => {
for expr in list { for expr in list {
self.compile_expr(expr)?; self.compile_expr(expr)?;
} }
self.emit(I::NewList(list.len() as u16)); self.emit(I::NewList(list.len() as u16));
}, },
Matrix(mat) => { E::Matrix(mat) => {
for expr in &mat.2 { for expr in &mat.2 {
self.compile_expr(expr)?; self.compile_expr(expr)?;
} }
self.emit(I::NewMatrix(mat.2.len() as u16, mat.1 as u8)); self.emit(I::NewMatrix(mat.2.len() as u16, mat.1 as u8));
}, },
Table(table) => { E::Table(table) => {
for (key, value) in table { for (key, value) in table {
self.compile_expr(key)?; self.compile_expr(key)?;
self.compile_expr(value)?; self.compile_expr(value)?;
} }
self.emit(I::NewTable(table.len() as u16)); self.emit(I::NewTable(table.len() as u16));
}, },
And(lhs, rhs) => { E::And(lhs, rhs) => {
self.compile_expr(lhs)?; self.compile_expr(lhs)?;
self.emit(I::Dup); self.emit(I::Dup);
let jmpidx = self.emit_temp(); let jmpidx = self.emit_temp();
self.compile_expr(rhs)?; self.compile_expr(rhs)?;
self.re_emit(I::JumpFalse(self.cur()), jmpidx); self.re_emit(I::JumpFalse(self.cur()), jmpidx);
}, },
Or(lhs, rhs) => { E::Or(lhs, rhs) => {
self.compile_expr(lhs)?; self.compile_expr(lhs)?;
self.emit(I::Dup); self.emit(I::Dup);
let jmpidx = self.emit_temp(); let jmpidx = self.emit_temp();
@ -310,164 +433,13 @@ impl<'c> Compiler<'c> {
Ok(()) Ok(())
} }
fn finish_loop(&mut self) { fn compile_function(&mut self, name: Rc<str>, params: &Vec<Rc<str>>, body: &Box<Expr>) -> Result<Chunk> {
use Instruction as I;
self.loop_top.pop();
while let Some(tmp) = self.loop_bot.pop() {
self.re_emit(I::Jump(self.cur()), tmp as usize);
}
}
fn compile_assign(&mut self, assign: &Assign) -> Result<()> {
use Assign as A;
use Expr as E;
use Instruction as I;
match assign {
A::Expr(expr) => self.compile_expr(expr)?,
A::Assign(lhs, rhs) => {
self.compile_assign(rhs)?;
match lhs {
E::Ident(name) => {
if let Some(global) = self.find_global(&name) {
self.emit(I::Dup);
self.emit(I::StoreGlobal(global as u16));
} else if let Some(local) = self.find_local(&name) {
self.emit(I::Dup);
self.emit(I::Store(local.idx as u16));
} else if self.can_make_globals() {
let global = self.create_global(name.clone());
self.emit(I::Dup);
self.emit(I::StoreGlobal(global as u16));
} else {
self.create_local(name.clone());
self.emit(I::Dup);
}
},
E::Index(_, _) => todo!("index"),
E::FieldAccess(_, _) => todo!("field access"),
_ => panic!("this should be handeled by the parser!!!")
}
}
};
Ok(())
}
fn compile_stmt(&mut self, stmt: &Stmt) -> Result<()> {
use Stmt::*;
use Instruction as I;
match stmt {
NoOp => {},
If(cond, ifb, elseb) => {
self.compile_expr(cond)?;
let jmpidx = self.emit_temp();
self.compile_stmt(ifb)?;
self.re_emit(I::JumpFalse(self.cur()), jmpidx);
if let Some(elseb) = elseb {
self.compile_stmt(elseb)?;
}
},
Function(name, params, body) => {
let chunk = self.compile_function(name.clone(), params, body)?;
let fun = Value::Function(Rc::new(
chunk::Function {
name: name.clone(),
arity: params.len(),
body: chunk
}
));
self.emit_const(fun);
if self.can_make_globals() {
let idx = self.create_global_checked(name.clone())?;
self.emit(I::StoreGlobal(idx as u16));
} else {
self.create_local_checked(name.clone())?;
}
},
Loop(stmt) => {
let idx = self.cur();
self.loop_top.push((idx as usize, self.scope));
self.compile_stmt(stmt)?;
self.emit(I::Jump(idx));
self.finish_loop();
},
While(cond, stmt) => {
let top = self.cur();
self.compile_expr(cond)?;
let jmpidx = self.emit_temp();
self.loop_top.push((top as usize, self.scope));
self.compile_stmt(stmt)?;
self.emit(I::Jump(top));
self.re_emit(I::JumpFalse(self.cur()), jmpidx);
self.finish_loop();
},
DoWhile(cond, stmt) => {
let top = self.cur();
self.loop_top.push((top as usize, self.scope));
self.compile_stmt(stmt)?;
self.compile_expr(cond)?;
self.emit(I::JumpTrue(top));
self.finish_loop();
},
Block(block) => {
self.begin_scope();
for stmt in block {
self.compile_stmt(stmt)?;
}
self.end_scope();
},
Expr(expr) => {
self.compile_expr(expr)?;
self.emit(I::Discard(1));
},
Assign(assign) => {
self.compile_assign(assign)?;
self.emit(I::Discard(1));
}
Let(name, expr) => {
self.compile_expr(expr)?;
if self.can_make_globals() {
let global = self.create_global_checked(name.clone())?;
self.emit(I::StoreGlobal(global as u16));
} else {
self.create_local_checked(name.clone())?;
}
},
Continue => {
let top = self.loop_top.pop();
if let Some((top, scope)) = top {
let diff = self.get_scope_diff(scope) as u16;
if diff > 0 {
self.emit(I::Discard(diff));
}
self.emit(I::Jump(top as u16));
} else {
return Err(Error::InvContinue.into())
}
},
Break => {
let top = self.loop_top.pop();
if let Some((_, scope)) = top {
self.emit(I::Discard(self.get_scope_diff(scope) as u16));
let tmpidx = self.emit_temp();
self.loop_bot.push(tmpidx);
} else {
return Err(Error::InvBreak.into())
}
},
Return(expr) => {
self.compile_expr(expr)?;
self.emit(I::Return);
},
};
Ok(())
}
fn compile_function(&mut self, name: Rc<str>, params: &Vec<Rc<str>>, body: &Box<Stmt>) -> Result<Chunk> {
let mut compiler = self.child(name); let mut compiler = self.child(name);
for name in params { for name in params {
compiler.create_local(name.clone()); compiler.create_local(name.clone());
compiler.emit(I::CreateLocal);
} }
compiler.compile_stmt(body)?; compiler.compile_expr(body)?;
compiler.finish()?; compiler.finish()?;
Ok(compiler.chunk) Ok(compiler.chunk)
} }
@ -493,7 +465,6 @@ impl<'c> Compiler<'c> {
} }
fn finish(&mut self) -> Result<()> { fn finish(&mut self) -> Result<()> {
use Instruction as I;
let ins = match self.chunk.code.last() { let ins = match self.chunk.code.last() {
Some(ins) => ins.clone(), Some(ins) => ins.clone(),
None => { None => {
@ -506,16 +477,8 @@ impl<'c> Compiler<'c> {
} }
}; };
match ins { match ins {
I::Discard(amt) if self.repl => {
self.chunk.code.pop().unwrap();
if amt > 1 {
self.emit(I::Discard(amt - 1));
}
self.emit(I::Return);
}
I::Return => {}, I::Return => {},
_ => { _ => {
self.emit(I::Nil);
self.emit(I::Return); self.emit(I::Return);
} }
}; };
@ -532,13 +495,13 @@ impl<'c> Compiler<'c> {
pub fn compile( pub fn compile(
&mut self, &mut self,
body: &Stmt, body: &Expr,
) -> Result<Rc<Function>> { ) -> Result<Rc<Function>> {
if let Stmt::Block(_) = body { if let Expr::Block(_) = body {
self.root_is_block = true; self.root_is_block = true;
} }
self.chunk = Chunk::new(); self.chunk = Chunk::new();
self.compile_stmt(body)?; self.compile_expr(body)?;
self.finish()?; self.finish()?;
let fun = Function { name: self.name.clone(), body: self.chunk.clone(), arity: 0 }; let fun = Function { name: self.name.clone(), body: self.chunk.clone(), arity: 0 };
Ok(Rc::new(fun)) Ok(Rc::new(fun))

View file

@ -1,7 +1,11 @@
use std::{fmt::Display, rc::Rc}; use std::{fmt::Display, rc::Rc};
use num_complex::Complex64; use num_complex::Complex64;
use crate::{lex::{Lexer, self, Token}, ast::{Expr, BinaryOp, UnaryOp, Stmt, Assign, optimize, self}, gc::Gc, value::{Value, self}, Result}; use crate::{lex::{Lexer, self, Token}, ast::{Expr, BinaryOp, UnaryOp, optimize}, gc::Gc, value::{Value, self}, Result};
use Value as V;
use Expr as E;
use Token as T;
pub struct ParserBuilder { pub struct ParserBuilder {
optimize: bool optimize: bool
@ -73,7 +77,7 @@ macro_rules! expr_parser {
$pattern => { $pattern => {
$parser.lexer.next_token_nl()?; $parser.lexer.next_token_nl()?;
let temp = $parser.$fn()?; let temp = $parser.$fn()?;
expr = Expr::BinaryOp(Box::new(expr), Box::new(temp), BinaryOp::from(tok)) expr = E::BinaryOp(Box::new(expr), Box::new(temp), BinaryOp::from(tok))
} }
_ => break _ => break
} }
@ -89,7 +93,7 @@ macro_rules! expr_parser_reverse {
Ok(match tok { Ok(match tok {
$pattern => { $pattern => {
$parser.lexer.next_token_nl()?; $parser.lexer.next_token_nl()?;
Expr::BinaryOp(Box::new(expr), Box::new($parser.$cur()?), BinaryOp::from(tok)) E::BinaryOp(Box::new(expr), Box::new($parser.$cur()?), BinaryOp::from(tok))
} }
_ => expr _ => expr
}) })
@ -117,11 +121,11 @@ impl Parser {
} }
fn parse_fn_call(&mut self) -> Result<Vec<Expr>> { fn parse_fn_call(&mut self) -> Result<Vec<Expr>> {
self.force_token(Token::LeftParen)?; self.force_token(T::LeftParen)?;
let mut params = Vec::new(); let mut params = Vec::new();
loop { loop {
let expr = match self.lexer.peek_token()? { let expr = match self.lexer.peek_token()? {
Token::RightParen => { T::RightParen => {
self.lexer.next_token()?; self.lexer.next_token()?;
break break
}, },
@ -130,8 +134,8 @@ impl Parser {
params.push(expr); params.push(expr);
let next = self.lexer.next_token()?; let next = self.lexer.next_token()?;
match next { match next {
Token::Comma => continue, T::Comma => continue,
Token::RightParen => break, T::RightParen => break,
_ => return Err(Error::UnexpectedToken(next).into()) _ => return Err(Error::UnexpectedToken(next).into())
}; };
} }
@ -139,11 +143,11 @@ impl Parser {
} }
fn parse_index(&mut self) -> Result<Vec<Expr>> { fn parse_index(&mut self) -> Result<Vec<Expr>> {
self.force_token(Token::LeftBrack)?; self.force_token(T::LeftBrack)?;
let mut indicies = Vec::new(); let mut indicies = Vec::new();
loop { loop {
let expr = match self.lexer.peek_token()? { let expr = match self.lexer.peek_token()? {
Token::RightBrack => { T::RightBrack => {
self.lexer.next_token()?; self.lexer.next_token()?;
break break
}, },
@ -152,8 +156,8 @@ impl Parser {
indicies.push(expr); indicies.push(expr);
let next = self.lexer.next_token()?; let next = self.lexer.next_token()?;
match next { match next {
Token::SemiColon => continue, T::SemiColon => continue,
Token::RightBrack => break, T::RightBrack => break,
_ => return Err(Error::UnexpectedToken(next).into()) _ => return Err(Error::UnexpectedToken(next).into())
}; };
} }
@ -164,13 +168,13 @@ impl Parser {
let mut part = Vec::new(); let mut part = Vec::new();
loop { loop {
let expr = match self.lexer.peek_token()? { let expr = match self.lexer.peek_token()? {
Token::SemiColon => break, T::SemiColon => break,
Token::RightBrack => break, T::RightBrack => break,
_ => self.parse_expr()? _ => self.parse_expr()?
}; };
part.push(expr); part.push(expr);
match self.lexer.peek_token()? { match self.lexer.peek_token()? {
Token::Comma => { T::Comma => {
self.lexer.next_token()?; self.lexer.next_token()?;
}, },
_ => {}, _ => {},
@ -180,20 +184,20 @@ impl Parser {
} }
fn parse_matrix(&mut self) -> Result<Expr> { fn parse_matrix(&mut self) -> Result<Expr> {
self.force_token(Token::LeftBrack)?; self.force_token(T::LeftBrack)?;
let mut parts = Vec::new(); let mut parts = Vec::new();
loop { loop {
let part = self.parse_matrix_part()?; let part = self.parse_matrix_part()?;
parts.push(part); parts.push(part);
let next = self.lexer.next_token()?; let next = self.lexer.next_token()?;
match next { match next {
Token::SemiColon => continue, T::SemiColon => continue,
Token::RightBrack => break, T::RightBrack => break,
_ => return Err(Error::UnexpectedToken(next).into()), _ => return Err(Error::UnexpectedToken(next).into()),
}; };
} }
if parts.len() == 1 { if parts.len() == 1 {
Ok(Expr::List(parts.pop().unwrap())) Ok(E::List(parts.pop().unwrap()))
} else { } else {
let codomain = parts[0].len(); let codomain = parts[0].len();
let domain = parts.len(); let domain = parts.len();
@ -207,216 +211,55 @@ impl Parser {
while let Some(part) = parts.pop() { while let Some(part) = parts.pop() {
data.extend(part); data.extend(part);
} }
Ok(Expr::Matrix((domain, codomain, data))) Ok(E::Matrix((domain, codomain, data)))
} }
} }
fn parse_table_key(&mut self) -> Result<Expr> { fn parse_table_key(&mut self) -> Result<Expr> {
let tok = self.lexer.next_token()?; let tok = self.lexer.next_token()?;
Ok(match tok { Ok(match tok {
Token::LeftBrack => { T::LeftBrack => {
let expr = self.parse_expr()?; let expr = self.parse_expr()?;
self.force_token(Token::RightBrack)?; self.force_token(T::RightBrack)?;
expr expr
}, },
Token::Ident(ident) => Expr::Ident(ident), T::Ident(ident) => E::Ident(ident),
Token::String(string) => Expr::Literal(Value::String(string.to_string().into())), T::String(string) => E::Literal(V::String(string.to_string().into())),
_ => return Err(Error::UnexpectedToken(tok).into()) _ => return Err(Error::UnexpectedToken(tok).into())
}) })
} }
fn parse_table(&mut self) -> Result<Expr> { fn parse_table(&mut self) -> Result<Expr> {
self.force_token(Token::LeftLeftBrace)?; self.force_token(T::LeftLeftBrace)?;
let mut table = Vec::new(); let mut table = Vec::new();
if self.lexer.peek_token()? == Token::RightRightBrace { if self.lexer.peek_token()? == T::RightRightBrace {
self.lexer.next_token()?; self.lexer.next_token()?;
return Ok(Expr::Table(table)) return Ok(E::Table(table))
} }
loop { loop {
let key = self.parse_table_key()?; let key = self.parse_table_key()?;
self.force_token(Token::Assign)?; self.force_token(T::Assign)?;
let value = self.parse_expr()?; let value = self.parse_expr()?;
table.push((key, value)); table.push((key, value));
let next = self.lexer.next_token()?; let next = self.lexer.next_token()?;
match next { match next {
Token::Comma => continue, T::Comma => continue,
Token::RightRightBrace => break, T::RightRightBrace => break,
_ => return Err(Error::UnexpectedToken(next).into()) _ => return Err(Error::UnexpectedToken(next).into())
} }
} }
Ok(Expr::Table(table)) Ok(E::Table(table))
} }
fn parse_paren(&mut self) -> Result<Expr> { fn parse_paren(&mut self) -> Result<Expr> {
self.force_token(Token::LeftParen)?; self.force_token(T::LeftParen)?;
let expr = self.parse_expr()?; let expr = self.parse_expr()?;
self.force_token(Token::RightParen)?; self.force_token(T::RightParen)?;
Ok(expr) Ok(expr)
} }
fn parse_term(&mut self) -> Result<Expr> {
use Token::*;
let tok = self.lexer.peek_token()?;
match tok {
LeftBrack => return self.parse_matrix(),
LeftLeftBrace => return self.parse_table(),
LeftParen => return self.parse_paren(),
_ => ()
}
self.lexer.next_token()?;
Ok(match tok {
Nil => Expr::Literal(Value::Nil),
Int(i) => Expr::Literal(Value::Int(i)),
Float(f) => Expr::Literal(Value::Float(f)),
Complex(c) => Expr::Literal(Value::Complex(Complex64::new(0.0, c))),
Regex(r) => Expr::Literal(Value::Regex(Gc::new(r.into()))),
String(s) => Expr::Literal(Value::String(s.to_string().into())),
True => Expr::Literal(Value::Bool(true)),
False => Expr::Literal(Value::Bool(false)),
Ident(ident) => Expr::Ident(ident),
_ => return Err(Error::UnexpectedToken(tok).into()),
})
}
fn parse_expr_expr_access(&mut self) -> Result<Expr> {
let mut expr = self.parse_term()?;
loop {
let tok = self.lexer.peek_token()?;
match tok {
Token::Access => {
self.force_token(Token::Access)?;
let temp = self.parse_term()?;
expr = Expr::FieldAccess(Box::new(expr), Box::new(temp));
},
_ => break
}
}
Ok(expr)
}
fn parse_expr_call(&mut self) -> Result<Expr> {
let mut expr = self.parse_expr_expr_access()?;
loop {
let tok = self.lexer.peek_token()?;
match tok {
Token::LeftBrack => {
let index = self.parse_index()?;
expr = Expr::Index(Box::new(expr), index);
},
Token::LeftParen => {
let params = self.parse_fn_call()?;
expr = Expr::FnCall(Box::new(expr), params);
}
_ => break
}
}
Ok(expr)
}
fn parse_expr_unary(&mut self) -> Result<Expr> {
let tok = self.lexer.peek_token_nl()?;
Ok(match tok {
Token::Not => {
self.lexer.next_token()?;
Expr::UnaryOp(Box::new(self.parse_expr_unary()?), UnaryOp::Not)
}
Token::Subtract => {
self.lexer.next_token()?;
Expr::UnaryOp(Box::new(self.parse_expr_unary()?), UnaryOp::Negate)
}
_ => self.parse_expr_call()?
})
}
fn parse_expr_pow(&mut self) -> Result<Expr> {
expr_parser_reverse!(
self,
Token::Power,
parse_expr_unary,
parse_expr_pow
)
}
fn parse_expr_mult(&mut self) -> Result<Expr> {
expr_parser!(self, Token::Multiply | Token::Divide | Token::Modulo, parse_expr_pow)
}
fn parse_expr_add(&mut self) -> Result<Expr> {
expr_parser!(self, Token::Add | Token::Subtract, parse_expr_mult)
}
fn parse_expr_shift(&mut self) -> Result<Expr> {
expr_parser!(
self,
Token::BitwiseShiftLeft | Token::BitwiseShiftRight,
parse_expr_add
)
}
fn parse_expr_bit_and(&mut self) -> Result<Expr> {
expr_parser!(self, Token::BitwiseAnd, parse_expr_shift)
}
fn parse_expr_bit_or(&mut self) -> Result<Expr> {
expr_parser!(self, Token::BitwiseOr, parse_expr_bit_and)
}
fn parse_expr_compare(&mut self) -> Result<Expr> {
expr_parser!(
self,
Token::Equal | Token::NotEqual |
Token::LessThan | Token::GreaterThan |
Token::LessEqual | Token::GreaterEqual,
parse_expr_bit_or
)
}
fn parse_expr_and(&mut self) -> Result<Expr> {
let mut expr = self.parse_expr_compare()?;
loop {
let tok = self.lexer.peek_token()?;
match tok {
Token::And => {
self.force_token(Token::And)?;
let temp = self.parse_expr_compare()?;
expr = Expr::And(Box::new(expr), Box::new(temp));
},
_ => break
}
}
Ok(expr)
}
fn parse_expr(&mut self) -> Result<Expr> {
let mut expr = self.parse_expr_and()?;
loop {
let tok = self.lexer.peek_token()?;
match tok {
Token::Or => {
self.force_token(Token::Or)?;
let temp = self.parse_expr_and()?;
expr = Expr::Or(Box::new(expr), Box::new(temp));
},
_ => break
}
}
Ok(expr)
}
fn parse_assign(&mut self) -> Result<Assign> {
let expr = self.parse_expr()?;
if !expr.is_assignable() {
return Ok(Assign::Expr(expr));
}
if self.lexer.peek_token()? != Token::Assign {
return Ok(Assign::Expr(expr));
}
self.lexer.next_token()?;
Ok(Assign::Assign(expr, Box::new(self.parse_assign()?)))
}
fn parse_params(&mut self) -> Result<Vec<Rc<str>>> { fn parse_params(&mut self) -> Result<Vec<Rc<str>>> {
use Token::*; use T::*;
let tok = self.lexer.next_token()?; let tok = self.lexer.next_token()?;
match tok { match tok {
Ident(ident) => return Ok(vec![ident]), Ident(ident) => return Ok(vec![ident]),
@ -426,7 +269,7 @@ impl Parser {
let mut params = Vec::new(); let mut params = Vec::new();
if self.lexer.peek_token()? == Token::RightParen { if self.lexer.peek_token()? == T::RightParen {
self.lexer.next_token()?; self.lexer.next_token()?;
return Ok(params); return Ok(params);
} }
@ -446,7 +289,7 @@ impl Parser {
} }
fn parse_ident(&mut self) -> Result<Rc<str>> { fn parse_ident(&mut self) -> Result<Rc<str>> {
if let Token::Ident(ident) = self.lexer.next_token()? { if let T::Ident(ident) = self.lexer.next_token()? {
Ok(ident) Ok(ident)
} else { } else {
Err(Error::ExpectedTokenName("Ident").into()) Err(Error::ExpectedTokenName("Ident").into())
@ -454,81 +297,124 @@ impl Parser {
} }
fn parse_ident_nl(&mut self) -> Result<Rc<str>> { fn parse_ident_nl(&mut self) -> Result<Rc<str>> {
if let Token::Ident(ident) = self.lexer.next_token_nl()? { if let T::Ident(ident) = self.lexer.next_token_nl()? {
Ok(ident) Ok(ident)
} else { } else {
Err(Error::ExpectedTokenName("Ident").into()) Err(Error::ExpectedTokenName("Ident").into())
} }
} }
fn parse_function(&mut self) -> Result<Stmt> { fn parse_function(&mut self) -> Result<Expr> {
self.force_token(Token::Function)?; self.force_token(T::Function)?;
let ident = self.parse_ident()?; let ident = self.parse_ident()?;
let params = match self.lexer.peek_token()? { let params = match self.lexer.peek_token()? {
Token::LeftBrace => vec![], T::LeftBrace => vec![],
_ => self.parse_params()?, _ => self.parse_params()?,
}; };
let stmt = self.parse_stmt()?;
Ok(Stmt::Function(ident, params, Box::new(stmt)))
}
fn parse_do_while(&mut self) -> Result<Stmt> {
self.force_token(Token::Do)?;
let stmt = self.parse_stmt()?;
self.force_token(Token::While)?;
let expr = self.parse_expr()?; let expr = self.parse_expr()?;
Ok(Stmt::DoWhile(expr, Box::new(stmt))) Ok(E::Function(ident, params, Box::new(expr)))
} }
fn parse_while(&mut self) -> Result<Stmt> { fn parse_do_while(&mut self) -> Result<Expr> {
self.force_token(Token::While)?; self.force_token(T::Do)?;
let expr = Box::new(self.parse_expr()?);
self.force_token(T::While)?;
let cond = Box::new(self.parse_expr()?);
Ok(E::DoWhile(expr, cond))
}
fn parse_while(&mut self) -> Result<Expr> {
self.force_token(T::While)?;
let cond = Box::new(self.parse_expr()?);
let expr = Box::new(self.parse_expr()?);
Ok(E::While(cond, expr))
}
fn parse_loop(&mut self) -> Result<Expr> {
self.force_token(T::Loop)?;
let expr = self.parse_expr()?; let expr = self.parse_expr()?;
let stmt = self.parse_stmt()?; Ok(E::Loop(Box::new(expr)))
Ok(Stmt::While(expr, Box::new(stmt)))
} }
fn parse_loop(&mut self) -> Result<Stmt> { fn parse_if(&mut self) -> Result<Expr> {
self.force_token(Token::Loop)?; self.force_token(T::If)?;
let stmt = self.parse_stmt()?; let cond = Box::new(self.parse_expr()?);
Ok(Stmt::Loop(Box::new(stmt))) let expr = Box::new(self.parse_expr()?);
}
fn parse_if(&mut self) -> Result<Stmt> { if self.lexer.peek_token()? != T::Else {
self.force_token(Token::If)?; return Ok(E::If(cond, expr, None))
let expr = self.parse_expr()?;
let stmt = Box::new(self.parse_stmt()?);
if self.lexer.peek_token()? != Token::Else {
return Ok(Stmt::If(expr, stmt, None))
} }
self.lexer.next_token()?; self.lexer.next_token()?;
if self.lexer.peek_token()? == Token::If { if self.lexer.peek_token()? == T::If {
Ok(Stmt::If(expr, stmt, Some(Box::new(self.parse_if()?)))) Ok(E::If(cond, expr, Some(Box::new(self.parse_if()?))))
} else { } else {
Ok(Stmt::If(expr, stmt, Some(Box::new(self.parse_stmt()?)))) Ok(E::If(cond, expr, Some(Box::new(self.parse_expr()?))))
} }
} }
fn parse_let(&mut self) -> Result<Stmt> { fn parse_let(&mut self) -> Result<Expr> {
self.force_token(Token::Let)?; self.force_token(T::Let)?;
let ident = self.parse_ident_nl()?; let ident = self.parse_ident_nl()?;
if self.lexer.peek_token_nl()? == Token::Assign { if self.lexer.peek_token_nl()? == T::Assign {
self.force_token_nl(Token::Assign)?; self.force_token_nl(T::Assign)?;
Ok(Stmt::Let(ident, self.parse_expr()?)) Ok(E::Let(ident, Box::new(self.parse_expr()?)))
} else { } else {
Ok(Stmt::Let(ident, Expr::Literal(Value::Nil))) Ok(E::Let(ident, Box::new(E::Literal(V::Nil))))
} }
} }
fn parse_return(&mut self) -> Result<Stmt> { fn parse_return(&mut self) -> Result<Expr> {
self.force_token(Token::Return)?; self.force_token(T::Return)?;
Ok(Stmt::Return(self.parse_expr()?)) Ok(E::Return(Box::new(self.parse_expr()?)))
} }
fn parse_stmt(&mut self) -> Result<Stmt> { fn parse_block(&mut self) -> Result<Expr> {
use Token::*; let mut block = Vec::new();
self.force_token(T::LeftBrace)?;
loop {
let expr = match self.lexer.peek_token()? {
T::RightBrace => break,
T::SemiColon => {
self.lexer.next_token()?;
continue;
}
_ => self.parse_expr()?
};
block.push(expr);
let next = self.lexer.next_token()?;
match next {
T::SemiColon => continue,
T::RightBrace => break,
_ => return Err(Error::UnexpectedToken(next).into())
}
}
if self.lexer.peek_token()? == T::RightBrace {
self.lexer.next_token()?;
}
Ok(E::Block(block))
}
fn parse_value(&mut self) -> Result<Expr> {
let tok = self.lexer.next_token()?;
Ok(match tok {
T::Nil => E::Literal(V::Nil),
T::Int(i) => E::Literal(V::Int(i)),
T::Float(f) => E::Literal(V::Float(f)),
T::Complex(c) => E::Literal(V::Complex(Complex64::new(0.0, c))),
T::Regex(r) => E::Literal(V::Regex(Gc::new(r.into()))),
T::String(s) => E::Literal(V::String(s.to_string().into())),
T::True => E::Literal(V::Bool(true)),
T::False => E::Literal(V::Bool(false)),
T::Ident(ident) => E::Ident(ident),
_ => return Err(Error::UnexpectedToken(tok).into()),
})
}
fn parse_term(&mut self) -> Result<Expr> {
use T::*;
match self.lexer.peek_token()? { match self.lexer.peek_token()? {
Function => self.parse_function(),
Do => self.parse_do_while(), Do => self.parse_do_while(),
While => self.parse_while(), While => self.parse_while(),
Let => self.parse_let(), Let => self.parse_let(),
@ -538,80 +424,177 @@ impl Parser {
Loop => self.parse_loop(), Loop => self.parse_loop(),
Break => { Break => {
self.lexer.next_token()?; self.lexer.next_token()?;
Ok(Stmt::Break) Ok(E::Break)
}, },
Continue => { Continue => {
self.lexer.next_token()?; self.lexer.next_token()?;
Ok(Stmt::Continue) Ok(E::Continue)
}, },
_ => { LeftBrack => self.parse_matrix(),
let assign = self.parse_assign()?; LeftLeftBrace => self.parse_table(),
Ok(match assign { LeftParen => self.parse_paren(),
ast::Assign::Expr(expr) => Stmt::Expr(expr), _ => self.parse_value(),
_ => Stmt::Assign(assign), }
}
fn parse_expr_expr_access(&mut self) -> Result<Expr> {
let mut expr = self.parse_term()?;
loop {
let tok = self.lexer.peek_token()?;
match tok {
T::Access => {
self.force_token(T::Access)?;
let temp = self.parse_term()?;
expr = E::FieldAccess(Box::new(expr), Box::new(temp));
},
_ => break
}
}
Ok(expr)
}
fn parse_expr_call(&mut self) -> Result<Expr> {
let mut expr = self.parse_expr_expr_access()?;
loop {
let tok = self.lexer.peek_token()?;
match tok {
T::LeftBrack => {
let index = self.parse_index()?;
expr = E::Index(Box::new(expr), index);
},
T::LeftParen => {
let params = self.parse_fn_call()?;
expr = E::FnCall(Box::new(expr), params);
}
_ => break
}
}
Ok(expr)
}
fn parse_expr_unary(&mut self) -> Result<Expr> {
let tok = self.lexer.peek_token_nl()?;
Ok(match tok {
T::Not => {
self.lexer.next_token()?;
E::UnaryOp(Box::new(self.parse_expr_unary()?), UnaryOp::Not)
}
T::Subtract => {
self.lexer.next_token()?;
E::UnaryOp(Box::new(self.parse_expr_unary()?), UnaryOp::Negate)
}
_ => self.parse_expr_call()?
}) })
} }
}
fn parse_expr_pow(&mut self) -> Result<Expr> {
expr_parser_reverse!(
self,
T::Power,
parse_expr_unary,
parse_expr_pow
)
} }
fn parse_block(&mut self) -> Result<Stmt> { fn parse_expr_mult(&mut self) -> Result<Expr> {
let mut block = Vec::new(); expr_parser!(self, T::Multiply | T::Divide | T::Modulo, parse_expr_pow)
self.force_token(Token::LeftBrace)?; }
fn parse_expr_add(&mut self) -> Result<Expr> {
expr_parser!(self, T::Add | T::Subtract, parse_expr_mult)
}
fn parse_expr_shift(&mut self) -> Result<Expr> {
expr_parser!(
self,
T::BitwiseShiftLeft | T::BitwiseShiftRight,
parse_expr_add
)
}
fn parse_expr_bit_and(&mut self) -> Result<Expr> {
expr_parser!(self, T::BitwiseAnd, parse_expr_shift)
}
fn parse_expr_bit_or(&mut self) -> Result<Expr> {
expr_parser!(self, T::BitwiseOr, parse_expr_bit_and)
}
fn parse_expr_compare(&mut self) -> Result<Expr> {
expr_parser!(
self,
T::Equal | T::NotEqual |
T::LessThan | T::GreaterThan |
T::LessEqual | T::GreaterEqual,
parse_expr_bit_or
)
}
fn parse_expr_and(&mut self) -> Result<Expr> {
let mut expr = self.parse_expr_compare()?;
loop { loop {
let stmt = match self.lexer.peek_token()? { let tok = self.lexer.peek_token()?;
Token::RightBrace => break, match tok {
Token::SemiColon => { T::And => {
self.lexer.next_token()?; self.force_token(T::And)?;
continue; let temp = self.parse_expr_compare()?;
expr = E::And(Box::new(expr), Box::new(temp));
},
_ => break
} }
_ => self.parse_stmt()? }
Ok(expr)
}
fn parse_expr_or(&mut self) -> Result<Expr> {
let mut expr = self.parse_expr_and()?;
loop {
let tok = self.lexer.peek_token()?;
match tok {
T::Or => {
self.force_token(T::Or)?;
let temp = self.parse_expr_and()?;
expr = E::Or(Box::new(expr), Box::new(temp));
},
_ => break
}
}
Ok(expr)
}
fn parse_expr(&mut self) -> Result<Expr> {
let expr = self.parse_expr_or()?;
let tok = self.lexer.peek_token_nl()?;
Ok(match tok {
T::Assign => {
self.lexer.next_token_nl()?;
E::Assign(Box::new(expr),Box::new(self.parse_expr()?))
}
_ => expr
})
}
fn parse_root(&mut self) -> Result<Expr> {
let mut block = Vec::new();
loop {
match self.lexer.peek_token()? {
T::Eof => break,
T::SemiColon => {
self.lexer.next_token()?;
continue
}
_ => {}
}; };
block.push(stmt); let expr = self.parse_expr()?;
let next = self.lexer.next_token()?; block.push(expr);
match next {
Token::SemiColon => continue,
Token::RightBrace => break,
_ => return Err(Error::UnexpectedToken(next).into())
} }
} Ok(E::Block(block))
if self.lexer.peek_token()? == Token::RightBrace {
self.lexer.next_token()?;
}
Ok(Stmt::Block(block))
} }
fn parse_root_stmt(&mut self) -> Result<Stmt> { pub fn parse<T: Into<String>>(&mut self, into: T) -> Result<Expr> {
if self.lexer.peek_token()? == Token::Function {
self.parse_function()
} else {
self.parse_stmt()
}
}
pub fn parse<T: Into<String>>(&mut self, into: T) -> Result<Stmt> {
let lexer = Lexer::new(into); let lexer = Lexer::new(into);
self.lexer = lexer; self.lexer = lexer;
let ast = self.parse_root()?;
let mut block = Vec::new();
loop {
let expr = match self.lexer.peek_token()? {
Token::Eof => break,
Token::SemiColon => {
self.lexer.next_token()?;
continue;
}
_ => self.parse_root_stmt()?
};
block.push(expr);
let next = self.lexer.next_token()?;
match next {
Token::SemiColon => continue,
Token::Eof => break,
_ => return Err(Error::UnexpectedToken(next).into())
}
}
let ast = Stmt::Block(block);
if self.optimize { if self.optimize {
Ok(optimize(ast)?) Ok(optimize(ast)?)
} else { } else {

View file

@ -1,5 +1,5 @@
use std::{collections::HashMap, rc::Rc, fmt::{Debug, Display}, usize, cell::RefCell, ops::{Index, IndexMut}}; use std::{rc::Rc, fmt::{Debug, Display}, usize, ops::{Index, IndexMut}, collections::HashMap};
use crate::{value::{Value, self, ValueMap}, gc::Gc, chunk::{Function, Instruction}, compiler::Globals, Result}; use crate::{value::{Value, self, ValueMap}, gc::Gc, chunk::{Function, Instruction}, Result};
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
@ -105,9 +105,9 @@ impl StackFrame {
pub struct Vm { pub struct Vm {
stack: Stack<Value>, stack: Stack<Value>,
locals: Stack<Value>,
frames: Vec<StackFrame>, frames: Vec<StackFrame>,
global: HashMap<String, Value>, globals: HashMap<u16, Value>,
global_table: Globals,
} }
impl Vm { impl Vm {
@ -123,16 +123,12 @@ impl Vm {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
stack: Stack::new(), stack: Stack::new(),
locals: Stack::new(),
frames: Vec::new(), frames: Vec::new(),
global: HashMap::new(), globals: HashMap::new(),
global_table: Rc::new(RefCell::new(Vec::new()))
} }
} }
pub fn globals(&self) -> Globals {
self.global_table.clone()
}
pub fn run(&mut self, fun: Rc<Function>) -> Result<Value> { pub fn run(&mut self, fun: Rc<Function>) -> Result<Value> {
let mut frame = StackFrame::new(&self, fun); let mut frame = StackFrame::new(&self, fun);
loop { loop {
@ -141,20 +137,20 @@ impl Vm {
frame.ip += 1; frame.ip += 1;
match ins { match ins {
NoOp => {}, NoOp => {},
Load(idx) => self.push(self.stack[frame.bp + idx as usize].clone()), CreateLocal => self.locals.push(self.stack.pop()),
Store(idx) => self.stack[frame.bp + idx as usize] = self.pop(), LoadLocal(idx) => {self.stack.push(self.locals[idx as usize].clone());},
StoreLocal(idx) => self.stack[frame.bp + idx as usize] = self.pop(),
DiscardLocals(count) => {self.locals.truncate(self.locals.len() - count as usize)},
LoadGlobal(idx) => { LoadGlobal(idx) => {
let name = self.global_table.borrow()[idx as usize].clone(); let val = self.globals
let val = self.global .get(&idx)
.get(name.as_ref()) .unwrap()
.ok_or(self::Error::UndefinedGlobal(name.into()))?
.clone(); .clone();
self.stack.push(val); self.stack.push(val);
}, },
StoreGlobal(idx) => { StoreGlobal(idx) => {
let name = self.global_table.borrow()[idx as usize].clone(); let val = self.pop();
let store = self.pop(); self.globals.insert(idx, val);
self.global.insert(name.to_string(), store);
}, },
Const(idx) => self.push(frame.fun.body.constants[idx as usize].clone()), Const(idx) => self.push(frame.fun.body.constants[idx as usize].clone()),
Int(i) => self.push(Value::Int(i as i64)), Int(i) => self.push(Value::Int(i as i64)),