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
-2
View File
@@ -24,7 +24,6 @@ bitflags! {
#[derive(Debug, Display, Clone, Copy, From, TryInto, PartialEq, Eq, Hash)]
pub enum Value<'l> {
Uninit,
#[display("{_0}")]
Constant(AnyConst<'l>),
#[display("{_0}")]
@@ -47,7 +46,6 @@ impl<'l> Value<'l> {
Value::Constant(v) => v.ty(),
Value::Instruction(v) => v.value_ty(),
Value::Parameter(i, f) => f.ty.par_t[*i],
Value::Uninit => unreachable!(),
}
}
+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!(),
+13 -13
View File
@@ -1,7 +1,7 @@
use std::ops::Range;
use arcstr::Substr;
use derive_more::Deref;
use std::ops::Range;
use std::sync::Arc;
#[derive(Debug, Deref)]
pub struct Ident(pub Substr);
@@ -25,29 +25,29 @@ pub enum Expr {
Number(Number),
String(Substr),
#[debug("{_0:?}")]
Binary(Box<BinaryExpr>),
Index(Box<IndexingExpr>),
Binary(Arc<BinaryExpr>),
Index(Arc<IndexingExpr>),
Tuple(Vec<Expr>),
List(Vec<Expr>),
Struct(Box<StructCtor>),
Struct(Arc<StructCtor>),
#[debug("{_0:?}")]
Block(Block),
#[debug("{_0:?}")]
Func(Box<Function>),
Func(Arc<Function>),
#[debug("{_0:?}")]
Type(Box<Type>),
Type(Arc<Type>),
#[debug("{_0:?}")]
ConstDecl(Box<ConstDecl>),
ConstDecl(Arc<ConstDecl>),
#[debug("{_0:?}")]
VarDecl(Box<VarDecl>),
VarDecl(Arc<VarDecl>),
#[debug("{_0:?}")]
For(Box<For>),
For(Arc<For>),
#[debug("{_0:?}")]
While(Box<While>),
While(Arc<While>),
Call {
func: Box<Expr>,
func: Arc<Expr>,
args: Vec<Expr>,
},
}
@@ -135,7 +135,7 @@ pub struct Function {
pub text: Substr,
pub args: Vec<NameValuePair>,
pub ret: Option<Expr>,
pub block: Option<Block>,
pub block: Option<Arc<Block>>,
}
#[derive(Debug)]
+26 -25
View File
@@ -3,6 +3,7 @@ use crate::ast::*;
use arcstr::Substr;
use peg::{Parse, ParseElem, ParseLiteral, ParseSlice};
pub use peg::{error::*, str::LineCol};
use std::sync::Arc;
impl Parse for SourceCode {
type PositionRepr = LineCol;
@@ -69,40 +70,40 @@ peg::parser! {
// ### EXPRESSIONS ####
rule expr() -> Expr = precedence! {
lhs:(@) __ op:$("as") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Cast(op), rhs })) }
lhs:(@) __ op:$("as") __ rhs:@ { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Cast(op), rhs })) }
--
lhs:@ __ op:$("=") __ rhs:expr() { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Assign(op), rhs })) }
lhs:(@) __ op:$(".") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Dot(op), rhs })) }
lhs:(@) "(" __ args:(expr() ** ("," __)) __ ")" { Expr::Call { func: Box::new(lhs), args } }
value:(@) "[" __ index:expr() __ "]" { Expr::Index(Box::new(IndexingExpr { value, index })) }
r#type:(@) _ "{" __ values:name_value_pairs() __ "}" { Expr::Struct(Box::new(StructCtor { r#type, values })) }
lhs:@ __ op:$("=") __ rhs:expr() { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Assign(op), rhs })) }
lhs:(@) __ op:$(".") __ rhs:@ { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Dot(op), rhs })) }
lhs:(@) "(" __ args:(expr() ** ("," __)) __ ")" { Expr::Call { func: Arc::new(lhs), args } }
value:(@) "[" __ index:expr() __ "]" { Expr::Index(Arc::new(IndexingExpr { value, index })) }
r#type:(@) _ "{" __ values:name_value_pairs() __ "}" { Expr::Struct(Arc::new(StructCtor { r#type, values })) }
--
lhs:(@) __ op:$("+") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Add(op), rhs })) }
lhs:(@) __ op:$("-") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Sub(op), rhs })) }
lhs:(@) __ op:$("+") __ rhs:@ { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Add(op), rhs })) }
lhs:(@) __ op:$("-") __ rhs:@ { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Sub(op), rhs })) }
--
lhs:(@) __ op:$("*") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Mul(op), rhs })) }
lhs:(@) __ op:$("/") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Div(op), rhs })) }
lhs:(@) __ op:$("%") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Mod(op), rhs })) }
lhs:(@) __ op:$("*") __ rhs:@ { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Mul(op), rhs })) }
lhs:(@) __ op:$("/") __ rhs:@ { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Div(op), rhs })) }
lhs:(@) __ op:$("%") __ rhs:@ { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Mod(op), rhs })) }
--
lhs:(@) __ op:$("..") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Range(op), rhs })) }
lhs:(@) __ op:$("..") __ rhs:@ { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Range(op), rhs })) }
--
lhs:(@) __ op:$("==") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Eq(op), rhs })) }
lhs:(@) __ op:$("!=") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Ne(op), rhs })) }
lhs:(@) __ op:$("<") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Lt(op), rhs })) }
lhs:(@) __ op:$(">") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Gt(op), rhs })) }
lhs:(@) __ op:$("<=") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Le(op), rhs })) }
lhs:(@) __ op:$(">=") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Ge(op), rhs })) }
lhs:(@) __ op:$("==") __ rhs:@ { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Eq(op), rhs })) }
lhs:(@) __ op:$("!=") __ rhs:@ { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Ne(op), rhs })) }
lhs:(@) __ op:$("<") __ rhs:@ { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Lt(op), rhs })) }
lhs:(@) __ op:$(">") __ rhs:@ { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Gt(op), rhs })) }
lhs:(@) __ op:$("<=") __ rhs:@ { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Le(op), rhs })) }
lhs:(@) __ op:$(">=") __ rhs:@ { Expr::Binary(Arc::new(BinaryExpr { lhs, op: BinaryOp::Ge(op), rhs })) }
--
block:block() { Expr::Block(block)}
for_loop:for_loop() { Expr::For(Box::new(for_loop))}
while_loop:while_loop() { Expr::While(Box::new(while_loop))}
func:func() { Expr::Func(Box::new(func))}
var_decl:var_decl() { Expr::VarDecl(Box::new(var_decl)) }
const_decl:const_decl() { Expr::ConstDecl(Box::new(const_decl)) }
for_loop:for_loop() { Expr::For(Arc::new(for_loop))}
while_loop:while_loop() { Expr::While(Arc::new(while_loop))}
func:func() { Expr::Func(Arc::new(func))}
var_decl:var_decl() { Expr::VarDecl(Arc::new(var_decl)) }
const_decl:const_decl() { Expr::ConstDecl(Arc::new(const_decl)) }
"(" __ tuple:(expr() **<2,> ("," __)) __ ")" { Expr::Tuple(tuple) }
"[" __ list:(expr() ** ("," __)) __ "]" { Expr::List(list) }
"(" __ v:expr() __ ")" { v }
"*" __ m:"mut"? __ v:expr() { Expr::Type(Box::new(Type::Ptr { base:v, mutable: m.is_some() })) }
"*" __ m:"mut"? __ v:expr() { Expr::Type(Arc::new(Type::Ptr { base:v, mutable: m.is_some() })) }
v:string() { Expr::String(v) }
v:number() { Expr::Number(v) }
v:ident() { Expr::Ident(v) }
@@ -113,7 +114,7 @@ peg::parser! {
rule func() -> Function
= s:position!() t:$"fn" __ "(" __ args:name_value_pairs() __ ")" __ ret:("->" __ e:expr() {e})? __ block:block()? e:position!()
{ Function { args, ret, block, text: t.parent().substr(s..e), } }
{ Function { args, ret, block: block.map(Arc::new), text: t.parent().substr(s..e), } }
rule name_value_pair() -> NameValuePair
= name:ident() __ ":" __ r#type:expr() { NameValuePair { name, r#type } }