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()
|
let compiler = CompilerBuilder::new()
|
||||||
.repl(repl)
|
.repl(repl)
|
||||||
.debug(args.debug)
|
.debug(args.debug)
|
||||||
.globals(vm.globals())
|
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
(Self { parser, vm, compiler, repl }, file)
|
(Self { parser, vm, compiler, repl }, file)
|
||||||
|
|
|
@ -36,6 +36,8 @@ pub enum BinaryOp {
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum Expr {
|
pub enum Expr {
|
||||||
|
NoOp,
|
||||||
|
|
||||||
Literal(Value),
|
Literal(Value),
|
||||||
Ident(Rc<str>),
|
Ident(Rc<str>),
|
||||||
|
|
||||||
|
@ -52,34 +54,24 @@ pub enum Expr {
|
||||||
|
|
||||||
And(Box<Expr>, Box<Expr>),
|
And(Box<Expr>, Box<Expr>),
|
||||||
Or(Box<Expr>, Box<Expr>),
|
Or(Box<Expr>, Box<Expr>),
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
Assign(Box<Expr>, Box<Expr>),
|
||||||
pub enum Assign {
|
|
||||||
Expr(Expr),
|
|
||||||
Assign(Expr, Box<Assign>)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
If(Box<Expr>, Box<Expr>, Option<Box<Expr>>),
|
||||||
pub enum Stmt {
|
Function(Rc<str>, Vec<Rc<str>>, Box<Expr>),
|
||||||
NoOp,
|
|
||||||
|
|
||||||
If(Expr, Box<Stmt>, Option<Box<Stmt>>),
|
|
||||||
Function(Rc<str>, Vec<Rc<str>>, Box<Stmt>),
|
|
||||||
|
|
||||||
Loop(Box<Stmt>),
|
Loop(Box<Expr>),
|
||||||
While(Expr, Box<Stmt>),
|
While(Box<Expr>, Box<Expr>),
|
||||||
DoWhile(Expr, Box<Stmt>),
|
DoWhile(Box<Expr>, Box<Expr>),
|
||||||
|
|
||||||
Block(Vec<Stmt>),
|
Block(Vec<Expr>),
|
||||||
Expr(Expr),
|
|
||||||
|
|
||||||
Let(Rc<str>, Expr),
|
Let(Rc<str>, Box<Expr>),
|
||||||
Assign(Assign),
|
|
||||||
|
|
||||||
Continue,
|
Continue,
|
||||||
Break,
|
Break,
|
||||||
Return(Expr),
|
Return(Box<Expr>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Neg for BinaryOp {
|
impl Neg for BinaryOp {
|
||||||
|
@ -156,181 +148,156 @@ impl Not for Expr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn optimize_expr(expr: Expr) -> Result<Expr> {
|
pub fn optimize(expr: Expr) -> Result<Expr> {
|
||||||
use Expr::*;
|
use Expr as E;
|
||||||
Ok(match expr {
|
Ok(match expr {
|
||||||
UnaryOp(expr, op) => {
|
E::UnaryOp(expr, op) => {
|
||||||
let expr = optimize_expr(*expr)?;
|
let expr = optimize(*expr)?;
|
||||||
match match op {
|
match match op {
|
||||||
self::UnaryOp::Negate => -expr,
|
UnaryOp::Negate => -expr,
|
||||||
self::UnaryOp::Not => !expr,
|
UnaryOp::Not => !expr,
|
||||||
} {
|
} {
|
||||||
Ok(expr) => expr,
|
Ok(expr) => expr,
|
||||||
Err(expr) => UnaryOp(Box::new(expr), op)
|
Err(expr) => E::UnaryOp(Box::new(expr), op)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
BinaryOp(lhs, rhs, op) => {
|
E::BinaryOp(lhs, rhs, op) => {
|
||||||
let lhs = optimize_expr(*lhs)?;
|
let lhs = optimize(*lhs)?;
|
||||||
let rhs = optimize_expr(*rhs)?;
|
let rhs = optimize(*rhs)?;
|
||||||
if let (Literal(l), Literal(r)) = (lhs.clone(), rhs.clone()) {
|
if let (E::Literal(l), E::Literal(r)) = (lhs.clone(), rhs.clone()) {
|
||||||
match Value::binary_op(op, l, r) {
|
match Value::binary_op(op, l, r) {
|
||||||
Err(err) => return Err(err),
|
Err(err) => return Err(err),
|
||||||
Ok(value) => return Ok(Expr::Literal(value)),
|
Ok(value) => return Ok(Expr::Literal(value)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BinaryOp(Box::new(lhs), Box::new(rhs), op)
|
E::BinaryOp(Box::new(lhs), Box::new(rhs), op)
|
||||||
},
|
},
|
||||||
FnCall(ident, values) => {
|
E::FnCall(ident, values) => {
|
||||||
FnCall(ident, values
|
E::FnCall(ident, values
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(optimize_expr)
|
.map(optimize)
|
||||||
.collect::<Result<Vec<Expr>>>()?)
|
.collect::<Result<Vec<Expr>>>()?)
|
||||||
}
|
}
|
||||||
FieldAccess(key, val) => {
|
E::FieldAccess(key, val) => {
|
||||||
let key = optimize_expr(*key)?;
|
let key = optimize(*key)?;
|
||||||
let val = optimize_expr(*val)?;
|
let val = optimize(*val)?;
|
||||||
FieldAccess(Box::new(key), Box::new(val))
|
E::FieldAccess(Box::new(key), Box::new(val))
|
||||||
},
|
},
|
||||||
List(list) =>
|
E::List(list) =>
|
||||||
List(list.into_iter()
|
E::List(list.into_iter()
|
||||||
.map(optimize_expr)
|
.map(optimize)
|
||||||
.collect::<Result<Vec<Expr>>>()?),
|
.collect::<Result<Vec<Expr>>>()?),
|
||||||
Matrix(mat) =>
|
E::Matrix(mat) =>
|
||||||
Matrix((mat.0, mat.1,
|
E::Matrix((mat.0, mat.1,
|
||||||
mat.2.into_iter().map(optimize_expr)
|
mat.2.into_iter().map(optimize)
|
||||||
.collect::<Result<Vec<Expr>>>()?)),
|
.collect::<Result<Vec<Expr>>>()?)),
|
||||||
Table(table) =>
|
E::Table(table) =>
|
||||||
Table(table
|
E::Table(table
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(k, v)| {
|
.map(|(k, v)| {
|
||||||
let k = optimize_expr(k)?;
|
let k = optimize(k)?;
|
||||||
let v = optimize_expr(v)?;
|
let v = optimize(v)?;
|
||||||
Ok((k, v))
|
Ok((k, v))
|
||||||
}).collect::<Result<Vec<(Expr, Expr)>>>()?),
|
}).collect::<Result<Vec<(Expr, Expr)>>>()?),
|
||||||
And(lhs, rhs) => {
|
E::And(lhs, rhs) => {
|
||||||
let lhs = optimize_expr(*lhs)?;
|
let lhs = optimize(*lhs)?;
|
||||||
let rhs = optimize_expr(*rhs)?;
|
let rhs = optimize(*rhs)?;
|
||||||
if let (Literal(l), r) = (lhs.clone(), rhs.clone()) {
|
if let (E::Literal(l), r) = (lhs.clone(), rhs.clone()) {
|
||||||
match !!l.clone() {
|
match !!l.clone() {
|
||||||
true => r,
|
true => r,
|
||||||
false => Literal(l),
|
false => E::Literal(l),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
And(Box::new(lhs), Box::new(rhs))
|
E::And(Box::new(lhs), Box::new(rhs))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Or(lhs, rhs) => {
|
E::Or(lhs, rhs) => {
|
||||||
let lhs = optimize_expr(*lhs)?;
|
let lhs = optimize(*lhs)?;
|
||||||
let rhs = optimize_expr(*rhs)?;
|
let rhs = optimize(*rhs)?;
|
||||||
if let (Literal(l), r) = (lhs.clone(), rhs.clone()) {
|
if let (E::Literal(l), r) = (lhs.clone(), rhs.clone()) {
|
||||||
match !l.clone() {
|
match !l.clone() {
|
||||||
true => r,
|
true => r,
|
||||||
false => Literal(l),
|
false => E::Literal(l),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
And(Box::new(lhs), Box::new(rhs))
|
E::And(Box::new(lhs), Box::new(rhs))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => expr
|
E::Block(b) => {
|
||||||
})
|
let len = b.len();
|
||||||
}
|
let b: Vec<Expr> =
|
||||||
|
|
||||||
fn optimize_assign(assign: Assign) -> Result<Assign> {
|
|
||||||
use self::Assign::*;
|
|
||||||
Ok(match assign {
|
|
||||||
Expr(expr) => {
|
|
||||||
let expr = optimize_expr(expr)?;
|
|
||||||
Expr(expr)
|
|
||||||
},
|
|
||||||
Assign(expr, assign) => {
|
|
||||||
let expr = optimize_expr(expr)?;
|
|
||||||
let assign = optimize_assign(*assign)?;
|
|
||||||
Assign(expr, Box::new(assign))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn optimize(stmt: Stmt) -> Result<Stmt> {
|
|
||||||
use Stmt::*;
|
|
||||||
Ok(match stmt {
|
|
||||||
Block(b) => {
|
|
||||||
let b: Vec<Stmt> =
|
|
||||||
b.into_iter()
|
b.into_iter()
|
||||||
.map(optimize)
|
.map(optimize)
|
||||||
.collect::<Result<Vec<Stmt>>>()?
|
.collect::<Result<Vec<Expr>>>()?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|e| NoOp != *e)
|
.enumerate()
|
||||||
|
.filter(|(i, e)| {
|
||||||
|
if let E::Literal(_) = e {
|
||||||
|
return i + 1 == len
|
||||||
|
}
|
||||||
|
E::NoOp != *e
|
||||||
|
})
|
||||||
|
.map(|e| e.1)
|
||||||
.collect();
|
.collect();
|
||||||
if b.is_empty() {
|
if b.is_empty() {
|
||||||
NoOp
|
E::NoOp
|
||||||
} else {
|
} else {
|
||||||
Block(b)
|
E::Block(b)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
If(cond, block, else_block) => {
|
E::If(cond, block, else_block) => {
|
||||||
let cond = optimize_expr(cond)?;
|
let cond = optimize(*cond)?;
|
||||||
let block = optimize(*block)?;
|
let block = optimize(*block)?;
|
||||||
let else_block = else_block.map(|e| optimize(*e)).transpose()?;
|
let else_block = else_block.map(|e| optimize(*e)).transpose()?;
|
||||||
if let self::Expr::Literal(lit) = cond {
|
if let E::Literal(lit) = cond {
|
||||||
if !!lit {
|
if !!lit {
|
||||||
return Ok(block)
|
return Ok(block)
|
||||||
}
|
}
|
||||||
return Ok(else_block.unwrap_or(NoOp))
|
return Ok(else_block.unwrap_or(E::NoOp))
|
||||||
}
|
}
|
||||||
If(cond, Box::new(block), else_block.map(|e| Box::new(e)))
|
E::If(Box::new(cond), Box::new(block), else_block.map(|e| Box::new(e)))
|
||||||
},
|
},
|
||||||
While(cond, block) => {
|
E::While(cond, block) => {
|
||||||
let cond = optimize_expr(cond)?;
|
let cond = optimize(*cond)?;
|
||||||
let block = optimize(*block)?;
|
let block = optimize(*block)?;
|
||||||
if let self::Expr::Literal(lit) = cond {
|
if let E::Literal(lit) = cond {
|
||||||
if !!lit {
|
if !!lit {
|
||||||
return Ok(Loop(Box::new(block)))
|
return Ok(E::Loop(Box::new(block)))
|
||||||
}
|
}
|
||||||
return Ok(NoOp)
|
return Ok(E::NoOp)
|
||||||
}
|
}
|
||||||
While(cond, Box::new(block))
|
E::While(Box::new(cond), Box::new(block))
|
||||||
},
|
},
|
||||||
DoWhile(cond, block) => {
|
E::DoWhile(block, cond) => {
|
||||||
let cond = optimize_expr(cond)?;
|
let cond = optimize(*cond)?;
|
||||||
let block = optimize(*block)?;
|
let block = optimize(*block)?;
|
||||||
if let self::Expr::Literal(lit) = cond.clone() {
|
if let E::Literal(lit) = cond.clone() {
|
||||||
if !!lit {
|
if !!lit {
|
||||||
return Ok(Loop(Box::new(block)))
|
return Ok(E::Loop(Box::new(block)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DoWhile(cond, Box::new(block))
|
E::DoWhile(Box::new(block), Box::new(cond))
|
||||||
}
|
}
|
||||||
Loop(block) => {
|
E::Loop(block) => {
|
||||||
let block = optimize(*block)?;
|
let block = Box::new(optimize(*block)?);
|
||||||
Loop(Box::new(block))
|
E::Loop(block)
|
||||||
},
|
},
|
||||||
Function(ident, params, stmt) => {
|
E::Function(ident, params, stmt) => {
|
||||||
let stmt = optimize(*stmt)?;
|
let stmt = Box::new(optimize(*stmt)?);
|
||||||
Function(ident, params, Box::new(stmt))
|
E::Function(ident, params, stmt)
|
||||||
}
|
}
|
||||||
Expr(expr) => {
|
E::Let(ident, expr) => {
|
||||||
Expr(optimize_expr(expr)?)
|
E::Let(ident, Box::new(optimize(*expr)?))
|
||||||
},
|
},
|
||||||
Let(ident, expr) => {
|
E::Assign(lhs, rhs) => {
|
||||||
Let(ident, optimize_expr(expr)?)
|
let lhs = Box::new(optimize(*lhs)?);
|
||||||
}
|
let rhs = Box::new(optimize(*rhs)?);
|
||||||
Assign(assign) => {
|
E::Assign(lhs, rhs)
|
||||||
use self::Assign as A;
|
},
|
||||||
match assign {
|
E::Return(expr) => {
|
||||||
A::Expr(expr) => {
|
E::Return(Box::new(optimize(*expr)?))
|
||||||
let expr = optimize_expr(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
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{value::Value, ast::{UnaryOp, BinaryOp}, Result};
|
use crate::{value::Value, ast::{UnaryOp, BinaryOp}};
|
||||||
use std::{fmt::{Debug, Display}, rc::Rc};
|
use std::{fmt::{Debug, Display}, rc::Rc};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -14,10 +14,6 @@ impl Chunk {
|
||||||
code: Vec::new()
|
code: Vec::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_compiled(_buf: &[u8]) -> Result<Self> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Chunk {
|
impl Debug for Chunk {
|
||||||
|
@ -52,8 +48,11 @@ pub struct Function {
|
||||||
pub enum Instruction {
|
pub enum Instruction {
|
||||||
NoOp,
|
NoOp,
|
||||||
|
|
||||||
Load(u16),
|
CreateLocal,
|
||||||
Store(u16),
|
LoadLocal(u16),
|
||||||
|
StoreLocal(u16),
|
||||||
|
DiscardLocals(u16),
|
||||||
|
|
||||||
LoadGlobal(u16),
|
LoadGlobal(u16),
|
||||||
StoreGlobal(u16),
|
StoreGlobal(u16),
|
||||||
|
|
||||||
|
@ -88,8 +87,10 @@ impl Display for Instruction {
|
||||||
use Instruction::*;
|
use Instruction::*;
|
||||||
match self {
|
match self {
|
||||||
NoOp => write!(f, "noop"),
|
NoOp => write!(f, "noop"),
|
||||||
Load(idx) => write!(f, "load \x1b[33m{idx}\x1b[0m"),
|
CreateLocal => write!(f, "create local"),
|
||||||
Store(idx) => write!(f, "store \x1b[33m{idx}\x1b[0m"),
|
LoadLocal(idx) => write!(f, "load local \x1b[33m{idx}\x1b[0m"),
|
||||||
|
StoreLocal(idx) => write!(f, "store local \x1b[33m{idx}\x1b[0m"),
|
||||||
|
DiscardLocals(count) => write!(f, "discard locals \x1b[35m{count}\x1b[0m"),
|
||||||
LoadGlobal(name) => write!(f, "load global \x1b[36m{name}\x1b[0m"),
|
LoadGlobal(name) => write!(f, "load global \x1b[36m{name}\x1b[0m"),
|
||||||
StoreGlobal(name) => write!(f, "store global \x1b[36m{name}\x1b[0m"),
|
StoreGlobal(name) => write!(f, "store global \x1b[36m{name}\x1b[0m"),
|
||||||
Const(idx) => write!(f, "const \x1b[33m{idx}\x1b[0m"),
|
Const(idx) => write!(f, "const \x1b[33m{idx}\x1b[0m"),
|
||||||
|
@ -98,7 +99,7 @@ impl Display for Instruction {
|
||||||
False => write!(f, "push \x1b[34mfalse\x1b[0m"),
|
False => write!(f, "push \x1b[34mfalse\x1b[0m"),
|
||||||
Nil => write!(f, "push \x1b[34mnil\x1b[0m"),
|
Nil => write!(f, "push \x1b[34mnil\x1b[0m"),
|
||||||
Dup => write!(f, "duplicate"),
|
Dup => write!(f, "duplicate"),
|
||||||
Discard(count) => write!(f, "discard \x1b[33m{count}\x1b[0m"),
|
Discard(count) => write!(f, "discard \x1b[35m{count}\x1b[0m"),
|
||||||
UnaryOp(op) => write!(f, "unary \x1b[32m{op:?}\x1b[0m"),
|
UnaryOp(op) => write!(f, "unary \x1b[32m{op:?}\x1b[0m"),
|
||||||
BinaryOp(op) => write!(f, "binary \x1b[32m{op:?}\x1b[0m"),
|
BinaryOp(op) => write!(f, "binary \x1b[32m{op:?}\x1b[0m"),
|
||||||
NewList(len) => write!(f, "list \x1b[35m{len}\x1b[0m"),
|
NewList(len) => write!(f, "list \x1b[35m{len}\x1b[0m"),
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
use std::{fmt::Display, rc::Rc, cell::RefCell};
|
use std::{fmt::Display, rc::Rc, cell::RefCell};
|
||||||
use crate::{ast::{Stmt, Expr, Assign}, chunk::{Function, Instruction}, chunk::{Chunk, self}, value::Value, Result};
|
use crate::{ast::Expr, chunk::{Function, Instruction}, chunk::{Chunk, self}, value::Value, Result};
|
||||||
|
|
||||||
pub type Globals = Rc<RefCell<Vec<Rc<str>>>>;
|
use Instruction as I;
|
||||||
|
use Value as V;
|
||||||
|
use Expr as E;
|
||||||
|
|
||||||
pub struct CompilerBuilder<'c> {
|
pub struct CompilerBuilder<'c> {
|
||||||
globals: Globals,
|
globals: Rc<RefCell<Vec<Rc<str>>>>,
|
||||||
repl: bool,
|
repl: bool,
|
||||||
debug: bool,
|
debug: bool,
|
||||||
name: Rc<str>,
|
name: Rc<str>,
|
||||||
|
@ -33,7 +35,7 @@ impl<'c> CompilerBuilder<'c> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn globals(mut self, globals: Globals) -> Self {
|
pub fn globals(mut self, globals: Rc<RefCell<Vec<Rc<str>>>>) -> Self {
|
||||||
self.globals = globals;
|
self.globals = globals;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -55,7 +57,7 @@ impl<'c> CompilerBuilder<'c> {
|
||||||
globals: self.globals,
|
globals: self.globals,
|
||||||
repl: self.repl,
|
repl: self.repl,
|
||||||
debug: self.debug,
|
debug: self.debug,
|
||||||
scope: 0,
|
scopes: Vec::new(),
|
||||||
locals: Vec::new(),
|
locals: Vec::new(),
|
||||||
chunk: Chunk::new(),
|
chunk: Chunk::new(),
|
||||||
loop_top: Vec::new(),
|
loop_top: Vec::new(),
|
||||||
|
@ -74,7 +76,7 @@ pub struct Compiler<'c> {
|
||||||
|
|
||||||
root_is_block: bool,
|
root_is_block: bool,
|
||||||
|
|
||||||
scope: usize,
|
scopes: Vec<usize>,
|
||||||
chunk: Chunk,
|
chunk: Chunk,
|
||||||
|
|
||||||
loop_top: Vec<(usize, usize)>,
|
loop_top: Vec<(usize, usize)>,
|
||||||
|
@ -94,8 +96,10 @@ struct Local {
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
Undefined(Rc<str>),
|
Undefined(Rc<str>),
|
||||||
Redefined(Rc<str>),
|
Redefined(Rc<str>),
|
||||||
|
InvAssign(Expr),
|
||||||
InvContinue,
|
InvContinue,
|
||||||
InvBreak,
|
InvBreak,
|
||||||
|
NotImplemented(&'static str),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::error::Error for self::Error {}
|
impl std::error::Error for self::Error {}
|
||||||
|
@ -106,8 +110,10 @@ impl Display for self::Error {
|
||||||
match self {
|
match self {
|
||||||
Undefined(name) => write!(f, "value {name} is undefined"),
|
Undefined(name) => write!(f, "value {name} is undefined"),
|
||||||
Redefined(name) => write!(f, "cannot redefine {name} in the same scope"),
|
Redefined(name) => write!(f, "cannot redefine {name} in the same scope"),
|
||||||
|
InvAssign(expr) => write!(f, "cannot assign to {expr:?}"),
|
||||||
InvContinue => write!(f, "cannot continue outside a loop"),
|
InvContinue => write!(f, "cannot continue outside a loop"),
|
||||||
InvBreak => write!(f, "cannot break outside a loop"),
|
InvBreak => write!(f, "cannot break outside a loop"),
|
||||||
|
NotImplemented(str) => write!(f, "{str} is not implemented yet")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -127,45 +133,34 @@ impl<'c> Compiler<'c> {
|
||||||
if self.root_is_block {
|
if self.root_is_block {
|
||||||
self.root_is_block = false;
|
self.root_is_block = false;
|
||||||
} else {
|
} else {
|
||||||
self.scope += 1;
|
self.scopes.push(self.locals.len())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_scope_start(&self, scope: usize) -> usize {
|
fn collapse_scopes(&mut self, top_scope: usize) {
|
||||||
let mut stack_cutoff = None;
|
let mut cutoff = usize::MAX;
|
||||||
for (i, local) in self.locals.iter().enumerate() {
|
while self.scopes.len() > top_scope {
|
||||||
if local.scope == scope {
|
cutoff = self.scopes.pop().unwrap()
|
||||||
stack_cutoff = Some(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if let Some(cutoff) = stack_cutoff {
|
if cutoff < self.locals.len() {
|
||||||
cutoff
|
self.emit(Instruction::DiscardLocals((self.locals.len() - cutoff) as u16));
|
||||||
} else {
|
self.locals.truncate(cutoff);
|
||||||
self.locals.len()
|
};
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_scope_diff(&self, scope: usize) -> usize {
|
|
||||||
let cutoff = self.get_scope_start(scope);
|
|
||||||
self.locals.len() - cutoff
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn end_scope(&mut self) {
|
fn end_scope(&mut self) {
|
||||||
let cutoff = self.get_scope_start(self.scope);
|
let Some(cutoff) = self.scopes.pop() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
if cutoff < self.locals.len() {
|
if cutoff < self.locals.len() {
|
||||||
self.emit(Instruction::Discard((self.locals.len() - cutoff) as u16));
|
self.emit(Instruction::DiscardLocals((self.locals.len() - cutoff) as u16));
|
||||||
self.locals.truncate(cutoff);
|
self.locals.truncate(cutoff);
|
||||||
};
|
};
|
||||||
if self.scope != 0 {
|
|
||||||
self.scope -= 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_local(&mut self, name: Rc<str>) -> Rc<Local> {
|
fn create_local(&mut self, name: Rc<str>) {
|
||||||
let local = Local { name, idx: self.locals.len(), scope: self.scope };
|
let local = Local { name, idx: self.locals.len(), scope: self.scopes.len()};
|
||||||
self.locals.push(Rc::new(local));
|
self.locals.push(Rc::new(local));
|
||||||
self.locals[self.locals.len() - 1].clone()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_global(&mut self, name: Rc<str>) -> usize {
|
fn create_global(&mut self, name: Rc<str>) -> usize {
|
||||||
|
@ -174,13 +169,14 @@ impl<'c> Compiler<'c> {
|
||||||
c
|
c
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_local_checked(&mut self, name: Rc<str>) -> Result<Rc<Local>> {
|
fn create_local_checked(&mut self, name: Rc<str>) -> Result<()> {
|
||||||
if let Some(local) = self.find_local(&name) {
|
if let Some(local) = self.find_local(&name) {
|
||||||
if local.scope == self.scope {
|
if local.scope == self.scopes.len() {
|
||||||
return Err(Error::Redefined(name).into())
|
return Err(Error::Redefined(name).into())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(self.create_local(name))
|
self.create_local(name);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_global_checked(&mut self, name: Rc<str>) -> Result<usize> {
|
fn create_global_checked(&mut self, name: Rc<str>) -> Result<usize> {
|
||||||
|
@ -219,16 +215,14 @@ impl<'c> Compiler<'c> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn can_make_globals(&self) -> bool {
|
fn can_make_globals(&self) -> bool {
|
||||||
self.repl && self.parent.is_none() && self.scope == 0
|
self.repl && self.parent.is_none() && self.scopes.len() == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_value(&mut self, val: &Value) {
|
fn compile_value(&mut self, val: &Value) {
|
||||||
use Value::*;
|
|
||||||
use Instruction as I;
|
|
||||||
match val {
|
match val {
|
||||||
Nil => self.emit(I::Nil),
|
V::Nil => self.emit(I::Nil),
|
||||||
Bool(b) => if *b { self.emit(I::True) } else { self.emit(I::False) },
|
V::Bool(b) => if *b { self.emit(I::True) } else { self.emit(I::False) },
|
||||||
Int(i) => {
|
V::Int(i) => {
|
||||||
if let Ok(i) = i16::try_from(*i) {
|
if let Ok(i) = i16::try_from(*i) {
|
||||||
self.emit(I::Int(i));
|
self.emit(I::Int(i));
|
||||||
} else {
|
} else {
|
||||||
|
@ -241,65 +235,194 @@ impl<'c> Compiler<'c> {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
fn finish_loop(&mut self) {
|
||||||
|
self.loop_top.pop();
|
||||||
|
while let Some(tmp) = self.loop_bot.pop() {
|
||||||
|
self.re_emit(I::Jump(self.cur()), tmp as usize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn compile_expr(&mut self, expr: &Expr) -> Result<()> {
|
fn compile_expr(&mut self, expr: &Expr) -> Result<()> {
|
||||||
use Expr::*;
|
|
||||||
use Instruction as I;
|
|
||||||
match expr {
|
match expr {
|
||||||
Literal(val) => self.compile_value(val),
|
E::NoOp => {},
|
||||||
Ident(name) => {
|
E::If(cond, ifb, elseb) => {
|
||||||
|
self.compile_expr(cond)?;
|
||||||
|
let jmpidx = self.emit_temp();
|
||||||
|
self.compile_expr(ifb)?;
|
||||||
|
self.re_emit(I::JumpFalse(self.cur()), jmpidx);
|
||||||
|
if let Some(elseb) = elseb {
|
||||||
|
self.compile_expr(elseb)?;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
E::Function(name, params, body) => {
|
||||||
|
let chunk = self.compile_function(name.clone(), params, body)?;
|
||||||
|
let fun = Value::Function(Rc::new(
|
||||||
|
chunk::Function {
|
||||||
|
name: name.clone(),
|
||||||
|
arity: params.len(),
|
||||||
|
body: chunk
|
||||||
|
}
|
||||||
|
));
|
||||||
|
self.emit_const(fun);
|
||||||
|
self.emit(I::Dup);
|
||||||
|
if self.can_make_globals() {
|
||||||
|
let idx = self.create_global_checked(name.clone())?;
|
||||||
|
self.emit(I::StoreGlobal(idx as u16));
|
||||||
|
} else {
|
||||||
|
self.create_local_checked(name.clone())?;
|
||||||
|
self.emit(I::CreateLocal);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
E::Loop(expr) => {
|
||||||
|
let idx = self.cur();
|
||||||
|
self.loop_top.push((idx as usize, self.scopes.len()));
|
||||||
|
self.compile_expr(expr)?;
|
||||||
|
self.emit(I::Discard(1));
|
||||||
|
self.emit(I::Jump(idx));
|
||||||
|
self.finish_loop();
|
||||||
|
self.emit(I::Nil);
|
||||||
|
},
|
||||||
|
E::While(cond, expr) => {
|
||||||
|
let top = self.cur();
|
||||||
|
self.compile_expr(cond)?;
|
||||||
|
let jmpidx = self.emit_temp();
|
||||||
|
self.loop_top.push((top as usize, self.scopes.len()));
|
||||||
|
self.compile_expr(expr)?;
|
||||||
|
self.emit(I::Discard(1));
|
||||||
|
self.emit(I::Jump(top));
|
||||||
|
self.re_emit(I::JumpFalse(self.cur()), jmpidx);
|
||||||
|
self.finish_loop();
|
||||||
|
self.emit(I::Nil);
|
||||||
|
},
|
||||||
|
E::DoWhile(expr, cond) => {
|
||||||
|
let top = self.cur();
|
||||||
|
self.loop_top.push((top as usize, self.scopes.len()));
|
||||||
|
self.compile_expr(expr)?;
|
||||||
|
self.emit(I::Discard(1));
|
||||||
|
self.compile_expr(cond)?;
|
||||||
|
self.emit(I::JumpTrue(top));
|
||||||
|
self.finish_loop();
|
||||||
|
self.emit(I::Nil);
|
||||||
|
},
|
||||||
|
E::Block(block) => {
|
||||||
|
self.begin_scope();
|
||||||
|
for (i, expr) in block.iter().enumerate() {
|
||||||
|
self.compile_expr(expr)?;
|
||||||
|
if i + 1 != block.len() {
|
||||||
|
self.emit(I::Discard(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.end_scope();
|
||||||
|
},
|
||||||
|
E::Let(name, expr) => {
|
||||||
|
self.compile_expr(expr)?;
|
||||||
|
self.emit(I::Dup);
|
||||||
|
if self.can_make_globals() {
|
||||||
|
let global = self.create_global_checked(name.clone())?;
|
||||||
|
self.emit(I::StoreGlobal(global as u16));
|
||||||
|
} else {
|
||||||
|
self.create_local_checked(name.clone())?;
|
||||||
|
self.emit(I::CreateLocal);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
E::Continue => {
|
||||||
|
let top = self.loop_top.pop();
|
||||||
|
if let Some((top, scope)) = top {
|
||||||
|
self.collapse_scopes(scope);
|
||||||
|
self.emit(I::Jump(top as u16));
|
||||||
|
} else {
|
||||||
|
return Err(Error::InvContinue.into())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
E::Break => {
|
||||||
|
let top = self.loop_top.pop();
|
||||||
|
if let Some((_, scope)) = top {
|
||||||
|
self.collapse_scopes(scope);
|
||||||
|
let tmpidx = self.emit_temp();
|
||||||
|
self.loop_bot.push(tmpidx);
|
||||||
|
} else {
|
||||||
|
return Err(Error::InvBreak.into())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
E::Return(expr) => {
|
||||||
|
self.compile_expr(expr)?;
|
||||||
|
self.emit(I::Return);
|
||||||
|
},
|
||||||
|
E::Literal(val) => self.compile_value(val),
|
||||||
|
E::Ident(name) => {
|
||||||
if let Some(local) = self.find_local(name) {
|
if let Some(local) = self.find_local(name) {
|
||||||
self.emit(I::Load(local.idx as u16));
|
self.emit(I::LoadLocal(local.idx as u16));
|
||||||
} else if let Some(global) = self.find_global(name) {
|
} else if let Some(global) = self.find_global(name) {
|
||||||
self.emit(I::LoadGlobal(global as u16));
|
self.emit(I::LoadGlobal(global as u16));
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::Undefined(name.clone()).into())
|
return Err(self::Error::Undefined(name.clone()).into())
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
UnaryOp(expr, op) => {
|
E::Assign(lhs, rhs) => {
|
||||||
|
self.compile_expr(rhs)?;
|
||||||
|
self.emit(I::Dup);
|
||||||
|
match lhs.as_ref() {
|
||||||
|
E::Ident(name) => {
|
||||||
|
if let Some(local) = self.find_local(&name) {
|
||||||
|
self.emit(I::StoreLocal(local.idx as u16));
|
||||||
|
} else if let Some(global) = self.find_global(&name) {
|
||||||
|
self.emit(I::StoreGlobal(global as u16));
|
||||||
|
} else if self.can_make_globals() {
|
||||||
|
let global = self.create_global_checked(name.clone())?;
|
||||||
|
self.emit(I::StoreGlobal(global as u16));
|
||||||
|
} else {
|
||||||
|
self.create_local_checked(name.clone())?;
|
||||||
|
self.emit(I::CreateLocal);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => return Err(self::Error::InvAssign(*lhs.clone()).into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
E::UnaryOp(expr, op) => {
|
||||||
self.compile_expr(expr)?;
|
self.compile_expr(expr)?;
|
||||||
self.emit(I::UnaryOp(*op));
|
self.emit(I::UnaryOp(*op));
|
||||||
},
|
},
|
||||||
BinaryOp(lhs, rhs, op) => {
|
E::BinaryOp(lhs, rhs, op) => {
|
||||||
self.compile_expr(lhs)?;
|
self.compile_expr(lhs)?;
|
||||||
self.compile_expr(rhs)?;
|
self.compile_expr(rhs)?;
|
||||||
self.emit(I::BinaryOp(*op));
|
self.emit(I::BinaryOp(*op));
|
||||||
},
|
},
|
||||||
Index(_, _) => todo!("index"),
|
E::Index(_, _) => return Err(self::Error::NotImplemented("indexing").into()),
|
||||||
FnCall(fun, params) => {
|
E::FnCall(fun, params) => {
|
||||||
for expr in params {
|
for expr in params {
|
||||||
self.compile_expr(expr)?;
|
self.compile_expr(expr)?;
|
||||||
}
|
}
|
||||||
self.compile_expr(fun)?;
|
self.compile_expr(fun)?;
|
||||||
self.emit(I::Call(params.len() as u8));
|
self.emit(I::Call(params.len() as u8));
|
||||||
},
|
},
|
||||||
FieldAccess(_, _) => todo!("field access"),
|
E::FieldAccess(_, _) => return Err(self::Error::NotImplemented("filed access").into()),
|
||||||
List(list) => {
|
E::List(list) => {
|
||||||
for expr in list {
|
for expr in list {
|
||||||
self.compile_expr(expr)?;
|
self.compile_expr(expr)?;
|
||||||
}
|
}
|
||||||
self.emit(I::NewList(list.len() as u16));
|
self.emit(I::NewList(list.len() as u16));
|
||||||
},
|
},
|
||||||
Matrix(mat) => {
|
E::Matrix(mat) => {
|
||||||
for expr in &mat.2 {
|
for expr in &mat.2 {
|
||||||
self.compile_expr(expr)?;
|
self.compile_expr(expr)?;
|
||||||
}
|
}
|
||||||
self.emit(I::NewMatrix(mat.2.len() as u16, mat.1 as u8));
|
self.emit(I::NewMatrix(mat.2.len() as u16, mat.1 as u8));
|
||||||
},
|
},
|
||||||
Table(table) => {
|
E::Table(table) => {
|
||||||
for (key, value) in table {
|
for (key, value) in table {
|
||||||
self.compile_expr(key)?;
|
self.compile_expr(key)?;
|
||||||
self.compile_expr(value)?;
|
self.compile_expr(value)?;
|
||||||
}
|
}
|
||||||
self.emit(I::NewTable(table.len() as u16));
|
self.emit(I::NewTable(table.len() as u16));
|
||||||
},
|
},
|
||||||
And(lhs, rhs) => {
|
E::And(lhs, rhs) => {
|
||||||
self.compile_expr(lhs)?;
|
self.compile_expr(lhs)?;
|
||||||
self.emit(I::Dup);
|
self.emit(I::Dup);
|
||||||
let jmpidx = self.emit_temp();
|
let jmpidx = self.emit_temp();
|
||||||
self.compile_expr(rhs)?;
|
self.compile_expr(rhs)?;
|
||||||
self.re_emit(I::JumpFalse(self.cur()), jmpidx);
|
self.re_emit(I::JumpFalse(self.cur()), jmpidx);
|
||||||
},
|
},
|
||||||
Or(lhs, rhs) => {
|
E::Or(lhs, rhs) => {
|
||||||
self.compile_expr(lhs)?;
|
self.compile_expr(lhs)?;
|
||||||
self.emit(I::Dup);
|
self.emit(I::Dup);
|
||||||
let jmpidx = self.emit_temp();
|
let jmpidx = self.emit_temp();
|
||||||
|
@ -310,164 +433,13 @@ impl<'c> Compiler<'c> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish_loop(&mut self) {
|
fn compile_function(&mut self, name: Rc<str>, params: &Vec<Rc<str>>, body: &Box<Expr>) -> Result<Chunk> {
|
||||||
use Instruction as I;
|
|
||||||
self.loop_top.pop();
|
|
||||||
while let Some(tmp) = self.loop_bot.pop() {
|
|
||||||
self.re_emit(I::Jump(self.cur()), tmp as usize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compile_assign(&mut self, assign: &Assign) -> Result<()> {
|
|
||||||
use Assign as A;
|
|
||||||
use Expr as E;
|
|
||||||
use Instruction as I;
|
|
||||||
match assign {
|
|
||||||
A::Expr(expr) => self.compile_expr(expr)?,
|
|
||||||
A::Assign(lhs, rhs) => {
|
|
||||||
self.compile_assign(rhs)?;
|
|
||||||
match lhs {
|
|
||||||
E::Ident(name) => {
|
|
||||||
if let Some(global) = self.find_global(&name) {
|
|
||||||
self.emit(I::Dup);
|
|
||||||
self.emit(I::StoreGlobal(global as u16));
|
|
||||||
} else if let Some(local) = self.find_local(&name) {
|
|
||||||
self.emit(I::Dup);
|
|
||||||
self.emit(I::Store(local.idx as u16));
|
|
||||||
} else if self.can_make_globals() {
|
|
||||||
let global = self.create_global(name.clone());
|
|
||||||
self.emit(I::Dup);
|
|
||||||
self.emit(I::StoreGlobal(global as u16));
|
|
||||||
} else {
|
|
||||||
self.create_local(name.clone());
|
|
||||||
self.emit(I::Dup);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
E::Index(_, _) => todo!("index"),
|
|
||||||
E::FieldAccess(_, _) => todo!("field access"),
|
|
||||||
_ => panic!("this should be handeled by the parser!!!")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compile_stmt(&mut self, stmt: &Stmt) -> Result<()> {
|
|
||||||
use Stmt::*;
|
|
||||||
use Instruction as I;
|
|
||||||
match stmt {
|
|
||||||
NoOp => {},
|
|
||||||
If(cond, ifb, elseb) => {
|
|
||||||
self.compile_expr(cond)?;
|
|
||||||
let jmpidx = self.emit_temp();
|
|
||||||
self.compile_stmt(ifb)?;
|
|
||||||
self.re_emit(I::JumpFalse(self.cur()), jmpidx);
|
|
||||||
if let Some(elseb) = elseb {
|
|
||||||
self.compile_stmt(elseb)?;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Function(name, params, body) => {
|
|
||||||
let chunk = self.compile_function(name.clone(), params, body)?;
|
|
||||||
let fun = Value::Function(Rc::new(
|
|
||||||
chunk::Function {
|
|
||||||
name: name.clone(),
|
|
||||||
arity: params.len(),
|
|
||||||
body: chunk
|
|
||||||
}
|
|
||||||
));
|
|
||||||
self.emit_const(fun);
|
|
||||||
if self.can_make_globals() {
|
|
||||||
let idx = self.create_global_checked(name.clone())?;
|
|
||||||
self.emit(I::StoreGlobal(idx as u16));
|
|
||||||
} else {
|
|
||||||
self.create_local_checked(name.clone())?;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Loop(stmt) => {
|
|
||||||
let idx = self.cur();
|
|
||||||
self.loop_top.push((idx as usize, self.scope));
|
|
||||||
self.compile_stmt(stmt)?;
|
|
||||||
self.emit(I::Jump(idx));
|
|
||||||
self.finish_loop();
|
|
||||||
},
|
|
||||||
While(cond, stmt) => {
|
|
||||||
let top = self.cur();
|
|
||||||
self.compile_expr(cond)?;
|
|
||||||
let jmpidx = self.emit_temp();
|
|
||||||
self.loop_top.push((top as usize, self.scope));
|
|
||||||
self.compile_stmt(stmt)?;
|
|
||||||
self.emit(I::Jump(top));
|
|
||||||
self.re_emit(I::JumpFalse(self.cur()), jmpidx);
|
|
||||||
self.finish_loop();
|
|
||||||
},
|
|
||||||
DoWhile(cond, stmt) => {
|
|
||||||
let top = self.cur();
|
|
||||||
self.loop_top.push((top as usize, self.scope));
|
|
||||||
self.compile_stmt(stmt)?;
|
|
||||||
self.compile_expr(cond)?;
|
|
||||||
self.emit(I::JumpTrue(top));
|
|
||||||
self.finish_loop();
|
|
||||||
},
|
|
||||||
Block(block) => {
|
|
||||||
self.begin_scope();
|
|
||||||
for stmt in block {
|
|
||||||
self.compile_stmt(stmt)?;
|
|
||||||
}
|
|
||||||
self.end_scope();
|
|
||||||
},
|
|
||||||
Expr(expr) => {
|
|
||||||
self.compile_expr(expr)?;
|
|
||||||
self.emit(I::Discard(1));
|
|
||||||
},
|
|
||||||
Assign(assign) => {
|
|
||||||
self.compile_assign(assign)?;
|
|
||||||
self.emit(I::Discard(1));
|
|
||||||
}
|
|
||||||
Let(name, expr) => {
|
|
||||||
self.compile_expr(expr)?;
|
|
||||||
if self.can_make_globals() {
|
|
||||||
let global = self.create_global_checked(name.clone())?;
|
|
||||||
self.emit(I::StoreGlobal(global as u16));
|
|
||||||
} else {
|
|
||||||
self.create_local_checked(name.clone())?;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Continue => {
|
|
||||||
let top = self.loop_top.pop();
|
|
||||||
if let Some((top, scope)) = top {
|
|
||||||
let diff = self.get_scope_diff(scope) as u16;
|
|
||||||
if diff > 0 {
|
|
||||||
self.emit(I::Discard(diff));
|
|
||||||
}
|
|
||||||
self.emit(I::Jump(top as u16));
|
|
||||||
} else {
|
|
||||||
return Err(Error::InvContinue.into())
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Break => {
|
|
||||||
let top = self.loop_top.pop();
|
|
||||||
if let Some((_, scope)) = top {
|
|
||||||
self.emit(I::Discard(self.get_scope_diff(scope) as u16));
|
|
||||||
let tmpidx = self.emit_temp();
|
|
||||||
self.loop_bot.push(tmpidx);
|
|
||||||
} else {
|
|
||||||
return Err(Error::InvBreak.into())
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Return(expr) => {
|
|
||||||
self.compile_expr(expr)?;
|
|
||||||
self.emit(I::Return);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compile_function(&mut self, name: Rc<str>, params: &Vec<Rc<str>>, body: &Box<Stmt>) -> Result<Chunk> {
|
|
||||||
let mut compiler = self.child(name);
|
let mut compiler = self.child(name);
|
||||||
for name in params {
|
for name in params {
|
||||||
compiler.create_local(name.clone());
|
compiler.create_local(name.clone());
|
||||||
|
compiler.emit(I::CreateLocal);
|
||||||
}
|
}
|
||||||
compiler.compile_stmt(body)?;
|
compiler.compile_expr(body)?;
|
||||||
compiler.finish()?;
|
compiler.finish()?;
|
||||||
Ok(compiler.chunk)
|
Ok(compiler.chunk)
|
||||||
}
|
}
|
||||||
|
@ -493,7 +465,6 @@ impl<'c> Compiler<'c> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish(&mut self) -> Result<()> {
|
fn finish(&mut self) -> Result<()> {
|
||||||
use Instruction as I;
|
|
||||||
let ins = match self.chunk.code.last() {
|
let ins = match self.chunk.code.last() {
|
||||||
Some(ins) => ins.clone(),
|
Some(ins) => ins.clone(),
|
||||||
None => {
|
None => {
|
||||||
|
@ -506,16 +477,8 @@ impl<'c> Compiler<'c> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
match ins {
|
match ins {
|
||||||
I::Discard(amt) if self.repl => {
|
|
||||||
self.chunk.code.pop().unwrap();
|
|
||||||
if amt > 1 {
|
|
||||||
self.emit(I::Discard(amt - 1));
|
|
||||||
}
|
|
||||||
self.emit(I::Return);
|
|
||||||
}
|
|
||||||
I::Return => {},
|
I::Return => {},
|
||||||
_ => {
|
_ => {
|
||||||
self.emit(I::Nil);
|
|
||||||
self.emit(I::Return);
|
self.emit(I::Return);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -532,13 +495,13 @@ impl<'c> Compiler<'c> {
|
||||||
|
|
||||||
pub fn compile(
|
pub fn compile(
|
||||||
&mut self,
|
&mut self,
|
||||||
body: &Stmt,
|
body: &Expr,
|
||||||
) -> Result<Rc<Function>> {
|
) -> Result<Rc<Function>> {
|
||||||
if let Stmt::Block(_) = body {
|
if let Expr::Block(_) = body {
|
||||||
self.root_is_block = true;
|
self.root_is_block = true;
|
||||||
}
|
}
|
||||||
self.chunk = Chunk::new();
|
self.chunk = Chunk::new();
|
||||||
self.compile_stmt(body)?;
|
self.compile_expr(body)?;
|
||||||
self.finish()?;
|
self.finish()?;
|
||||||
let fun = Function { name: self.name.clone(), body: self.chunk.clone(), arity: 0 };
|
let fun = Function { name: self.name.clone(), body: self.chunk.clone(), arity: 0 };
|
||||||
Ok(Rc::new(fun))
|
Ok(Rc::new(fun))
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
use std::{fmt::Display, rc::Rc};
|
use std::{fmt::Display, rc::Rc};
|
||||||
use num_complex::Complex64;
|
use num_complex::Complex64;
|
||||||
|
|
||||||
use crate::{lex::{Lexer, self, Token}, ast::{Expr, BinaryOp, UnaryOp, Stmt, Assign, optimize, self}, gc::Gc, value::{Value, self}, Result};
|
use crate::{lex::{Lexer, self, Token}, ast::{Expr, BinaryOp, UnaryOp, optimize}, gc::Gc, value::{Value, self}, Result};
|
||||||
|
|
||||||
|
use Value as V;
|
||||||
|
use Expr as E;
|
||||||
|
use Token as T;
|
||||||
|
|
||||||
pub struct ParserBuilder {
|
pub struct ParserBuilder {
|
||||||
optimize: bool
|
optimize: bool
|
||||||
|
@ -73,7 +77,7 @@ macro_rules! expr_parser {
|
||||||
$pattern => {
|
$pattern => {
|
||||||
$parser.lexer.next_token_nl()?;
|
$parser.lexer.next_token_nl()?;
|
||||||
let temp = $parser.$fn()?;
|
let temp = $parser.$fn()?;
|
||||||
expr = Expr::BinaryOp(Box::new(expr), Box::new(temp), BinaryOp::from(tok))
|
expr = E::BinaryOp(Box::new(expr), Box::new(temp), BinaryOp::from(tok))
|
||||||
}
|
}
|
||||||
_ => break
|
_ => break
|
||||||
}
|
}
|
||||||
|
@ -89,7 +93,7 @@ macro_rules! expr_parser_reverse {
|
||||||
Ok(match tok {
|
Ok(match tok {
|
||||||
$pattern => {
|
$pattern => {
|
||||||
$parser.lexer.next_token_nl()?;
|
$parser.lexer.next_token_nl()?;
|
||||||
Expr::BinaryOp(Box::new(expr), Box::new($parser.$cur()?), BinaryOp::from(tok))
|
E::BinaryOp(Box::new(expr), Box::new($parser.$cur()?), BinaryOp::from(tok))
|
||||||
}
|
}
|
||||||
_ => expr
|
_ => expr
|
||||||
})
|
})
|
||||||
|
@ -117,11 +121,11 @@ impl Parser {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_fn_call(&mut self) -> Result<Vec<Expr>> {
|
fn parse_fn_call(&mut self) -> Result<Vec<Expr>> {
|
||||||
self.force_token(Token::LeftParen)?;
|
self.force_token(T::LeftParen)?;
|
||||||
let mut params = Vec::new();
|
let mut params = Vec::new();
|
||||||
loop {
|
loop {
|
||||||
let expr = match self.lexer.peek_token()? {
|
let expr = match self.lexer.peek_token()? {
|
||||||
Token::RightParen => {
|
T::RightParen => {
|
||||||
self.lexer.next_token()?;
|
self.lexer.next_token()?;
|
||||||
break
|
break
|
||||||
},
|
},
|
||||||
|
@ -130,8 +134,8 @@ impl Parser {
|
||||||
params.push(expr);
|
params.push(expr);
|
||||||
let next = self.lexer.next_token()?;
|
let next = self.lexer.next_token()?;
|
||||||
match next {
|
match next {
|
||||||
Token::Comma => continue,
|
T::Comma => continue,
|
||||||
Token::RightParen => break,
|
T::RightParen => break,
|
||||||
_ => return Err(Error::UnexpectedToken(next).into())
|
_ => return Err(Error::UnexpectedToken(next).into())
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -139,11 +143,11 @@ impl Parser {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_index(&mut self) -> Result<Vec<Expr>> {
|
fn parse_index(&mut self) -> Result<Vec<Expr>> {
|
||||||
self.force_token(Token::LeftBrack)?;
|
self.force_token(T::LeftBrack)?;
|
||||||
let mut indicies = Vec::new();
|
let mut indicies = Vec::new();
|
||||||
loop {
|
loop {
|
||||||
let expr = match self.lexer.peek_token()? {
|
let expr = match self.lexer.peek_token()? {
|
||||||
Token::RightBrack => {
|
T::RightBrack => {
|
||||||
self.lexer.next_token()?;
|
self.lexer.next_token()?;
|
||||||
break
|
break
|
||||||
},
|
},
|
||||||
|
@ -152,8 +156,8 @@ impl Parser {
|
||||||
indicies.push(expr);
|
indicies.push(expr);
|
||||||
let next = self.lexer.next_token()?;
|
let next = self.lexer.next_token()?;
|
||||||
match next {
|
match next {
|
||||||
Token::SemiColon => continue,
|
T::SemiColon => continue,
|
||||||
Token::RightBrack => break,
|
T::RightBrack => break,
|
||||||
_ => return Err(Error::UnexpectedToken(next).into())
|
_ => return Err(Error::UnexpectedToken(next).into())
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -164,13 +168,13 @@ impl Parser {
|
||||||
let mut part = Vec::new();
|
let mut part = Vec::new();
|
||||||
loop {
|
loop {
|
||||||
let expr = match self.lexer.peek_token()? {
|
let expr = match self.lexer.peek_token()? {
|
||||||
Token::SemiColon => break,
|
T::SemiColon => break,
|
||||||
Token::RightBrack => break,
|
T::RightBrack => break,
|
||||||
_ => self.parse_expr()?
|
_ => self.parse_expr()?
|
||||||
};
|
};
|
||||||
part.push(expr);
|
part.push(expr);
|
||||||
match self.lexer.peek_token()? {
|
match self.lexer.peek_token()? {
|
||||||
Token::Comma => {
|
T::Comma => {
|
||||||
self.lexer.next_token()?;
|
self.lexer.next_token()?;
|
||||||
},
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
|
@ -180,20 +184,20 @@ impl Parser {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_matrix(&mut self) -> Result<Expr> {
|
fn parse_matrix(&mut self) -> Result<Expr> {
|
||||||
self.force_token(Token::LeftBrack)?;
|
self.force_token(T::LeftBrack)?;
|
||||||
let mut parts = Vec::new();
|
let mut parts = Vec::new();
|
||||||
loop {
|
loop {
|
||||||
let part = self.parse_matrix_part()?;
|
let part = self.parse_matrix_part()?;
|
||||||
parts.push(part);
|
parts.push(part);
|
||||||
let next = self.lexer.next_token()?;
|
let next = self.lexer.next_token()?;
|
||||||
match next {
|
match next {
|
||||||
Token::SemiColon => continue,
|
T::SemiColon => continue,
|
||||||
Token::RightBrack => break,
|
T::RightBrack => break,
|
||||||
_ => return Err(Error::UnexpectedToken(next).into()),
|
_ => return Err(Error::UnexpectedToken(next).into()),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if parts.len() == 1 {
|
if parts.len() == 1 {
|
||||||
Ok(Expr::List(parts.pop().unwrap()))
|
Ok(E::List(parts.pop().unwrap()))
|
||||||
} else {
|
} else {
|
||||||
let codomain = parts[0].len();
|
let codomain = parts[0].len();
|
||||||
let domain = parts.len();
|
let domain = parts.len();
|
||||||
|
@ -207,216 +211,55 @@ impl Parser {
|
||||||
while let Some(part) = parts.pop() {
|
while let Some(part) = parts.pop() {
|
||||||
data.extend(part);
|
data.extend(part);
|
||||||
}
|
}
|
||||||
Ok(Expr::Matrix((domain, codomain, data)))
|
Ok(E::Matrix((domain, codomain, data)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_table_key(&mut self) -> Result<Expr> {
|
fn parse_table_key(&mut self) -> Result<Expr> {
|
||||||
let tok = self.lexer.next_token()?;
|
let tok = self.lexer.next_token()?;
|
||||||
Ok(match tok {
|
Ok(match tok {
|
||||||
Token::LeftBrack => {
|
T::LeftBrack => {
|
||||||
let expr = self.parse_expr()?;
|
let expr = self.parse_expr()?;
|
||||||
self.force_token(Token::RightBrack)?;
|
self.force_token(T::RightBrack)?;
|
||||||
expr
|
expr
|
||||||
},
|
},
|
||||||
Token::Ident(ident) => Expr::Ident(ident),
|
T::Ident(ident) => E::Ident(ident),
|
||||||
Token::String(string) => Expr::Literal(Value::String(string.to_string().into())),
|
T::String(string) => E::Literal(V::String(string.to_string().into())),
|
||||||
_ => return Err(Error::UnexpectedToken(tok).into())
|
_ => return Err(Error::UnexpectedToken(tok).into())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_table(&mut self) -> Result<Expr> {
|
fn parse_table(&mut self) -> Result<Expr> {
|
||||||
self.force_token(Token::LeftLeftBrace)?;
|
self.force_token(T::LeftLeftBrace)?;
|
||||||
let mut table = Vec::new();
|
let mut table = Vec::new();
|
||||||
if self.lexer.peek_token()? == Token::RightRightBrace {
|
if self.lexer.peek_token()? == T::RightRightBrace {
|
||||||
self.lexer.next_token()?;
|
self.lexer.next_token()?;
|
||||||
return Ok(Expr::Table(table))
|
return Ok(E::Table(table))
|
||||||
}
|
}
|
||||||
loop {
|
loop {
|
||||||
let key = self.parse_table_key()?;
|
let key = self.parse_table_key()?;
|
||||||
self.force_token(Token::Assign)?;
|
self.force_token(T::Assign)?;
|
||||||
let value = self.parse_expr()?;
|
let value = self.parse_expr()?;
|
||||||
table.push((key, value));
|
table.push((key, value));
|
||||||
let next = self.lexer.next_token()?;
|
let next = self.lexer.next_token()?;
|
||||||
match next {
|
match next {
|
||||||
Token::Comma => continue,
|
T::Comma => continue,
|
||||||
Token::RightRightBrace => break,
|
T::RightRightBrace => break,
|
||||||
_ => return Err(Error::UnexpectedToken(next).into())
|
_ => return Err(Error::UnexpectedToken(next).into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(Expr::Table(table))
|
Ok(E::Table(table))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_paren(&mut self) -> Result<Expr> {
|
fn parse_paren(&mut self) -> Result<Expr> {
|
||||||
self.force_token(Token::LeftParen)?;
|
self.force_token(T::LeftParen)?;
|
||||||
let expr = self.parse_expr()?;
|
let expr = self.parse_expr()?;
|
||||||
self.force_token(Token::RightParen)?;
|
self.force_token(T::RightParen)?;
|
||||||
Ok(expr)
|
Ok(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_term(&mut self) -> Result<Expr> {
|
|
||||||
use Token::*;
|
|
||||||
let tok = self.lexer.peek_token()?;
|
|
||||||
match tok {
|
|
||||||
LeftBrack => return self.parse_matrix(),
|
|
||||||
LeftLeftBrace => return self.parse_table(),
|
|
||||||
LeftParen => return self.parse_paren(),
|
|
||||||
_ => ()
|
|
||||||
}
|
|
||||||
self.lexer.next_token()?;
|
|
||||||
Ok(match tok {
|
|
||||||
Nil => Expr::Literal(Value::Nil),
|
|
||||||
Int(i) => Expr::Literal(Value::Int(i)),
|
|
||||||
Float(f) => Expr::Literal(Value::Float(f)),
|
|
||||||
Complex(c) => Expr::Literal(Value::Complex(Complex64::new(0.0, c))),
|
|
||||||
Regex(r) => Expr::Literal(Value::Regex(Gc::new(r.into()))),
|
|
||||||
String(s) => Expr::Literal(Value::String(s.to_string().into())),
|
|
||||||
True => Expr::Literal(Value::Bool(true)),
|
|
||||||
False => Expr::Literal(Value::Bool(false)),
|
|
||||||
Ident(ident) => Expr::Ident(ident),
|
|
||||||
_ => return Err(Error::UnexpectedToken(tok).into()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_expr_expr_access(&mut self) -> Result<Expr> {
|
|
||||||
let mut expr = self.parse_term()?;
|
|
||||||
loop {
|
|
||||||
let tok = self.lexer.peek_token()?;
|
|
||||||
match tok {
|
|
||||||
Token::Access => {
|
|
||||||
self.force_token(Token::Access)?;
|
|
||||||
let temp = self.parse_term()?;
|
|
||||||
expr = Expr::FieldAccess(Box::new(expr), Box::new(temp));
|
|
||||||
},
|
|
||||||
_ => break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(expr)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_expr_call(&mut self) -> Result<Expr> {
|
|
||||||
let mut expr = self.parse_expr_expr_access()?;
|
|
||||||
loop {
|
|
||||||
let tok = self.lexer.peek_token()?;
|
|
||||||
match tok {
|
|
||||||
Token::LeftBrack => {
|
|
||||||
let index = self.parse_index()?;
|
|
||||||
expr = Expr::Index(Box::new(expr), index);
|
|
||||||
},
|
|
||||||
Token::LeftParen => {
|
|
||||||
let params = self.parse_fn_call()?;
|
|
||||||
expr = Expr::FnCall(Box::new(expr), params);
|
|
||||||
}
|
|
||||||
_ => break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(expr)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_expr_unary(&mut self) -> Result<Expr> {
|
|
||||||
let tok = self.lexer.peek_token_nl()?;
|
|
||||||
Ok(match tok {
|
|
||||||
Token::Not => {
|
|
||||||
self.lexer.next_token()?;
|
|
||||||
Expr::UnaryOp(Box::new(self.parse_expr_unary()?), UnaryOp::Not)
|
|
||||||
}
|
|
||||||
Token::Subtract => {
|
|
||||||
self.lexer.next_token()?;
|
|
||||||
Expr::UnaryOp(Box::new(self.parse_expr_unary()?), UnaryOp::Negate)
|
|
||||||
}
|
|
||||||
_ => self.parse_expr_call()?
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_expr_pow(&mut self) -> Result<Expr> {
|
|
||||||
expr_parser_reverse!(
|
|
||||||
self,
|
|
||||||
Token::Power,
|
|
||||||
parse_expr_unary,
|
|
||||||
parse_expr_pow
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_expr_mult(&mut self) -> Result<Expr> {
|
|
||||||
expr_parser!(self, Token::Multiply | Token::Divide | Token::Modulo, parse_expr_pow)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_expr_add(&mut self) -> Result<Expr> {
|
|
||||||
expr_parser!(self, Token::Add | Token::Subtract, parse_expr_mult)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_expr_shift(&mut self) -> Result<Expr> {
|
|
||||||
expr_parser!(
|
|
||||||
self,
|
|
||||||
Token::BitwiseShiftLeft | Token::BitwiseShiftRight,
|
|
||||||
parse_expr_add
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_expr_bit_and(&mut self) -> Result<Expr> {
|
|
||||||
expr_parser!(self, Token::BitwiseAnd, parse_expr_shift)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_expr_bit_or(&mut self) -> Result<Expr> {
|
|
||||||
expr_parser!(self, Token::BitwiseOr, parse_expr_bit_and)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_expr_compare(&mut self) -> Result<Expr> {
|
|
||||||
expr_parser!(
|
|
||||||
self,
|
|
||||||
Token::Equal | Token::NotEqual |
|
|
||||||
Token::LessThan | Token::GreaterThan |
|
|
||||||
Token::LessEqual | Token::GreaterEqual,
|
|
||||||
parse_expr_bit_or
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_expr_and(&mut self) -> Result<Expr> {
|
|
||||||
let mut expr = self.parse_expr_compare()?;
|
|
||||||
loop {
|
|
||||||
let tok = self.lexer.peek_token()?;
|
|
||||||
match tok {
|
|
||||||
Token::And => {
|
|
||||||
self.force_token(Token::And)?;
|
|
||||||
let temp = self.parse_expr_compare()?;
|
|
||||||
expr = Expr::And(Box::new(expr), Box::new(temp));
|
|
||||||
},
|
|
||||||
_ => break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(expr)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_expr(&mut self) -> Result<Expr> {
|
|
||||||
let mut expr = self.parse_expr_and()?;
|
|
||||||
loop {
|
|
||||||
let tok = self.lexer.peek_token()?;
|
|
||||||
match tok {
|
|
||||||
Token::Or => {
|
|
||||||
self.force_token(Token::Or)?;
|
|
||||||
let temp = self.parse_expr_and()?;
|
|
||||||
expr = Expr::Or(Box::new(expr), Box::new(temp));
|
|
||||||
},
|
|
||||||
_ => break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(expr)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_assign(&mut self) -> Result<Assign> {
|
|
||||||
let expr = self.parse_expr()?;
|
|
||||||
if !expr.is_assignable() {
|
|
||||||
return Ok(Assign::Expr(expr));
|
|
||||||
}
|
|
||||||
if self.lexer.peek_token()? != Token::Assign {
|
|
||||||
return Ok(Assign::Expr(expr));
|
|
||||||
}
|
|
||||||
self.lexer.next_token()?;
|
|
||||||
Ok(Assign::Assign(expr, Box::new(self.parse_assign()?)))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_params(&mut self) -> Result<Vec<Rc<str>>> {
|
fn parse_params(&mut self) -> Result<Vec<Rc<str>>> {
|
||||||
use Token::*;
|
use T::*;
|
||||||
let tok = self.lexer.next_token()?;
|
let tok = self.lexer.next_token()?;
|
||||||
match tok {
|
match tok {
|
||||||
Ident(ident) => return Ok(vec![ident]),
|
Ident(ident) => return Ok(vec![ident]),
|
||||||
|
@ -426,7 +269,7 @@ impl Parser {
|
||||||
|
|
||||||
let mut params = Vec::new();
|
let mut params = Vec::new();
|
||||||
|
|
||||||
if self.lexer.peek_token()? == Token::RightParen {
|
if self.lexer.peek_token()? == T::RightParen {
|
||||||
self.lexer.next_token()?;
|
self.lexer.next_token()?;
|
||||||
return Ok(params);
|
return Ok(params);
|
||||||
}
|
}
|
||||||
|
@ -446,7 +289,7 @@ impl Parser {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_ident(&mut self) -> Result<Rc<str>> {
|
fn parse_ident(&mut self) -> Result<Rc<str>> {
|
||||||
if let Token::Ident(ident) = self.lexer.next_token()? {
|
if let T::Ident(ident) = self.lexer.next_token()? {
|
||||||
Ok(ident)
|
Ok(ident)
|
||||||
} else {
|
} else {
|
||||||
Err(Error::ExpectedTokenName("Ident").into())
|
Err(Error::ExpectedTokenName("Ident").into())
|
||||||
|
@ -454,81 +297,124 @@ impl Parser {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_ident_nl(&mut self) -> Result<Rc<str>> {
|
fn parse_ident_nl(&mut self) -> Result<Rc<str>> {
|
||||||
if let Token::Ident(ident) = self.lexer.next_token_nl()? {
|
if let T::Ident(ident) = self.lexer.next_token_nl()? {
|
||||||
Ok(ident)
|
Ok(ident)
|
||||||
} else {
|
} else {
|
||||||
Err(Error::ExpectedTokenName("Ident").into())
|
Err(Error::ExpectedTokenName("Ident").into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_function(&mut self) -> Result<Stmt> {
|
fn parse_function(&mut self) -> Result<Expr> {
|
||||||
self.force_token(Token::Function)?;
|
self.force_token(T::Function)?;
|
||||||
let ident = self.parse_ident()?;
|
let ident = self.parse_ident()?;
|
||||||
let params = match self.lexer.peek_token()? {
|
let params = match self.lexer.peek_token()? {
|
||||||
Token::LeftBrace => vec![],
|
T::LeftBrace => vec![],
|
||||||
_ => self.parse_params()?,
|
_ => self.parse_params()?,
|
||||||
};
|
};
|
||||||
let stmt = self.parse_stmt()?;
|
|
||||||
Ok(Stmt::Function(ident, params, Box::new(stmt)))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_do_while(&mut self) -> Result<Stmt> {
|
|
||||||
self.force_token(Token::Do)?;
|
|
||||||
let stmt = self.parse_stmt()?;
|
|
||||||
self.force_token(Token::While)?;
|
|
||||||
let expr = self.parse_expr()?;
|
let expr = self.parse_expr()?;
|
||||||
Ok(Stmt::DoWhile(expr, Box::new(stmt)))
|
Ok(E::Function(ident, params, Box::new(expr)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_while(&mut self) -> Result<Stmt> {
|
fn parse_do_while(&mut self) -> Result<Expr> {
|
||||||
self.force_token(Token::While)?;
|
self.force_token(T::Do)?;
|
||||||
|
let expr = Box::new(self.parse_expr()?);
|
||||||
|
self.force_token(T::While)?;
|
||||||
|
let cond = Box::new(self.parse_expr()?);
|
||||||
|
Ok(E::DoWhile(expr, cond))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_while(&mut self) -> Result<Expr> {
|
||||||
|
self.force_token(T::While)?;
|
||||||
|
let cond = Box::new(self.parse_expr()?);
|
||||||
|
let expr = Box::new(self.parse_expr()?);
|
||||||
|
Ok(E::While(cond, expr))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_loop(&mut self) -> Result<Expr> {
|
||||||
|
self.force_token(T::Loop)?;
|
||||||
let expr = self.parse_expr()?;
|
let expr = self.parse_expr()?;
|
||||||
let stmt = self.parse_stmt()?;
|
Ok(E::Loop(Box::new(expr)))
|
||||||
Ok(Stmt::While(expr, Box::new(stmt)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_loop(&mut self) -> Result<Stmt> {
|
fn parse_if(&mut self) -> Result<Expr> {
|
||||||
self.force_token(Token::Loop)?;
|
self.force_token(T::If)?;
|
||||||
let stmt = self.parse_stmt()?;
|
let cond = Box::new(self.parse_expr()?);
|
||||||
Ok(Stmt::Loop(Box::new(stmt)))
|
let expr = Box::new(self.parse_expr()?);
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_if(&mut self) -> Result<Stmt> {
|
if self.lexer.peek_token()? != T::Else {
|
||||||
self.force_token(Token::If)?;
|
return Ok(E::If(cond, expr, None))
|
||||||
let expr = self.parse_expr()?;
|
|
||||||
let stmt = Box::new(self.parse_stmt()?);
|
|
||||||
|
|
||||||
if self.lexer.peek_token()? != Token::Else {
|
|
||||||
return Ok(Stmt::If(expr, stmt, None))
|
|
||||||
}
|
}
|
||||||
self.lexer.next_token()?;
|
self.lexer.next_token()?;
|
||||||
|
|
||||||
if self.lexer.peek_token()? == Token::If {
|
if self.lexer.peek_token()? == T::If {
|
||||||
Ok(Stmt::If(expr, stmt, Some(Box::new(self.parse_if()?))))
|
Ok(E::If(cond, expr, Some(Box::new(self.parse_if()?))))
|
||||||
} else {
|
} else {
|
||||||
Ok(Stmt::If(expr, stmt, Some(Box::new(self.parse_stmt()?))))
|
Ok(E::If(cond, expr, Some(Box::new(self.parse_expr()?))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_let(&mut self) -> Result<Stmt> {
|
fn parse_let(&mut self) -> Result<Expr> {
|
||||||
self.force_token(Token::Let)?;
|
self.force_token(T::Let)?;
|
||||||
let ident = self.parse_ident_nl()?;
|
let ident = self.parse_ident_nl()?;
|
||||||
if self.lexer.peek_token_nl()? == Token::Assign {
|
if self.lexer.peek_token_nl()? == T::Assign {
|
||||||
self.force_token_nl(Token::Assign)?;
|
self.force_token_nl(T::Assign)?;
|
||||||
Ok(Stmt::Let(ident, self.parse_expr()?))
|
Ok(E::Let(ident, Box::new(self.parse_expr()?)))
|
||||||
} else {
|
} else {
|
||||||
Ok(Stmt::Let(ident, Expr::Literal(Value::Nil)))
|
Ok(E::Let(ident, Box::new(E::Literal(V::Nil))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_return(&mut self) -> Result<Stmt> {
|
fn parse_return(&mut self) -> Result<Expr> {
|
||||||
self.force_token(Token::Return)?;
|
self.force_token(T::Return)?;
|
||||||
Ok(Stmt::Return(self.parse_expr()?))
|
Ok(E::Return(Box::new(self.parse_expr()?)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_stmt(&mut self) -> Result<Stmt> {
|
fn parse_block(&mut self) -> Result<Expr> {
|
||||||
use Token::*;
|
let mut block = Vec::new();
|
||||||
|
self.force_token(T::LeftBrace)?;
|
||||||
|
loop {
|
||||||
|
let expr = match self.lexer.peek_token()? {
|
||||||
|
T::RightBrace => break,
|
||||||
|
T::SemiColon => {
|
||||||
|
self.lexer.next_token()?;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
_ => self.parse_expr()?
|
||||||
|
};
|
||||||
|
block.push(expr);
|
||||||
|
let next = self.lexer.next_token()?;
|
||||||
|
match next {
|
||||||
|
T::SemiColon => continue,
|
||||||
|
T::RightBrace => break,
|
||||||
|
_ => return Err(Error::UnexpectedToken(next).into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if self.lexer.peek_token()? == T::RightBrace {
|
||||||
|
self.lexer.next_token()?;
|
||||||
|
}
|
||||||
|
Ok(E::Block(block))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_value(&mut self) -> Result<Expr> {
|
||||||
|
let tok = self.lexer.next_token()?;
|
||||||
|
Ok(match tok {
|
||||||
|
T::Nil => E::Literal(V::Nil),
|
||||||
|
T::Int(i) => E::Literal(V::Int(i)),
|
||||||
|
T::Float(f) => E::Literal(V::Float(f)),
|
||||||
|
T::Complex(c) => E::Literal(V::Complex(Complex64::new(0.0, c))),
|
||||||
|
T::Regex(r) => E::Literal(V::Regex(Gc::new(r.into()))),
|
||||||
|
T::String(s) => E::Literal(V::String(s.to_string().into())),
|
||||||
|
T::True => E::Literal(V::Bool(true)),
|
||||||
|
T::False => E::Literal(V::Bool(false)),
|
||||||
|
T::Ident(ident) => E::Ident(ident),
|
||||||
|
_ => return Err(Error::UnexpectedToken(tok).into()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_term(&mut self) -> Result<Expr> {
|
||||||
|
use T::*;
|
||||||
match self.lexer.peek_token()? {
|
match self.lexer.peek_token()? {
|
||||||
|
Function => self.parse_function(),
|
||||||
Do => self.parse_do_while(),
|
Do => self.parse_do_while(),
|
||||||
While => self.parse_while(),
|
While => self.parse_while(),
|
||||||
Let => self.parse_let(),
|
Let => self.parse_let(),
|
||||||
|
@ -538,80 +424,177 @@ impl Parser {
|
||||||
Loop => self.parse_loop(),
|
Loop => self.parse_loop(),
|
||||||
Break => {
|
Break => {
|
||||||
self.lexer.next_token()?;
|
self.lexer.next_token()?;
|
||||||
Ok(Stmt::Break)
|
Ok(E::Break)
|
||||||
},
|
},
|
||||||
Continue => {
|
Continue => {
|
||||||
self.lexer.next_token()?;
|
self.lexer.next_token()?;
|
||||||
Ok(Stmt::Continue)
|
Ok(E::Continue)
|
||||||
},
|
},
|
||||||
_ => {
|
LeftBrack => self.parse_matrix(),
|
||||||
let assign = self.parse_assign()?;
|
LeftLeftBrace => self.parse_table(),
|
||||||
Ok(match assign {
|
LeftParen => self.parse_paren(),
|
||||||
ast::Assign::Expr(expr) => Stmt::Expr(expr),
|
_ => self.parse_value(),
|
||||||
_ => Stmt::Assign(assign),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_block(&mut self) -> Result<Stmt> {
|
fn parse_expr_expr_access(&mut self) -> Result<Expr> {
|
||||||
let mut block = Vec::new();
|
let mut expr = self.parse_term()?;
|
||||||
self.force_token(Token::LeftBrace)?;
|
|
||||||
loop {
|
loop {
|
||||||
let stmt = match self.lexer.peek_token()? {
|
let tok = self.lexer.peek_token()?;
|
||||||
Token::RightBrace => break,
|
match tok {
|
||||||
Token::SemiColon => {
|
T::Access => {
|
||||||
self.lexer.next_token()?;
|
self.force_token(T::Access)?;
|
||||||
continue;
|
let temp = self.parse_term()?;
|
||||||
}
|
expr = E::FieldAccess(Box::new(expr), Box::new(temp));
|
||||||
_ => self.parse_stmt()?
|
},
|
||||||
};
|
_ => break
|
||||||
block.push(stmt);
|
|
||||||
let next = self.lexer.next_token()?;
|
|
||||||
match next {
|
|
||||||
Token::SemiColon => continue,
|
|
||||||
Token::RightBrace => break,
|
|
||||||
_ => return Err(Error::UnexpectedToken(next).into())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if self.lexer.peek_token()? == Token::RightBrace {
|
Ok(expr)
|
||||||
self.lexer.next_token()?;
|
|
||||||
}
|
|
||||||
Ok(Stmt::Block(block))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_root_stmt(&mut self) -> Result<Stmt> {
|
fn parse_expr_call(&mut self) -> Result<Expr> {
|
||||||
if self.lexer.peek_token()? == Token::Function {
|
let mut expr = self.parse_expr_expr_access()?;
|
||||||
self.parse_function()
|
loop {
|
||||||
} else {
|
let tok = self.lexer.peek_token()?;
|
||||||
self.parse_stmt()
|
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);
|
let lexer = Lexer::new(into);
|
||||||
self.lexer = lexer;
|
self.lexer = lexer;
|
||||||
|
let ast = self.parse_root()?;
|
||||||
let mut block = Vec::new();
|
|
||||||
loop {
|
|
||||||
let expr = match self.lexer.peek_token()? {
|
|
||||||
Token::Eof => break,
|
|
||||||
Token::SemiColon => {
|
|
||||||
self.lexer.next_token()?;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
_ => self.parse_root_stmt()?
|
|
||||||
};
|
|
||||||
block.push(expr);
|
|
||||||
let next = self.lexer.next_token()?;
|
|
||||||
match next {
|
|
||||||
Token::SemiColon => continue,
|
|
||||||
Token::Eof => break,
|
|
||||||
_ => return Err(Error::UnexpectedToken(next).into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let ast = Stmt::Block(block);
|
|
||||||
if self.optimize {
|
if self.optimize {
|
||||||
Ok(optimize(ast)?)
|
Ok(optimize(ast)?)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use std::{collections::HashMap, rc::Rc, fmt::{Debug, Display}, usize, cell::RefCell, ops::{Index, IndexMut}};
|
use std::{rc::Rc, fmt::{Debug, Display}, usize, ops::{Index, IndexMut}, collections::HashMap};
|
||||||
use crate::{value::{Value, self, ValueMap}, gc::Gc, chunk::{Function, Instruction}, compiler::Globals, Result};
|
use crate::{value::{Value, self, ValueMap}, gc::Gc, chunk::{Function, Instruction}, Result};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
@ -105,9 +105,9 @@ impl StackFrame {
|
||||||
|
|
||||||
pub struct Vm {
|
pub struct Vm {
|
||||||
stack: Stack<Value>,
|
stack: Stack<Value>,
|
||||||
|
locals: Stack<Value>,
|
||||||
frames: Vec<StackFrame>,
|
frames: Vec<StackFrame>,
|
||||||
global: HashMap<String, Value>,
|
globals: HashMap<u16, Value>,
|
||||||
global_table: Globals,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Vm {
|
impl Vm {
|
||||||
|
@ -123,16 +123,12 @@ impl Vm {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
stack: Stack::new(),
|
stack: Stack::new(),
|
||||||
|
locals: Stack::new(),
|
||||||
frames: Vec::new(),
|
frames: Vec::new(),
|
||||||
global: HashMap::new(),
|
globals: HashMap::new(),
|
||||||
global_table: Rc::new(RefCell::new(Vec::new()))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn globals(&self) -> Globals {
|
|
||||||
self.global_table.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run(&mut self, fun: Rc<Function>) -> Result<Value> {
|
pub fn run(&mut self, fun: Rc<Function>) -> Result<Value> {
|
||||||
let mut frame = StackFrame::new(&self, fun);
|
let mut frame = StackFrame::new(&self, fun);
|
||||||
loop {
|
loop {
|
||||||
|
@ -141,20 +137,20 @@ impl Vm {
|
||||||
frame.ip += 1;
|
frame.ip += 1;
|
||||||
match ins {
|
match ins {
|
||||||
NoOp => {},
|
NoOp => {},
|
||||||
Load(idx) => self.push(self.stack[frame.bp + idx as usize].clone()),
|
CreateLocal => self.locals.push(self.stack.pop()),
|
||||||
Store(idx) => self.stack[frame.bp + idx as usize] = self.pop(),
|
LoadLocal(idx) => {self.stack.push(self.locals[idx as usize].clone());},
|
||||||
|
StoreLocal(idx) => self.stack[frame.bp + idx as usize] = self.pop(),
|
||||||
|
DiscardLocals(count) => {self.locals.truncate(self.locals.len() - count as usize)},
|
||||||
LoadGlobal(idx) => {
|
LoadGlobal(idx) => {
|
||||||
let name = self.global_table.borrow()[idx as usize].clone();
|
let val = self.globals
|
||||||
let val = self.global
|
.get(&idx)
|
||||||
.get(name.as_ref())
|
.unwrap()
|
||||||
.ok_or(self::Error::UndefinedGlobal(name.into()))?
|
|
||||||
.clone();
|
.clone();
|
||||||
self.stack.push(val);
|
self.stack.push(val);
|
||||||
},
|
},
|
||||||
StoreGlobal(idx) => {
|
StoreGlobal(idx) => {
|
||||||
let name = self.global_table.borrow()[idx as usize].clone();
|
let val = self.pop();
|
||||||
let store = self.pop();
|
self.globals.insert(idx, val);
|
||||||
self.global.insert(name.to_string(), store);
|
|
||||||
},
|
},
|
||||||
Const(idx) => self.push(frame.fun.body.constants[idx as usize].clone()),
|
Const(idx) => self.push(frame.fun.body.constants[idx as usize].clone()),
|
||||||
Int(i) => self.push(Value::Int(i as i64)),
|
Int(i) => self.push(Value::Int(i as i64)),
|
||||||
|
|
Loading…
Reference in a new issue