diff --git a/crates/codegen/src/lib.rs b/crates/codegen/src/lib.rs index fe6678d..7618ebc 100644 --- a/crates/codegen/src/lib.rs +++ b/crates/codegen/src/lib.rs @@ -108,11 +108,12 @@ impl GenRust for Attribute { match self { Self::Path(path) => cg.add(&path.get_rust()), Self::NameValue { path, value } => { - cg.add(&format!("{} =", path.get_rust())); + cg.add(&format!("{} = ", path.get_rust())); value.gen_rust(ctx, cg); } Self::List { path, items } => { cg.add(&path.get_rust()); + cg.add("("); for (i, item) in items.iter().enumerate() { if i > 0 { cg.add(", "); @@ -120,6 +121,7 @@ impl GenRust for Attribute { item.gen_rust(ctx, cg); } + cg.add(")"); } } } diff --git a/crates/codegen/src/top_level.rs b/crates/codegen/src/top_level.rs index b13c531..871155e 100644 --- a/crates/codegen/src/top_level.rs +++ b/crates/codegen/src/top_level.rs @@ -325,6 +325,7 @@ impl GenRust for TopLevelKind { visibility, name, generics, + inherits, fields, constructor, items, @@ -338,6 +339,12 @@ impl GenRust for TopLevelKind { )); 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()); @@ -395,6 +402,38 @@ impl GenRust for TopLevelKind { 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("}"); + } } } } diff --git a/crates/parser/src/ast/top_level.rs b/crates/parser/src/ast/top_level.rs index 8de8531..f87d011 100644 --- a/crates/parser/src/ast/top_level.rs +++ b/crates/parser/src/ast/top_level.rs @@ -54,6 +54,7 @@ pub enum TopLevelKind { visibility: Visibility, name: Identifier, generics: GenericsDecl, + inherits: Option, fields: Vec>, constructor: Spanned, items: Vec, diff --git a/crates/parser/src/grammar.pest b/crates/parser/src/grammar.pest index 9635b1d..ee1af10 100644 --- a/crates/parser/src/grammar.pest +++ b/crates/parser/src/grammar.pest @@ -285,7 +285,7 @@ class_item = _{ } class_decl = { - visibility? ~ "class" ~ identifier ~ generics_decl? ~ "{" ~ class_fields ~ class_constructor ~ class_item* ~ "}" + visibility? ~ "class" ~ identifier ~ generics_decl? ~ (":" ~ type_expr)? ~ "{" ~ class_fields ~ class_constructor ~ class_item* ~ "}" } // ====================================================== diff --git a/crates/parser/src/parser/items/attribute.rs b/crates/parser/src/parser/items/attribute.rs index f3b22ec..7095725 100644 --- a/crates/parser/src/parser/items/attribute.rs +++ b/crates/parser/src/parser/items/attribute.rs @@ -28,11 +28,11 @@ impl<'a> TryFrom> for Attribute { } Some(next) => match next.as_rule() { - Rule::primary => { + Rule::literal => { // #[path = literal] Ok(Attribute::NameValue { path, - value: inner.next().unwrap().try_into().get()?, + value: next.try_into().get()?, }) } diff --git a/crates/parser/src/parser/items/mod.rs b/crates/parser/src/parser/items/mod.rs index fe45403..7b49a1a 100644 --- a/crates/parser/src/parser/items/mod.rs +++ b/crates/parser/src/parser/items/mod.rs @@ -69,6 +69,10 @@ impl<'a> TryFrom> for TopLevelKind { .transpose() .map(|v| v.unwrap_or_default()), + inherits: consume_rule(&mut inner, Rule::type_expr) + .map(TypeExpr::try_from) + .transpose(), + fields: collect_recovered(inner.next().unwrap().into_inner()), constructor: inner.next().unwrap().try_into(),