[fine] Multi-module compilation

It's a little bit complicated, loading a module is a two-step dance
but here's how it's done. Probably some surface-area refactoring needs
to happen so that we do the right thing.
This commit is contained in:
John Doty 2024-03-30 16:33:27 -07:00
parent ab477cd783
commit a3d4c24f11
8 changed files with 506 additions and 274 deletions

View file

@ -3,7 +3,9 @@ use std::rc::Rc;
use crate::{
parser::{Child, SyntaxTree, Tree, TreeKind, TreeRef},
semantics::{string_constant_to_string, Declaration, Location, Origin, Semantics, Type},
semantics::{
string_constant_to_string, Declaration, Location, ModuleId, Origin, Semantics, Type,
},
tokens::TokenKind,
};
@ -62,6 +64,8 @@ pub enum Instruction {
StoreSlot(usize),
StringAdd,
NewList(usize),
ModulePrefix(ModuleId),
}
pub enum Export {
@ -69,23 +73,31 @@ pub enum Export {
Global(usize),
}
pub struct Module {
pub struct CompiledModule {
pub id: ModuleId,
pub functions: Vec<Rc<Function>>, // Functions
pub globals: usize, // The number of global variables
pub exports: HashMap<String, Export>, // Exports by name
pub init: usize, // The index of the initialization function
pub deps: Vec<ModuleId>, // Modules I depend on
}
impl Module {
pub fn new() -> Self {
Module {
impl CompiledModule {
pub fn new(id: ModuleId) -> Self {
CompiledModule {
id,
functions: Vec::new(),
globals: 0,
exports: HashMap::new(),
init: 0,
deps: Vec::new(),
}
}
pub fn init_function(&self) -> &Rc<Function> {
&self.functions[self.init]
}
pub fn functions(&self) -> &[Rc<Function>] {
&self.functions
}
@ -147,7 +159,7 @@ struct Compiler<'a> {
semantics: &'a Semantics,
syntax: &'a SyntaxTree,
module: Module,
module: CompiledModule,
function: Function,
}
@ -268,7 +280,7 @@ fn function_from_class_decl(source: &str, tree: &Tree) -> Result<Function, &'sta
Ok(Function::new(name, field_count))
}
pub fn compile(semantics: &Semantics) -> Rc<Module> {
pub fn compile_module(semantics: &Semantics) -> Rc<CompiledModule> {
let source = semantics.source();
let syntax_tree = semantics.tree();
@ -277,7 +289,7 @@ pub fn compile(semantics: &Semantics) -> Rc<Module> {
semantics: &semantics,
syntax: &syntax_tree,
module: Module::new(),
module: CompiledModule::new(semantics.mid()),
function: Function::new("<< module >>", 0),
};
@ -318,6 +330,7 @@ pub fn compile(semantics: &Semantics) -> Rc<Module> {
module.functions.push(f.unwrap());
}
module.deps.append(&mut semantics.import_ids());
Rc::new(module)
}
@ -650,8 +663,6 @@ fn compile_identifier_expression(c: &mut Compiler, t: TreeRef, tree: &Tree) -> C
}
fn compile_load_declaration(c: &mut Compiler, t: TreeRef, declaration: &Declaration) -> CR {
// TODO: Handle load of non-local value.
let index = declaration.index;
let instruction = match declaration.location {
Location::Local => {
@ -665,7 +676,12 @@ fn compile_load_declaration(c: &mut Compiler, t: TreeRef, declaration: &Declarat
Instruction::LoadArgument(index)
}
Location::Module => {
compiler_assert!(c, t, index < c.module.globals);
if declaration.module != c.semantics.mid() {
// TODO: Assert here too?
c.push(Instruction::ModulePrefix(declaration.module));
} else {
compiler_assert!(c, t, index < c.module.globals);
}
Instruction::LoadModule(index)
}
Location::Slot => {
@ -673,7 +689,12 @@ fn compile_load_declaration(c: &mut Compiler, t: TreeRef, declaration: &Declarat
Instruction::LoadSlot(index)
}
Location::Function => Instruction::LoadFunction(index),
Location::Function => {
if declaration.module != c.semantics.mid() {
c.push(Instruction::ModulePrefix(declaration.module));
}
Instruction::LoadFunction(index)
}
Location::ExternalFunction => Instruction::LoadExternFunction(index),
@ -1059,6 +1080,8 @@ fn compile_statement(c: &mut Compiler, t: TreeRef, gen_value: bool) {
TreeKind::LetStatement => compile_let_statement(c, t, tree, gen_value),
TreeKind::ReturnStatement => compile_return_statement(c, tree),
TreeKind::WhileStatement => compile_while_statement(c, tree, gen_value),
TreeKind::Export => compile_export_statement(c, tree, gen_value),
TreeKind::ExportList => OK,
_ => ice!(c, t, "unsupported statement tree kind {:?}", tree.kind),
};
@ -1071,6 +1094,11 @@ fn compile_statement(c: &mut Compiler, t: TreeRef, gen_value: bool) {
}
}
fn compile_export_statement(c: &mut Compiler, tree: &Tree, gen_value: bool) -> CR {
compile_statement(c, tree.nth_tree(1).ok_or("nothing to export")?, gen_value);
OK
}
fn compile_if_statement(c: &mut Compiler, tree: &Tree, gen_value: bool) -> CR {
compile_expression(c, tree.nth_tree(0).ok_or("no expr")?);
if !gen_value {
@ -1120,7 +1148,9 @@ fn compile_let_statement(c: &mut Compiler, t: TreeRef, tree: &Tree, gen_value: b
Instruction::StoreLocal(index)
}
Location::Module => {
if index >= c.module.globals {
if declaration.module != c.semantics.mid() {
c.push(Instruction::ModulePrefix(declaration.module));
} else if index >= c.module.globals {
c.module.globals = index + 1;
}
Instruction::StoreModule(index)