grain
grain copied to clipboard
Lang: Implement macros
I could not find these features in docs.
Not yet! You might want to join our discord, so we don't need to open question style issues and can use them to track bugs and feature work.
I'll probably update this issue to be something along those lines in the future.
@phated Perhaps we could add a discussion section? That way people can ask and then can be converted to features if needed.
cc @ospencer to do a brief write-up on his thoughts about macros.
Generally, we want macros that provide succinct, expressive syntax for functionality that can/should happen at compile time rather than runtime. Think writing out JSON, writing a JSX component, or even constructing a regular expression. In the case of JSON, a user would need to choose between writing JsonArray([JsonNumber(1), JsonNumber(2), JSONNumber(3)]) or JSON.parse("[1, 2, 3]"). Of course, most devs would opt for the latter but we lose out on the compiler alerting us to a potential mistake that we wouldn't find out about until runtime. A macro gives us the best of both worlds, where we could write something like
json`[1, 2, 3]`
and get the concise, expressive syntax but still allow the compiler to have our back.
Here's an example of what this could look like in Grain for JSON:
enum JSON {
JsonString(String),
JsonNumber(Number),
JsonObject(List<(String, JSON)>),
JsonArray(List<JSON>),
JsonBoolean(Bool),
JsonNull,
}
macro json {
rule json {
'null' => JsonNull,
Macro.Const.boolean => JsonBoolean($1),
Macro.Const.number => JsonNumber($1),
Macro.Const.string => JsonString($1),
'[' json [',' json => $2]* ']' => JsonArray([$2, ...$3]),
'[' ']' => JsonArray([]),
'{' field [',' field => $2]* '}' => JsonObject([$2, ...$3]),
'{' '}' => JsonObject([]),
}
rule field {
Macro.Const.string ':' json => ($1, $3),
}
parse json
}
json`{ "foo": [5, 6] }`
I don't think we'd want Grain to deal with token streams directly, but this should be sufficient for many use cases. Combined with other metaprogramming constructs, this should eliminate the need for preprocessors like JavaScript's Babel or OCaml's ppx system.
I'll also note that this syntax is not final and the example should be used just to get a sense of the semantics. We'll workshop syntax when we're closer to the feature 🙂
Thanks @ospencer! This feature is very far away, so I'm going to limit this thread to Grain core team members until it gets closer.