diff --git a/crates/codegen/src/class_decl.rs b/crates/codegen/src/class_decl.rs index 6524ded..888a20c 100644 --- a/crates/codegen/src/class_decl.rs +++ b/crates/codegen/src/class_decl.rs @@ -51,7 +51,9 @@ impl ClassProcessedData { if matches!(method.item.visibility, Visibility::Public) { match &method.item.is_override { None => { - v_table.push(method.item.name.clone()); + if method.item.is_using_self() { + v_table.push(method.item.name.clone()); + } } Some(override_spec) => { override_v_table @@ -106,14 +108,12 @@ impl ClassProcessedData { )); cg.indent += 1; - cg.add_indentedln( - "pub _m_oop: (&'static [*const std::ffi::c_void], *mut std::ffi::c_void),", - ); - if let Some(ref inherits) = self.inherits { - cg.add_indented("pub _super: Box<"); + cg.add_indented("pub _super: "); cg.add(&get_type_from_path(inherits).get_rust()); - cg.addln(">,"); + cg.addln(","); + } else { + cg.add_indentedln("pub _vptr: &'static [*const std::ffi::c_void],"); } for field in &self.fields { @@ -133,9 +133,7 @@ impl ClassProcessedData { )); cg.indent += 1; - self.emit_v_table(cg); - - self.emit_super_v_table(cg); + self.emit_unified_vtable(cg); self.emit_super_v_tests(cg); self.emit_constructor(ctx, cg); @@ -145,85 +143,96 @@ impl ClassProcessedData { cg.addln("}\n"); } - fn emit_v_table(&self, cg: &mut RustCodegen) { + fn emit_unified_vtable(&self, cg: &mut RustCodegen) { + let has_parent = self.inherits.is_some(); + let parent_path = self + .inherits + .as_ref() + .map(|p| p.get_rust()) + .unwrap_or_default(); + + if has_parent { + cg.add_indentedln(&format!( + "pub const __PARENT_V_COUNT: usize = {}::__V_COUNT;", + parent_path + )); + } else { + cg.add_indentedln("pub const __PARENT_V_COUNT: usize = 0;"); + } + for (i, method_name) in self.v_table.iter().enumerate() { cg.add_indentedln(&format!( - "pub const __FN_{}: usize = {i};", + "pub const __FN_{}: usize = Self::__PARENT_V_COUNT + {i};", method_name.0.to_uppercase() )); } cg.add_indentedln(&format!( - "pub const __V_TABLE: [*const std::ffi::c_void; {}] = [", + "pub const __V_COUNT: usize = Self::__PARENT_V_COUNT + {};", self.v_table.len() )); + + cg.add_indentedln("pub const __V_TABLE: &'static [*const std::ffi::c_void] = &{"); cg.indent += 1; - for method_name in &self.v_table { - cg.add_indented("Self::__m_"); - cg.add(&method_name.get_rust()); - cg.add(" as *const std::ffi::c_void"); - cg.addln(","); - } + if has_parent { + cg.add_indentedln(&format!( + "let mut table = [std::ptr::null(); {}::__V_COUNT + {}];", + parent_path, + self.v_table.len() + )); - cg.indent -= 1; - cg.add_indentedln("];"); - } + cg.add_indentedln(&format!("let parent_table = {}::__V_TABLE;", parent_path)); + cg.add_indentedln(&format!( + "let mut i = 0; while i < {}::__V_COUNT {{ table[i] = parent_table[i]; i += 1; }}", + parent_path + )); - fn emit_super_v_table(&self, cg: &mut RustCodegen) { - if self.override_v_table.is_empty() { - return; - } - - cg.add_indentedln(&format!( - "pub const __SUPER_V_TABLES: [&'static [*const std::ffi::c_void]; {}] = [", - self.override_v_table.len() - )); - cg.indent += 1; - - for (override_tier, overriden_method_idents) in &self.override_v_table { - let target_path = match &override_tier.0 { - Some(path) => path.clone(), - None => { - if let Some(parent_path) = &self.inherits { - parent_path.clone() - } else { - continue; // Safeguard if AST has a dangling override without inheritance - } + for (override_tier, overriden_method_idents) in &self.override_v_table { + let base_class_path = override_tier + .0 + .as_ref() + .unwrap_or(self.inherits.as_ref().unwrap()) + .get_rust(); + for method_ident in &overriden_method_idents.item { + cg.add_indentedln(&format!( + "table[{}::__FN_{}] = {}::__m_{} as *const std::ffi::c_void;", + base_class_path, + method_ident.0.to_uppercase(), + self.self_path.get_rust(), + method_ident.get_rust() + )); } - }; + } - let target_rust_path = target_path.get_rust(); - - // 2. Emit the block for this specific index table - cg.add_indentedln("&{"); - cg.indent += 1; - - // Initialize this sub-table with the target parent class's base vtable - cg.add_indentedln(&format!("let mut table = {}::__V_TABLE;", target_rust_path)); - - // Patch the slots for every method registered under this specific override tier - for method_ident in &overriden_method_idents.item { + for method_name in &self.v_table { cg.add_indentedln(&format!( - "table[{}::__FN_{}] = {}::__m_{} as *const std::ffi::c_void;", - target_rust_path, - method_ident.0.to_uppercase(), - self.self_path.get_rust(), - method_ident.get_rust() + "table[Self::__FN_{}] = Self::__m_{} as *const std::ffi::c_void;", + method_name.0.to_uppercase(), + method_name.get_rust() )); } cg.add_indentedln("table"); + } else { + cg.add_indentedln("["); + cg.indent += 1; + for method_name in &self.v_table { + cg.add_indentedln(&format!( + "Self::__m_{} as *const std::ffi::c_void,", + method_name.get_rust() + )); + } cg.indent -= 1; - cg.add_indentedln("},"); + cg.add_indentedln("]"); } cg.indent -= 1; - cg.add_indentedln("];"); + cg.add_indentedln("};"); } fn emit_super_v_tests(&self, cg: &mut RustCodegen) { - cg.add_indentedln(&format!("const fn __test_vt() {{")); + cg.add_indentedln(&format!("fn __test_vt() {{")); cg.indent += 1; for (override_tier, _) in self.override_v_table.iter() { @@ -234,7 +243,7 @@ impl ClassProcessedData { if let Some(parent_path) = &self.inherits { parent_path.clone() } else { - continue; // Safeguard if AST has a dangling override without inheritance + continue; } } }; @@ -284,6 +293,19 @@ impl ClassProcessedData { } } + // Deref tests for override targets + if self.inherits.is_some() && !self.override_v_table.is_empty() { + cg.add_indentedln("let this: &Self = &unsafe { std::mem::MaybeUninit::::zeroed().assume_init() };"); + + for (override_tier, v) in &self.override_v_table { + if let Some(path) = &override_tier.0 { + cg.add_indentedln(&v.get_comment()); + // This forces the compiler to statically verify that &Self can Deref into &Target + cg.add_indentedln(&format!("let _: &{} = this;", path.get_rust())); + } + } + } + cg.indent -= 1; cg.add_indentedln("}"); } @@ -321,14 +343,12 @@ impl ClassProcessedData { param.gen_rust(ctx, cg); } - cg.addln(") -> Box {"); + cg.addln(") -> Self {"); cg.indent += 1; - cg.add_indentedln("let mut this = Box::new(unsafe { std::mem::MaybeUninit::::zeroed().assume_init() });"); - cg.add_indentedln("let this_ptr = &mut *this as *mut Self as *mut std::ffi::c_void;"); - cg.add_indentedln("this._m_oop = (&Self::__V_TABLE, this_ptr);"); + cg.add_indentedln("let mut this: Self = unsafe { std::mem::MaybeUninit::::zeroed().assume_init() };"); + cg.add_indentedln("this._vptr = &Self::__V_TABLE;"); - // Inline field declarations and initializers for field in &self.fields { let comment = field.get_comment(); @@ -349,28 +369,7 @@ impl ClassProcessedData { } cg.addln(");"); - if self.inherits.is_some() && !self.override_v_table.is_empty() { - for (idx, (override_tier, v)) in self.override_v_table.iter().enumerate() { - match &override_tier.0 { - // Direct base class layout updates - None => { - cg.add_indentedln(&format!( - "this._super._m_oop.0 = Self::__SUPER_V_TABLES[{}];", - idx - )); - } - // Deep ancestor trait table updates - Some(path) => { - cg.add_indentedln(&v.get_comment()); - cg.add_indentedln(&format!( - "(|v: &mut {}| {{v._m_oop.0 = Self::__SUPER_V_TABLES[{}];}})(&mut this);", - path.get_rust(), - idx - )); - } - } - } - } + cg.add_indentedln("this._vptr = &Self::__V_TABLE;"); cg.add_indentedln(&constructor_comment); @@ -378,7 +377,6 @@ impl ClassProcessedData { cg.indent -= 1; cg.add_indentedln("}\n"); - // Generate matching inner initialization body block let mut constructor_params = vec![VarDecl { name: Pattern::Path(false, Path(vec![Identifier(String::from("self"))])), type_: Some(TypeExpr::Ref { @@ -413,13 +411,17 @@ impl ClassProcessedData { for method in &self.methods { match method.item.visibility { Visibility::Public => { - if method.item.is_override.is_none() { - gen_method_point(&method.item, ctx, cg); - } + if method.item.is_using_self() { + if method.item.is_override.is_none() { + gen_method_point(&method.item, ctx, cg); + } - let mut prefixed = method.clone(); - prefixed.item.name.0.insert_str(0, "__m_"); - prefixed.gen_rust(ctx, cg); + let mut prefixed = method.clone(); + prefixed.item.name.0.insert_str(0, "__m_"); + prefixed.gen_rust(ctx, cg); + } else { + method.gen_rust(ctx, cg); + } } _ => { method.gen_rust(ctx, cg); @@ -552,7 +554,7 @@ pub fn gen_method_point(method: &FunctionDecl, ctx: &mut Context, cg: &mut RustC cg.indent += 1; cg.add_indentedln(&format!( - "let func_ptr = self._m_oop.0[Self::__FN_{}];", + "let func_ptr = self._vptr[Self::__FN_{}];", method.name.0.to_uppercase() )); @@ -566,14 +568,14 @@ pub fn gen_method_point(method: &FunctionDecl, ctx: &mut Context, cg: &mut RustC .filter_map(|v| v.type_) .collect(); - if !param_types.is_empty() { - param_types.remove(0); - } + let TypeExpr::Ref { mutable, .. } = param_types.remove(0) else { + panic!("") + }; param_types.insert( 0, TypeExpr::UnsafePtr { - mutable: true, + mutable, ty: Box::new(TypeExpr::Path( Path(vec![ Identifier(String::from("std")), @@ -588,11 +590,15 @@ pub fn gen_method_point(method: &FunctionDecl, ctx: &mut Context, cg: &mut RustC cg.add(&TypeExpr::StaticFn(param_types, method.return_type.clone().map(Box::new)).get_rust()); cg.addln(" = std::mem::transmute(func_ptr);"); - cg.add_indented("func(self._m_oop.1"); + if mutable { + cg.add_indented("func(self as *mut Self as *const std::ffi::c_void"); + } else { + cg.add_indented("func(self as *const Self as *const std::ffi::c_void"); + } for (i, param) in ¶ms { if *i == 0 { - continue; // self._m_oop.1 already fulfills it + continue; // self already fulfills it } cg.add(", "); ctx.expr_ensure_semicolon = false; diff --git a/crates/parser/src/ast/top_level.rs b/crates/parser/src/ast/top_level.rs index be4a4b3..2899893 100644 --- a/crates/parser/src/ast/top_level.rs +++ b/crates/parser/src/ast/top_level.rs @@ -125,3 +125,18 @@ pub struct FieldDeclStmt { pub decl: FieldDecl, pub init: Option, } + +impl FunctionDecl { + pub fn is_using_self(&self) -> bool { + match self.params.0.get(0) { + Some(VarDecl { name, .. }) => { + if let Pattern::Path(_, v) = name { + v.0.len() == 1 && v.0[0].0 == "self" + } else { + false + } + } + _ => false, + } + } +} diff --git a/mist-test/src/items/class_test.mist b/mist-test/src/items/class_test.mist index d50ff9c..8c441e4 100644 --- a/mist-test/src/items/class_test.mist +++ b/mist-test/src/items/class_test.mist @@ -15,11 +15,13 @@ pub class Animal { pub fn test_speak(*self) { self.speak(); } + + pub fn static_method() {} } pub class Mammal : Animal { constructor() { - super -> Super::new(); + super = Super::new(); } pub fn args_test(*self, x i32, y *str) {} @@ -31,7 +33,7 @@ pub class Mammal : Animal { pub class Dog : Mammal { constructor() { - super -> Super::new(); + super = Super::new(); } pub override(Animal) fn speak(*self) {