Skip to content

Commit

Permalink
start introducing namespacing for NIFs, and compile structure properl…
Browse files Browse the repository at this point in the history
…y now
  • Loading branch information
vincenthz committed Dec 20, 2023
1 parent 6504139 commit f3b1b81
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 80 deletions.
59 changes: 27 additions & 32 deletions werbolg-compile/src/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,34 +133,6 @@ impl<'a, L: Clone + Eq + core::hash::Hash> RewriteState<'a, L> {
}
}

pub(crate) fn alloc_fun(
state: &mut SymbolsTableData<FunId, ir::FunDef>,
fundef: ir::FunDef,
) -> Result<FunId, CompilationError> {
let ident = fundef.name.clone();
if let Some(ident) = ident {
state
.add(ident.clone(), fundef)
.ok_or_else(|| CompilationError::DuplicateSymbol(ident))
} else {
Ok(state.add_anon(fundef))
}
}

pub(crate) fn alloc_struct(
state: &mut SymbolsTableData<ConstrId, ConstrDef>,
ir::StructDef { name, fields }: ir::StructDef,
) -> Result<ConstrId, CompilationError> {
let stru = StructDef {
name: name.unspan(),
fields: fields.into_iter().map(|v| v.unspan()).collect(),
};
let name = stru.name.clone();
state
.add(name.clone(), ConstrDef::Struct(stru))
.ok_or_else(|| CompilationError::DuplicateSymbol(name))
}

pub(crate) fn rewrite_fun<'a, L: Clone + Eq + core::hash::Hash>(
state: &mut RewriteState<'a, L>,
fundef: ir::FunDef,
Expand Down Expand Up @@ -249,11 +221,34 @@ fn rewrite_expr2<'a, L: Clone + Eq + core::hash::Hash>(
rewrite_expr2(state, local, *in_expr)?;
Ok(())
}
ir::Expr::Field(expr, _ident) => {
ir::Expr::Field(expr, struct_ident, field_ident) => {
let (constr_id, constr_def) = state.constrs.get(&struct_ident.inner).ok_or(
CompilationError::MissingConstructor(
struct_ident.span.clone(),
struct_ident.inner.clone(),
),
)?;

let ConstrDef::Struct(struct_def) = constr_def else {
return Err(CompilationError::ConstructorNotStructure(
struct_ident.span,
struct_ident.inner,
));
};

let Some(index) = struct_def.find_field_index(&field_ident.inner) else {
return Err(CompilationError::StructureFieldNotExistant(
field_ident.span,
struct_ident.inner,
field_ident.inner,
));
};

rewrite_expr2(state, local, *expr)?;
//state.write_code().push(Instruction::AccessField(ident));
todo!()
//Ok(())
state
.write_code()
.push(Instruction::AccessField(constr_id, index));
Ok(())
}
ir::Expr::Lambda(_span, fundef) => {
let prev = state.set_in_lambda();
Expand Down
10 changes: 10 additions & 0 deletions werbolg-compile/src/defs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@ pub struct StructDef {
pub fields: Vec<Ident>,
}

impl StructDef {
/// Try to find the index for a given field
pub fn find_field_index(&self, ident: &Ident) -> Option<StructFieldIndex> {
self.fields
.iter()
.position(|x| x == ident)
.map(|x| StructFieldIndex(x as u8))
}
}

/// Enumeration definition
#[derive(Clone, Debug)]
pub struct EnumDef {
Expand Down
152 changes: 105 additions & 47 deletions werbolg-compile/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,16 @@ pub enum CompilationError {
DuplicateSymbol(Ident),
/// Cannot find the symbol during compilation
MissingSymbol(Span, Ident),
/// Cannot find the constructor symbol during compilation
MissingConstructor(Span, Ident),
/// Number of parameters for a functions is above the limit we chose
FunctionParamsMoreThanLimit(usize),
/// Core's Literal is not supported by this compiler
LiteralNotSupported(Literal),
/// The constructor specified is a not a structure, but trying to access inner field
ConstructorNotStructure(Span, Ident),
/// The structure specified doesn't have a field of the right name
StructureFieldNotExistant(Span, Ident, Ident),
}

/// A compiled unit
Expand All @@ -59,64 +65,116 @@ pub struct CompilationUnit<L> {
pub code: IdVec<InstructionAddress, Instruction>,
}

/// Compile a IR Module into an optimised-for-execution LIR Module
pub fn compile<'a, L: Clone + Eq + core::hash::Hash>(
params: &'a CompilationParams<L>,
module: ir::Module,
environ: &mut Environment,
) -> Result<CompilationUnit<L>, CompilationError> {
let mut funs = SymbolsTableData::new();
let mut constrs = SymbolsTableData::new();
/// State of compilation
pub struct CompilationState<L: Clone + Eq + core::hash::Hash> {
params: CompilationParams<L>,
funs: SymbolsTableData<FunId, ir::FunDef>,
constrs: SymbolsTableData<ConstrId, ConstrDef>,
}

for stmt in module.statements.into_iter() {
match stmt {
ir::Statement::Function(_span, fundef) => {
alloc_fun(&mut funs, fundef)?;
}
ir::Statement::Struct(_span, structdef) => {
alloc_struct(&mut constrs, structdef)?;
impl<L: Clone + Eq + core::hash::Hash> CompilationState<L> {
/// Create a new compilation state
pub fn new(params: CompilationParams<L>) -> Self {
Self {
params,
funs: SymbolsTableData::new(),
constrs: SymbolsTableData::new(),
}
}

/// Add a ir::module to the compilation state
pub fn add_module(&mut self, module: ir::Module) -> Result<(), CompilationError> {
for stmt in module.statements.into_iter() {
match stmt {
ir::Statement::Use(_u) => {
// todo
()
}
ir::Statement::Function(_span, fundef) => {
let ident = fundef.name.clone();
let _funid = if let Some(ident) = ident {
self.funs
.add(ident.clone(), fundef)
.ok_or_else(|| CompilationError::DuplicateSymbol(ident))?
} else {
self.funs.add_anon(fundef)
};
()
}
ir::Statement::Struct(_span, structdef) => {
let stru = StructDef {
name: structdef.name.unspan(),
fields: structdef.fields.into_iter().map(|v| v.unspan()).collect(),
};
let name = stru.name.clone();
self.constrs
.add(name.clone(), ConstrDef::Struct(stru))
.ok_or_else(|| CompilationError::DuplicateSymbol(name))?;
}
ir::Statement::Expr(_) => (),
}
ir::Statement::Expr(_) => (),
}
Ok(())
}

let SymbolsTableData { table, vecdata } = funs;
/// Finalize compilation and return a CompilationUnit containing all the modules compiled in the state
pub fn finalize(
self,
environ: &mut Environment,
) -> Result<CompilationUnit<L>, CompilationError> {
let SymbolsTableData { table, vecdata } = self.funs;

let mut bindings = BindingsStack::new();
for (_id, (ident, _idx)) in environ.symbols.vecdata.iter() {
bindings.add(ident.clone(), BindingType::Nif(_id))
}
let mut bindings = BindingsStack::new();
for (_id, (ident, _idx)) in environ.symbols.vecdata.iter() {
bindings.add(ident.clone(), BindingType::Nif(_id))
}

for (ident, fun_id) in table.iter() {
bindings.add(ident.clone(), BindingType::Fun(fun_id))
}
for (ident, fun_id) in table.iter() {
bindings.add(ident.clone(), BindingType::Fun(fun_id))
}

let mut state =
compile::RewriteState::new(params, table, IdVecAfter::new(vecdata.next_id()), bindings);
let mut state = compile::RewriteState::new(
&self.params,
table,
IdVecAfter::new(vecdata.next_id()),
bindings,
);

for (funid, fundef) in vecdata.into_iter() {
let lirdef = compile::rewrite_fun(&mut state, fundef)?;
let lirid = state.funs_vec.push(lirdef);
assert_eq!(funid, lirid)
}

for (funid, fundef) in vecdata.into_iter() {
let lirdef = compile::rewrite_fun(&mut state, fundef)?;
let lirid = state.funs_vec.push(lirdef);
assert_eq!(funid, lirid)
// merge the lambdas code with the main code
// also remap the fundef of all lambdas to include this new offset
let lambda_instruction_diff = state.main_code.merge(state.lambdas_code);
state
.lambdas
.remap(|fundef| fundef.code_pos += lambda_instruction_diff);

state.funs_vec.concat(&mut state.lambdas);
let funs = state.funs_vec;

Ok(CompilationUnit {
lits: state.lits.finalize(),
constrs: state.constrs,
funs: funs,
funs_tbl: state.funs_tbl,
code: state.main_code.finalize(),
})
}
}

// merge the lambdas code with the main code
// also remap the fundef of all lambdas to include this new offset
let lambda_instruction_diff = state.main_code.merge(state.lambdas_code);
state
.lambdas
.remap(|fundef| fundef.code_pos += lambda_instruction_diff);

state.funs_vec.concat(&mut state.lambdas);
let funs = state.funs_vec;

Ok(CompilationUnit {
lits: state.lits.finalize(),
constrs: state.constrs,
funs: funs,
funs_tbl: state.funs_tbl,
code: state.main_code.finalize(),
})
/// Compile a IR Module into an optimised-for-execution LIR Module
pub fn compile<'a, L: Clone + Eq + core::hash::Hash>(
params: &'a CompilationParams<L>,
module: ir::Module,
environ: &mut Environment,
) -> Result<CompilationUnit<L>, CompilationError> {
let mut compiler = CompilationState::new(params.clone());
compiler.add_module(module)?;
compiler.finalize(environ)
}

/// Dump the instructions to a buffer
Expand Down
1 change: 1 addition & 0 deletions werbolg-compile/src/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use super::CompilationError;
use werbolg_core::Literal;

/// User driven compilation parameters
#[derive(Clone)]
pub struct CompilationParams<L: Clone + Eq + core::hash::Hash> {
/// Map a werbolg-literal into a L type that will be used during execution
pub literal_mapper: fn(Literal) -> Result<L, CompilationError>,
Expand Down
6 changes: 6 additions & 0 deletions werbolg-compile/src/symbols.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ impl<ID: IdF, T> SymbolsTableData<ID, T> {
pub fn add_anon(&mut self, v: T) -> ID {
self.vecdata.push(v)
}

pub fn get(&self, ident: &Ident) -> Option<(ID, &T)> {
self.table
.get(ident)
.map(|constr_id| (constr_id, &self.vecdata[constr_id]))
}
}

pub struct UniqueTableBuilder<ID: IdF, T: Eq + Hash> {
Expand Down
17 changes: 16 additions & 1 deletion werbolg-core/src/ir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
//!
//! This try to remain generic to allow multiple different language (existing or new)
//! to target werbolg and be interpreted through it
//!
//! The AST try the terminology of Rust AST, but offer less / more flexibility at time,
//! as this is made for other languages to target also.
use super::basic::*;
use super::location::*;
Expand All @@ -23,11 +26,23 @@ pub struct Module {
/// * Naked expression
#[derive(Clone, Debug)]
pub enum Statement {
Use(Use),
Function(Span, FunDef),
Struct(Span, StructDef),
Expr(Expr),
}

/// AST Use/Import
#[derive(Clone, Debug)]
pub struct Use {
/// the name of the namespace to import
pub namespace: Ident,
/// hiding of symbols
pub hiding: Vec<Ident>,
/// renaming of symbols, e.g. `use namespace::{x as y}`
pub renames: Vec<(Ident, Ident)>,
}

/// AST for function definition
///
/// Function definitions are something like:
Expand Down Expand Up @@ -85,7 +100,7 @@ pub enum Binder {
pub enum Expr {
Literal(Span, Literal),
Ident(Span, Ident),
Field(Box<Expr>, Ident),
Field(Box<Expr>, Spanned<Ident>, Spanned<Ident>),
List(Span, Vec<Expr>),
Let(Binder, Box<Expr>, Box<Expr>),
Lambda(Span, Box<FunDef>),
Expand Down

0 comments on commit f3b1b81

Please sign in to comment.