diff --git a/assembly/src/values/mod.rs b/assembly/src/values/mod.rs index 42a8f95..e5ae463 100644 --- a/assembly/src/values/mod.rs +++ b/assembly/src/values/mod.rs @@ -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!(), } } diff --git a/compiler/src/lib.rs b/compiler/src/lib.rs index e920644..282e5e6 100644 --- a/compiler/src/lib.rs +++ b/compiler/src/lib.rs @@ -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; +type FuncQueue<'l> = VecDeque<(&'l Function<'l>, Arc, 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(()) diff --git a/compiler/src/scope.rs b/compiler/src/scope.rs index 493cacb..d127b67 100644 --- a/compiler/src/scope.rs +++ b/compiler/src/scope.rs @@ -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>>, 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!(), diff --git a/parser/src/ast.rs b/parser/src/ast.rs index 5da4315..894a282 100644 --- a/parser/src/ast.rs +++ b/parser/src/ast.rs @@ -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), - Index(Box), + Binary(Arc), + Index(Arc), Tuple(Vec), List(Vec), - Struct(Box), + Struct(Arc), #[debug("{_0:?}")] Block(Block), #[debug("{_0:?}")] - Func(Box), + Func(Arc), #[debug("{_0:?}")] - Type(Box), + Type(Arc), #[debug("{_0:?}")] - ConstDecl(Box), + ConstDecl(Arc), #[debug("{_0:?}")] - VarDecl(Box), + VarDecl(Arc), #[debug("{_0:?}")] - For(Box), + For(Arc), #[debug("{_0:?}")] - While(Box), + While(Arc), Call { - func: Box, + func: Arc, args: Vec, }, } @@ -135,7 +135,7 @@ pub struct Function { pub text: Substr, pub args: Vec, pub ret: Option, - pub block: Option, + pub block: Option>, } #[derive(Debug)] diff --git a/parser/src/parser.rs b/parser/src/parser.rs index 07f75c1..7297d72 100644 --- a/parser/src/parser.rs +++ b/parser/src/parser.rs @@ -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 } }