Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use named capture in error message? #289

Open
kfsone opened this issue Mar 22, 2024 · 1 comment
Open

Use named capture in error message? #289

kfsone opened this issue Mar 22, 2024 · 1 comment

Comments

@kfsone
Copy link

kfsone commented Mar 22, 2024

Consider the following which declares an enum grammar that wants to enforce a minimum requirement on the number of members. This works,

Enums <- Enum*
%whitespace <- [ \t\r\n]*
%word <- [A-Za-z0-9_.]+

NAME <- < [A-Za-z_][A-Za-z0-9_]* >

Enum <- 'enum' ↑ $name<NAME> '{' ↑ NAME+^enum_count '}'

enum_count <- '' { error_message "enum must contain at least one member" }

but it is inelegant:
image

It would be really nice if we could use the named capture in error_message. Some thoughts:

  • You could change the grammar to make allow error_message BACKREFERENCE (',' BACKREFERENCE) string_literal which would print the backreferences with a ': " after each one.
    meh.

  • You could allow sprintf or std::format formatting, error_message "{}: must have at least one member", $name,

  • You could perhaps provide an automatic "context stack". Consider, to which captures are automatically pushed/popped using '$^' instead of just '$', and $^'...' to push a literal:

TypeDef <- $^type<'type'> ↑ $^name<NAME> Parent? '{' Members '}'
Members <- Member (',' Member)* ','?
Member <- $^'member' $type<NAME> $^field<NAME> MemberDefault
MemberDefault <- '{' '}'  # imagine there's some complex recursion here

Now this has the capability automatically take:

type Connection { Status state {;} }

and report

1:33: type->Connection->member->state: unexpected ';', expecting '}'

Or perhaps rather than the ugly '$^'member' you could allow '^' infront of the production name to indicate it should push its name onto the context stack:

^Type <- 'type' ↑ $^name<NAME> Parent? '{' Members '}'
Members <- Member (',' Member)* ','?
^Member <- $type<NAME> $^field<NAME> DefaultValue
^DefaultValue <- '{' '}'
1:33: Type->Connection->Member->state->DefaultValue: unexpected ';', expecting '}'

If we tighten this down to one $^ per production, you can design the format so that, in rust terms:

match captures {
  Some(production), Some(capture) => { format!("{production} '{capture}': ") },
  Some(production), None => { format!("{production}: ") },
  None, Some(capture) => { format!("'{capture}': ") },
  None, None => { "" }
}
# given: `a b`
^JustType <- 'a' 'b' 'c'  # error: JustType: expecting 'c'
^JustCap <- 'a' $^name<'b'> 'c'  # error: 'b': expecting 'c'
^Both <- 'a' $^name<'b'> 'c'  # error: Both 'b': expecting 'c'
Neither <- 'a' 'b' 'c'  # error: expecting 'c'
@yhirose
Copy link
Owner

yhirose commented Mar 27, 2024

@kfsone thanks for the ideas. I am not planing to implement any of these at this point, but keep it as 'enhancement'.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants