Files
not-python2/src/compile/compiler.rs

139 lines
4.5 KiB
Rust
Raw Normal View History

use crate::compile::{scope::GlobalScope, thunk::Thunk};
use crate::obj::prelude::*;
use crate::obj::ObjPtr;
use crate::syn::ast::*;
use crate::vm::inst::Inst;
pub struct Compiler {
scope: GlobalScope,
}
impl Compiler {
pub fn new() -> Self {
Self {
scope: Default::default(),
}
}
/// Gets the global scope.
pub fn scope(&self) -> &GlobalScope {
&self.scope
}
/// Gets the global scope, mutably.
pub fn scope_mut(&mut self) -> &mut GlobalScope {
&mut self.scope
}
/// 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();
for stmt in stmts {
thunks.push(self.emit_stmt(stmt));
}
Thunk::List(thunks).flatten()
}
fn emit_stmt(&mut self, stmt: &SpStmt) -> Thunk {
match stmt.inner() {
Stmt::Assign(_lhs_expr, _expr) => todo!(),
Stmt::Expr(expr) => {
let mut thunk = self.emit_expr(expr);
thunk.push(Inst::Pop);
thunk
}
Stmt::If { .. } => todo!(),
Stmt::Def { .. } => todo!(),
Stmt::Import { .. } => todo!(),
}
}
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));
thunk.extend(args.iter().map(|arg| self.emit_expr(arg)));
let mut thunk = Thunk::List(thunk);
thunk.push(Inst::Call(args.len()));
thunk
}
Expr::Get(expr, name) => {
let mut thunk = self.emit_expr(expr);
thunk.push(Inst::GetAttr(name.clone()));
thunk
}
Expr::Atom(atom) => self.emit_atom(atom),
}
}
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::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::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.
let name = self
.scope()
.lookup_scoped(n)
.unwrap_or_else(|| self.scope_mut().insert_local(n));
Thunk::Block(vec![Inst::Load(name)])
}
}
}
/// Gather all names from the list of statements and add them to the scope.
fn gather_names(&mut self, stmts: &Vec<SpStmt>) {
for stmt in stmts {
match stmt.inner() {
Stmt::Assign(lhs, _) => match lhs {
AssignLhs::Name(name) => {
self.scope_mut().insert_local(name);
}
AssignLhs::Complex(expr, _) => self.gather_expr_names(expr.inner()),
},
Stmt::Def { name, .. } => {
self.scope_mut().insert_local(name);
}
Stmt::Expr(expr) => {
// Get the names of the variables used in this expr
self.gather_expr_names(expr.inner());
}
Stmt::If { .. } => {
todo!()
}
Stmt::Import { .. } => {
todo!()
}
}
}
}
/// Gather the names used inside of an expression, recursively.
fn gather_expr_names(&mut self, expr: &Expr) {
match expr {
Expr::Call(fun, args) => {
self.gather_expr_names(fun.inner());
for arg in args {
self.gather_expr_names(arg.inner());
}
}
Expr::Get(head, _) => {
self.gather_expr_names(head.inner());
}
Expr::Atom(atom) => match atom.inner() {
Atom::Name(name) => {
self.scope_mut().insert_local(name);
}
// TODO symbols
_ => { /* no-op on non-names */ }
},
}
}
}