diff --git a/edb/src/main.rs b/edb/src/main.rs index b0c274c0a..902d7f3db 100644 --- a/edb/src/main.rs +++ b/edb/src/main.rs @@ -31,7 +31,7 @@ enum Commands { #[arg(long)] name: Option, - /// Use a binary (application) template [default] + /// Use a binary (application) template \[default\] #[arg(long, group = "binary", default_value_t = true)] bin: bool, diff --git a/lib/edlang_ast/src/lib.rs b/lib/edlang_ast/src/lib.rs index b5fabd001..7b012a461 100644 --- a/lib/edlang_ast/src/lib.rs +++ b/lib/edlang_ast/src/lib.rs @@ -48,13 +48,20 @@ pub struct Ident { pub span: Span, } -// T: A + B #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Type { - pub name: Ident, - pub generics: Vec, - pub qualifiers: Vec, - pub span: Span, +pub enum Type { + Basic { + name: Ident, + generics: Vec, + qualifiers: Vec, + span: Span, + }, + Array { + of: Box, + size: Option, + qualifiers: Vec, + span: Span, + }, } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -184,6 +191,7 @@ pub enum Expression { Value(ValueExpr), FnCall(FnCallExpr), StructInit(StructInitExpr), + ArrayInit(ArrayInitExpr), Unary(UnaryOp, Box), Binary(Box, BinaryOp, Box), Deref(Box, Span), @@ -209,11 +217,18 @@ pub struct StructInitField { #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct StructInitExpr { - pub name: Type, + pub name: Ident, + pub generics: Vec, pub fields: BTreeMap, pub span: Span, } +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct ArrayInitExpr { + pub data: Vec, + pub span: Span, +} + #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct FnCallExpr { pub name: Ident, diff --git a/lib/edlang_codegen_llvm/src/codegen.rs b/lib/edlang_codegen_llvm/src/codegen.rs index e7d3ab2f6..75e60771b 100644 --- a/lib/edlang_codegen_llvm/src/codegen.rs +++ b/lib/edlang_codegen_llvm/src/codegen.rs @@ -21,7 +21,7 @@ use inkwell::{ values::{BasicValue, BasicValueEnum, PointerValue}, AddressSpace, }; -use ir::{LocalKind, ModuleBody, ProgramBody, TypeInfo, ValueTree}; +use ir::{LocalKind, ModuleBody, Place, ProgramBody, TypeInfo, ValueTree}; use llvm_sys::debuginfo::LLVMDIFlagPublic; use tracing::{info, trace}; @@ -160,7 +160,11 @@ pub fn compile(session: &Session, program: &ProgramBody) -> Result Result<(), BuilderError> _ => unreachable!(), } } - ir::PlaceElem::Index { .. } => todo!(), + ir::PlaceElem::Index { local } => { + let value = compile_load_place( + ctx, + fn_id, + &locals, + &Place { + local: *local, + projection: Default::default(), + }, + false, + )?; + + ptr = unsafe { + ctx.builder.build_in_bounds_gep( + ptr.get_type(), + ptr, + &[ + ctx.ctx.context.i32_type().const_int(0, false), + value.0.into_int_value(), + ], + "constindex", + )? + }; + } + ir::PlaceElem::ConstIndex { index } => { + ptr = unsafe { + ctx.builder.build_in_bounds_gep( + ptr.get_type(), + ptr, + &[ctx + .ctx + .context + .i32_type() + .const_int((*index) as u64, false)], + "constindex", + )? + }; + } } } @@ -1034,6 +1075,7 @@ fn compile_rvalue<'ctx>( } ir::PlaceElem::Field { .. } => todo!(), ir::PlaceElem::Index { .. } => todo!(), + ir::PlaceElem::ConstIndex { .. } => todo!(), } } @@ -1224,6 +1266,7 @@ fn compile_load_place<'ctx>( } } ir::PlaceElem::Index { .. } => todo!(), + ir::PlaceElem::ConstIndex { .. } => todo!(), } } @@ -1351,7 +1394,7 @@ fn compile_basic_type<'ctx>( match &ty.kind { ir::TypeKind::Unit => todo!(), ir::TypeKind::Bool => ctx.ctx.context.bool_type().as_basic_type_enum(), - ir::TypeKind::Char => ctx.ctx.context.i32_type().as_basic_type_enum(), + ir::TypeKind::Char => ctx.ctx.context.i8_type().as_basic_type_enum(), ir::TypeKind::Int(ty) => match ty { ir::IntTy::I128 => ctx.ctx.context.i128_type().as_basic_type_enum(), ir::IntTy::I64 => ctx.ctx.context.i64_type().as_basic_type_enum(), @@ -1437,6 +1480,26 @@ fn compile_basic_type<'ctx>( .struct_type(&fields, false) .as_basic_type_enum() } + ir::TypeKind::Slice(inner, size) => { + let inner = compile_basic_type(ctx, inner); + if let Some(size) = size { + inner.array_type(*size).as_basic_type_enum() + } else { + ctx.ctx + .context + .struct_type( + &[ + ctx.ctx + .context + .ptr_type(AddressSpace::default()) + .as_basic_type_enum(), + ctx.ctx.context.i64_type().as_basic_type_enum(), + ], + false, + ) + .as_basic_type_enum() + } + } } } @@ -1631,5 +1694,52 @@ fn compile_debug_type<'ctx>(ctx: &ModuleCompileCtx<'ctx, '_>, ty: &ir::TypeInfo) ) .as_type() } + ir::TypeKind::Slice(inner, size) => { + let real_ty = compile_basic_type(ctx, ty); + let inner_type = compile_debug_type(ctx, inner); + + if let Some(size) = size { + ctx.di_builder + .create_array_type( + inner_type, + ctx.target_data.get_abi_size(&real_ty), + ctx.target_data.get_abi_alignment(&real_ty), + #[allow(clippy::single_range_in_vec_init)] // false positive + &[0..((*size) as i64)], + ) + .as_type() + } else { + ctx.di_builder + .create_struct_type( + ctx.di_namespace, + "str", + ctx.di_unit.get_file(), + 0, + ctx.target_data.get_bit_size(&real_ty), + ctx.target_data.get_abi_alignment(&real_ty), + 0, + None, + &[ + ctx.di_builder + .create_pointer_type( + name, + inner_type, + (ctx.target_data.get_pointer_byte_size(None) * 8).into(), + ctx.target_data.get_pointer_byte_size(None), + AddressSpace::default(), + ) + .as_type(), + ctx.di_builder + .create_basic_type(name, 64, 0x7, LLVMDIFlagPublic) + .unwrap() + .as_type(), + ], + 0, + None, + "str", + ) + .as_type() + } + } } } diff --git a/lib/edlang_driver/src/linker.rs b/lib/edlang_driver/src/linker.rs index 8ecb6252d..b5dd01755 100644 --- a/lib/edlang_driver/src/linker.rs +++ b/lib/edlang_driver/src/linker.rs @@ -60,7 +60,6 @@ pub fn link_binary(objects: &[PathBuf], output_filename: &Path) -> std::io::Resu let mut args = vec![ "-L/usr/local/lib", "-L/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib", - &input_path.display().to_string(), ]; args.extend(objects.iter().map(|x| x.as_str())); diff --git a/lib/edlang_ir/src/lib.rs b/lib/edlang_ir/src/lib.rs index 15285d101..9221bec55 100644 --- a/lib/edlang_ir/src/lib.rs +++ b/lib/edlang_ir/src/lib.rs @@ -262,6 +262,7 @@ pub enum TypeKind { Ref(bool, Box), // name for print purposes Struct(DefId, String), // todo, add generics + Slice(Box, Option), } impl TypeKind { @@ -308,6 +309,7 @@ impl TypeKind { TypeKind::Ref(_, inner) => inner.kind.get_falsy_value(), TypeKind::Struct(_, _name) => todo!(), TypeKind::Str => todo!(), + TypeKind::Slice(_, _) => todo!(), } } } @@ -351,6 +353,15 @@ impl fmt::Display for TypeKind { write!(f, "&{word} {}", inner.kind) } TypeKind::Struct(_, name) => write!(f, "{}", name), + TypeKind::Slice(inner, size) => { + let size = if let Some(size) = size { + format!("; {size}") + } else { + "".to_string() + }; + + write!(f, "[{}{size}]", inner.kind) + } } } } @@ -477,6 +488,7 @@ pub enum PlaceElem { Deref, Field { field_idx: usize }, Index { local: usize }, + ConstIndex { index: usize }, } impl TypeKind { diff --git a/lib/edlang_lowering/src/lib.rs b/lib/edlang_lowering/src/lib.rs index e5bb74e3f..d8c49a823 100644 --- a/lib/edlang_lowering/src/lib.rs +++ b/lib/edlang_lowering/src/lib.rs @@ -645,15 +645,16 @@ fn find_expr_type(builder: &mut BodyBuilder, info: &ast::Expression) -> Option { // checks? todo!() } + ast::Expression::ArrayInit(_) => todo!(), }) } @@ -762,7 +763,7 @@ fn lower_expr( .get_module_body() .symbols .structs - .get(&info.name.name.name) + .get(&info.name.name) .expect("struct not found"); let struct_body = builder.ctx.body.structs.get(&id).unwrap().clone(); let ty = TypeKind::Struct(id, struct_body.name.clone()); @@ -832,6 +833,45 @@ fn lower_expr( (rvalue, kind, *span) } + ast::Expression::ArrayInit(info) => { + let ty = if let Some(type_hint) = type_hint { + type_hint.clone() + } else { + todo!() + }; + + let inner = if let TypeKind::Slice(inner, _) = &ty.kind { + inner + } else { + unreachable!() + }; + + let local = builder.add_temp_local(ty.kind.clone()); + builder.statements.push(Statement { + span: None, + kind: StatementKind::StorageLive(local), + }); + let place = Place { + local, + projection: Default::default(), + }; + for (i, x) in info.data.iter().enumerate() { + let (value, _ty, span) = lower_expr(builder, x, Some(inner))?; + let mut place = place.clone(); + place.projection.push(PlaceElem::ConstIndex { index: i }); + + builder.statements.push(Statement { + span: Some(span), + kind: StatementKind::Assign(place, value), + }); + } + + ( + RValue::Use(Operand::Move(place), info.span), + ty.kind, + info.span, + ) + } }) } @@ -1096,9 +1136,7 @@ fn lower_value( span: None, kind: ir::TypeKind::Char, }, - kind: ir::ConstKind::Value(ir::ValueTree::Leaf(ir::ConstValue::U32( - (*value) as u32, - ))), + kind: ir::ConstKind::Value(ir::ValueTree::Leaf(ir::ConstValue::U8((*value) as u8))), }), TypeKind::Char, *span, @@ -1475,82 +1513,106 @@ pub fn lower_type( t: &ast::Type, module_id: DefId, ) -> Result { - let mut ty = match t.name.name.as_str() { - "()" => ir::TypeInfo { - span: Some(t.span), - kind: ir::TypeKind::Unit, - }, - "u8" => ir::TypeInfo { - span: Some(t.span), - kind: ir::TypeKind::Uint(ir::UintTy::U8), - }, - "u16" => ir::TypeInfo { - span: Some(t.span), - kind: ir::TypeKind::Uint(ir::UintTy::U16), - }, - "u32" => ir::TypeInfo { - span: Some(t.span), - kind: ir::TypeKind::Uint(ir::UintTy::U32), - }, - "u64" => ir::TypeInfo { - span: Some(t.span), - kind: ir::TypeKind::Uint(ir::UintTy::U64), - }, - "u128" => ir::TypeInfo { - span: Some(t.span), - kind: ir::TypeKind::Uint(ir::UintTy::U128), - }, - "i8" => ir::TypeInfo { - span: Some(t.span), - kind: ir::TypeKind::Int(ir::IntTy::I8), - }, - "i16" => ir::TypeInfo { - span: Some(t.span), - kind: ir::TypeKind::Int(ir::IntTy::I16), - }, - "i32" => ir::TypeInfo { - span: Some(t.span), - kind: ir::TypeKind::Int(ir::IntTy::I32), - }, - "i64" => ir::TypeInfo { - span: Some(t.span), - kind: ir::TypeKind::Int(ir::IntTy::I64), - }, - "i128" => ir::TypeInfo { - span: Some(t.span), - kind: ir::TypeKind::Int(ir::IntTy::I128), - }, - "char" => ir::TypeInfo { - span: Some(t.span), - kind: ir::TypeKind::Char, - }, - "bool" => ir::TypeInfo { - span: Some(t.span), - kind: ir::TypeKind::Bool, - }, - "str" => ir::TypeInfo { - span: Some(t.span), - kind: ir::TypeKind::Str, - }, - 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, struct_body.name.clone()), + let (mut ty, qualifiers) = match t { + ast::Type::Basic { + name, + generics: _, + qualifiers, + span, + } => { + let ty = match name.name.as_str() { + "()" => ir::TypeInfo { + span: Some(*span), + kind: ir::TypeKind::Unit, + }, + "u8" => ir::TypeInfo { + span: Some(*span), + kind: ir::TypeKind::Uint(ir::UintTy::U8), + }, + "u16" => ir::TypeInfo { + span: Some(*span), + kind: ir::TypeKind::Uint(ir::UintTy::U16), + }, + "u32" => ir::TypeInfo { + span: Some(*span), + kind: ir::TypeKind::Uint(ir::UintTy::U32), + }, + "u64" => ir::TypeInfo { + span: Some(*span), + kind: ir::TypeKind::Uint(ir::UintTy::U64), + }, + "u128" => ir::TypeInfo { + span: Some(*span), + kind: ir::TypeKind::Uint(ir::UintTy::U128), + }, + "i8" => ir::TypeInfo { + span: Some(*span), + kind: ir::TypeKind::Int(ir::IntTy::I8), + }, + "i16" => ir::TypeInfo { + span: Some(*span), + kind: ir::TypeKind::Int(ir::IntTy::I16), + }, + "i32" => ir::TypeInfo { + span: Some(*span), + kind: ir::TypeKind::Int(ir::IntTy::I32), + }, + "i64" => ir::TypeInfo { + span: Some(*span), + kind: ir::TypeKind::Int(ir::IntTy::I64), + }, + "i128" => ir::TypeInfo { + span: Some(*span), + kind: ir::TypeKind::Int(ir::IntTy::I128), + }, + "char" => ir::TypeInfo { + span: Some(*span), + kind: ir::TypeKind::Char, + }, + "bool" => ir::TypeInfo { + span: Some(*span), + kind: ir::TypeKind::Bool, + }, + "str" => ir::TypeInfo { + span: Some(*span), + kind: ir::TypeKind::Str, + }, + 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, struct_body.name.clone()), + } + } else { + Err(LoweringError::UnrecognizedType { + span: name.span, + name: name.name.clone(), + file_id: module.file_id, + })? + } } - } else { - Err(LoweringError::UnrecognizedType { - span: t.name.span, - name: t.name.name.clone(), - file_id: module.file_id, - })? - } + }; + (ty, qualifiers) + } + ast::Type::Array { + of, + size, + qualifiers, + span, + } => { + let ty = ir::TypeInfo { + span: Some(*span), + kind: ir::TypeKind::Slice(Box::new(lower_type(ctx, of, module_id)?), *size), + }; + (ty, qualifiers) } }; - for qualifier in t.qualifiers.iter().rev() { + let span = ty.span; + + for qualifier in qualifiers.iter().rev() { let kind = match qualifier { ast::TypeQualifier::Ref => TypeKind::Ref(false, Box::new(ty)), ast::TypeQualifier::RefMut => TypeKind::Ref(true, Box::new(ty)), @@ -1558,10 +1620,7 @@ pub fn lower_type( ast::TypeQualifier::PtrMut => TypeKind::Ptr(true, Box::new(ty)), }; - ty = TypeInfo { - span: Some(t.span), - kind, - }; + ty = TypeInfo { span, kind }; } Ok(ty) diff --git a/lib/edlang_parser/src/grammar.lalrpop b/lib/edlang_parser/src/grammar.lalrpop index 976069c5f..b22f4f191 100644 --- a/lib/edlang_parser/src/grammar.lalrpop +++ b/lib/edlang_parser/src/grammar.lalrpop @@ -151,34 +151,36 @@ pub(crate) TypeQualifier: ast::TypeQualifier = { } pub(crate) Type: ast::Type = { - => ast::Type { + => ast::Type::Basic { name, generics: vec![], qualifiers, span: ast::Span::new(lo, hi), }, - "<" > ">" => ast::Type { + "<" > ">" => ast::Type::Basic { name, generics, qualifiers, span: ast::Span::new(lo, hi), }, + "[" "]" => ast::Type::Array { + of: Box::new(of), + size: None, + qualifiers, + span: ast::Span::new(lo, hi), + }, + "[" ";" "]" => ast::Type::Array { + of: Box::new(of), + size: Some(size.try_into().unwrap()), + qualifiers, + span: ast::Span::new(lo, hi), + }, } /// For things like A:: { a: value } -pub(crate) IdentWithOptionalType: ast::Type = { - => ast::Type { - name, - generics: vec![], - qualifiers: vec![], - span: ast::Span::new(lo, hi), - }, - "::" "<" > ">" => ast::Type { - name, - generics, - qualifiers: vec![], - span: ast::Span::new(lo, hi), - }, +pub(crate) IdentWithGenerics: (ast::Ident, Vec) = { + => (name, vec![]), + "::" "<" > ">" => (name, generics), } pub(crate) PathExpr: ast::PathExpr = { @@ -351,6 +353,7 @@ pub(crate) Expression: ast::Expression = { #[precedence(level="5")] #[assoc(side="left")] "as" => ast::Expression::Cast(Box::new(a), b, ast::Span::new(lo, hi)), "(" ")" => ast::Expression::StructInit(<>), + => ast::Expression::ArrayInit(<>), } pub BinaryFirstLvlOp: ast::BinaryOp = { @@ -412,13 +415,21 @@ pub(crate) StructInitField: (ast::Ident, ast::StructInitField) = { } pub(crate) StructInitExpr: ast::StructInitExpr = { - "{" > "}" => ast::StructInitExpr { - name, + "{" > "}" => ast::StructInitExpr { + name: name.0, + generics: name.1, fields: fields.into_iter().collect(), span: ast::Span::new(lo, hi), } } +pub(crate) ArrayInitExpr: ast::ArrayInitExpr = { + "[" > "]" => ast::ArrayInitExpr { + data: data.into_iter().collect(), + span: ast::Span::new(lo, hi), + } +} + pub(crate) FnParam: ast::FnParam = { ":" => ast::FnParam { name,