use crate::{CompilationContext, FuncQueue, diagnostics::*, events::Event, metadata::CodePosition}; use arcstr::{Substr, literal_substr}; use leaf_assembly::{ assembly::Assembly, functions::{ Function, ir::{Cmp, FunctionBodyBuilder, PhiValue}, }, types::{ IntT, Type, compound::{Field, FieldMap, StructT}, derivations::{PtrT, RefT}, }, values::{AnyConst, AnyValue, Int, Value, ValueFlags}, }; use leaf_parser::{ SourceCode, ast::{self, *}, }; use std::{ borrow::Cow, collections::HashMap, ops::Range, sync::{Arc, OnceLock}, }; struct ExpressionContext<'l, 'r> { decl_names: Option<&'r NamePattern>, type_hint: Option>, builder: Option<&'r mut FunctionBodyBuilder<'l>>, fn_queue: &'r mut FuncQueue<'l>, } impl<'l, 'r, 'a> ExpressionContext<'l, 'r> { pub fn with_type_hit(&'a mut self, type_hint: Option>) -> ExpressionContext<'l, 'a> { ExpressionContext { decl_names: self.decl_names, type_hint, builder: self.builder.as_mut().map(|b| &mut **b), fn_queue: self.fn_queue, } } } #[derive(Clone)] struct Variable<'l> { value: Arc>>, } #[derive(Clone)] pub struct Scope<'l> { ctx: &'l CompilationContext<'l>, assembly: &'l Assembly<'l>, source: Arc, values: HashMap>, } impl<'l> Scope<'l> { pub fn new( ctx: &'l CompilationContext<'l>, assembly: &'l Assembly<'l>, source: Arc, ) -> Self { Self { ctx, assembly, source, values: HashMap::default(), } } pub fn insert(&mut self, name: Substr, value: AnyValue<'l>) { self.values.insert( name, Variable { value: Arc::new(OnceLock::from(value)), }, ); } pub fn declare_constants(&mut self, decl: &[AstNode]) { for val in decl { for range in val.names.as_slice() { let name = self.get_text_arc(range); self.values.insert( name, Variable { value: Arc::default(), }, ); } } } pub fn define_constants( &mut self, decl: &[AstNode], fn_queue: &mut FuncQueue<'l>, ) -> Result<(), Diagnostic> { for val in decl { let expr = self.compile_expression( &val.value, &mut ExpressionContext { decl_names: Some(&val.names), builder: None, type_hint: None, fn_queue, }, )?; match &*val.names { NamePattern::Single(ident) => { let name = self.get_text(ident).to_string(); self.values .get_mut(&*name) .unwrap() .value .set(expr) .unwrap(); self.ctx.emit_event(Event::Definition { value: expr, position: CodePosition::new(self.source.clone(), ident.clone()), }); } NamePattern::Tuple(_) => todo!(), NamePattern::List(_) => todo!(), } } Ok(()) } pub fn compile_function( &mut self, func: &'l Function<'l>, block: &Arc>, fn_queue: &mut FuncQueue<'l>, ) -> Result<(), Diagnostic> { let mut builder = func.create_body().unwrap(); let mut ret = self.compile_block( block, &mut ExpressionContext { builder: Some(&mut builder), decl_names: None, type_hint: Some(func.ty.ret_t), fn_queue: fn_queue, }, )?; if !builder.current_block().has_termination() { match func.ty.ret_t { Type::Void => { builder.ret(None).unwrap(); } _ => { if ret.is_lvalue() { ret = builder.load(ret).unwrap(); } self.assert_ty_eq( &ret, &AstNode { range: block.range.clone(), node: Expr::Block(block.clone()), }, &func.ty.ret_t, )?; builder.ret(Some(ret)).unwrap(); } }; } builder.build().unwrap(); Ok(()) } fn compile_expression( &mut self, expr: &AstNode, ctx: &mut ExpressionContext<'l, '_>, ) -> Result, Diagnostic> { match &**expr { Expr::Ident(range) => { let name = self.get_text(range); match self.values.get(&*name) { None => Err(Diagnostic { kind: Kind::Error, code: Code::SymbolNotFound, message: format!("Symbol `{name}` does not exist in the current scope."), position: CodePosition::new(self.source.clone(), range.clone()), cause: None, }), Some(Variable { value, .. }) => match value.get() { None => Err(Diagnostic { kind: Kind::Error, code: Code::UninitializedSymbol, message: format!("Symbol `{name}` is not initialized at this time."), position: CodePosition::new(self.source.clone(), range.clone()), cause: None, }), Some(value) => { self.ctx.emit_event(Event::Symbol { value: *value, position: CodePosition::new(self.source.clone(), range.clone()), }); Ok(*value) } }, } } Expr::Func(func) => self .make_function(func, ctx) .map(|f| AnyValue::Constant(AnyConst::Function(f))) .map_err(|err| Diagnostic { kind: Kind::Error, code: Code::FunctionCompilationFailed, message: "Could not compile function.".to_string(), position: CodePosition::new(self.source.clone(), expr.range.clone()), cause: Some(Box::new(err)), }), Expr::ConstDecl(decl) => self.compile_decl(&decl.names, &decl.value, false, ctx), Expr::VarDecl(decl) => self.compile_decl(&decl.names, &decl.value, true, ctx), Expr::Number(n) => { macro_rules! parse_number { ($ty: ty, $id: ident) => {{ let text = self.get_text(&n.number); match text.split_at_checked(2) { Some(("0b", value)) => <$ty>::from_str_radix(value, 2), Some(("0x", value)) => <$ty>::from_str_radix(value, 16), _ => text.parse::<$ty>(), } .map(|v| AnyValue::Constant(AnyConst::Int(Int::$id(v)))) .map_err(|_| Diagnostic { kind: Kind::Error, code: Code::InvalidInteger, message: format!("`{}` is not a valid integer.", text), position: CodePosition::new(self.source.clone(), n.number.clone()), cause: None, }) }}; } let ty = n.ty.as_ref().map(|v| self.get_text(v)); let value = match ty.as_ref().map(|ty| &**ty) { None if ctx.type_hint == Some(Type::I8) => parse_number!(i8, I8), None if ctx.type_hint == Some(Type::I16) => parse_number!(i16, I16), None if ctx.type_hint == Some(Type::I32) => parse_number!(i32, I32), None if ctx.type_hint == Some(Type::I64) => parse_number!(i64, I64), None if ctx.type_hint == Some(Type::I128) => parse_number!(i128, I128), None if ctx.type_hint == Some(Type::ISIZE) => parse_number!(i64, ISize), None if ctx.type_hint == Some(Type::U8) => parse_number!(u8, U8), None if ctx.type_hint == Some(Type::U16) => parse_number!(u16, U16), None if ctx.type_hint == Some(Type::U32) => parse_number!(u32, U32), None if ctx.type_hint == Some(Type::U64) => parse_number!(u64, U64), None if ctx.type_hint == Some(Type::U128) => parse_number!(u128, U128), None if ctx.type_hint == Some(Type::USIZE) => parse_number!(u64, USize), None => parse_number!(i64, ISize), Some("i8") => parse_number!(i8, I8), Some("i16") => parse_number!(i16, I16), Some("i32") => parse_number!(i32, I32), Some("i64") => parse_number!(i64, I64), Some("i128") => parse_number!(i128, I128), Some("isize") => parse_number!(i64, ISize), Some("u8") => parse_number!(u8, U8), Some("u16") => parse_number!(u16, U16), Some("u32") => parse_number!(u32, U32), Some("u64") => parse_number!(u64, U64), Some("u128") => parse_number!(u128, U128), Some("usize") => parse_number!(u64, USize), Some(ty) => Err(Diagnostic { kind: Kind::Error, code: Code::InvalidIntegerType, message: format!("`{ty}` is not a valid integer type."), position: CodePosition::new(self.source.clone(), n.ty.clone().unwrap()), cause: None, }), }?; self.ctx.emit_event(Event::Symbol { value: value, position: CodePosition::new(self.source.clone(), n.number.clone()), }); Ok(value) } Expr::Access { value: value_expr, operator, field, } => { let value = self.compile_expression(value_expr, ctx)?; let name = self.get_text(field); if let Some(value) = value.get_associated_value(&*name) { return Ok(value); } let value = 'value: { match value.ty() { Type::Struct(StructT { fields, .. }) => { if let Some(fields) = fields.get() { if let Some(field) = fields.get(&*name) { let builder = ctx.builder.as_mut().unwrap(); break 'value Some( builder .get_element_value(value, field.name.as_any_value()) .unwrap() .as_any_value(), ); } } None } Type::Ptr(PtrT { base: Type::Struct(StructT { fields, .. }), .. }) => { if let Some(fields) = fields.get() { if let Some(field) = fields.get(&*name) { let builder = ctx.builder.as_mut().unwrap(); let inst = builder .get_element_ptr(value, field.name.as_any_value()) .unwrap() .as_any_value(); unsafe { if let AnyValue::Instruction(inst) = inst { inst.edit_flags(|f| f | ValueFlags::LValue); } } break 'value Some(inst); } } None } _ => None, } }; if let Some(value) = value { self.ctx.emit_event(Event::Symbol { value: value, position: CodePosition::new(self.source.clone(), field.clone()), }); return Ok(value); } return Err(Diagnostic { kind: Kind::Error, code: Code::FieldNotFound, message: format!("Value does not contain field `{name}`."), position: CodePosition::new(self.source.clone(), field.clone()), cause: None, }); } Expr::Binary { lhs: lhs_expr, rhs: rhs_expr, operator, } => { let mut lhs = self.compile_expression(lhs_expr, ctx)?; let type_hint = if lhs.is_lvalue() { let Type::Ptr(PtrT { base, .. }) = lhs.ty() else { unreachable!(); }; if !matches!(operator.node, BinaryOperator::Assign) { lhs = ctx.builder.as_mut().unwrap().load(lhs).unwrap(); } *base } else { lhs.ty() }; let mut rhs = self.compile_expression(rhs_expr, &mut ctx.with_type_hit(Some(type_hint)))?; if rhs.is_lvalue() { rhs = ctx.builder.as_mut().unwrap().load(rhs).unwrap(); } let builder = ctx.builder.as_mut().unwrap(); macro_rules! int_bin_ops { ( const exact $([$($ty:ident),*] $op:pat => |$a:ident, $b:ident| $expr:expr,)* ) => { match operator.node { $( $op => match (lhs, rhs) { $( ( AnyValue::Constant(AnyConst::Int(Int::$ty($a))), AnyValue::Constant(AnyConst::Int(Int::$ty($b))), ) => return Ok(AnyValue::Constant(AnyConst::Int(Int::$ty($expr)))), )* _ => {} } )* _ => {} } }; ( const auto $([$($ty:ident),*] $op:pat => |$a:ident, $b:ident| $expr:expr,)* ) => { match operator.node { $( $op => match (lhs, rhs) { $( ( AnyValue::Constant(AnyConst::Int(Int::$ty($a))), AnyValue::Constant(AnyConst::Int(Int::$ty($b))), ) => return Ok($expr.as_any_value()), )* _ => {} } )* _ => {} } }; } if lhs.is_const() && rhs.is_const() { int_bin_ops! { const exact [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOperator::Add => |a, b| a + b, [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOperator::Sub => |a, b| a - b, [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOperator::Mul => |a, b| a - b, [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOperator::Div => |a, b| a - b, [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOperator::Mod => |a, b| a - b, } int_bin_ops! { const auto [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOperator::Eq => |a, b| a == b, [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOperator::Ne => |a, b| a == b, [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOperator::Lt => |a, b| a == b, [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOperator::Gt => |a, b| a == b, [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOperator::Le => |a, b| a == b, [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOperator::Ge => |a, b| a == b, } } let (lhs_ty, rhs_ty) = (lhs.ty(), rhs.ty()); if match (lhs_ty, rhs_ty) { (Type::Int(a_ty), Type::Int(b_ty)) => a_ty == b_ty, _ => false, } { return Ok(match operator.node { BinaryOperator::Add => builder.add(lhs, rhs).unwrap(), BinaryOperator::Sub => builder.sub(lhs, rhs).unwrap(), BinaryOperator::Mul => builder.mul(lhs, rhs).unwrap(), BinaryOperator::Div => builder.div(lhs, rhs).unwrap(), BinaryOperator::Mod => builder.modulo(lhs, rhs).unwrap(), BinaryOperator::Eq => builder.cmp(lhs, rhs, Cmp::Eq).unwrap(), BinaryOperator::Ne => builder.cmp(lhs, rhs, Cmp::Ne).unwrap(), BinaryOperator::Lt => builder.cmp(lhs, rhs, Cmp::Lt).unwrap(), BinaryOperator::Gt => builder.cmp(lhs, rhs, Cmp::Gt).unwrap(), BinaryOperator::Le => builder.cmp(lhs, rhs, Cmp::Le).unwrap(), BinaryOperator::Ge => builder.cmp(lhs, rhs, Cmp::Ge).unwrap(), _ => todo!("{lhs:?} {:?} {rhs:?}", operator.node), }); } if match (lhs_ty, rhs_ty) { (Type::Ptr(a_ty), Type::Ptr(b_ty)) => a_ty == b_ty, _ => false, } { let lhs = builder.ptr_to_int(lhs, IntT::USIZE).unwrap(); let rhs = builder.ptr_to_int(rhs, IntT::USIZE).unwrap(); return Ok(match operator.node { BinaryOperator::Eq => builder.cmp(lhs, rhs, Cmp::Eq).unwrap(), BinaryOperator::Ne => builder.cmp(lhs, rhs, Cmp::Ne).unwrap(), BinaryOperator::Lt => builder.cmp(lhs, rhs, Cmp::Lt).unwrap(), BinaryOperator::Gt => builder.cmp(lhs, rhs, Cmp::Gt).unwrap(), BinaryOperator::Le => builder.cmp(lhs, rhs, Cmp::Le).unwrap(), BinaryOperator::Ge => builder.cmp(lhs, rhs, Cmp::Ge).unwrap(), _ => todo!("{lhs:?} {:?} {rhs:?}", operator.node), }); } match (lhs_ty, rhs_ty, operator.node) { (Type::Ptr(ptr @ PtrT { base, .. }), Type::USIZE, BinaryOperator::Add) => { let mut value = builder.ptr_to_int(lhs, IntT::USIZE).unwrap(); let add = builder.mul(rhs, AnyConst::SizeOf(*base).into()).unwrap(); value = builder.add(value, add).unwrap(); value = builder.int_to_ptr(value, ptr).unwrap(); Ok(value) } (Type::Ptr(PtrT { base, .. }), ty, BinaryOperator::Assign) => match *base == ty { true => Ok(builder.store(lhs, rhs).unwrap()), false => Err(Diagnostic { kind: Kind::Error, code: Code::InvalidType, message: format!( "Cannot assign a value of type `{ty}` to a value of type `{base}`." ), position: CodePosition::new(self.source.clone(), expr.range.clone()), cause: None, }), }, (src_ty, Type::Type, BinaryOperator::Cast) => { let dst_ty = self.assert_ty(rhs, rhs_expr).map_err(|err| Diagnostic { kind: Kind::Error, code: Code::InvalidCast, message: "Cannot perform cast.".to_string(), position: CodePosition::new(self.source.clone(), expr.range.clone()), cause: Some(Box::new(err)), })?; if src_ty == dst_ty { return Ok(lhs); } match (src_ty, dst_ty) { (Type::Int(src_ty), Type::Int(dst_ty)) => { if dst_ty.precision < src_ty.precision { return Ok(builder.trunc(lhs, dst_ty).unwrap()); } todo!("{src_ty} as {dst_ty}"); } (Type::Int(_), Type::Ptr(dst_ty)) => { return Ok(builder.int_to_ptr(lhs, dst_ty).unwrap()); } (Type::Ptr(_), dst_ty @ Type::Ptr(_)) => unsafe { return Ok(builder.reinterpret(lhs, dst_ty, lhs.flags()).unwrap()); }, _ => todo!("{src_ty} as {dst_ty}"), } } (a, b, _) => todo!( "{a} {op:?} {b} | {lhs:?} {op:?} {rhs:?}", op = operator.node, ), } } Expr::If(expr) => self.compile_if(expr, ctx), Expr::While(expr) => { let While { cond, block, .. } = &**expr; let mut builder = ctx.builder.as_mut().unwrap(); let cond_block = builder.create_block(); let exec_block = builder.create_block(); let exit_block = builder.create_block(); builder.jump(cond_block).unwrap(); builder.set_current_block(cond_block); let condition = self.compile_expression(cond, ctx)?; builder = ctx.builder.as_mut().unwrap(); builder.branch(condition, exec_block, exit_block).unwrap(); builder.set_current_block(exec_block); let ret = self.compile_block(block, ctx)?; builder = ctx.builder.as_mut().unwrap(); builder.jump(cond_block).unwrap(); builder.set_current_block(exit_block); Ok(ret) } Expr::Call { func, args: args_exprs, } => { let func = match self.compile_expression(func, ctx)? { AnyValue::Constant(AnyConst::Function(func)) => func, _ => { return Err(Diagnostic { kind: Kind::Error, code: Code::NotAFunction, message: "Value is not a function".into(), position: CodePosition::new(self.source.clone(), func.range.clone()), cause: None, }); } }; let mut arg_ty = func.ty.par_t.iter().cloned(); let mut args = Vec::with_capacity(args_exprs.len()); for expr in args_exprs { let mut arg = self.compile_expression(expr, &mut ctx.with_type_hit(arg_ty.next()))?; if arg.is_lvalue() { arg = ctx.builder.as_mut().unwrap().load(arg).unwrap(); } args.push(arg); } let builder = ctx.builder.as_mut().unwrap(); Ok(builder.call(func, args).unwrap()) } Expr::Ptr { mutable, base, .. } => match self.compile_expression(base, ctx)? { AnyValue::Constant(AnyConst::Type(ty)) => { Ok(AnyConst::Type(Type::Ptr(ty.make_ptr(mutable.is_some()))).into()) } AnyValue::Instruction(inst) if inst.is_lvalue() => { let Type::Ptr(PtrT { base, mutable: is_mut, .. }) = inst.ty() else { unreachable!() }; if mutable.is_some() && !*is_mut { return Err(Diagnostic { kind: Kind::Error, code: Code::NotAFunction, message: "Cannot obtain a mutable pointer to an immutable value." .into(), position: CodePosition::new(self.source.clone(), expr.range.clone()), cause: None, }); } let mut flags = inst.flags(); let builder = ctx.builder.as_mut().unwrap(); flags.remove(ValueFlags::Mutable | ValueFlags::Volatile | ValueFlags::LValue); let ptr = Type::Ptr(base.make_ptr(mutable.is_some())); unsafe { Ok(builder .reinterpret(AnyValue::Instruction(inst), ptr, flags) .unwrap()) } } v => todo!("{v:?}"), }, Expr::Struct { fields, .. } => { let name = match &ctx.decl_names { Some(NamePattern::Single(func_name)) => &*self.get_text(func_name), _ => "", }; let struct_ty = self.assembly.create_struct(name); let mut scope = self.clone(); let mut expr_ctx = ExpressionContext { builder: None, decl_names: None, type_hint: Some(Type::Type), fn_queue: ctx.fn_queue, }; let ctx = self.assembly.ctx(); scope.insert(literal_substr!("Self"), struct_ty.as_any_value()); let mut field_map = FieldMap::default(); for AstNode { range, node: ast::Field { name, ty: ty_expr, public, mutable, }, } in fields { let ty = scope.compile_expression(ty_expr, &mut expr_ctx)?; let name = ctx.intern_str(&self.get_text(name)); field_map.insert( name, Field { name, ty: self.assert_ty(ty, ty_expr)?, public: public.is_some(), mutable: mutable.is_some(), }, ); } struct_ty.fields.set(field_map).unwrap(); Ok(struct_ty.as_any_value()) } Expr::List(expr) => { let mut expr = expr.iter(); let mut values = Vec::with_capacity(expr.len()); match expr.next() { None => return Ok(AnyValue::Constant(AnyConst::Array(&[]))), Some(expr) => { let value = self.compile_expression(expr, ctx)?; // TODO Check if it matches the ctx type hint values.push(value); } }; let element_ty = values[0].ty(); for expr in expr { let value = self.compile_expression(expr, ctx)?; self.assert_ty_eq(&value, expr, &element_ty)?; values.push(value); } if values.iter().all(|v| matches!(v, AnyValue::Constant(_))) { let alloc = self.assembly.ctx().alloc(); return Ok(AnyValue::Constant(AnyConst::Array(alloc.alloc_slice( values.into_iter().map(|v| match v { AnyValue::Constant(c) => c, _ => unreachable!(), }), )))); } todo!() } Expr::Deref { value: expr, .. } => { let value = self.compile_expression(expr, ctx)?; let builder = ctx.builder.as_mut().unwrap(); let ty = value.ty(); match value.is_lvalue() { false => unsafe { if !matches!(ty, Type::Ptr(_)) { return Err(Diagnostic { kind: Kind::Error, code: Code::CannotDereference, message: format!("Cannot dereference a value of type `{ty}`."), position: CodePosition::new( self.source.clone(), expr.range.clone(), ), cause: None, }); } Ok(builder .reinterpret(value, value.ty(), value.flags() | ValueFlags::LValue) .unwrap()) }, true => unsafe { if !matches!( ty, Type::Ptr(PtrT { base: Type::Ptr(_), .. }) ) { let Type::Ptr(PtrT { base, .. }) = ty else { unreachable!() }; return Err(Diagnostic { kind: Kind::Error, code: Code::CannotDereference, message: format!("Cannot dereference a value of type `{base}`."), position: CodePosition::new( self.source.clone(), expr.range.clone(), ), cause: None, }); } let AnyValue::Instruction(value) = builder.load(value).unwrap() else { unreachable!() }; value.edit_flags(|v| v | ValueFlags::LValue); Ok(AnyValue::Instruction(value)) }, _ => unimplemented!("{}", value.is_lvalue()), } } Expr::Index { value, index: index_expr, } if index_expr.len() == 1 => { let mut value = self.compile_expression(value, ctx)?; let mut index = self.compile_expression(&index_expr[0], ctx)?; let builder = ctx.builder.as_mut().unwrap(); if index.is_lvalue() { index = builder.load(index).unwrap(); } // TODO Add support for custom indexing operations if index.ty() != Type::USIZE { return Err(Diagnostic { kind: Kind::Error, code: Code::InvalidType, message: "Value is not of type `usize`".into(), position: CodePosition::new( self.source.clone(), index_expr[0].range.clone(), ), cause: None, }); } // TODO This is probably wrong, make it better. while value.is_lvalue() && !matches!( value.ty(), Type::Ptr(PtrT { base: Type::Array(_), .. }) | Type::Ref(RefT { base: Type::Array(_), .. }) ) { value = builder.load(value).unwrap(); } if value.is_lvalue() { let gep = builder.get_element_ptr(value, index).unwrap(); return Ok(gep); } todo!("{:#?}", value.ty()); } Expr::StructCtor { ty: ctor_ty, values: ctor_values, } => { let ty = match ctor_ty { Some(ty) => self.compile_expression(ty, ctx)?, None => match ctx.type_hint { Some(ty) => AnyValue::Constant(AnyConst::Type(ty)), None => { return Err(Diagnostic { kind: Kind::Error, code: Code::CannotInferType, message: "Type cannot be inferred.".into(), position: CodePosition::new( self.source.clone(), expr.range.clone(), ), cause: None, }); } }, }; let AnyValue::Constant(AnyConst::Type(Type::Struct( struct_ty @ StructT { fields, .. }, ))) = ty else { return Err(Diagnostic { kind: Kind::Error, code: Code::NotAStruct, message: format!("Expected struct type, got value of type `{}`.", ty.ty()), position: CodePosition::new( self.source.clone(), match ctor_ty { None => expr.range.clone(), Some(ty) => ty.range.clone(), }, ), cause: None, }); }; let mut non_const = false; let fields = fields.get().unwrap(); let mut values = Vec::with_capacity(fields.len()); for Field { name: fld_name, ty, .. } in fields.values() { let Some(name_value_pair) = ctor_values.iter().find_map(|v| { let name = self.get_text(&v.name); match name == *fld_name { true => Some(&v.node), false => None, } }) else { return Err(Diagnostic { kind: Kind::Error, code: Code::UninitializedField, message: format!("Uninitialized field `{fld_name}`."), position: CodePosition::new(self.source.clone(), expr.range.clone()), cause: None, }); }; let mut ctx = ctx.with_type_hit(Some(*ty)); let value = self.compile_expression(&name_value_pair.value, &mut ctx)?; self.assert_ty_eq(&value, &name_value_pair.value, ty)?; non_const |= !value.flags().contains(ValueFlags::Const); values.push(value); } Ok(match non_const { true => { let builder = ctx.builder.as_mut().unwrap(); let values = self.assembly.ctx().alloc().alloc_slice(values.into_iter()); builder.make_struct(struct_ty, values).unwrap() } false => AnyValue::Constant(AnyConst::Struct( struct_ty, self.assembly .ctx() .alloc() .alloc_slice(values.into_iter().map(|v| { let AnyValue::Constant(c) = v else { unreachable!() }; c })), )), }) } _ => todo!("{expr:#?}"), } } fn make_function( &mut self, ast: &Arc>, ctx: &mut ExpressionContext<'l, '_>, ) -> Result<&'l Function<'l>, Diagnostic> { let ret_ty = match ast.ret.as_ref() { None => AnyValue::Constant(AnyConst::Type(Type::Void)), Some(ty) => self.compile_expression(ty, ctx)?, }; let ast_as_expr = AstNode { range: ast.range.clone(), node: Expr::Func(ast.clone()), }; let ret_ty = self.assert_ty(ret_ty, ast.ret.as_ref().unwrap_or(&ast_as_expr))?; let mut par_ty = Vec::with_capacity(ast.args.len()); for arg in &ast.args { let ty = self.compile_expression(&arg.value, ctx)?; let ty = self.assert_ty(ty, &arg.value)?; par_ty.push(ty); } let fn_ty = ret_ty.make_fn(par_ty); let name = match &ctx.decl_names { Some(NamePattern::Single(func_name)) => &*self.get_text(func_name), _ => "", }; let func = self.assembly.create_function(fn_ty, name); let Some(block) = &ast.block else { return Ok(func); }; let mut scope = self.clone(); for (i, arg) in ast.args.iter().enumerate() { let name = self.get_text_arc(&arg.name); scope.insert(name, AnyValue::Parameter(i, func)); } ctx.fn_queue.push_back((func, block.clone(), scope)); Ok(func) } fn compile_decl( &mut self, names: &NamePattern, value: &AstNode, mutable: bool, ctx: &mut ExpressionContext<'l, '_>, ) -> Result, Diagnostic> { let mut sub_ctx = ExpressionContext { decl_names: Some(names), builder: ctx.builder.as_deref_mut(), type_hint: None, //TODO fn_queue: ctx.fn_queue, }; let mut value = self.compile_expression(value, &mut sub_ctx)?; let builder = sub_ctx.builder.unwrap(); if value.is_lvalue() { value = builder.load(value).unwrap(); } if mutable { let variable = builder.stack_alloc(value.ty()).unwrap(); builder.store(variable, value).unwrap(); value = variable; } match names { NamePattern::Single(ident) => { let name = self.get_text_arc(ident); self.values.insert( name, Variable { value: Arc::new(OnceLock::from(value)), }, ); self.ctx.emit_event(Event::Definition { value: value, position: CodePosition::new(self.source.clone(), ident.clone()), }); } NamePattern::Tuple(_) => todo!(), NamePattern::List(_) => todo!(), } Ok(AnyConst::Void.into()) } fn compile_block( &mut self, block: &Block, ctx: &mut ExpressionContext<'l, '_>, ) -> Result, Diagnostic> { let mut scope = self.clone(); let builder = ctx.builder.as_mut().unwrap(); let mut last_expr = None; for (i, expr) in block.0.iter().enumerate() { let mut ctx = ExpressionContext { builder: Some(builder), decl_names: None, type_hint: match i == block.0.len() - 1 { true => ctx.type_hint, false => None, }, fn_queue: ctx.fn_queue, }; last_expr = Some(scope.compile_expression(expr, &mut ctx)?); } Ok(last_expr.unwrap_or(AnyValue::Constant(AnyConst::Void))) } fn compile_if( &mut self, expr: &If, ctx: &mut ExpressionContext<'l, '_>, ) -> Result, Diagnostic> { let If { cond, block, else_, .. } = expr; let condition = self.compile_expression(cond, ctx)?; self.assert_ty_eq(&condition, cond, &Type::Bool)?; let builder = ctx.builder.as_mut().unwrap(); let then_block = builder.create_block(); let else_block = builder.create_block(); builder.branch(condition, then_block, else_block).unwrap(); builder.set_current_block(then_block); let then_val = self.compile_block(block, ctx)?; let builder = ctx.builder.as_mut().unwrap(); let else_ = match else_ { None => { builder.jump(else_block).unwrap(); builder.set_current_block(else_block); return Ok(then_val); } Some(else_) => else_, }; let continue_block = builder.create_block(); builder.jump(continue_block).unwrap(); builder.set_current_block(else_block); let else_val = match &**else_ { Else::Block { expr, .. } => self.compile_block(expr, ctx)?, Else::If { expr, .. } => self.compile_if(expr, ctx)?, }; let builder = ctx.builder.as_mut().unwrap(); builder.jump(continue_block).unwrap(); builder.set_current_block(continue_block); if then_val.ty() != else_val.ty() { todo!() } Ok(builder .phi( [ PhiValue { value: then_val, block: then_block.id, }, PhiValue { value: else_val, block: else_block.id, }, ] .into_iter(), ) .unwrap() .into()) } fn assert_ty( &self, val: AnyValue<'l>, value_expr: &AstNode, ) -> Result, Diagnostic> { match val { AnyValue::Constant(AnyConst::Type(ty)) => Ok(ty), _ => Err(Diagnostic { kind: Kind::Error, code: Code::NotAType, message: "Value is not a type.".to_string(), position: CodePosition::new(self.source.clone(), value_expr.range.clone()), cause: None, }), } } pub fn assert_ty_eq( &self, value: &AnyValue<'l>, value_expr: &AstNode, expected: &Type<'l>, ) -> Result, Diagnostic> { let value_ty = value.ty(); match value_ty == *expected { true => Ok(value_ty), false => { return Err(Diagnostic { kind: Kind::Error, code: Code::InvalidType, message: format!("Expected value of type `{expected}`, found `{value_ty}`."), position: CodePosition::new(self.source.clone(), value_expr.range.clone()), cause: None, }); } } } fn get_text(&self, range: &Range) -> Cow<'_, str> { match &self.source.text { leaf_parser::Text::ArcStr(arc_str, _) => { Cow::Borrowed(&arc_str.as_str()[range.clone()]) } } } fn get_text_arc(&self, range: &Range) -> Substr { match &self.source.text { leaf_parser::Text::ArcStr(arc_str, _) => arc_str.substr(range.clone()), } } }