Skip to content

feat: add Alias option for reusable named grammar fragments - #474

Open
Pastalikek65 wants to merge 1 commit into
alecthomas:masterfrom
Pastalikek65:feat-22-aliases
Open

feat: add Alias option for reusable named grammar fragments#474
Pastalikek65 wants to merge 1 commit into
alecthomas:masterfrom
Pastalikek65:feat-22-aliases

Conversation

@Pastalikek65

Copy link
Copy Markdown
Contributor

Closes #22

Adds participle.Alias(name, grammar) — named, reusable grammar fragments referenced from struct tags as <name>:

participle.Alias("jqName", `"@" @Name ":" @Name`)

type parser struct {
    JQ qName `"@" @Name ":" @Name`
}
parser, _ := participle.Build[grammar](
    participle.Alias("delim", `"|"`),
)

type grammar struct {
    A string `@Ident <delim> @Ident`
    B string `<delim> @Ident`
}

Design

  • Non-capturing: aliases match literal and named-token patterns and compose with the normal tag operators (? * + !, groups, disjunction), but cannot bind values. Captures (@ and @@) always target a struct field of the surrounding production — an alias has no field, so @/@@ in an alias body is rejected at build time with a clear message (aliases cannot capture (@); move captures to a struct field). This avoids the index-out-of-range panic that naive attempts hit during development.
  • Syntax: <name> in parseTermNoModifiers (grammar.go), resolved from generatorContext.aliases. < was otherwise unused in the tag grammar, so no ambiguity with named token references.
  • lexStructFromTag (struct.go): a bare grammar string is lexed without a backing struct type.
  • Alias errors (unknown reference, duplicate name, empty name, invalid grammar) fail at build time.

Tests

10 tests: literal patterns, alias reuse across fields, multiple aliases, ? modifier, @/@@ rejection, unknown reference, duplicate, empty name.

One open question for maintainer: whether aliases should be capturing by binding to an implicit "value" the referenced field receives (e.g. a special syntax <name> meaning the fragment's captures flow into the field). This would require threads of field context through alias resolution beyond build time; offered as a follow-up rather than blocking this PR.

Alias(name, grammar) registers a named, reusable grammar fragment
referenced from struct tags as <name>. Aliases are non-capturing: they
match literals and named tokens (and compose via normal tag operators
such as ? * + and grouping) but cannot bind values, since captures (@
and @@) always belong to a struct field of the surrounding production —
such use is rejected at build time with a clear error.

- options.go: Alias option appends aliasDef.
- grammar.go: <name> syntax in parseTermNoModifiers via parseAlias,
  generatorContext.aliases map, addAliasDefs with extraction guard.
- struct.go: lexStructFromTag parses a bare grammar string.
- alias_test.go: 10 tests (pattern, reuse across fields, multiple
  aliases, modifiers, capture/struct-capture rejection, unknown ref,
  duplicate, empty name).

Closes alecthomas#22.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Proposal: Support grammar aliases.

1 participant