[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:
parent
ab477cd783
commit
a3d4c24f11
8 changed files with 506 additions and 274 deletions
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue