Incremental function compilation

This commit is contained in:
Mia
2026-03-06 17:17:12 +01:00
parent 92c02c6ca2
commit 81d1dfe3d3
5 changed files with 141 additions and 102 deletions
+12 -3
View File
@@ -3,17 +3,20 @@ use arcstr::literal_substr;
use leaf_allocators::SyncAllocator;
use leaf_assembly::{
assembly::{Assembly, AssemblyIdentifier, Context},
functions::Function,
types::Type,
values::{AnyConst, Value},
};
use leaf_parser::SourceCode;
use std::{ops::Deref, sync::Arc};
use leaf_parser::{SourceCode, ast};
use std::{collections::VecDeque, ops::Deref, sync::Arc};
mod error;
mod scope;
pub type SourceFile = Arc<SourceCode>;
type FuncQueue<'l> = VecDeque<(&'l Function<'l>, Arc<ast::Block>, Scope<'l>)>;
pub struct CompilationContext<'l> {
ctx: &'l Context<'l>,
alloc: &'l dyn SyncAllocator,
@@ -98,10 +101,16 @@ impl<'l> CompilationContext<'l> {
scope.declare_constants(&unit.decls);
}
let mut queue = FuncQueue::new();
for i in 0..sources.len() {
let unit = &units[i];
let scope = &mut scopes[i];
scope.define_constants(&unit.decls)?;
scope.define_constants(&unit.decls, &mut queue)?;
}
while let Some((func, block, mut scope)) = queue.pop_back() {
scope.compile_function(func, &block, &mut queue)?;
}
Ok(())
+90 -59
View File
@@ -1,3 +1,4 @@
use crate::{FuncQueue, error::*};
use arcstr::Substr;
use leaf_assembly::{
assembly::Assembly,
@@ -12,19 +13,20 @@ use leaf_parser::{
SourceCode,
ast::{self, BinaryExpr, BinaryOp, ConstDecl, Expr, Ident, IndexingExpr, NamePattern, While},
};
use std::{collections::HashMap, sync::Arc};
use std::{
collections::HashMap,
sync::{Arc, OnceLock},
};
use crate::error::*;
#[derive(Default)]
struct ExpressionContext<'l, 'r> {
decl_names: Option<&'r NamePattern>,
builder: Option<&'r mut FunctionBodyBuilder<'l>>,
fn_queue: &'r mut FuncQueue<'l>,
}
#[derive(Clone)]
struct Variable<'l> {
value: Value<'l>,
value: Arc<OnceLock<Value<'l>>>,
mutable: bool,
}
@@ -45,7 +47,13 @@ impl<'l> Scope<'l> {
}
pub fn insert(&mut self, name: Substr, value: Value<'l>, mutable: bool) {
self.values.insert(name, Variable { value, mutable });
self.values.insert(
name,
Variable {
value: Arc::new(OnceLock::from(value)),
mutable,
},
);
}
pub fn declare_constants(&mut self, decl: &[ConstDecl]) {
@@ -54,7 +62,7 @@ impl<'l> Scope<'l> {
self.values.insert(
name.clone(),
Variable {
value: Value::Uninit,
value: Arc::default(),
mutable: false,
},
);
@@ -62,19 +70,28 @@ impl<'l> Scope<'l> {
}
}
pub fn define_constants(&mut self, decl: &[ConstDecl]) -> Result<(), CompilationError> {
pub fn define_constants(
&mut self,
decl: &[ConstDecl],
fn_queue: &mut FuncQueue<'l>,
) -> Result<(), CompilationError> {
for val in decl {
let expr = self.compile_expression(
&val.value,
&mut ExpressionContext {
decl_names: Some(&val.names),
..Default::default()
builder: None,
fn_queue,
},
)?;
match &val.names {
NamePattern::Single(ident) => {
self.values.get_mut(&ident.0).unwrap().value = expr;
}
NamePattern::Single(ident) => self
.values
.get_mut(&ident.0)
.unwrap()
.value
.set(expr)
.unwrap(),
NamePattern::Tuple(_) => todo!(),
NamePattern::List(_) => todo!(),
}
@@ -82,6 +99,42 @@ impl<'l> Scope<'l> {
Ok(())
}
pub fn compile_function(
&mut self,
func: &'l Function<'l>,
block: &ast::Block,
fn_queue: &mut FuncQueue<'l>,
) -> Result<(), CompilationError> {
let mut builder = func.create_body().unwrap();
let mut ctx = ExpressionContext {
builder: Some(&mut builder),
decl_names: None,
fn_queue: fn_queue,
};
let mut last_expr = None;
for expr in &block.0 {
last_expr = Some(self.compile_expression(expr, &mut ctx)?);
}
if !builder.current_block().has_termination() {
match func.ty.ret_t {
Type::Void => builder.ret(None).unwrap(),
_ => {
if let Some(expr) = last_expr.as_mut()
&& expr.flags().contains(ValueFlags::LValue)
{
*expr = builder.load(*expr).unwrap();
}
builder.ret(last_expr).unwrap()
}
};
}
builder.build().unwrap();
Ok(())
}
fn compile_expression(
&mut self,
expr: &Expr,
@@ -98,23 +151,22 @@ impl<'l> Scope<'l> {
},
cause: None,
}),
Some(Variable {
value: Value::Uninit,
..
}) => Err(CompilationError {
kind: Kind::UninitializedSymbol,
message: format!("Symbol `{name}` is not initialized at this time."),
location: Location::Range {
file: self.source.clone(),
range: name.range(),
},
cause: None,
}),
Some(Variable { value, .. }) => Ok(*value),
Some(Variable { value, .. }) => match value.get() {
None => Err(CompilationError {
kind: Kind::UninitializedSymbol,
message: format!("Symbol `{name}` is not initialized at this time."),
location: Location::Range {
file: self.source.clone(),
range: name.range(),
},
cause: None,
}),
Some(value) => Ok(*value),
},
},
Expr::Func(func) => self
.compile_function(func, ctx)
.make_function(func, ctx)
.map(|f| Value::Constant(AnyConst::Function(f)))
.map_err(|err| CompilationError {
kind: Kind::FunctionCompilationFailed,
@@ -294,7 +346,8 @@ impl<'l> Scope<'l> {
let mut scope = self.clone();
let mut ctx = ExpressionContext {
builder: Some(builder),
..Default::default()
decl_names: None,
fn_queue: ctx.fn_queue,
};
let mut last_expr = None;
@@ -456,7 +509,7 @@ impl<'l> Scope<'l> {
}
}
fn compile_function(
fn make_function(
&mut self,
ast: &ast::Function,
ctx: &mut ExpressionContext<'l, '_>,
@@ -477,9 +530,6 @@ impl<'l> Scope<'l> {
let func = self.assembly.create_function(fn_ty);
if let Some(NamePattern::Single(func_name)) = &ctx.decl_names {
func.name.set(func.ctx().intern_str(&func_name.0)).unwrap();
if let Some(variable) = self.values.get_mut(func_name.as_str()) {
variable.value = Value::Constant(AnyConst::Function(func));
}
};
let Some(block) = &ast.block else {
@@ -491,32 +541,7 @@ impl<'l> Scope<'l> {
scope.insert(arg.name.0.clone(), Value::Parameter(i, func), false);
}
let mut builder = func.create_body().unwrap();
let mut ctx = ExpressionContext {
builder: Some(&mut builder),
..Default::default()
};
let mut last_expr = None;
for expr in &block.0 {
last_expr = Some(scope.compile_expression(expr, &mut ctx)?);
}
if !builder.current_block().has_termination() {
match func.ty.ret_t {
Type::Void => builder.ret(None).unwrap(),
_ => {
if let Some(expr) = last_expr.as_mut()
&& expr.flags().contains(ValueFlags::LValue)
{
*expr = builder.load(*expr).unwrap();
}
builder.ret(last_expr).unwrap()
}
};
}
builder.build().unwrap();
ctx.fn_queue.push_back((func, block.clone(), scope));
Ok(func)
}
@@ -531,6 +556,7 @@ impl<'l> Scope<'l> {
let mut sub_ctx = ExpressionContext {
decl_names: Some(names),
builder: ctx.builder.as_deref_mut(),
fn_queue: ctx.fn_queue,
};
let mut value = self.compile_expression(value, &mut sub_ctx)?;
if mutable {
@@ -541,8 +567,13 @@ impl<'l> Scope<'l> {
}
match names {
NamePattern::Single(ident) => {
self.values
.insert(ident.0.clone(), Variable { value, mutable });
self.values.insert(
ident.0.clone(),
Variable {
value: Arc::new(OnceLock::from(value)),
mutable,
},
);
}
NamePattern::Tuple(_) => todo!(),
NamePattern::List(_) => todo!(),