Open jfecher opened 3 months ago
Current goal is to get a vertical slice of metaprogramming working to support deriving a trait impl of a simple type on a simple trait like Default:
comptime fn derive_default(typ: TypeDefinition) -> Quoted {
let generics: [Quoted] = typ.generics();
assert(generics.is_empty(), "derive_default: Deriving Default on generic types is currently unimplemented");
let type_name: Type = typ.as_type();
let fields: [(Quoted, Type)] = typ.fields();
let fields: Quoted = fields.map(|(name, _)| quote { $name : Default::default(), })
.join();
quote {
impl Default for $type_name {
fn default() -> Self {
Self { $fields }
}
}
}
}
#[derive_default]
struct Foo {
x: Field
}
// Expected output:
//
// impl Default for Foo {
// fn default(this: Self) -> Self {
// Foo {
// x: Default::default(),
// }
// }
// }
Required unimplemented features:
TypeDefinition
: generics
, as_type
, and fields
Quoted
type for quoted, unparsed raw token streams. I think this is necessary to quote code fragments like quote { $name : Default::default(), }
which is only valid in the context of struct initialization. I've chosen this name to avoid confusion with crypto tokens that Tokens
or TokenStream
may cause.
quote { $name : Default::default(), }
where $name
is spliced in despite us not knowing what grammar rule it should be part of (is it an identifier? an expression?).Quoted
token streams will be the new default type of quoted values with alternate types like quote Type { ... }
or quote TopLevelItem { ... }
only being used to force a quoted value into a particular shape so that specific methods can be called on it. TypeDefinition
is the only type with methods on it above but we can imagine similar methods on a Type
value which would be meaningless on unparsed Quoted
values.}
is found.Quoted
values until they're expanded into a macro's call site: either a top level statement or an expression. When this happens, we parse the token stream and issue an error if we cannot parse into a top level statement or an expression.join
to join a slice of quoted values into one:
fn join(slice: [Quoted]) -> Quoted {
let mut ret = quote {};
for element in slice {
// Since quoted values are token streams, we do not need (or want) a `;` separator.
ret = quote { $ret $element };
}
ret
}
map
working in the interpreter. The work around for this is writing a monomorphic version of map
for Quoted
values.Edit: We used to have a Code
type for quoted code. Maybe we should use that name over Quoted
?
Proposal: https://hackmd.io/Tkzo_ryvTsWMPESmWHPiZw?view