Add local variable collection to compilation
* Upon entering a new body, the local scope variables are collected. * VM instruction PushLocal now uses a `Local` value instead of a `Sym` value * Compilation of a new AST body will implicitly create a new scope Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
@@ -50,7 +50,3 @@ impl Visit for CollectLocals<'_, '_> {
|
|||||||
fn visit_access_expr(&mut self, expr: &AccessExpr) -> Self::Out { DefaultAccept::default_accept(expr, self); }
|
fn visit_access_expr(&mut self, expr: &AccessExpr) -> Self::Out { DefaultAccept::default_accept(expr, self); }
|
||||||
fn visit_atom(&mut self, atom: &Atom) -> Self::Out { DefaultAccept::default_accept(atom, self); }
|
fn visit_atom(&mut self, atom: &Atom) -> Self::Out { DefaultAccept::default_accept(atom, self); }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn collect_locals(compile: &mut Compile, body: &Body) {
|
|
||||||
CollectLocals::new(compile).collect(body);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ pub mod error;
|
|||||||
mod locals;
|
mod locals;
|
||||||
pub mod thunk;
|
pub mod thunk;
|
||||||
|
|
||||||
use crate::{obj::prelude::*, vm::consts::*};
|
use crate::{syn::ast::Body, obj::prelude::*, vm::consts::*};
|
||||||
use std::collections::{BTreeMap, HashMap};
|
use std::collections::{BTreeMap, HashMap};
|
||||||
|
|
||||||
pub struct Compile<'t> {
|
pub struct Compile<'t> {
|
||||||
@@ -96,6 +96,11 @@ impl<'t> Compile<'t> {
|
|||||||
pub fn pop_scope_layer(&mut self) -> Option<BTreeMap<Sym, Local>> {
|
pub fn pop_scope_layer(&mut self) -> Option<BTreeMap<Sym, Local>> {
|
||||||
self.locals.pop()
|
self.locals.pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Collects local variables for the given AST body non-recursively.
|
||||||
|
pub fn collect_locals(&mut self, body: &Body) {
|
||||||
|
locals::CollectLocals::new(self).collect(body);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
|
|||||||
@@ -213,7 +213,10 @@ impl<'c, 't> CompileBody<'c, 't> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn compile(&mut self, body: &'c Body) -> Result<Thunk> {
|
pub fn compile(&mut self, body: &'c Body) -> Result<Thunk> {
|
||||||
self.visit_body(body)
|
self.compile.push_scope_layer();
|
||||||
|
let thunk = self.visit_body(body)?;
|
||||||
|
self.compile.pop_scope_layer();
|
||||||
|
Ok(thunk)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,6 +231,7 @@ impl Visit for CompileBody<'_, '_> {
|
|||||||
type Out = Result<Thunk>;
|
type Out = Result<Thunk>;
|
||||||
|
|
||||||
fn visit_body(&mut self, body: &Body) -> Self::Out {
|
fn visit_body(&mut self, body: &Body) -> Self::Out {
|
||||||
|
self.compile.collect_locals(body);
|
||||||
let mut thunk = Thunk::Nop;
|
let mut thunk = Thunk::Nop;
|
||||||
|
|
||||||
for stmt in body.body.iter() {
|
for stmt in body.body.iter() {
|
||||||
@@ -342,14 +346,10 @@ impl Visit for CompileBody<'_, '_> {
|
|||||||
fn visit_atom(&mut self, atom: &Atom) -> Self::Out {
|
fn visit_atom(&mut self, atom: &Atom) -> Self::Out {
|
||||||
let thunk = match atom {
|
let thunk = match atom {
|
||||||
Atom::Ident(ident) => {
|
Atom::Ident(ident) => {
|
||||||
// TODO : set up lexical name stack
|
let sym = global_sym(ident.to_string());
|
||||||
// - think about how lexical names in function defs need to be captured, so no
|
let local = self.compile.lookup_scope(sym).unwrap();
|
||||||
// references get prematurely GC'd
|
|
||||||
// - Python uses LOAD_CLOSURE and CREATE_FUNCTION ops, but is this necessary if we
|
|
||||||
// know the names being closed over at runtime? Hm.
|
|
||||||
|
|
||||||
// get local
|
// get local
|
||||||
Inst::PushLocal(global_sym(ident.to_string())).into()
|
Inst::PushLocal(local).into()
|
||||||
}
|
}
|
||||||
Atom::Sym(sym) => {
|
Atom::Sym(sym) => {
|
||||||
// push symbol
|
// push symbol
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ pub enum Inst {
|
|||||||
PushConst(ConstHandle),
|
PushConst(ConstHandle),
|
||||||
|
|
||||||
/// Looks up and pushes a local value.
|
/// Looks up and pushes a local value.
|
||||||
PushLocal(Sym),
|
PushLocal(Local),
|
||||||
|
|
||||||
/// Pop a value from the stack, possibly into a local symbol.
|
/// Pop a value from the stack, possibly into a local symbol.
|
||||||
Pop(Option<Sym>),
|
Pop(Option<Sym>),
|
||||||
|
|||||||
Reference in New Issue
Block a user