diff --git a/crates/codegen/src/class_decl.rs b/crates/codegen/src/class_decl.rs index 73f7713..ba1426b 100644 --- a/crates/codegen/src/class_decl.rs +++ b/crates/codegen/src/class_decl.rs @@ -1,106 +1,160 @@ +use std::collections::HashMap; + use mist_parser::ast::*; -use crate::Context; +use crate::{Context, GenRust, GetRust, RustCodegen}; -use crate::{GenRust, GetRust, RustCodegen}; +pub struct ClassProcessedData { + visibility: Visibility, + name: Identifier, + generics: GenericsDecl, + inherits: Option, + self_path: ExprPath, + self_ty: TypeExpr, + fields: Vec>, + constructor: Spanned, + items: Vec, + methods: Vec>, + v_table: Vec, + override_v_table: HashMap>, +} -pub fn class_decl( - ctx: &mut Context, - cg: &mut RustCodegen, +impl ClassProcessedData { + pub fn analyze( + visibility: &Visibility, + name: &Identifier, + generics: &GenericsDecl, + inherits: &Option, + fields: &Vec>, + constructor: &Spanned, + items: &Vec, + ) -> Self { + let self_path = ExprPath(vec![ExprPathSegment { + ident: name.clone(), + generics: generics.clone().into(), + }]); - visibility: &Visibility, - name: &Identifier, - generics: &GenericsDecl, - inherits: &Option, - fields: &Vec>, - constructor: &Spanned, - items: &Vec, -) { - let inherits = if let Some(inherits) = inherits { - let path = get_type_path(inherits); - ctx.expr_super = Some(path.clone()); - Some((inherits, path)) - } else { - None - }; + let self_ty = get_type_from_path(&self_path); - // Struct decl - cg.addln(&format!( - "{}struct {}{} {{", - visibility.get_rust(), - name.clone().get_rust(), - generics.clone().get_rust() - )); - cg.indent += 1; + let methods = items + .iter() + .filter_map(|item| match item { + ClassItem::ImplDecl(_) => None, + ClassItem::Method(method) => Some(method.clone()), + }) + .collect::>>(); - cg.add_indentedln( - "pub _m_oop: (&'static [*const std::ffi::c_void; Self::__V_COUNT], *mut std::ffi::c_void),", - ); + let mut v_table = Vec::new(); + let mut override_v_table = std::collections::HashMap::new(); - if let Some((inherits, _)) = inherits { - cg.add_indented("pub _super: Box<"); - cg.add(&inherits.get_rust()); - cg.addln(">,"); + for method in &methods { + if matches!(method.item.visibility, Visibility::Public) { + match &method.item.is_override { + None => { + v_table.push(method.item.name.clone()); + } + Some(override_spec) => { + override_v_table + .entry(override_spec.clone()) + .or_insert_with(Vec::new) + .push(method.item.name.clone()); + } + } + } + } + + ClassProcessedData { + visibility: visibility.clone(), + name: name.clone(), + generics: generics.clone(), + inherits: inherits.clone(), + self_path, + self_ty, + fields: fields.clone(), + constructor: constructor.clone(), + items: items.clone(), + methods, + v_table, + override_v_table, + } } - for field in fields.clone() { - cg.add_indentedln(&field.get_comment()); - cg.add_indentedln(&field.item.decl.get_rust()); + // ── Stage 2: Code Emission ─────────────────────────────────────── + + pub fn emit(&self, ctx: &mut Context, cg: &mut RustCodegen) { + ctx.expr_super = self.inherits.clone(); + + self.emit_struct_decl(cg); + self.emit_impl_block(ctx, cg); + self.emit_impl_decls(ctx, cg); + self.emit_deref_impls(cg); + + ctx.expr_super = None; } - cg.indent -= 1; - cg.addln("}\n"); + fn emit_struct_decl(&self, cg: &mut RustCodegen) { + cg.addln(&format!( + "{}struct {}{} {{", + self.visibility.get_rust(), + self.name.get_rust(), + self.generics.get_rust() + )); + cg.indent += 1; - // Constructor - cg.addln(&format!( - "impl{} {}{} {{", - generics.clone().get_rust(), - name.clone().get_rust(), - format!( - "<{}>", - generics - .clone() - .0 - .into_iter() - .map(|v| Generic::from(v).get_rust()) - .collect::>() - .join(", ") - ) - )); - cg.indent += 1; + cg.add_indentedln( + "pub _m_oop: (&'static [*const std::ffi::c_void], *mut std::ffi::c_void),", + ); - let methods = items - .clone() - .into_iter() - .filter_map(|item| match item { - ClassItem::ImplDecl(_) => None, - ClassItem::Method(method) => Some(method), - }) - .collect::>(); + if let Some(ref inherits) = self.inherits { + cg.add_indented("pub _super: Box<"); + cg.add(&get_type_from_path(inherits).get_rust()); + cg.addln(">,"); + } - let v_table = methods - .iter() - .filter_map(|method| match method.item.visibility { - Visibility::Public => Some((method.item.name.clone(), method.item.is_override)), - _ => None, - }) - .collect::>(); + for field in &self.fields { + cg.add_indentedln(&field.get_comment()); + cg.add_indentedln(&field.item.decl.get_rust()); + } - // V TABLE - { - cg.add_indentedln(&format!("pub const __V_COUNT: usize = {};", v_table.len())); + cg.indent -= 1; + cg.addln("}\n"); + } - for (i, method_name) in v_table.iter().enumerate() { + fn emit_impl_block(&self, ctx: &mut Context, cg: &mut RustCodegen) { + cg.addln(&format!( + "impl{} {} {{", + self.generics.get_rust(), + self.self_ty.get_rust() + )); + cg.indent += 1; + + self.emit_v_table(cg); + + self.emit_super_v_table(cg); + self.emit_super_v_tests(cg); + + self.emit_constructor(ctx, cg); + self.emit_methods(ctx, cg); + + cg.indent -= 1; + cg.addln("}\n"); + } + + fn emit_v_table(&self, cg: &mut RustCodegen) { + for (i, method_name) in self.v_table.iter().enumerate() { cg.add_indentedln(&format!( "pub const __FN_{}: usize = {i};", - method_name.0.0.to_uppercase() + method_name.0.to_uppercase() )); } - cg.add_indentedln("pub const __V_TABLE: [*const std::ffi::c_void; Self::__V_COUNT] = ["); + cg.add_indentedln(&format!( + "pub const __V_TABLE: [*const std::ffi::c_void; {}] = [", + self.v_table.len() + )); cg.indent += 1; - for (method_name, _) in &v_table { + 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"); @@ -111,77 +165,115 @@ pub fn class_decl( cg.add_indentedln("];"); } - // Super V Table - if let Some((inherits, inherit_path)) = &inherits { - cg.add_indented(&format!( - "pub const __SUPER_V_TABLE: [*const std::ffi::c_void; {}", - inherits.get_rust() - )); - - cg.addln("::__V_COUNT] = {"); - cg.indent += 1; - - cg.add_indented("let mut table = "); - cg.add(&inherits.get_rust()); - cg.addln("::__V_TABLE;"); - - for (name, is_override) in v_table { - if is_override { - cg.add_indentedln(&format!( - "table[{}::__FN_{}] = Self::__m_{} as *const std::ffi::c_void;", - inherits.get_rust(), - name.0.to_uppercase(), - name.get_rust() - )); - } + fn emit_super_v_table(&self, cg: &mut RustCodegen) { + if self.override_v_table.is_empty() { + return; } - cg.add_indentedln("table"); - - cg.indent -= 1; - cg.add_indentedln("};"); - - cg.add_indentedln("const fn __test_vt() {"); + cg.add_indentedln(&format!( + "pub const __SUPER_V_TABLES: [&'static [*const std::ffi::c_void]; {}] = [", + self.override_v_table.len() + )); cg.indent += 1; - for i in &methods { - if i.item.is_override { - let mut params = i - .item - .params - .clone() - .0 - .into_iter() - .filter_map(|v| v.type_) - .collect::>(); - - if params.len() == 0 { - continue; + 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 + } } + }; - match params.remove(0) { - TypeExpr::Ref { mutable, .. } => { - cg.add_indented(&inherit_path.get_rust()); - cg.add("::__m_"); - cg.add(&i.item.name.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 { + 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() + )); + } + + cg.add_indentedln("table"); + cg.indent -= 1; + cg.add_indentedln("},"); + } + + cg.indent -= 1; + cg.add_indentedln("];"); + } + + fn emit_super_v_tests(&self, cg: &mut RustCodegen) { + cg.add_indentedln(&format!("const fn __test_vt() {{")); + cg.indent += 1; + + for (override_tier, _) in self.override_v_table.iter() { + 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 + } + } + }; + + let target_rust_path = target_path.get_rust(); + + for method in &self.methods { + if method.item.is_override.as_ref() == Some(override_tier) { + let mut params = method + .item + .params + .0 + .clone() + .into_iter() + .filter_map(|v| v.type_) + .collect::>(); + + if params.is_empty() { + continue; + } + + if let TypeExpr::Ref { mutable, .. } = params.remove(0) { + cg.add_indented(&format!("{}::__m_", target_rust_path)); + cg.add(&method.item.name.get_rust()); cg.add(" as "); params.insert( 0, TypeExpr::Ref { lifetime: None, - mutable: mutable, - ty: Box::new((*inherits).clone()), + mutable, + ty: Box::new(get_type_from_path(&target_path)), }, ); cg.add( - &TypeExpr::StaticFn(params, i.item.return_type.clone().map(Box::new)) - .get_rust(), + &TypeExpr::StaticFn( + params, + method.item.return_type.clone().map(Box::new), + ) + .get_rust(), ); cg.addln(";"); } - _ => {} } } } @@ -190,94 +282,20 @@ pub fn class_decl( cg.add_indentedln("}"); } - let constructor_comment = constructor.get_comment(); + fn emit_constructor(&self, ctx: &mut Context, cg: &mut RustCodegen) { + let constructor_comment = self.constructor.get_comment(); - cg.add_indentedln("#[allow(invalid_value)]"); - cg.add_indentedln(&constructor_comment); + cg.add_indentedln("#[allow(invalid_value)]"); + cg.add_indentedln(&constructor_comment); - (fields, constructor, inherits.is_some()).gen_rust(ctx, cg); - - for mut method in methods { - match method.item.visibility { - Visibility::Public => { - if !method.item.is_override { - gen_method_point(&method.item, ctx, cg); - } - - method.item.name.0.insert_str(0, "__m_"); - } - _ => {} - } - - method.gen_rust(ctx, cg); - } - - cg.indent -= 1; - cg.addln("}\n"); - - for item in items { - match item { - ClassItem::ImplDecl(impl_) => { - let mut impl_ = impl_.clone(); - - impl_.item.trait_ = Some(impl_.item.target); - impl_.item.target = TypeExpr::Path(Path(vec![name.clone()]), None); - - impl_.gen_rust(ctx, cg); - } - ClassItem::Method(_) => {} - } - } - - if let Some((inherits, _)) = inherits { - cg.add("impl std::ops::Deref for "); - cg.add(&name.get_rust()); - - cg.addln(" {"); - cg.indent += 1; - - cg.add_indented("type Target = "); - cg.add(&inherits.get_rust()); - cg.addln(";"); - - cg.add_indentedln("fn deref(&self) -> &Self::Target {&self._super}"); - - cg.indent -= 1; - cg.addln("}"); - - // Mut - - cg.add("impl std::ops::DerefMut for "); - cg.add(&name.get_rust()); - - cg.addln(" {"); - cg.indent += 1; - - cg.add_indentedln("fn deref_mut(&mut self) -> &mut Self::Target {&mut self._super}"); - - cg.indent -= 1; - cg.addln("}"); - } - - ctx.expr_super = None; -} - -impl GenRust - for ( - &Vec>, - &Spanned, - bool, - ) -{ - fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) { cg.add_indented(&format!( "{}fn new{}(", - self.1.item.visibility.get_rust(), - self.1.item.generics.get_rust() + self.constructor.item.visibility.get_rust(), + self.constructor.item.generics.get_rust() )); let params = self - .1 + .constructor .item .params .0 @@ -294,7 +312,6 @@ impl GenRust if *i > 0 { cg.add(", "); } - param.gen_rust(ctx, cg); } @@ -305,40 +322,54 @@ impl GenRust 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);"); - for field in self.0 { + // Inline field declarations and initializers + for field in &self.fields { let comment = field.get_comment(); if let Some(init) = &field.item.init { cg.add_indentedln(&comment); - cg.add_indentedln(&format!("this.{} = ", field.item.decl.name.get_rust())); - init.gen_rust(ctx, cg); } } - cg.add_indented(&format!("this.constructor(")); - - for (i, param) in params { - if i > 0 { + cg.add_indented("this.constructor("); + for (i, param) in ¶ms { + if *i > 0 { cg.add(", "); } - ctx.expr_ensure_semicolon = false; param.name.gen_rust(ctx, cg); } - cg.addln(");"); - if self.2 { - cg.add_indentedln("this._super._m_oop.0 = &Self::__SUPER_V_TABLE;"); + if self.inherits.is_some() && !self.override_v_table.is_empty() { + for (idx, (override_tier, _)) 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(&format!( + "(|v: &mut {}| {{v._m_oop.0 = Self::__SUPER_V_TABLES[{}];}})(&mut this);", + path.get_rust(), + idx + )); + } + } + } } cg.add_indentedln("this"); - 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 { @@ -351,23 +382,117 @@ impl GenRust }), }]; - constructor_params.append(&mut self.1.item.params.0.clone()); + constructor_params.append(&mut self.constructor.item.params.0.clone()); Spanned { - line: self.1.line, - column: self.1.column, + line: self.constructor.line, + column: self.constructor.column, item: FunctionDecl { - visibility: self.1.item.visibility.clone(), - is_override: false, + visibility: self.constructor.item.visibility.clone(), + is_override: None, name: Identifier(String::from("constructor")), - generics: self.1.item.generics.clone(), + generics: self.constructor.item.generics.clone(), params: ParamList(constructor_params), return_type: Some(TypeExpr::Tuple(Vec::new())), - body: Some(self.1.item.body.clone()), + body: Some(self.constructor.item.body.clone()), }, } .gen_rust(ctx, cg); } + + fn emit_methods(&self, ctx: &mut Context, cg: &mut RustCodegen) { + 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); + } + + let mut prefixed = method.clone(); + prefixed.item.name.0.insert_str(0, "__m_"); + prefixed.gen_rust(ctx, cg); + } + _ => { + method.gen_rust(ctx, cg); + } + } + } + } + + fn emit_impl_decls(&self, ctx: &mut Context, cg: &mut RustCodegen) { + for item in &self.items { + if let ClassItem::ImplDecl(impl_) = item { + let mut impl_ = impl_.clone(); + impl_.item.trait_ = Some(impl_.item.target); + impl_.item.target = TypeExpr::Path(Path(vec![self.name.clone()]), None); + impl_.gen_rust(ctx, cg); + } + } + } + + fn emit_deref_impls(&self, cg: &mut RustCodegen) { + if let Some(ref inherits) = self.inherits { + let generics_str = self.generics.get_rust(); + let generics_expr_str = Generics::from(self.generics.clone()).get_rust(); + + cg.add(&format!( + "impl{} std::ops::Deref for {}{}", + generics_str, + self.name.get_rust(), + generics_expr_str + )); + + cg.addln(" {"); + cg.indent += 1; + + cg.add_indented("type Target = "); + cg.add(&inherits.get_rust()); + cg.addln(";"); + + cg.add_indentedln("fn deref(&self) -> &Self::Target { &self._super }"); + + cg.indent -= 1; + cg.addln("}"); + + cg.add(&format!( + "impl{} std::ops::DerefMut for {}{}", + generics_str, + self.name.get_rust(), + generics_expr_str + )); + + cg.addln(" {"); + cg.indent += 1; + + cg.add_indentedln("fn deref_mut(&mut self) -> &mut Self::Target { &mut self._super }"); + + cg.indent -= 1; + cg.addln("}"); + } + } +} + +pub fn class_decl( + ctx: &mut Context, + cg: &mut RustCodegen, + visibility: &Visibility, + name: &Identifier, + generics: &GenericsDecl, + inherits: &Option, + fields: &Vec>, + constructor: &Spanned, + items: &Vec, +) { + let data = ClassProcessedData::analyze( + visibility, + name, + generics, + inherits, + fields, + constructor, + items, + ); + data.emit(ctx, cg); } fn construct_pattern(pat: &Pattern, idx: usize) -> Pattern { @@ -386,11 +511,22 @@ pub fn gen_method_point(method: &FunctionDecl, ctx: &mut Context, cg: &mut RustC method.generics.get_rust(), )); - for (i, param) in method.params.0.iter().enumerate() { - if i > 0 { + let params = method + .params + .0 + .clone() + .into_iter() + .enumerate() + .map(|(idx, mut v)| { + v.name = construct_pattern(&v.name, idx); + (idx, v) + }) + .collect::>(); + + for (i, param) in ¶ms { + if *i > 0 { cg.add(", "); } - param.gen_rust(ctx, cg); } @@ -421,7 +557,9 @@ pub fn gen_method_point(method: &FunctionDecl, ctx: &mut Context, cg: &mut RustC .filter_map(|v| v.type_) .collect(); - param_types.remove(0); + if !param_types.is_empty() { + param_types.remove(0); + } param_types.insert( 0, @@ -439,24 +577,31 @@ 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_indentedln("func(self._m_oop.1)"); + cg.add_indented("func(self._m_oop.1"); - cg.indent -= 1; - cg.add_indentedln("}"); - - cg.indent -= 1; - cg.add_indentedln("}"); -} - -pub fn get_type_path(ty: &TypeExpr) -> Path { - match ty { - TypeExpr::Path(p, _) => p.clone(), - TypeExpr::Dyn(v) => get_type_path(v), - TypeExpr::Ref { ty, .. } => get_type_path(ty), - TypeExpr::UnsafePtr { ty, .. } => get_type_path(ty), - _ => unimplemented!(), + for (i, param) in ¶ms { + if *i == 0 { + continue; // self._m_oop.1 already fulfills it + } + cg.add(", "); + ctx.expr_ensure_semicolon = false; + param.name.gen_rust(ctx, cg); } + + cg.addln(")"); + + cg.indent -= 1; + cg.add_indentedln("}"); + + cg.indent -= 1; + cg.add_indentedln("}"); +} + +pub fn get_type_from_path(path: &ExprPath) -> TypeExpr { + TypeExpr::Path( + Path(path.0.iter().map(|v| v.ident.clone()).collect::>()), + path.0.last().unwrap().generics.clone(), + ) } diff --git a/crates/codegen/src/expr.rs b/crates/codegen/src/expr.rs index e4e2701..f6fb129 100644 --- a/crates/codegen/src/expr.rs +++ b/crates/codegen/src/expr.rs @@ -20,17 +20,7 @@ impl GetRust for ExprPath { if self.0[0].ident.0 == "super" && self.0.len() == 1 { a.0[0].ident.0 = String::from("self._super"); } else if self.0[0].ident.0 == "Super" { - a.0[0].ident = path.0[0].clone(); - - if path.0.len() > 1 { - a.0.splice( - 1..1, - path.0.clone().into_iter().skip(1).map(|v| ExprPathSegment { - ident: v, - generics: None, - }), - ); - } + a.0[0] = path.0[0].clone(); } } diff --git a/crates/codegen/src/lib.rs b/crates/codegen/src/lib.rs index f6c466b..cbcc7ef 100644 --- a/crates/codegen/src/lib.rs +++ b/crates/codegen/src/lib.rs @@ -7,7 +7,7 @@ use mist_parser::ast::*; pub struct Context { pub expr_ensure_semicolon: bool, - pub expr_super: Option, + pub expr_super: Option, } pub trait GenRust { diff --git a/crates/parser/src/ast/expr.rs b/crates/parser/src/ast/expr.rs index 04715c6..747ebbf 100644 --- a/crates/parser/src/ast/expr.rs +++ b/crates/parser/src/ast/expr.rs @@ -79,19 +79,19 @@ pub enum Prefix { Neg, } -#[derive(Debug, Clone, Serialize)] +#[derive(Debug, Clone, Serialize, PartialEq, Eq, Hash)] pub struct ExprPathSegment { pub ident: Identifier, pub generics: Option, } -#[derive(Debug, Clone, Serialize)] +#[derive(Debug, Clone, Serialize, PartialEq, Eq, Hash)] pub struct ExprPath(pub Vec); -#[derive(Debug, Clone, Serialize)] +#[derive(Debug, Clone, Serialize, PartialEq, Eq, Hash)] pub struct Generics(pub Vec); -#[derive(Debug, Clone, Serialize)] +#[derive(Debug, Clone, Serialize, PartialEq, Eq, Hash)] pub enum Generic { Lifetime(Identifier), Type(TypeExpr), diff --git a/crates/parser/src/ast/mod.rs b/crates/parser/src/ast/mod.rs index 89b12fb..28e8cf8 100644 --- a/crates/parser/src/ast/mod.rs +++ b/crates/parser/src/ast/mod.rs @@ -8,16 +8,16 @@ pub use expr::*; pub use statement::*; pub use top_level::*; -#[derive(Debug, Clone, Serialize)] +#[derive(Debug, Clone, Serialize, PartialEq, Eq, Hash)] pub struct Path(pub Vec); -#[derive(Debug, Clone, Serialize)] +#[derive(Debug, Clone, Serialize, PartialEq, Eq, Hash)] pub struct Identifier(pub String); #[derive(Debug, Clone, Serialize, Default)] pub struct ParamList(pub Vec); -#[derive(Debug, Clone, Serialize)] +#[derive(Debug, Clone, Serialize, PartialEq, Eq, Hash)] pub enum TypeExpr { Ref { lifetime: Option, @@ -51,6 +51,22 @@ impl From for Generic { } } +impl Into> for GenericsDecl { + fn into(self) -> Option { + if self.0.len() == 0 { + None + } else { + Some(self.into()) + } + } +} + +impl From for Generics { + fn from(value: GenericsDecl) -> Self { + Self(value.0.into_iter().map(Generic::from).collect()) + } +} + impl Spanned { pub fn get_comment(&self) -> String { format!("/* {}:{} */", self.line, self.column) diff --git a/crates/parser/src/ast/top_level.rs b/crates/parser/src/ast/top_level.rs index f6fe296..521fb97 100644 --- a/crates/parser/src/ast/top_level.rs +++ b/crates/parser/src/ast/top_level.rs @@ -54,7 +54,7 @@ pub enum TopLevelKind { visibility: Visibility, name: Identifier, generics: GenericsDecl, - inherits: Option, + inherits: Option, fields: Vec>, constructor: Spanned, items: Vec, @@ -91,10 +91,13 @@ pub struct ClassConstructor { pub body: Block, } +#[derive(Debug, Clone, Serialize, PartialEq, Eq, Hash)] +pub struct Override(pub Option); + #[derive(Debug, Clone, Serialize)] pub struct FunctionDecl { pub visibility: Visibility, - pub is_override: bool, + pub is_override: Option, pub name: Identifier, pub generics: GenericsDecl, pub params: ParamList, diff --git a/crates/parser/src/grammar.pest b/crates/parser/src/grammar.pest index 3c20825..67ab7d8 100644 --- a/crates/parser/src/grammar.pest +++ b/crates/parser/src/grammar.pest @@ -294,7 +294,7 @@ class_item = _{ } class_decl = { - visibility? ~ "class" ~ identifier ~ generics_decl? ~ (":" ~ type_expr)? ~ "{" ~ class_fields ~ class_constructor ~ class_item* ~ "}" + visibility? ~ "class" ~ identifier ~ generics_decl? ~ (":" ~ expr_path)? ~ "{" ~ class_fields ~ class_constructor ~ class_item* ~ "}" } // ====================================================== @@ -325,7 +325,7 @@ trait_decl = { // FUNCTIONS // ====================================================== -override_kw = { "override" } +override_kw = { "override" ~ ("(" ~ expr_path ~ ")")? } function_decl = { visibility? ~ override_kw? ~ "fn" ~ identifier ~ generics_decl? ~ "(" ~ method_args ~ ")" ~ type_expr? ~ (block | semicolon) diff --git a/crates/parser/src/parser/items/function.rs b/crates/parser/src/parser/items/function.rs index 4e68469..18b720b 100644 --- a/crates/parser/src/parser/items/function.rs +++ b/crates/parser/src/parser/items/function.rs @@ -13,7 +13,7 @@ impl<'a> TryFrom> for FunctionDecl { ast_ensure!(pair, Rule::function_decl => { let mut inner = pair.into_inner(); let visibility = Visibility::try_from(&mut inner); - let is_override: AstResult = Ok(listen_rule(&mut inner, Rule::override_kw)); + let is_override = consume_rule(&mut inner, Rule::override_kw).map(Override::try_from).transpose(); let name = Identifier::try_from(inner.next().unwrap()); let generics = consume_rule(&mut inner, Rule::generics_decl) @@ -77,3 +77,13 @@ impl<'a> TryFrom> for FunctionDecl { }) } } + +impl<'a> TryFrom> for Override { + type Error = AstError<'a, Self>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + ast_ensure!(pair, Rule::override_kw => { + ast_expr!(Override(pair.into_inner().next().map(ExprPath::try_from).transpose())) + }) + } +} diff --git a/crates/parser/src/parser/items/mod.rs b/crates/parser/src/parser/items/mod.rs index 7b49a1a..ebaf0a4 100644 --- a/crates/parser/src/parser/items/mod.rs +++ b/crates/parser/src/parser/items/mod.rs @@ -69,8 +69,8 @@ impl<'a> TryFrom> for TopLevelKind { .transpose() .map(|v| v.unwrap_or_default()), - inherits: consume_rule(&mut inner, Rule::type_expr) - .map(TypeExpr::try_from) + inherits: consume_rule(&mut inner, Rule::expr_path) + .map(ExprPath::try_from) .transpose(), fields: collect_recovered(inner.next().unwrap().into_inner()), diff --git a/mist-test/src/items/class_test.mist b/mist-test/src/items/class_test.mist index b95f19d..9c74c73 100644 --- a/mist-test/src/items/class_test.mist +++ b/mist-test/src/items/class_test.mist @@ -1,5 +1,6 @@ -pub class Animal { +pub class Animal { pub name String; + pub val T; constructor() { self.name = "Rex".to_string(); @@ -14,20 +15,42 @@ pub class Animal { } } -pub class Dog : Animal { +pub class Mammal : Animal { constructor() { unsafe { std::ptr::write(&mut super, Super::new()); } } - pub override fn speak(*self) { + pub fn args_test(*self, x i32, y *str) {} + + pub fn returning<'a>(*self) *'a str { + "Mammal" + } +} + +pub class Dog : Mammal { + constructor() { + unsafe { + std::ptr::write(&mut super, Super::new()); + } + } + + pub override(Animal) fn speak(*self) { println!("Woof!"); } + + pub override fn returning(*self) *str { + "Dog" + } } pub fn run_tests() { let dawg = Dog::new(); + dawg.args_test(10, "hello"); + dawg.test_speak(); + + println!("{}", dawg.returning()); }