Add base branch logic
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
use std::collections::VecDeque;
|
||||
|
||||
use crate::compile::{scope::GlobalScope, thunk::Thunk};
|
||||
use crate::obj::prelude::*;
|
||||
use crate::obj::ObjPtr;
|
||||
use crate::syn::ast::*;
|
||||
use crate::vm::inst::Inst;
|
||||
use crate::vm::inst::*;
|
||||
|
||||
pub struct Compiler {
|
||||
scope: GlobalScope,
|
||||
@@ -28,20 +30,28 @@ impl Compiler {
|
||||
/// Compile the given list of AST statements, returning the body.
|
||||
pub fn compile_stmts(&mut self, stmts: &Vec<SpStmt>) -> Vec<Inst> {
|
||||
self.gather_names(stmts);
|
||||
let mut thunks = Vec::new();
|
||||
let mut thunks = VecDeque::new();
|
||||
for stmt in stmts {
|
||||
thunks.push(self.emit_stmt(stmt));
|
||||
thunks.push_back(self.emit_stmt(stmt));
|
||||
}
|
||||
Thunk::List(thunks).flatten()
|
||||
}
|
||||
|
||||
fn emit_body(&mut self, body: &SpBody) -> Thunk {
|
||||
let mut thunks = VecDeque::new();
|
||||
for stmt in body.inner() {
|
||||
thunks.push_back(self.emit_stmt(stmt));
|
||||
}
|
||||
Thunk::List(thunks)
|
||||
}
|
||||
|
||||
fn emit_stmt(&mut self, stmt: &SpStmt) -> Thunk {
|
||||
match stmt.inner() {
|
||||
Stmt::Assign(lhs_expr, expr) => match lhs_expr.inner() {
|
||||
AssignLhs::Name(n) => {
|
||||
let name = self.scope().lookup_scoped(n).unwrap();
|
||||
let mut thunk = self.emit_expr(expr);
|
||||
thunk.push(Inst::Store(name));
|
||||
thunk.push_back(Inst::Store(name));
|
||||
thunk
|
||||
}
|
||||
AssignLhs::Complex(_, _) => {
|
||||
@@ -50,10 +60,80 @@ impl Compiler {
|
||||
},
|
||||
Stmt::Expr(expr) => {
|
||||
let mut thunk = self.emit_expr(expr);
|
||||
thunk.push(Inst::Pop);
|
||||
thunk.push_back(Inst::Pop);
|
||||
thunk
|
||||
}
|
||||
Stmt::If { .. } => todo!(),
|
||||
Stmt::If {
|
||||
if_true,
|
||||
elseif,
|
||||
else_body,
|
||||
} => {
|
||||
// compile the "else" thunk first - it doesn't need to jump
|
||||
let mut else_thunk = if let Some(else_body) = else_body {
|
||||
self.emit_body(else_body)
|
||||
} else {
|
||||
Thunk::empty()
|
||||
};
|
||||
else_thunk.push_front(Inst::Comment("else body".to_string()));
|
||||
|
||||
// compile the "else if" thunks next. These need to jump forward N
|
||||
// instructions at the very end
|
||||
let mut jump_forward: isize = (else_thunk.len() + 1).try_into().unwrap();
|
||||
let mut thunks = VecDeque::with_capacity(
|
||||
1 + // else thunk
|
||||
elseif.len() + // elseif thunks
|
||||
1, // if thunk
|
||||
);
|
||||
thunks.push_front(else_thunk);
|
||||
|
||||
for cond_block in elseif.iter().rev() {
|
||||
// do block, then condition
|
||||
let mut body_thunk = self.emit_body(&cond_block.inner().body);
|
||||
// jump forward by the previous jump forward distance
|
||||
body_thunk.push_front(Inst::Comment("elseif body".to_string()));
|
||||
body_thunk.push_back(Inst::JumpRelative(jump_forward, JumpCondition::Always));
|
||||
|
||||
let mut cond_thunk = self.emit_expr(&cond_block.inner().cond);
|
||||
cond_thunk.push_front(Inst::Comment("elseif compare ".to_string()));
|
||||
cond_thunk.push_back(Inst::Compare);
|
||||
// jump forward by the length of the body
|
||||
cond_thunk.push_back(Inst::JumpRelative(
|
||||
isize::try_from(body_thunk.len()).unwrap() + 1,
|
||||
JumpCondition::False,
|
||||
));
|
||||
|
||||
jump_forward +=
|
||||
isize::try_from(body_thunk.len() + cond_thunk.len()).unwrap() + 1;
|
||||
|
||||
thunks.push_front(body_thunk);
|
||||
thunks.push_front(cond_thunk);
|
||||
}
|
||||
|
||||
// same as above: do block, then condition
|
||||
let mut body_thunk = self.emit_body(&if_true.inner().body);
|
||||
body_thunk.push_front(Inst::Comment("if body".to_string()));
|
||||
body_thunk.push_back(Inst::JumpRelative(jump_forward, JumpCondition::Always));
|
||||
|
||||
let mut cond_thunk = self.emit_expr(&if_true.inner().cond);
|
||||
cond_thunk.push_front(Inst::Comment("if compare".to_string()));
|
||||
cond_thunk.push_back(Inst::Compare);
|
||||
cond_thunk.push_back(Inst::JumpRelative(
|
||||
// + 1 because otherwise we won't end up on the next instruction
|
||||
isize::try_from(body_thunk.len()).unwrap() + 1,
|
||||
JumpCondition::False,
|
||||
));
|
||||
|
||||
// don't need to add this
|
||||
//jump_forward += isize::try_from(body_thunk.len() + cond_thunk.len()).unwrap();
|
||||
|
||||
thunks.push_front(body_thunk);
|
||||
thunks.push_front(cond_thunk);
|
||||
thunks.push_back(Thunk::Block(
|
||||
vec![Inst::Comment("end of if block".to_string())].into(),
|
||||
));
|
||||
|
||||
Thunk::List(thunks)
|
||||
}
|
||||
Stmt::Def { .. } => todo!(),
|
||||
Stmt::Import { .. } => todo!(),
|
||||
}
|
||||
@@ -62,16 +142,16 @@ impl Compiler {
|
||||
fn emit_expr(&mut self, expr: &SpExpr) -> Thunk {
|
||||
match expr.inner() {
|
||||
Expr::Call(expr, args) => {
|
||||
let mut thunk = Vec::with_capacity(args.len() + 1);
|
||||
thunk.push(self.emit_expr(expr));
|
||||
let mut thunk = VecDeque::with_capacity(args.len() + 1);
|
||||
thunk.push_back(self.emit_expr(expr));
|
||||
thunk.extend(args.iter().map(|arg| self.emit_expr(arg)));
|
||||
let mut thunk = Thunk::List(thunk);
|
||||
thunk.push(Inst::Call(args.len()));
|
||||
thunk.push_back(Inst::Call(args.len()));
|
||||
thunk
|
||||
}
|
||||
Expr::Get(expr, name) => {
|
||||
let mut thunk = self.emit_expr(expr);
|
||||
thunk.push(Inst::GetAttr(name.clone()));
|
||||
thunk.push_back(Inst::GetAttr(name.clone()));
|
||||
thunk
|
||||
}
|
||||
Expr::Atom(atom) => self.emit_atom(atom),
|
||||
@@ -80,19 +160,19 @@ impl Compiler {
|
||||
|
||||
fn emit_atom(&mut self, atom: &SpAtom) -> Thunk {
|
||||
match atom.inner() {
|
||||
Atom::Int(i) => Thunk::Block(vec![Inst::Push(ObjPtr::new(Int::new(*i)))]),
|
||||
Atom::Int(i) => Thunk::Block(vec![Inst::Push(ObjPtr::new(Int::new(*i)))].into()),
|
||||
Atom::Float(_) => todo!(), // Thunk::Block(vec![Inst::Push(Gc::new(Float::new(*f)))]),
|
||||
Atom::Str(s) => Thunk::Block(vec![Inst::Push(ObjPtr::new(Str::new(s.clone())))]),
|
||||
Atom::Str(s) => Thunk::Block(vec![Inst::Push(ObjPtr::new(Str::new(s.clone())))].into()),
|
||||
Atom::Sym(_) => todo!(),
|
||||
Atom::Name(n) => {
|
||||
// Look up the symbol first. It may already exist.
|
||||
// If it doesn't exist, create it. It may be created
|
||||
// dynamically.
|
||||
// Dynamically.
|
||||
let name = self
|
||||
.scope()
|
||||
.lookup_scoped(n)
|
||||
.unwrap_or_else(|| self.scope_mut().insert_local(n));
|
||||
Thunk::Block(vec![Inst::Load(name)])
|
||||
Thunk::Block(vec![Inst::Load(name)].into())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -114,8 +194,22 @@ impl Compiler {
|
||||
// Get the names of the variables used in this expr
|
||||
self.gather_expr_names(expr.inner());
|
||||
}
|
||||
Stmt::If { .. } => {
|
||||
todo!()
|
||||
Stmt::If {
|
||||
if_true,
|
||||
elseif,
|
||||
else_body,
|
||||
} => {
|
||||
self.gather_expr_names(if_true.inner().cond.inner());
|
||||
self.gather_names(if_true.inner().body.inner());
|
||||
|
||||
for cond_body in elseif {
|
||||
self.gather_expr_names(cond_body.inner().cond.inner());
|
||||
self.gather_names(cond_body.inner().body.inner());
|
||||
}
|
||||
|
||||
if let Some(else_body) = else_body {
|
||||
self.gather_names(else_body.inner());
|
||||
}
|
||||
}
|
||||
Stmt::Import { .. } => {
|
||||
todo!()
|
||||
|
||||
Reference in New Issue
Block a user