lang is not expr based
This commit is contained in:
parent
ef4ada62f8
commit
671301383b
6 changed files with 590 additions and 681 deletions
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
},
|
||||
A::Assign(lhs, rhs) => {
|
||||
let assign = optimize_assign(A::Assign(lhs, rhs))?;
|
||||
Assign(assign)
|
||||
},
|
||||
}
|
||||
}
|
||||
Return(expr) => {
|
||||
Return(optimize_expr(expr)?)
|
||||
}
|
||||
_ => stmt
|
||||
E::Assign(lhs, rhs) => {
|
||||
let lhs = Box::new(optimize(*lhs)?);
|
||||
let rhs = Box::new(optimize(*rhs)?);
|
||||
E::Assign(lhs, rhs)
|
||||
},
|
||||
E::Return(expr) => {
|
||||
E::Return(Box::new(optimize(*expr)?))
|
||||
},
|
||||
_ => expr
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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_block(&mut self) -> Result<Stmt> {
|
||||
let mut block = Vec::new();
|
||||
self.force_token(Token::LeftBrace)?;
|
||||
fn parse_expr_expr_access(&mut self) -> Result<Expr> {
|
||||
let mut expr = self.parse_term()?;
|
||||
loop {
|
||||
let stmt = match self.lexer.peek_token()? {
|
||||
Token::RightBrace => break,
|
||||
Token::SemiColon => {
|
||||
self.lexer.next_token()?;
|
||||
continue;
|
||||
}
|
||||
_ => self.parse_stmt()?
|
||||
};
|
||||
block.push(stmt);
|
||||
let next = self.lexer.next_token()?;
|
||||
match next {
|
||||
Token::SemiColon => continue,
|
||||
Token::RightBrace => break,
|
||||
_ => return Err(Error::UnexpectedToken(next).into())
|
||||
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
|
||||
}
|
||||
}
|
||||
if self.lexer.peek_token()? == Token::RightBrace {
|
||||
self.lexer.next_token()?;
|
||||
}
|
||||
Ok(Stmt::Block(block))
|
||||
Ok(expr)
|
||||
}
|
||||
|
||||
fn parse_root_stmt(&mut self) -> Result<Stmt> {
|
||||
if self.lexer.peek_token()? == Token::Function {
|
||||
self.parse_function()
|
||||
} else {
|
||||
self.parse_stmt()
|
||||
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)
|
||||
}
|
||||
|
||||
pub fn parse<T: Into<String>>(&mut self, into: T) -> Result<Stmt> {
|
||||
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_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 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
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
let expr = self.parse_expr()?;
|
||||
block.push(expr);
|
||||
}
|
||||
Ok(E::Block(block))
|
||||
}
|
||||
|
||||
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 {
|
||||
|
|
|
@ -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)),
|
||||
|
|
Loading…
Reference in a new issue