Closed EliasC closed 4 months ago
@mjp41 I could always add another sample which uses this feature. Or were you thinking something smaller, more unit test-like?
I'm fixing up the Shrubbery parser to add as test cases (and a sample) to add to this PR.
This PR adds a single function to the
Make
class that allows checking the type of the parent of the current group during parsing. Just asm.in(Foo)
returns true if the cursor is in aFoo
node,m.group_in(Foo)
returns true if the cursor is in a group which in turn is in aFoo
node.A concrete use case for this is being able to parse lists with prefix separator:
For infix separators we can use
seq(Bar)
to push the current group under some separator. This is the behaviour we want for the second and third|
above, but for the first|
seq(Bar)
will make the groupmatch n with
a child of the first|
. Instead, we want to dopush(Bar)
for the first|
, but using that for the latter ones will nest the lists in each other. Withgroup_in
we can write the parser forBar
asAnother use case is to be able to conditionally terminate groups based on their parents:
Here,
block: subentry1
creates a deeper structure within the list and the last comma should get us back to the first level. Because we are in a group when parsingsubentry1
, currently the only way to see if the comma should terminate the current group or a group higher up is to speculatively terminate the group and see if we did the right thing (and if we didn't, there is no way to backtrack). Withgroup_in
we can parse commas like so:While both of these use cases might be solvable using further rewrite passes (or parsing modes, or other extra machinery in the parser), I would argue that
group_in
fits nicely into the idea of parsing as a series of local decisions based on the latest input string and the current position in the parse tree. The programmer never has to deal with creating groups, but once a group has been created it makes sense to be able to ask questions about that group. Thein(Foo)
method lets us ask "are we in the beginning of parsing (the inside of) aFoo
?" andin_group(Foo)
lets us ask "are we in the middle of parsing (the inside of) aFoo
?".Both of these examples comes from writing a parser for shrubbery notation, which is also indentation sensitive, meaning there is some grouping information that may only be available during parsing (or that we at least don't want to have to carry into the rewriting passes). This also complicates the approach of "parse stupidly, rewrite cleverly".