Add base branch logic

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
2023-04-07 00:00:04 -07:00
parent 4d005494a3
commit 7bac4306c3
17 changed files with 20302 additions and 5491 deletions

View File

@@ -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!()