Merge pull request #69 from mist-go/oop-inheritance

OOP & inheritance
This commit is contained in:
2026-06-07 23:48:53 +02:00
committed by GitHub
12 changed files with 591 additions and 284 deletions
+462
View File
@@ -0,0 +1,462 @@
use mist_parser::ast::*;
use crate::Context;
use crate::{GenRust, GetRust, RustCodegen};
pub fn class_decl(
ctx: &mut Context,
cg: &mut RustCodegen,
visibility: &Visibility,
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
cg.addln(&format!(
"{}struct {}{} {{",
visibility.get_rust(),
name.clone().get_rust(),
generics.clone().get_rust()
));
cg.indent += 1;
cg.add_indentedln(
"pub _m_oop: (&'static [*const std::ffi::c_void; Self::__V_COUNT], *mut std::ffi::c_void),",
);
if let Some((inherits, _)) = inherits {
cg.add_indented("pub _super: Box<");
cg.add(&inherits.get_rust());
cg.addln(">,");
}
for field in fields.clone() {
cg.add_indentedln(&field.get_comment());
cg.add_indentedln(&field.item.decl.get_rust());
}
cg.indent -= 1;
cg.addln("}\n");
// 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::<Vec<_>>()
.join(", ")
)
));
cg.indent += 1;
let methods = items
.clone()
.into_iter()
.filter_map(|item| match item {
ClassItem::ImplDecl(_) => None,
ClassItem::Method(method) => Some(method),
})
.collect::<Vec<_>>();
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::<Vec<_>>();
// V TABLE
{
cg.add_indentedln(&format!("pub const __V_COUNT: usize = {};", v_table.len()));
for (i, method_name) in v_table.iter().enumerate() {
cg.add_indentedln(&format!(
"pub const __FN_{}: usize = {i};",
method_name.0.0.to_uppercase()
));
}
cg.add_indentedln("pub const __V_TABLE: [*const std::ffi::c_void; Self::__V_COUNT] = [");
cg.indent += 1;
for (method_name, _) in &v_table {
cg.add_indented("Self::__m_");
cg.add(&method_name.get_rust());
cg.add(" as *const std::ffi::c_void");
cg.addln(",");
}
cg.indent -= 1;
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()
));
}
}
cg.add_indentedln("table");
cg.indent -= 1;
cg.add_indentedln("};");
cg.add_indentedln("const fn __test_vt() {");
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::<Vec<_>>();
if params.len() == 0 {
continue;
}
match params.remove(0) {
TypeExpr::Ref { mutable, .. } => {
cg.add_indented(&inherit_path.get_rust());
cg.add("::__m_");
cg.add(&i.item.name.get_rust());
cg.add(" as ");
params.insert(
0,
TypeExpr::Ref {
lifetime: None,
mutable: mutable,
ty: Box::new((*inherits).clone()),
},
);
cg.add(
&TypeExpr::StaticFn(params, i.item.return_type.clone().map(Box::new))
.get_rust(),
);
cg.addln(";");
}
_ => {}
}
}
}
cg.indent -= 1;
cg.add_indentedln("}");
}
let constructor_comment = constructor.get_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<FieldDeclStmt>>,
&Spanned<ClassConstructor>,
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()
));
let params = self
.1
.item
.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 &params {
if *i > 0 {
cg.add(", ");
}
param.gen_rust(ctx, cg);
}
cg.addln(") -> Box<Self> {");
cg.indent += 1;
cg.add_indentedln("let mut this = Box::new(unsafe { std::mem::MaybeUninit::<Self>::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);");
for field in self.0 {
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(", ");
}
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;");
}
cg.add_indentedln("this");
cg.indent -= 1;
cg.add_indentedln("}\n");
let mut constructor_params = vec![VarDecl {
name: Pattern::Path(false, Path(vec![Identifier(String::from("self"))])),
type_: Some(TypeExpr::Ref {
lifetime: None,
mutable: true,
ty: Box::new(TypeExpr::Path(
Path(vec![Identifier(String::from("Self"))]),
None,
)),
}),
}];
constructor_params.append(&mut self.1.item.params.0.clone());
Spanned {
line: self.1.line,
column: self.1.column,
item: FunctionDecl {
visibility: self.1.item.visibility.clone(),
is_override: false,
name: Identifier(String::from("constructor")),
generics: self.1.item.generics.clone(),
params: ParamList(constructor_params),
return_type: Some(TypeExpr::Tuple(Vec::new())),
body: Some(self.1.item.body.clone()),
},
}
.gen_rust(ctx, cg);
}
}
fn construct_pattern(pat: &Pattern, idx: usize) -> Pattern {
match pat {
Pattern::Literal(v) => Pattern::Literal(v.clone()),
Pattern::Path(is_mut, v) => Pattern::Path(*is_mut, v.clone().into()),
_ => Pattern::Path(false, Path(vec![Identifier(format!("_{idx}"))])),
}
}
pub fn gen_method_point(method: &FunctionDecl, ctx: &mut Context, cg: &mut RustCodegen) {
cg.add(&format!(
"{}fn {}{}(",
method.visibility.get_rust(),
method.name.get_rust(),
method.generics.get_rust(),
));
for (i, param) in method.params.0.iter().enumerate() {
if i > 0 {
cg.add(", ");
}
param.gen_rust(ctx, cg);
}
cg.add(") ");
if let Some(return_type) = &method.return_type {
cg.add("-> ");
cg.add(&return_type.get_rust());
}
cg.addln("{");
cg.indent += 1;
cg.add_indentedln("unsafe {");
cg.indent += 1;
cg.add_indentedln(&format!(
"let func_ptr = self._m_oop.0[Self::__FN_{}];",
method.name.0.to_uppercase()
));
cg.add_indented("let func: ");
let mut param_types: Vec<TypeExpr> = method
.params
.clone()
.0
.into_iter()
.filter_map(|v| v.type_)
.collect();
param_types.remove(0);
param_types.insert(
0,
TypeExpr::UnsafePtr {
mutable: true,
ty: Box::new(TypeExpr::Path(
Path(vec![
Identifier(String::from("std")),
Identifier(String::from("ffi")),
Identifier(String::from("c_void")),
]),
None,
)),
},
);
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.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!(),
}
}
+25 -1
View File
@@ -12,6 +12,30 @@ impl GetRust for ExprPath {
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join("::") .join("::")
} }
fn get_rust_ctx(&self, cx: &mut Context) -> String {
let mut a = self.clone();
if let Some(path) = &cx.expr_super {
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.get_rust()
}
} }
impl GetRust for ExprPathSegment { impl GetRust for ExprPathSegment {
@@ -63,7 +87,7 @@ impl GenRust for Expression {
}; };
match self { match self {
Expression::Path(path) => cg.add(&path.get_rust()), Expression::Path(path) => cg.add(&path.get_rust_ctx(ctx)),
Expression::Literal(literal) => literal.gen_rust(ctx, cg), Expression::Literal(literal) => literal.gen_rust(ctx, cg),
Expression::Statement(stmt) => stmt.gen_rust(ctx, cg), Expression::Statement(stmt) => stmt.gen_rust(ctx, cg),
Expression::Array(values) => { Expression::Array(values) => {
+36 -17
View File
@@ -1,3 +1,4 @@
pub mod class_decl;
pub mod expr; pub mod expr;
pub mod statement; pub mod statement;
pub mod top_level; pub mod top_level;
@@ -6,6 +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 trait GenRust { pub trait GenRust {
@@ -14,6 +16,10 @@ pub trait GenRust {
pub trait GetRust { pub trait GetRust {
fn get_rust(&self) -> String; fn get_rust(&self) -> String;
fn get_rust_ctx(&self, cx: &mut Context) -> String {
let _ = cx;
self.get_rust()
}
} }
#[derive(Default)] #[derive(Default)]
@@ -56,6 +62,7 @@ impl RustCodegen {
pub fn generate(&mut self, toplevels: Vec<TopLevel>) -> String { pub fn generate(&mut self, toplevels: Vec<TopLevel>) -> String {
let mut ctx = Context { let mut ctx = Context {
expr_ensure_semicolon: true, expr_ensure_semicolon: true,
expr_super: None,
}; };
for tl in toplevels { for tl in toplevels {
@@ -175,16 +182,11 @@ impl GetRust for Identifier {
impl GetRust for TypeExpr { impl GetRust for TypeExpr {
fn get_rust(&self) -> String { fn get_rust(&self) -> String {
match self { match self {
// TypePostfix::Ref => format!("&"),
// TypePostfix::RefMut => format!("&mut "),
// TypePostfix::RefLifetime(lifetime) => format!("&'{} ", lifetime.get_rust()),
// TypePostfix::RefMutLifetime(lifetime) => format!("&'{} mut ", lifetime.get_rust()),
// TypePostfix::Dyn => format!("dyn "),
Self::Path(path, generics) => { Self::Path(path, generics) => {
if let Some(generics) = generics { if let Some(generics) = generics {
format!("{}{}", get_static_type_path(path), generics.get_rust()) format!("{}{}", path.get_rust(), generics.get_rust())
} else { } else {
get_static_type_path(path) path.get_rust()
} }
} }
Self::Lifetime(name) => format!("'{}", name.get_rust()), Self::Lifetime(name) => format!("'{}", name.get_rust()),
@@ -196,6 +198,33 @@ impl GetRust for TypeExpr {
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join(", ") .join(", ")
), ),
Self::StaticFn(types, return_type) => {
if let Some(return_type) = return_type {
format!(
"fn({}) -> {}",
types
.into_iter()
.map(|t| t.get_rust())
.collect::<Vec<_>>()
.join(", "),
return_type.get_rust()
)
} else {
format!(
"fn({})",
types
.into_iter()
.map(|t| t.get_rust())
.collect::<Vec<_>>()
.join(", "),
)
}
}
Self::UnsafePtr { mutable, ty } => {
let mutable = if *mutable { "mut " } else { "const " };
format!("*{mutable}{}", ty.get_rust())
}
Self::Ref { Self::Ref {
lifetime, lifetime,
@@ -218,16 +247,6 @@ impl GetRust for TypeExpr {
} }
} }
pub fn get_static_type_path(path: &Path) -> String {
let rust_path = path.get_rust();
if rust_path == "void" {
format!("()")
} else {
rust_path
}
}
impl GenRust for Pattern { impl GenRust for Pattern {
fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) { fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
match self { match self {
+6 -2
View File
@@ -6,16 +6,20 @@ use crate::{GenRust, GetRust, RustCodegen};
impl GenRust for Block { impl GenRust for Block {
fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) { fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
if self.is_unsafe {
cg.add("unsafe ");
}
cg.addln("{"); cg.addln("{");
cg.indent += 1; cg.indent += 1;
for stmt in &self.0 { for stmt in &self.statements {
ctx.expr_ensure_semicolon = true; ctx.expr_ensure_semicolon = true;
stmt.gen_rust(ctx, cg); stmt.gen_rust(ctx, cg);
cg.addln(""); cg.addln("");
} }
if let Some(soft_return) = &self.1 { if let Some(soft_return) = &self.soft_return {
ctx.expr_ensure_semicolon = false; ctx.expr_ensure_semicolon = false;
soft_return.gen_rust(ctx, cg); soft_return.gen_rust(ctx, cg);
cg.addln(""); cg.addln("");
+12 -209
View File
@@ -1,6 +1,6 @@
use mist_parser::ast::*; use mist_parser::ast::*;
use crate::Context; use crate::{Context, class_decl};
use crate::{GenRust, GetRust, RustCodegen}; use crate::{GenRust, GetRust, RustCodegen};
@@ -170,109 +170,6 @@ impl GenRust for TopLevel {
} }
} }
impl GenRust for (&Vec<Spanned<FieldDeclStmt>>, &Spanned<ClassConstructor>) {
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()
));
let params = self
.1
.item
.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 &params {
if *i > 0 {
cg.add(", ");
}
param.gen_rust(ctx, cg);
}
cg.addln(") -> Self {");
cg.indent += 1;
cg.add_indentedln("let mut this: Self = unsafe { std::mem::MaybeUninit::<Self>::zeroed().assume_init() };");
for field in self.0 {
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(", ");
}
ctx.expr_ensure_semicolon = false;
param.name.gen_rust(ctx, cg);
}
cg.addln(");");
cg.add_indentedln("this");
cg.indent -= 1;
cg.add_indentedln("}\n");
let mut constructor_params = vec![VarDecl {
name: Pattern::Path(false, Path(vec![Identifier(String::from("self"))])),
type_: Some(TypeExpr::Ref {
lifetime: None,
mutable: true,
ty: Box::new(TypeExpr::Path(
Path(vec![Identifier(String::from("Self"))]),
None,
)),
}),
}];
constructor_params.append(&mut self.1.item.params.0.clone());
Spanned {
line: self.1.line,
column: self.1.column,
item: FunctionDecl {
visibility: self.1.item.visibility.clone(),
name: Identifier(String::from("constructor")),
generics: self.1.item.generics.clone(),
params: ParamList(constructor_params),
return_type: Some(TypeExpr::Tuple(Vec::new())),
body: Some(self.1.item.body.clone()),
},
}
.gen_rust(ctx, cg);
}
}
fn construct_pattern(pat: &Pattern, idx: usize) -> Pattern {
match pat {
Pattern::Literal(v) => Pattern::Literal(v.clone()),
Pattern::Path(is_mut, v) => Pattern::Path(*is_mut, v.clone().into()),
_ => Pattern::Path(false, Path(vec![Identifier(format!("_{idx}"))])),
}
}
impl GenRust for TopLevelKind { impl GenRust for TopLevelKind {
fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) { fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
match self { match self {
@@ -365,111 +262,17 @@ impl GenRust for TopLevelKind {
fields, fields,
constructor, constructor,
items, items,
} => { } => class_decl::class_decl(
// Struct decl ctx,
cg.addln(&format!( cg,
"{}struct {}{} {{", visibility,
visibility.get_rust(), name,
name.clone().get_rust(), generics,
generics.clone().get_rust() inherits,
)); fields,
cg.indent += 1; constructor,
items,
if let Some(inherits) = inherits { ),
cg.add_indented("pub _super: ");
cg.add(&inherits.get_rust());
cg.addln(",");
}
for field in fields.clone() {
cg.add_indentedln(&field.get_comment());
cg.add_indentedln(&field.item.decl.get_rust());
}
cg.indent -= 1;
cg.addln("}\n");
// 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::<Vec<_>>()
.join(", ")
)
));
cg.indent += 1;
let constructor_comment = constructor.get_comment();
cg.add_indentedln("#[allow(invalid_value)]");
cg.add_indentedln(&constructor_comment);
(fields, constructor).gen_rust(ctx, cg);
for item in items.clone() {
match item {
ClassItem::ImplDecl(_) => {}
ClassItem::Method(method) => 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("}");
}
}
} }
} }
} }
+5
View File
@@ -24,8 +24,13 @@ pub enum TypeExpr {
mutable: bool, mutable: bool,
ty: Box<TypeExpr>, ty: Box<TypeExpr>,
}, },
UnsafePtr {
mutable: bool,
ty: Box<TypeExpr>,
},
Dyn(Box<TypeExpr>), Dyn(Box<TypeExpr>),
Path(Path, Option<Generics>), Path(Path, Option<Generics>),
StaticFn(Vec<TypeExpr>, Option<Box<TypeExpr>>),
Tuple(Vec<TypeExpr>), Tuple(Vec<TypeExpr>),
Lifetime(Identifier), Lifetime(Identifier),
} }
+6 -4
View File
@@ -3,10 +3,12 @@ use serde::Serialize;
use super::*; use super::*;
#[derive(Debug, Clone, Serialize, Default)] #[derive(Debug, Clone, Serialize, Default)]
pub struct Block( pub struct Block {
pub Vec<Spanned<Expression>>, pub is_unsafe: bool,
pub Option<Spanned<Expression>>,
); pub statements: Vec<Spanned<Expression>>,
pub soft_return: Option<Spanned<Expression>>,
}
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
pub enum StatementBody { pub enum StatementBody {
+1
View File
@@ -94,6 +94,7 @@ pub struct ClassConstructor {
#[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 name: Identifier, pub name: Identifier,
pub generics: GenericsDecl, pub generics: GenericsDecl,
pub params: ParamList, pub params: ParamList,
+7 -2
View File
@@ -32,6 +32,7 @@ keyword = {
| "loop" | "loop"
| "fn" | "fn"
| "unsafe" | "unsafe"
| "override"
} }
identifier = @{ identifier = @{
@@ -63,6 +64,8 @@ static_path = {
identifier ~ ("::" ~ identifier)* identifier ~ ("::" ~ identifier)*
} }
unsafe_kw = { "unsafe" }
// ====================================================== // ======================================================
// PROGRAM // PROGRAM
// ====================================================== // ======================================================
@@ -322,8 +325,10 @@ trait_decl = {
// FUNCTIONS // FUNCTIONS
// ====================================================== // ======================================================
override_kw = { "override" }
function_decl = { function_decl = {
visibility? ~ "fn" ~ identifier ~ generics_decl? ~ "(" ~ method_args ~ ")" ~ type_expr? ~ (block | semicolon) visibility? ~ override_kw? ~ "fn" ~ identifier ~ generics_decl? ~ "(" ~ method_args ~ ")" ~ type_expr? ~ (block | semicolon)
} }
// ====================================================== // ======================================================
@@ -340,7 +345,7 @@ top_level = {
// ====================================================== // ======================================================
block = { block = {
"{" ~ statement_list ~ expr? ~ "}" unsafe_kw? ~ "{" ~ statement_list ~ expr? ~ "}"
} }
statement_list = { statement_list = {
+7 -2
View File
@@ -2,7 +2,8 @@ use crate::{
Rule, Rule,
ast::*, ast::*,
ast_ensure, ast_expr, ast_ensure, ast_expr,
error::{AstError, IntoErr, collect_recovered}, error::{AstError, AstResult, IntoErr, collect_recovered},
parser::listen_rule,
}; };
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Block { impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Block {
@@ -12,7 +13,11 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Block {
let mut inner = pair.clone().into_inner(); let mut inner = pair.clone().into_inner();
ast_ensure!(pair, Rule::block => { ast_ensure!(pair, Rule::block => {
ast_expr!(Block(collect_recovered(inner.next().unwrap().into_inner()), inner.next().map(Spanned::try_from).transpose())) ast_expr!(Block {
is_unsafe: Ok(listen_rule(&mut inner, Rule::unsafe_kw)) as AstResult<bool>,
statements: collect_recovered(inner.next().unwrap().into_inner()),
soft_return: inner.next().map(Spanned::try_from).transpose(),
})
}) })
} }
} }
@@ -13,6 +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 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)
@@ -66,6 +67,7 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for FunctionDecl {
ast_expr!(Self { ast_expr!(Self {
visibility: visibility, visibility: visibility,
is_override: is_override,
return_type: return_type, return_type: return_type,
name: name, name: name,
generics: generics, generics: generics,
+22 -47
View File
@@ -1,58 +1,33 @@
pub class Counter { pub class Animal {
pub count i32;
pub constructor(start i32) {
self.count = start;
}
pub fn increment(*mut self) {
self.count++;
}
pub fn get(*self) i32 {
self.count
}
}
pub fn test_class_create() {
let c = Counter::new(0);
assert_eq!(c.get(), 0);
}
pub fn test_class_method() {
let mut c = Counter::new(5);
c.increment();
assert_eq!(c.get(), 6);
}
pub fn test_class_field_access() {
let c = Counter::new(42);
assert_eq!(c.count, 42);
}
class NamedCounter : Counter {
pub name String; pub name String;
pub constructor(start i32, name String) { constructor() {
self._super = Counter::new(start); self.name = "Rex".to_string();
self.name = name;
} }
pub fn get_name(*self) String { pub fn speak(*self) {
self.name.clone() println!("Unknown");
}
pub fn test_speak(*self) {
self.speak();
} }
} }
pub fn test_class_inherit() { pub class Dog : Animal {
let nc = NamedCounter::new(10, "test".to_string()); constructor() {
assert_eq!(nc.get_name(), "test"); unsafe {
assert_eq!(nc.count, 10); std::ptr::write(&mut super, Super::new());
}
}
pub override fn speak(*self) {
println!("Woof!");
}
} }
pub fn run_tests() { pub fn run_tests() {
test_class_create(); let dawg = Dog::new();
test_class_method();
test_class_field_access(); dawg.test_speak();
test_class_inherit();
} }