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()
.repl(repl)
.debug(args.debug)
.globals(vm.globals())
.build();
(Self { parser, vm, compiler, repl }, file)

View file

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

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};
#[derive(Clone)]
@ -14,10 +14,6 @@ impl Chunk {
code: Vec::new()
}
}
pub fn from_compiled(_buf: &[u8]) -> Result<Self> {
todo!()
}
}
impl Debug for Chunk {
@ -52,8 +48,11 @@ pub struct Function {
pub enum Instruction {
NoOp,
Load(u16),
Store(u16),
CreateLocal,
LoadLocal(u16),
StoreLocal(u16),
DiscardLocals(u16),
LoadGlobal(u16),
StoreGlobal(u16),
@ -88,8 +87,10 @@ impl Display for Instruction {
use Instruction::*;
match self {
NoOp => write!(f, "noop"),
Load(idx) => write!(f, "load \x1b[33m{idx}\x1b[0m"),
Store(idx) => write!(f, "store \x1b[33m{idx}\x1b[0m"),
CreateLocal => write!(f, "create local"),
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"),
StoreGlobal(name) => write!(f, "store global \x1b[36m{name}\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"),
Nil => write!(f, "push \x1b[34mnil\x1b[0m"),
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"),
BinaryOp(op) => write!(f, "binary \x1b[32m{op:?}\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 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> {
globals: Globals,
globals: Rc<RefCell<Vec<Rc<str>>>>,
repl: bool,
debug: bool,
name: Rc<str>,
@ -33,7 +35,7 @@ impl<'c> CompilerBuilder<'c> {
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
}
@ -55,7 +57,7 @@ impl<'c> CompilerBuilder<'c> {
globals: self.globals,
repl: self.repl,
debug: self.debug,
scope: 0,
scopes: Vec::new(),
locals: Vec::new(),
chunk: Chunk::new(),
loop_top: Vec::new(),
@ -74,7 +76,7 @@ pub struct Compiler<'c> {
root_is_block: bool,
scope: usize,
scopes: Vec<usize>,
chunk: Chunk,
loop_top: Vec<(usize, usize)>,
@ -94,8 +96,10 @@ struct Local {
pub enum Error {
Undefined(Rc<str>),
Redefined(Rc<str>),
InvAssign(Expr),
InvContinue,
InvBreak,
NotImplemented(&'static str),
}
impl std::error::Error for self::Error {}
@ -106,8 +110,10 @@ impl Display for self::Error {
match self {
Undefined(name) => write!(f, "value {name} is undefined"),
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"),
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 {
self.root_is_block = false;
} else {
self.scope += 1;
self.scopes.push(self.locals.len())
}
}
fn get_scope_start(&self, scope: usize) -> usize {
let mut stack_cutoff = None;
for (i, local) in self.locals.iter().enumerate() {
if local.scope == scope {
stack_cutoff = Some(i);
break;
fn collapse_scopes(&mut self, top_scope: usize) {
let mut cutoff = usize::MAX;
while self.scopes.len() > top_scope {
cutoff = self.scopes.pop().unwrap()
}
}
if let Some(cutoff) = stack_cutoff {
cutoff
} else {
self.locals.len()
}
}
fn get_scope_diff(&self, scope: usize) -> usize {
let cutoff = self.get_scope_start(scope);
self.locals.len() - cutoff
if cutoff < self.locals.len() {
self.emit(Instruction::DiscardLocals((self.locals.len() - cutoff) as u16));
self.locals.truncate(cutoff);
};
}
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() {
self.emit(Instruction::Discard((self.locals.len() - cutoff) as u16));
self.emit(Instruction::DiscardLocals((self.locals.len() - cutoff) as u16));
self.locals.truncate(cutoff);
};
if self.scope != 0 {
self.scope -= 1;
}
}
fn create_local(&mut self, name: Rc<str>) -> Rc<Local> {
let local = Local { name, idx: self.locals.len(), scope: self.scope };
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));
self.locals[self.locals.len() - 1].clone()
}
fn create_global(&mut self, name: Rc<str>) -> usize {
@ -174,13 +169,14 @@ impl<'c> Compiler<'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 local.scope == self.scope {
if local.scope == self.scopes.len() {
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> {
@ -219,16 +215,14 @@ impl<'c> Compiler<'c> {
}
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) {
use Value::*;
use Instruction as I;
match val {
Nil => self.emit(I::Nil),
Bool(b) => if *b { self.emit(I::True) } else { self.emit(I::False) },
Int(i) => {
V::Nil => self.emit(I::Nil),
V::Bool(b) => if *b { self.emit(I::True) } else { self.emit(I::False) },
V::Int(i) => {
if let Ok(i) = i16::try_from(*i) {
self.emit(I::Int(i));
} 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<()> {
use Expr::*;
use Instruction as I;
match expr {
Literal(val) => self.compile_value(val),
Ident(name) => {
E::NoOp => {},
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) {
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) {
self.emit(I::LoadGlobal(global as u16));
} 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.emit(I::UnaryOp(*op));
},
BinaryOp(lhs, rhs, op) => {
E::BinaryOp(lhs, rhs, op) => {
self.compile_expr(lhs)?;
self.compile_expr(rhs)?;
self.emit(I::BinaryOp(*op));
},
Index(_, _) => todo!("index"),
FnCall(fun, params) => {
E::Index(_, _) => return Err(self::Error::NotImplemented("indexing").into()),
E::FnCall(fun, params) => {
for expr in params {
self.compile_expr(expr)?;
}
self.compile_expr(fun)?;
self.emit(I::Call(params.len() as u8));
},
FieldAccess(_, _) => todo!("field access"),
List(list) => {
E::FieldAccess(_, _) => return Err(self::Error::NotImplemented("filed access").into()),
E::List(list) => {
for expr in list {
self.compile_expr(expr)?;
}
self.emit(I::NewList(list.len() as u16));
},
Matrix(mat) => {
E::Matrix(mat) => {
for expr in &mat.2 {
self.compile_expr(expr)?;
}
self.emit(I::NewMatrix(mat.2.len() as u16, mat.1 as u8));
},
Table(table) => {
E::Table(table) => {
for (key, value) in table {
self.compile_expr(key)?;
self.compile_expr(value)?;
}
self.emit(I::NewTable(table.len() as u16));
},
And(lhs, rhs) => {
E::And(lhs, rhs) => {
self.compile_expr(lhs)?;
self.emit(I::Dup);
let jmpidx = self.emit_temp();
self.compile_expr(rhs)?;
self.re_emit(I::JumpFalse(self.cur()), jmpidx);
},
Or(lhs, rhs) => {
E::Or(lhs, rhs) => {
self.compile_expr(lhs)?;
self.emit(I::Dup);
let jmpidx = self.emit_temp();
@ -310,164 +433,13 @@ impl<'c> Compiler<'c> {
Ok(())
}
fn finish_loop(&mut self) {
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> {
fn compile_function(&mut self, name: Rc<str>, params: &Vec<Rc<str>>, body: &Box<Expr>) -> Result<Chunk> {
let mut compiler = self.child(name);
for name in params {
compiler.create_local(name.clone());
compiler.emit(I::CreateLocal);
}
compiler.compile_stmt(body)?;
compiler.compile_expr(body)?;
compiler.finish()?;
Ok(compiler.chunk)
}
@ -493,7 +465,6 @@ impl<'c> Compiler<'c> {
}
fn finish(&mut self) -> Result<()> {
use Instruction as I;
let ins = match self.chunk.code.last() {
Some(ins) => ins.clone(),
None => {
@ -506,16 +477,8 @@ impl<'c> Compiler<'c> {
}
};
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 => {},
_ => {
self.emit(I::Nil);
self.emit(I::Return);
}
};
@ -532,13 +495,13 @@ impl<'c> Compiler<'c> {
pub fn compile(
&mut self,
body: &Stmt,
body: &Expr,
) -> Result<Rc<Function>> {
if let Stmt::Block(_) = body {
if let Expr::Block(_) = body {
self.root_is_block = true;
}
self.chunk = Chunk::new();
self.compile_stmt(body)?;
self.compile_expr(body)?;
self.finish()?;
let fun = Function { name: self.name.clone(), body: self.chunk.clone(), arity: 0 };
Ok(Rc::new(fun))

View file

@ -1,7 +1,11 @@
use std::{fmt::Display, rc::Rc};
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 {
optimize: bool
@ -73,7 +77,7 @@ macro_rules! expr_parser {
$pattern => {
$parser.lexer.next_token_nl()?;
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
}
@ -89,7 +93,7 @@ macro_rules! expr_parser_reverse {
Ok(match tok {
$pattern => {
$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
})
@ -117,11 +121,11 @@ impl Parser {
}
fn parse_fn_call(&mut self) -> Result<Vec<Expr>> {
self.force_token(Token::LeftParen)?;
self.force_token(T::LeftParen)?;
let mut params = Vec::new();
loop {
let expr = match self.lexer.peek_token()? {
Token::RightParen => {
T::RightParen => {
self.lexer.next_token()?;
break
},
@ -130,8 +134,8 @@ impl Parser {
params.push(expr);
let next = self.lexer.next_token()?;
match next {
Token::Comma => continue,
Token::RightParen => break,
T::Comma => continue,
T::RightParen => break,
_ => return Err(Error::UnexpectedToken(next).into())
};
}
@ -139,11 +143,11 @@ impl Parser {
}
fn parse_index(&mut self) -> Result<Vec<Expr>> {
self.force_token(Token::LeftBrack)?;
self.force_token(T::LeftBrack)?;
let mut indicies = Vec::new();
loop {
let expr = match self.lexer.peek_token()? {
Token::RightBrack => {
T::RightBrack => {
self.lexer.next_token()?;
break
},
@ -152,8 +156,8 @@ impl Parser {
indicies.push(expr);
let next = self.lexer.next_token()?;
match next {
Token::SemiColon => continue,
Token::RightBrack => break,
T::SemiColon => continue,
T::RightBrack => break,
_ => return Err(Error::UnexpectedToken(next).into())
};
}
@ -164,13 +168,13 @@ impl Parser {
let mut part = Vec::new();
loop {
let expr = match self.lexer.peek_token()? {
Token::SemiColon => break,
Token::RightBrack => break,
T::SemiColon => break,
T::RightBrack => break,
_ => self.parse_expr()?
};
part.push(expr);
match self.lexer.peek_token()? {
Token::Comma => {
T::Comma => {
self.lexer.next_token()?;
},
_ => {},
@ -180,20 +184,20 @@ impl Parser {
}
fn parse_matrix(&mut self) -> Result<Expr> {
self.force_token(Token::LeftBrack)?;
self.force_token(T::LeftBrack)?;
let mut parts = Vec::new();
loop {
let part = self.parse_matrix_part()?;
parts.push(part);
let next = self.lexer.next_token()?;
match next {
Token::SemiColon => continue,
Token::RightBrack => break,
T::SemiColon => continue,
T::RightBrack => break,
_ => return Err(Error::UnexpectedToken(next).into()),
};
}
if parts.len() == 1 {
Ok(Expr::List(parts.pop().unwrap()))
Ok(E::List(parts.pop().unwrap()))
} else {
let codomain = parts[0].len();
let domain = parts.len();
@ -207,216 +211,55 @@ impl Parser {
while let Some(part) = parts.pop() {
data.extend(part);
}
Ok(Expr::Matrix((domain, codomain, data)))
Ok(E::Matrix((domain, codomain, data)))
}
}
fn parse_table_key(&mut self) -> Result<Expr> {
let tok = self.lexer.next_token()?;
Ok(match tok {
Token::LeftBrack => {
T::LeftBrack => {
let expr = self.parse_expr()?;
self.force_token(Token::RightBrack)?;
self.force_token(T::RightBrack)?;
expr
},
Token::Ident(ident) => Expr::Ident(ident),
Token::String(string) => Expr::Literal(Value::String(string.to_string().into())),
T::Ident(ident) => E::Ident(ident),
T::String(string) => E::Literal(V::String(string.to_string().into())),
_ => return Err(Error::UnexpectedToken(tok).into())
})
}
fn parse_table(&mut self) -> Result<Expr> {
self.force_token(Token::LeftLeftBrace)?;
self.force_token(T::LeftLeftBrace)?;
let mut table = Vec::new();
if self.lexer.peek_token()? == Token::RightRightBrace {
if self.lexer.peek_token()? == T::RightRightBrace {
self.lexer.next_token()?;
return Ok(Expr::Table(table))
return Ok(E::Table(table))
}
loop {
let key = self.parse_table_key()?;
self.force_token(Token::Assign)?;
self.force_token(T::Assign)?;
let value = self.parse_expr()?;
table.push((key, value));
let next = self.lexer.next_token()?;
match next {
Token::Comma => continue,
Token::RightRightBrace => break,
T::Comma => continue,
T::RightRightBrace => break,
_ => return Err(Error::UnexpectedToken(next).into())
}
}
Ok(Expr::Table(table))
Ok(E::Table(table))
}
fn parse_paren(&mut self) -> Result<Expr> {
self.force_token(Token::LeftParen)?;
self.force_token(T::LeftParen)?;
let expr = self.parse_expr()?;
self.force_token(Token::RightParen)?;
self.force_token(T::RightParen)?;
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>>> {
use Token::*;
use T::*;
let tok = self.lexer.next_token()?;
match tok {
Ident(ident) => return Ok(vec![ident]),
@ -426,7 +269,7 @@ impl Parser {
let mut params = Vec::new();
if self.lexer.peek_token()? == Token::RightParen {
if self.lexer.peek_token()? == T::RightParen {
self.lexer.next_token()?;
return Ok(params);
}
@ -446,7 +289,7 @@ impl Parser {
}
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)
} else {
Err(Error::ExpectedTokenName("Ident").into())
@ -454,81 +297,124 @@ impl Parser {
}
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)
} else {
Err(Error::ExpectedTokenName("Ident").into())
}
}
fn parse_function(&mut self) -> Result<Stmt> {
self.force_token(Token::Function)?;
fn parse_function(&mut self) -> Result<Expr> {
self.force_token(T::Function)?;
let ident = self.parse_ident()?;
let params = match self.lexer.peek_token()? {
Token::LeftBrace => vec![],
T::LeftBrace => vec![],
_ => 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()?;
Ok(Stmt::DoWhile(expr, Box::new(stmt)))
Ok(E::Function(ident, params, Box::new(expr)))
}
fn parse_while(&mut self) -> Result<Stmt> {
self.force_token(Token::While)?;
fn parse_do_while(&mut self) -> Result<Expr> {
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 stmt = self.parse_stmt()?;
Ok(Stmt::While(expr, Box::new(stmt)))
Ok(E::Loop(Box::new(expr)))
}
fn parse_loop(&mut self) -> Result<Stmt> {
self.force_token(Token::Loop)?;
let stmt = self.parse_stmt()?;
Ok(Stmt::Loop(Box::new(stmt)))
}
fn parse_if(&mut self) -> Result<Expr> {
self.force_token(T::If)?;
let cond = Box::new(self.parse_expr()?);
let expr = Box::new(self.parse_expr()?);
fn parse_if(&mut self) -> Result<Stmt> {
self.force_token(Token::If)?;
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))
if self.lexer.peek_token()? != T::Else {
return Ok(E::If(cond, expr, None))
}
self.lexer.next_token()?;
if self.lexer.peek_token()? == Token::If {
Ok(Stmt::If(expr, stmt, Some(Box::new(self.parse_if()?))))
if self.lexer.peek_token()? == T::If {
Ok(E::If(cond, expr, Some(Box::new(self.parse_if()?))))
} 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> {
self.force_token(Token::Let)?;
fn parse_let(&mut self) -> Result<Expr> {
self.force_token(T::Let)?;
let ident = self.parse_ident_nl()?;
if self.lexer.peek_token_nl()? == Token::Assign {
self.force_token_nl(Token::Assign)?;
Ok(Stmt::Let(ident, self.parse_expr()?))
if self.lexer.peek_token_nl()? == T::Assign {
self.force_token_nl(T::Assign)?;
Ok(E::Let(ident, Box::new(self.parse_expr()?)))
} 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> {
self.force_token(Token::Return)?;
Ok(Stmt::Return(self.parse_expr()?))
fn parse_return(&mut self) -> Result<Expr> {
self.force_token(T::Return)?;
Ok(E::Return(Box::new(self.parse_expr()?)))
}
fn parse_stmt(&mut self) -> Result<Stmt> {
use Token::*;
fn parse_block(&mut self) -> Result<Expr> {
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()? {
Function => self.parse_function(),
Do => self.parse_do_while(),
While => self.parse_while(),
Let => self.parse_let(),
@ -538,80 +424,177 @@ impl Parser {
Loop => self.parse_loop(),
Break => {
self.lexer.next_token()?;
Ok(Stmt::Break)
Ok(E::Break)
},
Continue => {
self.lexer.next_token()?;
Ok(Stmt::Continue)
Ok(E::Continue)
},
_ => {
let assign = self.parse_assign()?;
Ok(match assign {
ast::Assign::Expr(expr) => Stmt::Expr(expr),
_ => Stmt::Assign(assign),
LeftBrack => self.parse_matrix(),
LeftLeftBrace => self.parse_table(),
LeftParen => self.parse_paren(),
_ => self.parse_value(),
}
}
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> {
let mut block = Vec::new();
self.force_token(Token::LeftBrace)?;
fn parse_expr_mult(&mut self) -> Result<Expr> {
expr_parser!(self, T::Multiply | T::Divide | T::Modulo, parse_expr_pow)
}
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 {
let stmt = match self.lexer.peek_token()? {
Token::RightBrace => break,
Token::SemiColon => {
self.lexer.next_token()?;
continue;
let tok = self.lexer.peek_token()?;
match tok {
T::And => {
self.force_token(T::And)?;
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 next = self.lexer.next_token()?;
match next {
Token::SemiColon => continue,
Token::RightBrace => break,
_ => return Err(Error::UnexpectedToken(next).into())
let expr = self.parse_expr()?;
block.push(expr);
}
}
if self.lexer.peek_token()? == Token::RightBrace {
self.lexer.next_token()?;
}
Ok(Stmt::Block(block))
Ok(E::Block(block))
}
fn parse_root_stmt(&mut self) -> Result<Stmt> {
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> {
pub fn parse<T: Into<String>>(&mut self, into: T) -> Result<Expr> {
let lexer = Lexer::new(into);
self.lexer = lexer;
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);
let ast = self.parse_root()?;
if self.optimize {
Ok(optimize(ast)?)
} else {

View file

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