diff --git a/examples/triple_import_main.reid b/examples/triple_import_main.reid new file mode 100644 index 0000000..a4e6613 --- /dev/null +++ b/examples/triple_import_main.reid @@ -0,0 +1,5 @@ + +import triple_import_vec2::Vec2; +import triple_import_ship::Ship; + +fn main() -> i32 { return 0; } \ No newline at end of file diff --git a/examples/triple_import_ship.reid b/examples/triple_import_ship.reid new file mode 100644 index 0000000..4f5b017 --- /dev/null +++ b/examples/triple_import_ship.reid @@ -0,0 +1,3 @@ + +import triple_import_vec2::Vec2; +struct Ship { position: Vec2 } \ No newline at end of file diff --git a/examples/triple_import_vec2.reid b/examples/triple_import_vec2.reid new file mode 100644 index 0000000..5dd4a9d --- /dev/null +++ b/examples/triple_import_vec2.reid @@ -0,0 +1,2 @@ + +struct Vec2 { x: f32, y: f32 } \ No newline at end of file diff --git a/reid-lsp/src/analysis.rs b/reid-lsp/src/analysis.rs index afbe287..f6e2600 100644 --- a/reid-lsp/src/analysis.rs +++ b/reid-lsp/src/analysis.rs @@ -743,7 +743,6 @@ pub fn analyze_block( analyze_expr(context, source_module, expression, scope); } mir::StmtKind::While(WhileStatement { condition, block, .. }) => { - dbg!(condition); analyze_expr(context, source_module, condition, scope); analyze_block(context, source_module, block, scope); } @@ -852,8 +851,8 @@ pub fn analyze_expr( analyze_expr(context, source_module, expr, scope); } } - mir::ExprKind::Struct(struct_name, items) => { - let struct_type = TypeKind::CustomType(CustomTypeKey(struct_name.clone(), source_module.module_id)); + mir::ExprKind::Struct(key, items) => { + let struct_type = TypeKind::CustomType(key.clone()); let struct_idx = scope .token_idx(&expr.1, |t| matches!(t, Token::Identifier(_))) .unwrap_or(expr.1.range.end); diff --git a/reid/src/codegen/intrinsics.rs b/reid/src/codegen/intrinsics.rs index 74eb203..8d42abe 100644 --- a/reid/src/codegen/intrinsics.rs +++ b/reid/src/codegen/intrinsics.rs @@ -703,7 +703,6 @@ impl IntrinsicFunction for IntrinsicMemcpy { .unwrap(); let bytes = scope.block.build(Instr::Mul(sizeof, length.instr())).unwrap(); - dbg!(self.0.size_of(&scope.type_map) / 8); let params = vec![ dest.instr(), src.instr(), diff --git a/reid/src/codegen/mod.rs b/reid/src/codegen/mod.rs index 1d7d69e..b00401c 100644 --- a/reid/src/codegen/mod.rs +++ b/reid/src/codegen/mod.rs @@ -1,4 +1,8 @@ -use std::{cell::RefCell, collections::HashMap, rc::Rc}; +use std::{ + cell::RefCell, + collections::{HashMap, HashSet}, + rc::Rc, +}; use allocator::{Allocator, AllocatorScope}; use intrinsics::*; @@ -180,7 +184,40 @@ impl mir::Module { let mut typedefs = self.typedefs.clone(); typedefs.sort_by(|a, b| b.source_module.cmp(&a.source_module)); - for typedef in typedefs { + // Since we know by this point that no types are recursive, we can + // somewhat easily sort the type-definitions such that we can process + // the ones with no depencencies first, and later the ones that depend + // on the earlier ones. + let mut typekeys_seen = HashSet::new(); + let mut typedefs_sorted = Vec::new(); + let mut typedefs_left = typedefs.clone(); + typedefs_left.reverse(); + while let Some(typedef) = typedefs_left.pop() { + match &typedef.kind { + TypeDefinitionKind::Struct(StructType(fields)) => { + let mut is_ok = true; + for field in fields { + match &field.1 { + TypeKind::CustomType(type_key) => { + if !typekeys_seen.contains(type_key) { + is_ok = false; + break; + } + } + _ => {} + } + } + if is_ok { + typekeys_seen.insert(CustomTypeKey(typedef.name.clone(), typedef.source_module)); + typedefs_sorted.push(typedef); + } else { + typedefs_left.insert(0, typedef.clone()); + } + } + }; + } + + for typedef in typedefs_sorted { let type_key = CustomTypeKey(typedef.name.clone(), typedef.source_module); type_map.insert(type_key.clone(), typedef.clone()); @@ -190,9 +227,6 @@ impl mir::Module { typedef.name.clone(), fields .iter() - // TODO: Reorder custom-type definitions such that - // inner types get evaluated first. Otherwise this - // will cause a panic! .map(|StructField(_, t, _)| t.get_type(&type_values)) .collect(), ))) diff --git a/reid/src/mir/linker.rs b/reid/src/mir/linker.rs index dc95e92..bfbee92 100644 --- a/reid/src/mir/linker.rs +++ b/reid/src/mir/linker.rs @@ -111,11 +111,12 @@ impl<'map> Pass for LinkerPass<'map> { let mut modules_to_process: Vec>> = modules.values().cloned().collect(); - let mut already_imported_types = HashSet::::new(); - let mut already_imported_binops = HashSet::::new(); + let mut still_required_types = HashSet::::new(); while let Some(module) = modules_to_process.pop() { let mut extern_types = HashMap::new(); + let mut already_imported_binops = HashSet::::new(); + let mut already_imported_types = HashSet::::new(); let mut importer_module = module.borrow_mut(); for import in importer_module.imports.clone() { @@ -208,7 +209,7 @@ impl<'map> Pass for LinkerPass<'map> { let Some((import_name, _)) = path.get(1) else { continue; }; - let import_id = imported.module_id; + let imported_id = imported.module_id; let mut imported_types = Vec::new(); @@ -351,7 +352,7 @@ impl<'map> Pass for LinkerPass<'map> { return_type, parameters: param_tys, kind: super::FunctionDefinitionKind::Extern(true), - source: Some(import_id), + source: Some(imported_id), signature_meta: func.signature_meta, }, )); @@ -367,6 +368,13 @@ impl<'map> Pass for LinkerPass<'map> { let mut seen = HashSet::new(); let mut current_extern_types = HashSet::new(); seen.extend(imported_types.clone().iter().map(|t| t.0.clone())); + + for ty in still_required_types.clone() { + if ty.1 == imported_id && !seen.contains(&ty) { + imported_types.push((ty, false)); + } + } + current_extern_types.extend(imported_types.clone().iter().filter(|t| t.1).map(|t| t.0.clone())); for extern_type in ¤t_extern_types { extern_types.insert(extern_type.0.clone(), extern_type.1); @@ -378,10 +386,16 @@ impl<'map> Pass for LinkerPass<'map> { for typekey in imported_types.clone() { let typedef = imported_mod_typedefs .iter() - .find(|ty| CustomTypeKey(ty.name.clone(), imported_mod_id) == typekey.0) + .find(|ty| CustomTypeKey(ty.name.clone(), ty.source_module) == typekey.0) .unwrap(); - let inner = find_inner_types(typedef, seen.clone(), imported_mod_id); - seen.extend(inner.iter().cloned()); + let inner = find_inner_types(typedef, seen.clone(), imported_mod_typedefs); + for ty in inner { + if ty.1 == imported_id && imported_mod_typedefs.iter().find(|t| t.name == ty.0).is_some() { + seen.insert(ty); + } else { + still_required_types.insert(ty); + } + } } // TODO: Unable to import same-named type from multiple places.. @@ -573,28 +587,31 @@ fn import_type(ty: &TypeKind, usable_import: bool) -> Vec<(CustomTypeKey, bool)> fn find_inner_types( typedef: &TypeDefinition, mut seen: HashSet, - mod_id: SourceModuleId, + typedefs: &Vec, ) -> Vec { match &typedef.kind { crate::mir::TypeDefinitionKind::Struct(struct_type) => { - let typenames = struct_type + let typekeys = struct_type .0 .iter() - .filter(|t| matches!(t.1, TypeKind::CustomType(..))) - .map(|t| match &t.1 { - TypeKind::CustomType(CustomTypeKey(t, _)) => t, - _ => panic!(), + .filter_map(|t| match &t.1 { + TypeKind::CustomType(key) => Some(key), + _ => None, }) .cloned() .collect::>(); - for typename in typenames { - if seen.contains(&CustomTypeKey(typename.clone(), mod_id)) { + for typekey in typekeys { + if seen.contains(&typekey) { continue; } - let inner = find_inner_types(typedef, seen.clone(), mod_id); - seen.insert(CustomTypeKey(typename, mod_id)); - seen.extend(inner); + seen.insert(typekey.clone()); + if typekey.1 == typedef.source_module { + if let Some(inner) = typedefs.iter().find(|t| t.name == typekey.0) { + let ret = find_inner_types(inner, seen.clone(), typedefs); + seen.extend(ret); + } + } } seen.into_iter().collect() diff --git a/reid/tests/e2e.rs b/reid/tests/e2e.rs index 7ba6c9f..e69de29 100644 --- a/reid/tests/e2e.rs +++ b/reid/tests/e2e.rs @@ -1,171 +0,0 @@ -use std::{path::PathBuf, process::Command, time::SystemTime}; - -use reid::{ - compile_module, - ld::LDRunner, - mir::{self}, - parse_module, perform_all_passes, -}; -use reid_lib::{compile::CompileOutput, Context}; -use util::assert_err; - -mod util; - -fn test_compile(source: &str, name: &str) -> CompileOutput { - assert_err(assert_err(std::panic::catch_unwind(|| { - let mut map = Default::default(); - let (id, tokens) = assert_err(parse_module(source, name, None, &mut map, None)); - - let module = assert_err(assert_err(compile_module(id, tokens, &mut map, None, true)).map_err(|(_, e)| e)); - let mut mir_context = mir::Context::from(vec![module], Default::default()); - assert_err(perform_all_passes(&mut mir_context, &mut map)); - - let context = Context::new(format!("Reid ({})", env!("CARGO_PKG_VERSION"))); - - let codegen = assert_err(mir_context.codegen(&context)); - - Ok::<_, ()>(codegen.compile(None, Vec::new()).output()) - }))) -} - -fn test(source: &str, name: &str, expected_exit_code: Option) { - assert_err(assert_err(std::panic::catch_unwind(|| { - let output = test_compile(source, name); - - let time = SystemTime::now(); - let in_path = PathBuf::from(format!( - "/tmp/temp-{}.o", - time.duration_since(SystemTime::UNIX_EPOCH).unwrap().as_nanos() - )); - - std::fs::write(&in_path, &output.obj_buffer).expect("Could not write OBJ-file!"); - - let out_path = in_path.with_extension("out"); - LDRunner::from_command("ld") - .with_library("c") - .invoke(&in_path, &out_path); - std::fs::remove_file(in_path).unwrap(); - - let executed = Command::new(&out_path).output(); - std::fs::remove_file(out_path).unwrap(); - - if let Some(expected_exit_code) = expected_exit_code { - assert_eq!(expected_exit_code, executed.unwrap().status.code().unwrap()); - } - - Ok::<(), ()>(()) - }))) -} - -#[test] -fn arithmetic_compiles_well() { - test(include_str!("../../examples/arithmetic.reid"), "test", Some(48)); -} -#[test] -fn array_structs_compiles_well() { - test(include_str!("../../examples/array_structs.reid"), "test", Some(5)); -} -#[test] -fn array_compiles_well() { - test(include_str!("../../examples/array.reid"), "test", Some(3)); -} -#[test] -fn borrow_compiles_well() { - test(include_str!("../../examples/borrow.reid"), "test", Some(17)); -} -#[test] -fn borrow_hard_compiles_well() { - test(include_str!("../../examples/borrow_hard.reid"), "test", Some(17)); -} -#[test] -fn cast_compiles_well() { - test(include_str!("../../examples/cast.reid"), "test", Some(6)); -} -#[test] -fn char_compiles_well() { - test(include_str!("../../examples/char.reid"), "test", Some(98)); -} -#[test] -fn div_mod_compiles_well() { - test(include_str!("../../examples/div_mod.reid"), "test", Some(12)); -} -#[test] -fn fibonacci_compiles_well() { - test(include_str!("../../examples/fibonacci.reid"), "test", Some(1)); -} -#[test] -fn float_compiles_well() { - test(include_str!("../../examples/float.reid"), "test", Some(1)); -} -#[test] -fn hello_world_compiles_well() { - test(include_str!("../../examples/hello_world.reid"), "test", None); -} -#[test] -fn hello_world_harder_compiles_well() { - test(include_str!("../../examples/hello_world_harder.reid"), "test", None); -} -#[test] -fn mutable_compiles_well() { - test(include_str!("../../examples/mutable.reid"), "test", Some(21)); -} -#[test] -fn ptr_compiles_well() { - test(include_str!("../../examples/ptr.reid"), "test", Some(5)); -} -#[test] -fn std_test_compiles_well() { - test(include_str!("../../examples/std_test.reid"), "test", Some(3)); -} -#[test] -fn strings_compiles_well() { - test(include_str!("../../examples/strings.reid"), "test", Some(5)); -} -#[test] -fn struct_compiles_well() { - test(include_str!("../../examples/struct.reid"), "test", Some(17)); -} -#[test] -fn loops_compiles_well() { - test(include_str!("../../examples/loops.reid"), "test", Some(10)); -} -#[test] -fn ptr_hard_compiles_well() { - test(include_str!("../../examples/ptr_hard.reid"), "test", Some(0)); -} -#[test] -fn loop_hard_compiles_well() { - test(include_str!("../../examples/loop_hard.reid"), "test", Some(0)); -} -#[test] -fn custom_binop_compiles_well() { - test(include_str!("../../examples/custom_binop.reid"), "test", Some(21)); -} - -#[test] -fn array_short_compiles_well() { - test(include_str!("../../examples/array_short.reid"), "test", Some(5)); -} -#[test] -fn imported_type_compiles_well() { - test(include_str!("../../examples/imported_type.reid"), "test", Some(0)); -} - -#[test] -fn associated_functions() { - test( - include_str!("../../examples/associated_functions.reid"), - "test", - Some(4), - ); -} - -#[test] -fn mutable_inner_functions() { - test(include_str!("../../examples/mutable_inner.reid"), "test", Some(0)); -} - -#[test] -fn cpu_raytracer_compiles() { - test_compile(include_str!("../../examples/cpu_raytracer.reid"), "test"); -}