diff --git a/crates/codegen/src/class_decl.rs b/crates/codegen/src/class_decl.rs new file mode 100644 index 0000000..73f7713 --- /dev/null +++ b/crates/codegen/src/class_decl.rs @@ -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, + 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 + }; + + // 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::>() + .join(", ") + ) + )); + cg.indent += 1; + + let methods = items + .clone() + .into_iter() + .filter_map(|item| match item { + ClassItem::ImplDecl(_) => None, + ClassItem::Method(method) => Some(method), + }) + .collect::>(); + + 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::>(); + + // 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::>(); + + 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, + 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::>(); + + for (i, param) in ¶ms { + if *i > 0 { + cg.add(", "); + } + + param.gen_rust(ctx, cg); + } + + cg.addln(") -> Box {"); + 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);"); + + 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 = 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!(), + } +} diff --git a/crates/codegen/src/expr.rs b/crates/codegen/src/expr.rs index fbfdfe8..e4e2701 100644 --- a/crates/codegen/src/expr.rs +++ b/crates/codegen/src/expr.rs @@ -12,6 +12,30 @@ impl GetRust for ExprPath { .collect::>() .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 { @@ -63,7 +87,7 @@ impl GenRust for Expression { }; 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::Statement(stmt) => stmt.gen_rust(ctx, cg), Expression::Array(values) => { diff --git a/crates/codegen/src/lib.rs b/crates/codegen/src/lib.rs index 168b0af..f6c466b 100644 --- a/crates/codegen/src/lib.rs +++ b/crates/codegen/src/lib.rs @@ -1,3 +1,4 @@ +pub mod class_decl; pub mod expr; pub mod statement; pub mod top_level; @@ -6,6 +7,7 @@ use mist_parser::ast::*; pub struct Context { pub expr_ensure_semicolon: bool, + pub expr_super: Option, } pub trait GenRust { @@ -14,6 +16,10 @@ pub trait GenRust { pub trait GetRust { fn get_rust(&self) -> String; + fn get_rust_ctx(&self, cx: &mut Context) -> String { + let _ = cx; + self.get_rust() + } } #[derive(Default)] @@ -56,6 +62,7 @@ impl RustCodegen { pub fn generate(&mut self, toplevels: Vec) -> String { let mut ctx = Context { expr_ensure_semicolon: true, + expr_super: None, }; for tl in toplevels { @@ -175,16 +182,11 @@ impl GetRust for Identifier { impl GetRust for TypeExpr { fn get_rust(&self) -> String { 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) => { if let Some(generics) = generics { - format!("{}{}", get_static_type_path(path), generics.get_rust()) + format!("{}{}", path.get_rust(), generics.get_rust()) } else { - get_static_type_path(path) + path.get_rust() } } Self::Lifetime(name) => format!("'{}", name.get_rust()), @@ -196,6 +198,33 @@ impl GetRust for TypeExpr { .collect::>() .join(", ") ), + Self::StaticFn(types, return_type) => { + if let Some(return_type) = return_type { + format!( + "fn({}) -> {}", + types + .into_iter() + .map(|t| t.get_rust()) + .collect::>() + .join(", "), + return_type.get_rust() + ) + } else { + format!( + "fn({})", + types + .into_iter() + .map(|t| t.get_rust()) + .collect::>() + .join(", "), + ) + } + } + + Self::UnsafePtr { mutable, ty } => { + let mutable = if *mutable { "mut " } else { "const " }; + format!("*{mutable}{}", ty.get_rust()) + } Self::Ref { 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 { fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) { match self { diff --git a/crates/codegen/src/statement.rs b/crates/codegen/src/statement.rs index fb2d3aa..601b20b 100644 --- a/crates/codegen/src/statement.rs +++ b/crates/codegen/src/statement.rs @@ -6,16 +6,20 @@ use crate::{GenRust, GetRust, RustCodegen}; impl GenRust for Block { fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) { + if self.is_unsafe { + cg.add("unsafe "); + } + cg.addln("{"); cg.indent += 1; - for stmt in &self.0 { + for stmt in &self.statements { ctx.expr_ensure_semicolon = true; stmt.gen_rust(ctx, cg); cg.addln(""); } - if let Some(soft_return) = &self.1 { + if let Some(soft_return) = &self.soft_return { ctx.expr_ensure_semicolon = false; soft_return.gen_rust(ctx, cg); cg.addln(""); diff --git a/crates/codegen/src/top_level.rs b/crates/codegen/src/top_level.rs index 94073c5..1b2ff11 100644 --- a/crates/codegen/src/top_level.rs +++ b/crates/codegen/src/top_level.rs @@ -1,6 +1,6 @@ use mist_parser::ast::*; -use crate::Context; +use crate::{Context, class_decl}; use crate::{GenRust, GetRust, RustCodegen}; @@ -170,109 +170,6 @@ impl GenRust for TopLevel { } } -impl GenRust for (&Vec>, &Spanned) { - 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::>(); - - for (i, param) in ¶ms { - 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::::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 { fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) { match self { @@ -365,111 +262,17 @@ impl GenRust for TopLevelKind { fields, constructor, items, - } => { - // Struct decl - cg.addln(&format!( - "{}struct {}{} {{", - visibility.get_rust(), - name.clone().get_rust(), - generics.clone().get_rust() - )); - cg.indent += 1; - - 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::>() - .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("}"); - } - } + } => class_decl::class_decl( + ctx, + cg, + visibility, + name, + generics, + inherits, + fields, + constructor, + items, + ), } } } diff --git a/crates/parser/src/ast/mod.rs b/crates/parser/src/ast/mod.rs index 6a975df..89b12fb 100644 --- a/crates/parser/src/ast/mod.rs +++ b/crates/parser/src/ast/mod.rs @@ -24,8 +24,13 @@ pub enum TypeExpr { mutable: bool, ty: Box, }, + UnsafePtr { + mutable: bool, + ty: Box, + }, Dyn(Box), Path(Path, Option), + StaticFn(Vec, Option>), Tuple(Vec), Lifetime(Identifier), } diff --git a/crates/parser/src/ast/statement.rs b/crates/parser/src/ast/statement.rs index 412e2f0..e9b41a8 100644 --- a/crates/parser/src/ast/statement.rs +++ b/crates/parser/src/ast/statement.rs @@ -3,10 +3,12 @@ use serde::Serialize; use super::*; #[derive(Debug, Clone, Serialize, Default)] -pub struct Block( - pub Vec>, - pub Option>, -); +pub struct Block { + pub is_unsafe: bool, + + pub statements: Vec>, + pub soft_return: Option>, +} #[derive(Debug, Clone, Serialize)] pub enum StatementBody { diff --git a/crates/parser/src/ast/top_level.rs b/crates/parser/src/ast/top_level.rs index dd29e9b..f6fe296 100644 --- a/crates/parser/src/ast/top_level.rs +++ b/crates/parser/src/ast/top_level.rs @@ -94,6 +94,7 @@ pub struct ClassConstructor { #[derive(Debug, Clone, Serialize)] pub struct FunctionDecl { pub visibility: Visibility, + pub is_override: bool, pub name: Identifier, pub generics: GenericsDecl, pub params: ParamList, diff --git a/crates/parser/src/grammar.pest b/crates/parser/src/grammar.pest index e4f33fb..3c20825 100644 --- a/crates/parser/src/grammar.pest +++ b/crates/parser/src/grammar.pest @@ -32,6 +32,7 @@ keyword = { | "loop" | "fn" | "unsafe" + | "override" } identifier = @{ @@ -63,6 +64,8 @@ static_path = { identifier ~ ("::" ~ identifier)* } +unsafe_kw = { "unsafe" } + // ====================================================== // PROGRAM // ====================================================== @@ -322,8 +325,10 @@ trait_decl = { // FUNCTIONS // ====================================================== +override_kw = { "override" } + 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 = { - "{" ~ statement_list ~ expr? ~ "}" + unsafe_kw? ~ "{" ~ statement_list ~ expr? ~ "}" } statement_list = { diff --git a/crates/parser/src/parser/common/statement.rs b/crates/parser/src/parser/common/statement.rs index 5ca288e..1947928 100644 --- a/crates/parser/src/parser/common/statement.rs +++ b/crates/parser/src/parser/common/statement.rs @@ -2,7 +2,8 @@ use crate::{ Rule, ast::*, ast_ensure, ast_expr, - error::{AstError, IntoErr, collect_recovered}, + error::{AstError, AstResult, IntoErr, collect_recovered}, + parser::listen_rule, }; impl<'a> TryFrom> for Block { @@ -12,7 +13,11 @@ impl<'a> TryFrom> for Block { let mut inner = pair.clone().into_inner(); 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, + statements: collect_recovered(inner.next().unwrap().into_inner()), + soft_return: inner.next().map(Spanned::try_from).transpose(), + }) }) } } diff --git a/crates/parser/src/parser/items/function.rs b/crates/parser/src/parser/items/function.rs index 3919cce..4e68469 100644 --- a/crates/parser/src/parser/items/function.rs +++ b/crates/parser/src/parser/items/function.rs @@ -13,6 +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 name = Identifier::try_from(inner.next().unwrap()); let generics = consume_rule(&mut inner, Rule::generics_decl) @@ -66,6 +67,7 @@ impl<'a> TryFrom> for FunctionDecl { ast_expr!(Self { visibility: visibility, + is_override: is_override, return_type: return_type, name: name, generics: generics, diff --git a/mist-test/src/items/class_test.mist b/mist-test/src/items/class_test.mist index 7c44635..b95f19d 100644 --- a/mist-test/src/items/class_test.mist +++ b/mist-test/src/items/class_test.mist @@ -1,58 +1,33 @@ -pub class Counter { - 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 class Animal { pub name String; - pub constructor(start i32, name String) { - self._super = Counter::new(start); - - self.name = name; + constructor() { + self.name = "Rex".to_string(); } - pub fn get_name(*self) String { - self.name.clone() + pub fn speak(*self) { + println!("Unknown"); + } + + pub fn test_speak(*self) { + self.speak(); } } -pub fn test_class_inherit() { - let nc = NamedCounter::new(10, "test".to_string()); - assert_eq!(nc.get_name(), "test"); - assert_eq!(nc.count, 10); +pub class Dog : Animal { + constructor() { + unsafe { + std::ptr::write(&mut super, Super::new()); + } + } + + pub override fn speak(*self) { + println!("Woof!"); + } } pub fn run_tests() { - test_class_create(); - test_class_method(); - test_class_field_access(); - test_class_inherit(); + let dawg = Dog::new(); + + dawg.test_speak(); }