Incremental function compilation
This commit is contained in:
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 } }
|
||||
|
||||
Reference in New Issue
Block a user