diff --git a/lib/edlang_codegen_llvm/src/codegen.rs b/lib/edlang_codegen_llvm/src/codegen.rs index f4d433412..9170d4ad3 100644 --- a/lib/edlang_codegen_llvm/src/codegen.rs +++ b/lib/edlang_codegen_llvm/src/codegen.rs @@ -1160,6 +1160,21 @@ fn compile_basic_type<'ctx>( .ptr_sized_int_type(&ctx.target_data, None) .ptr_type(AddressSpace::default()) .as_basic_type_enum(), + ir::TypeKind::Struct(id) => { + let body = ctx.ctx.program.structs.get(id).unwrap(); + + let mut fields = Vec::new(); + + for field in &body.variants { + let ty = compile_basic_type(ctx, &field.ty); + fields.push(ty); + } + + ctx.ctx + .context + .struct_type(&fields, false) + .as_basic_type_enum() + } } } @@ -1277,5 +1292,40 @@ fn compile_debug_type<'ctx>(ctx: &ModuleCompileCtx<'ctx, '_>, ty: &ir::TypeInfo) .di_builder .create_reference_type(compile_debug_type(ctx, inner), 0x10) .as_type(), + ir::TypeKind::Struct(id) => { + let body = ctx.ctx.program.structs.get(id).unwrap(); + + let mut fields = Vec::new(); + + for field in &body.variants { + let ty = compile_debug_type(ctx, &field.ty); + fields.push(ty); + } + + let (_, line, _column) = ctx + .ctx + .session + .source + .get_offset_line(body.span.lo) + .unwrap(); + let real_ty = compile_basic_type(ctx, ty); + + ctx.di_builder + .create_struct_type( + ctx.di_namespace, + &body.name, + ctx.di_unit.get_file(), + (line + 1).try_into().unwrap(), + ctx.target_data.get_bit_size(&real_ty), + ctx.target_data.get_abi_alignment(&real_ty), + 0, + None, + &fields, + 0, + None, + &body.name, + ) + .as_type() + } } } diff --git a/lib/edlang_ir/src/lib.rs b/lib/edlang_ir/src/lib.rs index 78adedc7c..49731e845 100644 --- a/lib/edlang_ir/src/lib.rs +++ b/lib/edlang_ir/src/lib.rs @@ -26,6 +26,7 @@ pub struct ProgramBody { pub modules: BTreeMap, /// This stores all the functions from all modules pub functions: BTreeMap, + pub structs: BTreeMap, /// The function signatures. pub function_signatures: BTreeMap, TypeInfo)>, } @@ -87,6 +88,23 @@ impl Body { } } +#[derive(Debug, Clone)] +pub struct AdtBody { + pub def_id: DefId, + pub is_pub: bool, + pub name: String, + pub variants: Vec, + pub span: Span, +} + +/// struct field or enum variant +#[derive(Debug, Clone)] +pub struct AdtVariant { + pub def_id: DefId, + pub name: String, + pub ty: TypeInfo, +} + #[derive(Debug, Clone)] pub struct DebugInfo { pub id: usize, @@ -205,6 +223,7 @@ pub enum TypeKind { FnDef(DefId, Vec), // The vec are generic types, not arg types Ptr(Box), Ref(bool, Box), + Struct(DefId), } impl TypeKind { @@ -241,6 +260,7 @@ impl TypeKind { TypeKind::FnDef(_, _) => unreachable!(), TypeKind::Ptr(_pointee) => todo!(), TypeKind::Ref(_, inner) => inner.kind.get_falsy_value(), + TypeKind::Struct(_) => todo!(), } } } diff --git a/lib/edlang_lowering/src/lib.rs b/lib/edlang_lowering/src/lib.rs index 353a584f7..73dff9bb7 100644 --- a/lib/edlang_lowering/src/lib.rs +++ b/lib/edlang_lowering/src/lib.rs @@ -5,8 +5,8 @@ use common::{BodyBuilder, BuildCtx}; use edlang_ast as ast; use edlang_ir as ir; use ir::{ - BasicBlock, Body, DefId, Local, LocalKind, Operand, Place, PlaceElem, ProgramBody, RValue, - Statement, StatementKind, SwitchTarget, Terminator, TypeInfo, TypeKind, + AdtBody, AdtVariant, BasicBlock, Body, DefId, Local, LocalKind, Operand, Place, PlaceElem, + ProgramBody, RValue, Statement, StatementKind, SwitchTarget, Terminator, TypeInfo, TypeKind, }; use tracing::trace; @@ -40,6 +40,18 @@ pub fn lower_modules(modules: &[ast::Module]) -> ProgramBody { } fn lower_module(mut ctx: BuildCtx, module: &ast::Module, id: DefId) -> BuildCtx { + // lower first structs, constants, types + for content in &module.contents { + match content { + ModuleStatement::Constant(_) => todo!(), + ModuleStatement::Struct(info) => { + ctx = lower_struct(ctx, info, id); + } + // ModuleStatement::Type(_) => todo!(), + _ => {} + } + } + let body = ctx.body.modules.get(&id).unwrap(); // fill fn sigs @@ -51,12 +63,12 @@ fn lower_module(mut ctx: BuildCtx, module: &ast::Module, id: DefId) -> BuildCtx let ret_type; for arg in &fn_def.params { - let ty = lower_type(&ctx, &arg.arg_type); + let ty = lower_type(&ctx, &arg.arg_type, id); args.push(ty); } if let Some(ty) = &fn_def.return_type { - ret_type = lower_type(&ctx, ty); + ret_type = lower_type(&ctx, ty, id); } else { ret_type = TypeInfo { span: None, @@ -70,19 +82,43 @@ fn lower_module(mut ctx: BuildCtx, module: &ast::Module, id: DefId) -> BuildCtx for content in &module.contents { match content { - ModuleStatement::Constant(_) => todo!(), ModuleStatement::Function(fn_def) => { ctx = lower_function(ctx, fn_def, id); } - ModuleStatement::Struct(_) => todo!(), // ModuleStatement::Type(_) => todo!(), ModuleStatement::Module(_mod_def) => {} + _ => {} } } ctx } +fn lower_struct(mut ctx: BuildCtx, info: &ast::Struct, module_id: DefId) -> BuildCtx { + let mut body = AdtBody { + def_id: { + let body = ctx.body.modules.get(&module_id).unwrap(); + *body.symbols.structs.get(&info.name.name).unwrap() + }, + is_pub: true, // todo struct pub + name: info.name.name.clone(), + variants: Vec::new(), + span: info.span, + }; + + for field in &info.fields { + let variant = AdtVariant { + def_id: ctx.gen.next_defid(), + name: field.name.name.clone(), + ty: lower_type(&ctx, &field.r#type, module_id), + }; + body.variants.push(variant); + } + + ctx.body.structs.insert(body.def_id, body); + ctx +} + fn lower_function(ctx: BuildCtx, func: &ast::Function, module_id: DefId) -> BuildCtx { let mut builder = BodyBuilder { body: Body { @@ -141,7 +177,7 @@ fn lower_function(ctx: BuildCtx, func: &ast::Function, module_id: DefId) -> Buil // Get all user defined locals for stmt in &func.body.body { if let ast::Statement::Let(info) = stmt { - let ty = lower_type(&builder.ctx, &info.r#type); + let ty = lower_type(&builder.ctx, &info.r#type, builder.local_module); builder .name_to_local .insert(info.name.name.clone(), builder.body.locals.len()); @@ -360,7 +396,7 @@ fn lower_if_stmt(builder: &mut BodyBuilder, info: &ast::IfStmt, ret_type: &TypeK } fn lower_let(builder: &mut BodyBuilder, info: &ast::LetStmt) { - let ty = lower_type(&builder.ctx, &info.r#type); + let ty = lower_type(&builder.ctx, &info.r#type, builder.local_module); let (rvalue, _ty) = lower_expr(builder, &info.value, Some(&ty.kind)); let local_idx = builder.name_to_local.get(&info.name.name).copied().unwrap(); builder.statements.push(Statement { @@ -665,10 +701,13 @@ fn lower_fn_call(builder: &mut BodyBuilder, info: &ast::FnCallExpr) -> (Operand, .get(&fn_id) .unwrap(); - let args: Vec<_> = args.iter().map(|x| lower_type(&builder.ctx, x)).collect(); + let args: Vec<_> = args + .iter() + .map(|x| lower_type(&builder.ctx, x, builder.local_module)) + .collect(); let ret = ret .as_ref() - .map(|x| lower_type(&builder.ctx, x)) + .map(|x| lower_type(&builder.ctx, x, builder.local_module)) .unwrap_or(TypeInfo { span: None, kind: TypeKind::Unit, @@ -904,7 +943,7 @@ fn lower_path(builder: &mut BodyBuilder, info: &ast::PathExpr) -> (ir::Place, Ty } #[allow(clippy::only_used_in_recursion)] -pub fn lower_type(ctx: &BuildCtx, t: &ast::Type) -> ir::TypeInfo { +pub fn lower_type(ctx: &BuildCtx, t: &ast::Type, module_id: DefId) -> ir::TypeInfo { let inner_ty = match t.name.name.as_str() { "()" => ir::TypeInfo { span: Some(t.span), @@ -960,9 +999,24 @@ pub fn lower_type(ctx: &BuildCtx, t: &ast::Type) -> ir::TypeInfo { }, "ptr" => ir::TypeInfo { span: Some(t.span), - kind: ir::TypeKind::Ptr(Box::new(lower_type(ctx, t.generics.first().unwrap()))), + kind: ir::TypeKind::Ptr(Box::new(lower_type( + ctx, + t.generics.first().unwrap(), + module_id, + ))), }, - x => todo!("{:?}", x), + other => { + let module = ctx.body.modules.get(&module_id).expect("module not found"); + if let Some(struct_id) = module.symbols.structs.get(other) { + let struct_body = ctx.body.structs.get(struct_id).unwrap(); + ir::TypeInfo { + span: Some(struct_body.span), + kind: TypeKind::Struct(*struct_id), + } + } else { + todo!("{:?}", other) + } + } }; match t.is_ref {