Merge pull request #70 from mist-go/fully-working-inheritance
Fully working inheritance & OOP
This commit is contained in:
+397
-252
@@ -1,106 +1,160 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use mist_parser::ast::*;
|
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<ExprPath>,
|
||||||
|
self_path: ExprPath,
|
||||||
|
self_ty: TypeExpr,
|
||||||
|
fields: Vec<Spanned<FieldDeclStmt>>,
|
||||||
|
constructor: Spanned<ClassConstructor>,
|
||||||
|
items: Vec<ClassItem>,
|
||||||
|
methods: Vec<Spanned<FunctionDecl>>,
|
||||||
|
v_table: Vec<Identifier>,
|
||||||
|
override_v_table: HashMap<Override, Vec<Identifier>>,
|
||||||
|
}
|
||||||
|
|
||||||
pub fn class_decl(
|
impl ClassProcessedData {
|
||||||
ctx: &mut Context,
|
pub fn analyze(
|
||||||
cg: &mut RustCodegen,
|
visibility: &Visibility,
|
||||||
|
name: &Identifier,
|
||||||
|
generics: &GenericsDecl,
|
||||||
|
inherits: &Option<ExprPath>,
|
||||||
|
fields: &Vec<Spanned<FieldDeclStmt>>,
|
||||||
|
constructor: &Spanned<ClassConstructor>,
|
||||||
|
items: &Vec<ClassItem>,
|
||||||
|
) -> Self {
|
||||||
|
let self_path = ExprPath(vec![ExprPathSegment {
|
||||||
|
ident: name.clone(),
|
||||||
|
generics: generics.clone().into(),
|
||||||
|
}]);
|
||||||
|
|
||||||
visibility: &Visibility,
|
let self_ty = get_type_from_path(&self_path);
|
||||||
name: &Identifier,
|
|
||||||
generics: &GenericsDecl,
|
|
||||||
inherits: &Option<TypeExpr>,
|
|
||||||
fields: &Vec<Spanned<FieldDeclStmt>>,
|
|
||||||
constructor: &Spanned<ClassConstructor>,
|
|
||||||
items: &Vec<ClassItem>,
|
|
||||||
) {
|
|
||||||
let inherits = if let Some(inherits) = inherits {
|
|
||||||
let path = get_type_path(inherits);
|
|
||||||
ctx.expr_super = Some(path.clone());
|
|
||||||
Some((inherits, path))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
// Struct decl
|
let methods = items
|
||||||
cg.addln(&format!(
|
.iter()
|
||||||
"{}struct {}{} {{",
|
.filter_map(|item| match item {
|
||||||
visibility.get_rust(),
|
ClassItem::ImplDecl(_) => None,
|
||||||
name.clone().get_rust(),
|
ClassItem::Method(method) => Some(method.clone()),
|
||||||
generics.clone().get_rust()
|
})
|
||||||
));
|
.collect::<Vec<Spanned<FunctionDecl>>>();
|
||||||
cg.indent += 1;
|
|
||||||
|
|
||||||
cg.add_indentedln(
|
let mut v_table = Vec::new();
|
||||||
"pub _m_oop: (&'static [*const std::ffi::c_void; Self::__V_COUNT], *mut std::ffi::c_void),",
|
let mut override_v_table = std::collections::HashMap::new();
|
||||||
);
|
|
||||||
|
|
||||||
if let Some((inherits, _)) = inherits {
|
for method in &methods {
|
||||||
cg.add_indented("pub _super: Box<");
|
if matches!(method.item.visibility, Visibility::Public) {
|
||||||
cg.add(&inherits.get_rust());
|
match &method.item.is_override {
|
||||||
cg.addln(">,");
|
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() {
|
// ── Stage 2: Code Emission ───────────────────────────────────────
|
||||||
cg.add_indentedln(&field.get_comment());
|
|
||||||
cg.add_indentedln(&field.item.decl.get_rust());
|
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;
|
fn emit_struct_decl(&self, cg: &mut RustCodegen) {
|
||||||
cg.addln("}\n");
|
cg.addln(&format!(
|
||||||
|
"{}struct {}{} {{",
|
||||||
|
self.visibility.get_rust(),
|
||||||
|
self.name.get_rust(),
|
||||||
|
self.generics.get_rust()
|
||||||
|
));
|
||||||
|
cg.indent += 1;
|
||||||
|
|
||||||
// Constructor
|
cg.add_indentedln(
|
||||||
cg.addln(&format!(
|
"pub _m_oop: (&'static [*const std::ffi::c_void], *mut std::ffi::c_void),",
|
||||||
"impl{} {}{} {{",
|
);
|
||||||
generics.clone().get_rust(),
|
|
||||||
name.clone().get_rust(),
|
|
||||||
format!(
|
|
||||||
"<{}>",
|
|
||||||
generics
|
|
||||||
.clone()
|
|
||||||
.0
|
|
||||||
.into_iter()
|
|
||||||
.map(|v| Generic::from(v).get_rust())
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(", ")
|
|
||||||
)
|
|
||||||
));
|
|
||||||
cg.indent += 1;
|
|
||||||
|
|
||||||
let methods = items
|
if let Some(ref inherits) = self.inherits {
|
||||||
.clone()
|
cg.add_indented("pub _super: Box<");
|
||||||
.into_iter()
|
cg.add(&get_type_from_path(inherits).get_rust());
|
||||||
.filter_map(|item| match item {
|
cg.addln(">,");
|
||||||
ClassItem::ImplDecl(_) => None,
|
}
|
||||||
ClassItem::Method(method) => Some(method),
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let v_table = methods
|
for field in &self.fields {
|
||||||
.iter()
|
cg.add_indentedln(&field.get_comment());
|
||||||
.filter_map(|method| match method.item.visibility {
|
cg.add_indentedln(&field.item.decl.get_rust());
|
||||||
Visibility::Public => Some((method.item.name.clone(), method.item.is_override)),
|
}
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
// V TABLE
|
cg.indent -= 1;
|
||||||
{
|
cg.addln("}\n");
|
||||||
cg.add_indentedln(&format!("pub const __V_COUNT: usize = {};", v_table.len()));
|
}
|
||||||
|
|
||||||
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!(
|
cg.add_indentedln(&format!(
|
||||||
"pub const __FN_{}: usize = {i};",
|
"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;
|
cg.indent += 1;
|
||||||
|
|
||||||
for (method_name, _) in &v_table {
|
for method_name in &self.v_table {
|
||||||
cg.add_indented("Self::__m_");
|
cg.add_indented("Self::__m_");
|
||||||
cg.add(&method_name.get_rust());
|
cg.add(&method_name.get_rust());
|
||||||
cg.add(" as *const std::ffi::c_void");
|
cg.add(" as *const std::ffi::c_void");
|
||||||
@@ -111,77 +165,115 @@ pub fn class_decl(
|
|||||||
cg.add_indentedln("];");
|
cg.add_indentedln("];");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Super V Table
|
fn emit_super_v_table(&self, cg: &mut RustCodegen) {
|
||||||
if let Some((inherits, inherit_path)) = &inherits {
|
if self.override_v_table.is_empty() {
|
||||||
cg.add_indented(&format!(
|
return;
|
||||||
"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()
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cg.add_indentedln("table");
|
cg.add_indentedln(&format!(
|
||||||
|
"pub const __SUPER_V_TABLES: [&'static [*const std::ffi::c_void]; {}] = [",
|
||||||
cg.indent -= 1;
|
self.override_v_table.len()
|
||||||
cg.add_indentedln("};");
|
));
|
||||||
|
|
||||||
cg.add_indentedln("const fn __test_vt() {");
|
|
||||||
cg.indent += 1;
|
cg.indent += 1;
|
||||||
|
|
||||||
for i in &methods {
|
for (override_tier, overriden_method_idents) in &self.override_v_table {
|
||||||
if i.item.is_override {
|
let target_path = match &override_tier.0 {
|
||||||
let mut params = i
|
Some(path) => path.clone(),
|
||||||
.item
|
None => {
|
||||||
.params
|
if let Some(parent_path) = &self.inherits {
|
||||||
.clone()
|
parent_path.clone()
|
||||||
.0
|
} else {
|
||||||
.into_iter()
|
continue; // Safeguard if AST has a dangling override without inheritance
|
||||||
.filter_map(|v| v.type_)
|
}
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
if params.len() == 0 {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
match params.remove(0) {
|
let target_rust_path = target_path.get_rust();
|
||||||
TypeExpr::Ref { mutable, .. } => {
|
|
||||||
cg.add_indented(&inherit_path.get_rust());
|
// 2. Emit the block for this specific index table
|
||||||
cg.add("::__m_");
|
cg.add_indentedln("&{");
|
||||||
cg.add(&i.item.name.get_rust());
|
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::<Vec<_>>();
|
||||||
|
|
||||||
|
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 ");
|
cg.add(" as ");
|
||||||
|
|
||||||
params.insert(
|
params.insert(
|
||||||
0,
|
0,
|
||||||
TypeExpr::Ref {
|
TypeExpr::Ref {
|
||||||
lifetime: None,
|
lifetime: None,
|
||||||
mutable: mutable,
|
mutable,
|
||||||
ty: Box::new((*inherits).clone()),
|
ty: Box::new(get_type_from_path(&target_path)),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
cg.add(
|
cg.add(
|
||||||
&TypeExpr::StaticFn(params, i.item.return_type.clone().map(Box::new))
|
&TypeExpr::StaticFn(
|
||||||
.get_rust(),
|
params,
|
||||||
|
method.item.return_type.clone().map(Box::new),
|
||||||
|
)
|
||||||
|
.get_rust(),
|
||||||
);
|
);
|
||||||
cg.addln(";");
|
cg.addln(";");
|
||||||
}
|
}
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -190,94 +282,20 @@ pub fn class_decl(
|
|||||||
cg.add_indentedln("}");
|
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("#[allow(invalid_value)]");
|
||||||
cg.add_indentedln(&constructor_comment);
|
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<FieldDeclStmt>>,
|
|
||||||
&Spanned<ClassConstructor>,
|
|
||||||
bool,
|
|
||||||
)
|
|
||||||
{
|
|
||||||
fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
|
|
||||||
cg.add_indented(&format!(
|
cg.add_indented(&format!(
|
||||||
"{}fn new{}(",
|
"{}fn new{}(",
|
||||||
self.1.item.visibility.get_rust(),
|
self.constructor.item.visibility.get_rust(),
|
||||||
self.1.item.generics.get_rust()
|
self.constructor.item.generics.get_rust()
|
||||||
));
|
));
|
||||||
|
|
||||||
let params = self
|
let params = self
|
||||||
.1
|
.constructor
|
||||||
.item
|
.item
|
||||||
.params
|
.params
|
||||||
.0
|
.0
|
||||||
@@ -294,7 +312,6 @@ impl GenRust
|
|||||||
if *i > 0 {
|
if *i > 0 {
|
||||||
cg.add(", ");
|
cg.add(", ");
|
||||||
}
|
}
|
||||||
|
|
||||||
param.gen_rust(ctx, cg);
|
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("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("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();
|
let comment = field.get_comment();
|
||||||
|
|
||||||
if let Some(init) = &field.item.init {
|
if let Some(init) = &field.item.init {
|
||||||
cg.add_indentedln(&comment);
|
cg.add_indentedln(&comment);
|
||||||
|
|
||||||
cg.add_indentedln(&format!("this.{} = ", field.item.decl.name.get_rust()));
|
cg.add_indentedln(&format!("this.{} = ", field.item.decl.name.get_rust()));
|
||||||
|
|
||||||
init.gen_rust(ctx, cg);
|
init.gen_rust(ctx, cg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cg.add_indented(&format!("this.constructor("));
|
cg.add_indented("this.constructor(");
|
||||||
|
for (i, param) in ¶ms {
|
||||||
for (i, param) in params {
|
if *i > 0 {
|
||||||
if i > 0 {
|
|
||||||
cg.add(", ");
|
cg.add(", ");
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.expr_ensure_semicolon = false;
|
ctx.expr_ensure_semicolon = false;
|
||||||
param.name.gen_rust(ctx, cg);
|
param.name.gen_rust(ctx, cg);
|
||||||
}
|
}
|
||||||
|
|
||||||
cg.addln(");");
|
cg.addln(");");
|
||||||
|
|
||||||
if self.2 {
|
if self.inherits.is_some() && !self.override_v_table.is_empty() {
|
||||||
cg.add_indentedln("this._super._m_oop.0 = &Self::__SUPER_V_TABLE;");
|
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.add_indentedln("this");
|
||||||
|
|
||||||
cg.indent -= 1;
|
cg.indent -= 1;
|
||||||
cg.add_indentedln("}\n");
|
cg.add_indentedln("}\n");
|
||||||
|
|
||||||
|
// Generate matching inner initialization body block
|
||||||
let mut constructor_params = vec![VarDecl {
|
let mut constructor_params = vec![VarDecl {
|
||||||
name: Pattern::Path(false, Path(vec![Identifier(String::from("self"))])),
|
name: Pattern::Path(false, Path(vec![Identifier(String::from("self"))])),
|
||||||
type_: Some(TypeExpr::Ref {
|
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 {
|
Spanned {
|
||||||
line: self.1.line,
|
line: self.constructor.line,
|
||||||
column: self.1.column,
|
column: self.constructor.column,
|
||||||
item: FunctionDecl {
|
item: FunctionDecl {
|
||||||
visibility: self.1.item.visibility.clone(),
|
visibility: self.constructor.item.visibility.clone(),
|
||||||
is_override: false,
|
is_override: None,
|
||||||
name: Identifier(String::from("constructor")),
|
name: Identifier(String::from("constructor")),
|
||||||
generics: self.1.item.generics.clone(),
|
generics: self.constructor.item.generics.clone(),
|
||||||
params: ParamList(constructor_params),
|
params: ParamList(constructor_params),
|
||||||
return_type: Some(TypeExpr::Tuple(Vec::new())),
|
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);
|
.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<ExprPath>,
|
||||||
|
fields: &Vec<Spanned<FieldDeclStmt>>,
|
||||||
|
constructor: &Spanned<ClassConstructor>,
|
||||||
|
items: &Vec<ClassItem>,
|
||||||
|
) {
|
||||||
|
let data = ClassProcessedData::analyze(
|
||||||
|
visibility,
|
||||||
|
name,
|
||||||
|
generics,
|
||||||
|
inherits,
|
||||||
|
fields,
|
||||||
|
constructor,
|
||||||
|
items,
|
||||||
|
);
|
||||||
|
data.emit(ctx, cg);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn construct_pattern(pat: &Pattern, idx: usize) -> Pattern {
|
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(),
|
method.generics.get_rust(),
|
||||||
));
|
));
|
||||||
|
|
||||||
for (i, param) in method.params.0.iter().enumerate() {
|
let params = method
|
||||||
if i > 0 {
|
.params
|
||||||
|
.0
|
||||||
|
.clone()
|
||||||
|
.into_iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(idx, mut v)| {
|
||||||
|
v.name = construct_pattern(&v.name, idx);
|
||||||
|
(idx, v)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
for (i, param) in ¶ms {
|
||||||
|
if *i > 0 {
|
||||||
cg.add(", ");
|
cg.add(", ");
|
||||||
}
|
}
|
||||||
|
|
||||||
param.gen_rust(ctx, cg);
|
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_)
|
.filter_map(|v| v.type_)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
param_types.remove(0);
|
if !param_types.is_empty() {
|
||||||
|
param_types.remove(0);
|
||||||
|
}
|
||||||
|
|
||||||
param_types.insert(
|
param_types.insert(
|
||||||
0,
|
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.add(&TypeExpr::StaticFn(param_types, method.return_type.clone().map(Box::new)).get_rust());
|
||||||
|
|
||||||
cg.addln(" = std::mem::transmute(func_ptr);");
|
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;
|
for (i, param) in ¶ms {
|
||||||
cg.add_indentedln("}");
|
if *i == 0 {
|
||||||
|
continue; // self._m_oop.1 already fulfills it
|
||||||
cg.indent -= 1;
|
}
|
||||||
cg.add_indentedln("}");
|
cg.add(", ");
|
||||||
}
|
ctx.expr_ensure_semicolon = false;
|
||||||
|
param.name.gen_rust(ctx, cg);
|
||||||
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!(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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::<Vec<_>>()),
|
||||||
|
path.0.last().unwrap().generics.clone(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,17 +20,7 @@ impl GetRust for ExprPath {
|
|||||||
if self.0[0].ident.0 == "super" && self.0.len() == 1 {
|
if self.0[0].ident.0 == "super" && self.0.len() == 1 {
|
||||||
a.0[0].ident.0 = String::from("self._super");
|
a.0[0].ident.0 = String::from("self._super");
|
||||||
} else if self.0[0].ident.0 == "Super" {
|
} else if self.0[0].ident.0 == "Super" {
|
||||||
a.0[0].ident = path.0[0].clone();
|
a.0[0] = 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,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use mist_parser::ast::*;
|
|||||||
|
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
pub expr_ensure_semicolon: bool,
|
pub expr_ensure_semicolon: bool,
|
||||||
pub expr_super: Option<Path>,
|
pub expr_super: Option<ExprPath>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait GenRust {
|
pub trait GenRust {
|
||||||
|
|||||||
@@ -79,19 +79,19 @@ pub enum Prefix {
|
|||||||
Neg,
|
Neg,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize, PartialEq, Eq, Hash)]
|
||||||
pub struct ExprPathSegment {
|
pub struct ExprPathSegment {
|
||||||
pub ident: Identifier,
|
pub ident: Identifier,
|
||||||
pub generics: Option<Generics>,
|
pub generics: Option<Generics>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize, PartialEq, Eq, Hash)]
|
||||||
pub struct ExprPath(pub Vec<ExprPathSegment>);
|
pub struct ExprPath(pub Vec<ExprPathSegment>);
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize, PartialEq, Eq, Hash)]
|
||||||
pub struct Generics(pub Vec<Generic>);
|
pub struct Generics(pub Vec<Generic>);
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize, PartialEq, Eq, Hash)]
|
||||||
pub enum Generic {
|
pub enum Generic {
|
||||||
Lifetime(Identifier),
|
Lifetime(Identifier),
|
||||||
Type(TypeExpr),
|
Type(TypeExpr),
|
||||||
|
|||||||
@@ -8,16 +8,16 @@ pub use expr::*;
|
|||||||
pub use statement::*;
|
pub use statement::*;
|
||||||
pub use top_level::*;
|
pub use top_level::*;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize, PartialEq, Eq, Hash)]
|
||||||
pub struct Path(pub Vec<Identifier>);
|
pub struct Path(pub Vec<Identifier>);
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize, PartialEq, Eq, Hash)]
|
||||||
pub struct Identifier(pub String);
|
pub struct Identifier(pub String);
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Default)]
|
#[derive(Debug, Clone, Serialize, Default)]
|
||||||
pub struct ParamList(pub Vec<VarDecl>);
|
pub struct ParamList(pub Vec<VarDecl>);
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize, PartialEq, Eq, Hash)]
|
||||||
pub enum TypeExpr {
|
pub enum TypeExpr {
|
||||||
Ref {
|
Ref {
|
||||||
lifetime: Option<Identifier>,
|
lifetime: Option<Identifier>,
|
||||||
@@ -51,6 +51,22 @@ impl From<GenericDecl> for Generic {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Into<Option<Generics>> for GenericsDecl {
|
||||||
|
fn into(self) -> Option<Generics> {
|
||||||
|
if self.0.len() == 0 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(self.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<GenericsDecl> for Generics {
|
||||||
|
fn from(value: GenericsDecl) -> Self {
|
||||||
|
Self(value.0.into_iter().map(Generic::from).collect())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> Spanned<T> {
|
impl<T> Spanned<T> {
|
||||||
pub fn get_comment(&self) -> String {
|
pub fn get_comment(&self) -> String {
|
||||||
format!("/* {}:{} */", self.line, self.column)
|
format!("/* {}:{} */", self.line, self.column)
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ pub enum TopLevelKind {
|
|||||||
visibility: Visibility,
|
visibility: Visibility,
|
||||||
name: Identifier,
|
name: Identifier,
|
||||||
generics: GenericsDecl,
|
generics: GenericsDecl,
|
||||||
inherits: Option<TypeExpr>,
|
inherits: Option<ExprPath>,
|
||||||
fields: Vec<Spanned<FieldDeclStmt>>,
|
fields: Vec<Spanned<FieldDeclStmt>>,
|
||||||
constructor: Spanned<ClassConstructor>,
|
constructor: Spanned<ClassConstructor>,
|
||||||
items: Vec<ClassItem>,
|
items: Vec<ClassItem>,
|
||||||
@@ -91,10 +91,13 @@ pub struct ClassConstructor {
|
|||||||
pub body: Block,
|
pub body: Block,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, PartialEq, Eq, Hash)]
|
||||||
|
pub struct Override(pub Option<ExprPath>);
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct FunctionDecl {
|
pub struct FunctionDecl {
|
||||||
pub visibility: Visibility,
|
pub visibility: Visibility,
|
||||||
pub is_override: bool,
|
pub is_override: Option<Override>,
|
||||||
pub name: Identifier,
|
pub name: Identifier,
|
||||||
pub generics: GenericsDecl,
|
pub generics: GenericsDecl,
|
||||||
pub params: ParamList,
|
pub params: ParamList,
|
||||||
|
|||||||
@@ -294,7 +294,7 @@ class_item = _{
|
|||||||
}
|
}
|
||||||
|
|
||||||
class_decl = {
|
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
|
// FUNCTIONS
|
||||||
// ======================================================
|
// ======================================================
|
||||||
|
|
||||||
override_kw = { "override" }
|
override_kw = { "override" ~ ("(" ~ expr_path ~ ")")? }
|
||||||
|
|
||||||
function_decl = {
|
function_decl = {
|
||||||
visibility? ~ override_kw? ~ "fn" ~ identifier ~ generics_decl? ~ "(" ~ method_args ~ ")" ~ type_expr? ~ (block | semicolon)
|
visibility? ~ override_kw? ~ "fn" ~ identifier ~ generics_decl? ~ "(" ~ method_args ~ ")" ~ type_expr? ~ (block | semicolon)
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for FunctionDecl {
|
|||||||
ast_ensure!(pair, Rule::function_decl => {
|
ast_ensure!(pair, Rule::function_decl => {
|
||||||
let mut inner = pair.into_inner();
|
let mut inner = pair.into_inner();
|
||||||
let visibility = Visibility::try_from(&mut inner);
|
let visibility = Visibility::try_from(&mut inner);
|
||||||
let is_override: AstResult<bool> = 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 name = Identifier::try_from(inner.next().unwrap());
|
||||||
|
|
||||||
let generics = consume_rule(&mut inner, Rule::generics_decl)
|
let generics = consume_rule(&mut inner, Rule::generics_decl)
|
||||||
@@ -77,3 +77,13 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for FunctionDecl {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Override {
|
||||||
|
type Error = AstError<'a, Self>;
|
||||||
|
|
||||||
|
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
|
||||||
|
ast_ensure!(pair, Rule::override_kw => {
|
||||||
|
ast_expr!(Override(pair.into_inner().next().map(ExprPath::try_from).transpose()))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -69,8 +69,8 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for TopLevelKind {
|
|||||||
.transpose()
|
.transpose()
|
||||||
.map(|v| v.unwrap_or_default()),
|
.map(|v| v.unwrap_or_default()),
|
||||||
|
|
||||||
inherits: consume_rule(&mut inner, Rule::type_expr)
|
inherits: consume_rule(&mut inner, Rule::expr_path)
|
||||||
.map(TypeExpr::try_from)
|
.map(ExprPath::try_from)
|
||||||
.transpose(),
|
.transpose(),
|
||||||
|
|
||||||
fields: collect_recovered(inner.next().unwrap().into_inner()),
|
fields: collect_recovered(inner.next().unwrap().into_inner()),
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
pub class Animal {
|
pub class Animal<T> {
|
||||||
pub name String;
|
pub name String;
|
||||||
|
pub val T;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
self.name = "Rex".to_string();
|
self.name = "Rex".to_string();
|
||||||
@@ -14,20 +15,42 @@ pub class Animal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub class Dog : Animal {
|
pub class Mammal<T> : Animal<T> {
|
||||||
constructor() {
|
constructor() {
|
||||||
unsafe {
|
unsafe {
|
||||||
std::ptr::write(&mut super, Super::new());
|
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<i32> {
|
||||||
|
constructor() {
|
||||||
|
unsafe {
|
||||||
|
std::ptr::write(&mut super, Super::new());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub override(Animal<i32>) fn speak(*self) {
|
||||||
println!("Woof!");
|
println!("Woof!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub override fn returning(*self) *str {
|
||||||
|
"Dog"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_tests() {
|
pub fn run_tests() {
|
||||||
let dawg = Dog::new();
|
let dawg = Dog::new();
|
||||||
|
|
||||||
|
dawg.args_test(10, "hello");
|
||||||
|
|
||||||
dawg.test_speak();
|
dawg.test_speak();
|
||||||
|
|
||||||
|
println!("{}", dawg.returning());
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user