diff options
-rw-r--r-- | README.md | 64 | ||||
-rw-r--r-- | driver/parser_test.go | 68 | ||||
-rw-r--r-- | driver/semantic_action.go | 6 | ||||
-rw-r--r-- | driver/syntax_error_test.go | 47 | ||||
-rw-r--r-- | grammar/grammar.go | 123 | ||||
-rw-r--r-- | grammar/grammar_test.go | 46 | ||||
-rw-r--r-- | grammar/parsing_table.go | 7 | ||||
-rw-r--r-- | spec/grammar/description.go | 1 | ||||
-rw-r--r-- | spec/grammar/parser.go | 2 | ||||
-rw-r--r-- | spec/grammar/parser_test.go | 132 | ||||
-rw-r--r-- | spec/test/parser.go | 6 | ||||
-rw-r--r-- | spec/test/tree-report.json | 2 | ||||
-rw-r--r-- | spec/test/tree_semantic_action.go | 6 |
13 files changed, 233 insertions, 277 deletions
@@ -304,14 +304,12 @@ Alternative: <element-1> <element-2> ... <element-N> ``` -An element an alternative contains is a terminal symbol, a non-terminal symbol, or a string literal. Unlike string literals, patterns cannot be contained in alternatives. - -You can define terminal symbols in the same grammar as non-terminal symbols. +An element an alternative contains is a terminal symbol or a non-terminal symbol. If a production rule satisfies all of the following conditions, it is considered to define a terminal symbol. -* A production rule has only one alternative. -* the alternative has only one pattern or string literal. +* A rule has only one alternative. +* The alternative has only one pattern or string literal. Fragment: @@ -367,15 +365,21 @@ Consider a grammar that accepts comma-separated list of integers. You can avoid #name example; list - : '[' elems ']' #ast elems... + : l_bracket elems r_bracket #ast elems... ; elems - : elems ',' int #ast elems... int + : elems comma int #ast elems... int | int ; ws #skip - : "[\u{0009}\u{0020}]+"; + : "[\u{0009}\u{0020}]+"; +l_bracket + : '['; +r_bracket + : ']'; +comma + : ','; int : "0|[1-9][0-9]*"; ``` @@ -398,11 +402,15 @@ Consider a grammar that accepts ternary-if expression (`<condition> ? <value if #name example; if_expr - : id '?' int@true ':' int@false #ast id true false + : id q int@true colon int@false #ast id true false ; ws #skip : "[\u{0009}\u{0020}]+"; +q + : '?'; +colon + : ':'; id : "[a-z_][0-9a-z_]*"; int @@ -677,45 +685,49 @@ By default, a parser will stop syntax analysis on a syntax error. If you want to When a syntax error occurs, the parser pops states from a state stack. If a state containing the `error` symbol appears, a parser stops popping the states. It then shifts the `error` symbol and resumes syntax analysis. -Consider grammar of simple assignment statements. +Consider grammar of simple equivalent expressions. ``` #name example; -statements - : statements statement #ast statements... statement - | statement #ast statement +eq_exprs + : eq_exprs eq_expr #ast eq_exprs... eq_expr + | eq_expr ; -statement - : name '=' int ';' #ast name int - | error ';' #recover +eq_expr + : name eq int semi_colon #ast name int + | error semi_colon #recover ; ws #skip : "[\u{0009}\u{0020}]"; +eq + : '='; +semi_colon + : ';'; name : "[a-z_][0-9a-z_]*"; int : "0|[1-9][0-9]*"; ``` -The alternative `error ';'` traps a syntax error and discards symbols until the parser shifts `';'`. When the parser shifts `';'` and reduces `statement`, the parser will recover from an error state immediately by the `#recover` directive. +The alternative `error semi_colon` traps a syntax error and discards symbols until the parser shifts `';'`. When the parser shifts `';'` and reduces `eq_expr`, the parser will recover from an error state immediately by the `#recover` directive. In the following example, you can see the parser print syntax error messages and an AST. This result means the parser had continued syntax analysis and semantic actions even if syntax errors occurred. ``` +$ vartan compile example.vartan -o example.json $ echo -n 'x; x =; x = 1;' | vartan parse example.json -1:2: unexpected token: ';': expected: = -1:7: unexpected token: ';': expected: int - -statements -├─ statement +eq_exprs +├─ eq_expr │ ├─ error -│ └─ <anonymous> ";" -├─ statement +│ └─ semi_colon ";" +├─ eq_expr │ ├─ error -│ └─ <anonymous> ";" -└─ statement +│ └─ semi_colon ";" +└─ eq_expr ├─ name "x" └─ int "1" +1:2: unexpected token: ';' (semi_colon): expected: eq +1:7: unexpected token: ';' (semi_colon): expected: int ``` diff --git a/driver/parser_test.go b/driver/parser_test.go index dd58dd5..da4f714 100644 --- a/driver/parser_test.go +++ b/driver/parser_test.go @@ -186,7 +186,9 @@ bar : bar_text | ; -bar_text: "bar"; + +bar_text + : "bar"; `, src: `bar`, cst: nonTermNode("s", @@ -399,8 +401,10 @@ white_space #skip s : tagline ; -tagline: "\f{words} IS OUT THERE."; -fragment words: "[A-Za-z\u{0020}]+"; +tagline + : "\f{words} IS OUT THERE."; +fragment words + : "[A-Za-z\u{0020}]+"; `, src: `THE TRUTH IS OUT THERE.`, }, @@ -410,15 +414,21 @@ fragment words: "[A-Za-z\u{0020}]+"; #name test; list - : '[' elems ']' #ast elems... + : l_bracket elems r_bracket #ast elems... ; elems - : elems ',' id #ast elems... id + : elems comma id #ast elems... id | id ; whitespace #skip : "\u{0020}+"; +l_bracket + : '['; +r_bracket + : ']'; +comma + : ','; id : "[A-Za-z]+"; `, @@ -453,10 +463,12 @@ s : a #ast a... ; a - : a ',' foo #ast a... foo + : a comma foo #ast a... foo | foo ; +comma + : ','; foo : 'foo'; `, @@ -473,12 +485,14 @@ foo #name test; s - : a ';' #ast a... + : a semi_colon #ast a... ; - a : ; + +semi_colon + : ';'; `, src: `;`, ast: nonTermNode("s"), @@ -497,9 +511,13 @@ expr | expr@lhs sub expr@rhs #ast sub lhs rhs | num ; -add: '+'; -sub: '-'; -num: "0|[1-9][0-9]*"; + +add + : '+'; +sub + : '-'; +num + : "0|[1-9][0-9]*"; `, src: `1+2-3`, ast: nonTermNode("expr", @@ -524,9 +542,11 @@ num: "0|[1-9][0-9]*"; #name test; s - : foo@x ';' #ast foo + : foo@x semi_colon #ast foo ; +semi_colon + : ';'; foo : 'foo'; `, @@ -648,12 +668,14 @@ div #name test; s - : id id id ';' - | error ';' + : id id id semi_colon + | error semi_colon ; ws #skip : "[\u{0009}\u{0020}]+"; +semi_colon + : ';'; id : "[A-Za-z_]+"; `, @@ -665,10 +687,12 @@ id #name test; s - : foo ';' - | error ';' #ast error + : foo semi_colon + | error semi_colon #ast error ; +semi_colon + : ';'; foo : 'foo'; `, @@ -684,10 +708,12 @@ foo #name test; s - : foo ';' - | error@e ';' #ast e + : foo semi_colon + | error@e semi_colon #ast e ; +semi_colon + : ';'; foo : 'foo'; `, @@ -707,12 +733,14 @@ seq | elem ; elem - : id id id ';' - | error ';' #recover + : id id id semi_colon + | error semi_colon #recover ; ws #skip : "[\u{0009}\u{0020}]+"; +semi_colon + : ';'; id : "[A-Za-z_]+"; `, diff --git a/driver/semantic_action.go b/driver/semantic_action.go index 54d3291..7e5a773 100644 --- a/driver/semantic_action.go +++ b/driver/semantic_action.go @@ -340,11 +340,7 @@ func printTree(w io.Writer, node *Node, ruledLine string, childRuledLinePrefix s case NodeTypeError: fmt.Fprintf(w, "%v%v\n", ruledLine, node.KindName) case NodeTypeTerminal: - if node.KindName == "" { - fmt.Fprintf(w, "%v<anonymous> %v\n", ruledLine, strconv.Quote(node.Text)) - } else { - fmt.Fprintf(w, "%v%v %v\n", ruledLine, node.KindName, strconv.Quote(node.Text)) - } + fmt.Fprintf(w, "%v%v %v\n", ruledLine, node.KindName, strconv.Quote(node.Text)) case NodeTypeNonTerminal: fmt.Fprintf(w, "%v%v\n", ruledLine, node.KindName) diff --git a/driver/syntax_error_test.go b/driver/syntax_error_test.go index ada1fb0..683e355 100644 --- a/driver/syntax_error_test.go +++ b/driver/syntax_error_test.go @@ -26,7 +26,8 @@ s : foo ; -foo: 'foo'; +foo + : 'foo'; `, src: `bar`, synErrCount: 1, @@ -37,9 +38,9 @@ foo: 'foo'; #name test; seq - : seq elem ';' - | elem ';' - | error ';' #recover + : seq elem semi_colon + | elem semi_colon + | error semi_colon #recover ; elem : a b c @@ -47,6 +48,8 @@ elem ws #skip : "[\u{0009}\u{0020}]+"; +semi_colon + : ';'; a : 'a'; b @@ -63,9 +66,9 @@ c #name test; seq - : seq elem ';' - | elem ';' - | error ';' #recover + : seq elem semi_colon + | elem semi_colon + | error semi_colon #recover ; elem : a b c @@ -73,6 +76,8 @@ elem ws #skip : "[\u{0009}\u{0020}]+"; +semi_colon + : ';'; a : 'a'; b @@ -91,9 +96,9 @@ c #name test; seq - : seq elem ';' - | elem ';' - | error '*' '*' ';' + : seq elem semi_colon + | elem semi_colon + | error star star semi_colon ; elem : a b c @@ -101,6 +106,10 @@ elem ws #skip : "[\u{0009}\u{0020}]+"; +semi_colon + : ';'; +star + : '*'; a : 'a'; b @@ -241,24 +250,6 @@ foo "<eof>", }, }, - { - caption: "when an anonymous symbol is expected, an expected symbol list contains an auto-generated name with the prefix `x_`", - specSrc: ` -#name test; - -s - : foo 'bar' - ; - -foo - : 'foo'; -`, - src: `foobaz`, - cause: `baz`, - expected: []string{ - "x_1", - }, - }, } for i, tt := range tests { t.Run(fmt.Sprintf("#%v", i), func(t *testing.T) { diff --git a/grammar/grammar.go b/grammar/grammar.go index e2f9ba0..16126ec 100644 --- a/grammar/grammar.go +++ b/grammar/grammar.go @@ -84,7 +84,6 @@ type Grammar struct { name string lexSpec *mlspec.LexSpec skipLexKinds []mlspec.LexKindName - sym2AnonPat map[symbol]string productionSet *productionSet augmentedStartSymbol symbol errorSymbol symbol @@ -211,7 +210,6 @@ func (b *GrammarBuilder) Build() (*Grammar, error) { name: specName, lexSpec: symTabAndLexSpec.lexSpec, skipLexKinds: symTabAndLexSpec.skip, - sym2AnonPat: symTabAndLexSpec.sym2AnonPat, productionSet: prodsAndActs.prods, augmentedStartSymbol: prodsAndActs.augStartSym, errorSymbol: symTabAndLexSpec.errSym, @@ -383,18 +381,14 @@ func collectUserDefinedIDsFromDirective(dir *spec.DirectiveNode) []string { } type symbolTableAndLexSpec struct { - symTab *symbolTable - anonPat2Sym map[string]symbol - sym2AnonPat map[symbol]string - lexSpec *mlspec.LexSpec - errSym symbol - skip []mlspec.LexKindName - skipSyms []string + symTab *symbolTable + lexSpec *mlspec.LexSpec + errSym symbol + skip []mlspec.LexKindName + skipSyms []string } func (b *GrammarBuilder) genSymbolTableAndLexSpec(root *spec.RootNode) (*symbolTableAndLexSpec, error) { - // Anonymous patterns take precedence over explicitly defined lexical specifications (named patterns). - // Thus anonymous patterns must be registered to `symTab` and `entries` before named patterns. symTab := newSymbolTable() entries := []*mlspec.LexEntry{} @@ -408,57 +402,6 @@ func (b *GrammarBuilder) genSymbolTableAndLexSpec(root *spec.RootNode) (*symbolT errSym = sym } - anonPat2Sym := map[string]symbol{} - sym2AnonPat := map[symbol]string{} - { - knownPats := map[string]struct{}{} - anonPats := []string{} - literalPats := map[string]struct{}{} - for _, prod := range root.Productions { - for _, alt := range prod.RHS { - for _, elem := range alt.Elements { - if elem.Pattern == "" { - continue - } - - var pattern string - if elem.Literally { - pattern = mlspec.EscapePattern(elem.Pattern) - } else { - pattern = elem.Pattern - } - - if _, ok := knownPats[pattern]; ok { - continue - } - - knownPats[pattern] = struct{}{} - anonPats = append(anonPats, pattern) - if elem.Literally { - literalPats[pattern] = struct{}{} - } - } - } - } - - for i, p := range anonPats { - kind := fmt.Sprintf("x_%v", i+1) - - sym, err := symTab.registerTerminalSymbol(kind) - if err != nil { - return nil, err - } - - anonPat2Sym[p] = sym - sym2AnonPat[sym] = p - - entries = append(entries, &mlspec.LexEntry{ - Kind: mlspec.LexKindName(kind), - Pattern: mlspec.LexPattern(p), - }) - } - } - skipKinds := []mlspec.LexKindName{} skipSyms := []string{} for _, prod := range root.LexProductions { @@ -522,9 +465,7 @@ func (b *GrammarBuilder) genSymbolTableAndLexSpec(root *spec.RootNode) (*symbolT } return &symbolTableAndLexSpec{ - symTab: symTab, - anonPat2Sym: anonPat2Sym, - sym2AnonPat: sym2AnonPat, + symTab: symTab, lexSpec: &mlspec.LexSpec{ Entries: entries, }, @@ -652,7 +593,6 @@ type productionsAndActions struct { func (b *GrammarBuilder) genProductionsAndActions(root *spec.RootNode, symTabAndLexSpec *symbolTableAndLexSpec) (*productionsAndActions, error) { symTab := symTabAndLexSpec.symTab - anonPat2Sym := symTabAndLexSpec.anonPat2Sym errSym := symTabAndLexSpec.errSym if len(root.Productions) == 0 { @@ -751,33 +691,15 @@ func (b *GrammarBuilder) genProductionsAndActions(root *spec.RootNode, symTabAnd offsets := map[string]int{} ambiguousIDOffsets := map[string]struct{}{} for i, elem := range alt.Elements { - var sym symbol - if elem.Pattern != "" { - var pattern string - if elem.Literally { - pattern = mlspec.EscapePattern(elem.Pattern) - } else { - pattern = elem.Pattern - } - - var ok bool - sym, ok = anonPat2Sym[pattern] - if !ok { - // All patterns are assumed to be pre-detected, so it's a bug if we cannot find them here. - return nil, fmt.Errorf("pattern '%v' is undefined", pattern) - } - } else { - var ok bool - sym, ok = symTab.toSymbol(elem.ID) - if !ok { - b.errs = append(b.errs, &verr.SpecError{ - Cause: semErrUndefinedSym, - Detail: elem.ID, - Row: elem.Pos.Row, - Col: elem.Pos.Col, - }) - continue LOOP_RHS - } + sym, ok := symTab.toSymbol(elem.ID) + if !ok { + b.errs = append(b.errs, &verr.SpecError{ + Cause: semErrUndefinedSym, + Detail: elem.ID, + Row: elem.Pos.Row, + Col: elem.Pos.Col, + }) + continue LOOP_RHS } altSyms[i] = sym @@ -933,6 +855,9 @@ func (b *GrammarBuilder) genProductionsAndActions(root *spec.RootNode, symTabAnd if param.Expansion { elem := alt.Elements[offset] if elem.Pattern != "" { + // Currently, it is a bug to reach here because it is + // forbidden to have anything other than ID appear in + // production rules. b.errs = append(b.errs, &verr.SpecError{ Cause: semErrDirInvalidParam, Detail: fmt.Sprintf("the expansion symbol cannot be applied to a pattern (%v: \"%v\")", param.ID, elem.Pattern), @@ -1319,13 +1244,6 @@ func Compile(gram *Grammar, opts ...CompileOption) (*spec.CompiledGrammar, *spec if err != nil { return nil, nil, err } - terms := make([]string, len(termTexts)) - for i, t := range termTexts { - // NOTE: For anonymous symbol, `t` is a name with `x_` as a prefix. However, - // this name is not intentionally set by a user, so a message containing this - // name will result in an unfriendly message. - terms[i] = t - } nonTerms, err := gram.symbolTable.nonTerminalTexts() if err != nil { @@ -1353,10 +1271,9 @@ func Compile(gram *Grammar, opts ...CompileOption) (*spec.CompiledGrammar, *spec b := &lrTableBuilder{ automaton: lalr1.lr0Automaton, prods: gram.productionSet, - termCount: len(terms), + termCount: len(termTexts), nonTermCount: len(nonTerms), symTab: gram.symbolTable, - sym2AnonPat: gram.sym2AnonPat, precAndAssoc: gram.precAndAssoc, } tab, err = b.build() @@ -1426,7 +1343,7 @@ func Compile(gram *Grammar, opts ...CompileOption) (*spec.CompiledGrammar, *spec StartProduction: productionNumStart.Int(), LHSSymbols: lhsSyms, AlternativeSymbolCounts: altSymCounts, - Terminals: terms, + Terminals: termTexts, TerminalCount: tab.terminalCount, NonTerminals: nonTerms, NonTerminalCount: tab.nonTerminalCount, diff --git a/grammar/grammar_test.go b/grammar/grammar_test.go index 80613aa..f6cb681 100644 --- a/grammar/grammar_test.go +++ b/grammar/grammar_test.go @@ -1723,12 +1723,14 @@ foo ); s - : foo ';' - | error ';' + : foo semi_colon + | error semi_colon ; foo : 'foo'; +semi_colon + : ';'; `, errs: []*SemanticError{semErrDirInvalidParam}, }, @@ -1965,12 +1967,14 @@ foo ); s - : foo ';' - | error ';' + : foo semi_colon + | error semi_colon ; foo : 'foo'; +semi_colon + : ';'; `, errs: []*SemanticError{semErrDirInvalidParam}, }, @@ -2207,12 +2211,14 @@ foo ); s - : foo ';' - | error ';' + : foo semi_colon + | error semi_colon ; foo : 'foo'; +semi_colon + : ';'; `, errs: []*SemanticError{semErrDirInvalidParam}, }, @@ -2680,34 +2686,6 @@ foo `, errs: []*SemanticError{semErrDirInvalidParam}, }, - { - caption: "the expansion operator cannot be applied to a pattern", - specSrc: ` -#name test; - -s - : foo 'bar'@b #ast foo b... - ; - -foo - : "foo"; -`, - errs: []*SemanticError{semErrDirInvalidParam}, - }, - { - caption: "the expansion operator cannot be applied to a string", - specSrc: ` -#name test; - -s - : foo 'bar'@b #ast foo b... - ; - -foo - : "foo"; -`, - errs: []*SemanticError{semErrDirInvalidParam}, - }, } altPrecDirTests := []*specErrTest{ diff --git a/grammar/parsing_table.go b/grammar/parsing_table.go index e980902..1eaf63d 100644 --- a/grammar/parsing_table.go +++ b/grammar/parsing_table.go @@ -152,7 +152,6 @@ type lrTableBuilder struct { termCount int nonTermCount int symTab *symbolTable - sym2AnonPat map[symbol]string precAndAssoc *precAndAssoc conflicts []conflict @@ -328,12 +327,6 @@ func (b *lrTableBuilder) genReport(tab *ParsingTable, gram *Grammar) (*spec.Repo Name: name, } - pat, ok := b.sym2AnonPat[sym] - if ok { - term.Anonymous = true - term.Pattern = pat - } - prec := b.precAndAssoc.terminalPrecedence(sym.num()) if prec != precNil { term.Precedence = prec diff --git a/spec/grammar/description.go b/spec/grammar/description.go index 68b16be..0d2a0b7 100644 --- a/spec/grammar/description.go +++ b/spec/grammar/description.go @@ -3,7 +3,6 @@ package grammar type Terminal struct { Number int `json:"number"` Name string `json:"name"` - Anonymous bool `json:"anonymous"` Pattern string `json:"pattern"` Precedence int `json:"prec"` Associativity string `json:"assoc"` diff --git a/spec/grammar/parser.go b/spec/grammar/parser.go index 946d877..27a7c7d 100644 --- a/spec/grammar/parser.go +++ b/spec/grammar/parser.go @@ -351,7 +351,7 @@ func (p *parser) parseProduction() *ProductionNode { if !prod.isLexical() { for _, alt := range prod.RHS { for _, elem := range alt.Elements { - if elem.Pattern != "" && !elem.Literally { + if elem.Pattern != "" { raiseSyntaxError(elem.Pos.Row, synErrPatternInAlt) } } diff --git a/spec/grammar/parser_test.go b/spec/grammar/parser_test.go index 4fd7e9f..5a2e07f 100644 --- a/spec/grammar/parser_test.go +++ b/spec/grammar/parser_test.go @@ -272,56 +272,102 @@ func TestParse(t *testing.T) { { caption: "multiple productions are a valid grammar", src: ` -e: e '+' t | e '-' t | t; -t: t '*' f | t '/' f | f; -f: '(' e ')' | id; -id: "[A-Za-z_][0-9A-Za-z_]*"; +e + : e add t + | e sub t + | t + ; +t + : t mul f + | t div f + | f + ; +f + : l_paren e r_paren + | id + ; + +add + : '+'; +sub + : '-'; +mul + : '*'; +div + : '/'; +l_paren + : '('; +r_paren + : ')'; +id + : "[A-Za-z_][0-9A-Za-z_]*"; `, ast: &RootNode{ Productions: []*ProductionNode{ prod("e", - alt(id("e"), pat(`+`), id("t")), - alt(id("e"), pat(`-`), id("t")), + alt(id("e"), id("add"), id("t")), + alt(id("e"), id("sub"), id("t")), alt(id("t")), ), prod("t", - alt(id("t"), pat(`*`), id("f")), - alt(id("t"), pat(`/`), id("f")), + alt(id("t"), id("mul"), id("f")), + alt(id("t"), id("div"), id("f")), alt(id("f")), ), prod("f", - alt(pat(`(`), id("e"), pat(`)`)), + alt(id("l_paren"), id("e"), id("r_paren")), alt(id("id")), ), }, LexProductions: []*ProductionNode{ - prod("id", - alt(pat(`[A-Za-z_][0-9A-Za-z_]*`)), - ), + prod("add", alt(pat(`+`))), + prod("sub", alt(pat(`-`))), + prod("mul", alt(pat(`*`))), + prod("div", alt(pat(`/`))), + prod("l_paren", alt(pat(`(`))), + prod("r_paren", alt(pat(`)`))), + prod("id", alt(pat(`[A-Za-z_][0-9A-Za-z_]*`))), }, }, }, { caption: "productions can contain the empty alternative", src: ` -a: 'foo' | ; -b: | 'bar'; -c: ; +a + : foo + | + ; +b + : + | bar + ; +c + : + ; + +foo + : 'foo'; +bar + : 'bar'; `, ast: &RootNode{ Productions: []*ProductionNode{ prod("a", - alt(pat(`foo`)), + alt(id("foo")), alt(), ), prod("b", alt(), - alt(pat(`bar`)), + alt(id("bar")), ), prod("c", alt(), ), }, + LexProductions: []*ProductionNode{ + prod("foo", alt(pat(`foo`))), + prod("bar", alt(pat(`bar`))), + }, }, }, { @@ -332,35 +378,23 @@ a: $x; synErr: synErrNoSemicolon, }, { - caption: "an alternative can contain a string literal without a terminal symbol", + caption: "an alternative cannot contain a pattern directly", src: ` s - : 'foo' bar + : "foo" bar ; bar - : 'bar'; + : "bar"; `, - ast: &RootNode{ - Productions: []*ProductionNode{ - prod("s", - alt(pat(`foo`), id("bar")), - ), - }, - LexProductions: []*ProductionNode{ - prod("bar", - alt(pat(`bar`)), - ), - }, - }, + synErr: synErrPatternInAlt, }, { - caption: "an alternative cannot contain a pattern directly", + caption: "an alternative cannot contain a string directly", src: ` s - : "foo" bar + : 'foo' bar ; - bar : "bar"; `, @@ -721,12 +755,14 @@ a caption: "an AST has node positions", src: ` exp - : exp '+' id #ast exp id + : exp add id #ast exp id | id ; whitespace #skip : "\u{0020}+"; +add + : '+'; id : "\f{letter}(\f{letter}|\f{number})*"; fragment letter @@ -743,7 +779,7 @@ fragment number withAltDir( alt( withElemPos(id("exp"), newPos(3)), - withElemPos(pat(`+`), newPos(3)), + withElemPos(id("add"), newPos(3)), withElemPos(id("id"), newPos(3)), ), withDirPos( @@ -788,11 +824,11 @@ fragment number newPos(7), ), withProdPos( - prod("id", + prod("add", withAltPos( alt( withElemPos( - pat(`\f{letter}(\f{letter}|\f{number})*`), + pat(`+`), newPos(10), ), ), @@ -801,15 +837,29 @@ fragment number ), newPos(9), ), + withProdPos( + prod("id", + withAltPos( + alt( + withElemPos( + pat(`\f{letter}(\f{letter}|\f{number})*`), + newPos(12), + ), + ), + newPos(12), + ), + ), + newPos(11), + ), }, Fragments: []*FragmentNode{ withFragmentPos( frag("letter", "[A-Za-z_]"), - newPos(11), + newPos(13), ), withFragmentPos( frag("number", "[0-9]"), - newPos(13), + newPos(15), ), }, }, diff --git a/spec/test/parser.go b/spec/test/parser.go index c30d45c..b7265d7 100644 --- a/spec/test/parser.go +++ b/spec/test/parser.go @@ -78,11 +78,7 @@ func (t *Tree) format(buf *bytes.Buffer, depth int) { buf.WriteString(" ") } buf.WriteString("(") - if t.Kind == "" { - buf.WriteString("<anonymous>") - } else { - buf.WriteString(t.Kind) - } + buf.WriteString(t.Kind) if len(t.Children) > 0 { buf.WriteString("\n") for i, c := range t.Children { diff --git a/spec/test/tree-report.json b/spec/test/tree-report.json index 3bfba2c..c2018e5 100644 --- a/spec/test/tree-report.json +++ b/spec/test/tree-report.json @@ -1 +1 @@ -{"terminals":[null,{"number":1,"name":"\u003ceof\u003e","anonymous":false,"pattern":"","prec":0,"assoc":""},{"number":2,"name":"error","anonymous":false,"pattern":"","prec":0,"assoc":""},{"number":3,"name":"ws","anonymous":false,"pattern":"","prec":0,"assoc":""},{"number":4,"name":"l_paren","anonymous":false,"pattern":"","prec":1,"assoc":""},{"number":5,"name":"r_paren","anonymous":false,"pattern":"","prec":0,"assoc":""},{"number":6,"name":"identifier","anonymous":false,"pattern":"","prec":0,"assoc":""},{"number":7,"name":"raw_string_open","anonymous":false,"pattern":"","prec":0,"assoc":""},{"number":8,"name":"raw_string_body","anonymous":false,"pattern":"","prec":0,"assoc":""},{"number":9,"name":"raw_string_close","anonymous":false,"pattern":"","prec":0,"assoc":""},{"number":10,"name":"interpreted_string_open","anonymous":false,"pattern":"","prec":0,"assoc":""},{"number":11,"name":"interpreted_seq","anonymous":false,"pattern":"","prec":0,"assoc":""},{"number":12,"name":"codepoint_prefix","anonymous":false,"pattern":"","prec":0,"assoc":""},{"number":13,"name":"l_brace","anonymous":false,"pattern":"","prec":0,"assoc":""},{"number":14,"name":"r_brace","anonymous":false,"pattern":"","prec":0,"assoc":""},{"number":15,"name":"hex_digits","anonymous":false,"pattern":"","prec":0,"assoc":""},{"number":16,"name":"escaped_seq","anonymous":false,"pattern":"","prec":0,"assoc":""},{"number":17,"name":"escape_char","anonymous":false,"pattern":"","prec":0,"assoc":""},{"number":18,"name":"interpreted_string_close","anonymous":false,"pattern":"","prec":0,"assoc":""}],"non_terminals":[null,{"number":1,"name":"tree'"},{"number":2,"name":"tree"},{"number":3,"name":"tree_list"},{"number":4,"name":"string"},{"number":5,"name":"raw_string"},{"number":6,"name":"opt_raw_string_body"},{"number":7,"name":"interpreted_string"},{"number":8,"name":"opt_interpreted_string_body"},{"number":9,"name":"interpreted_string_body"},{"number":10,"name":"interpreted_string_elem"},{"number":11,"name":"codepoint_expr"}],"productions":[null,{"number":1,"lhs":1,"rhs":[-2],"prec":0,"assoc":""},{"number":2,"lhs":2,"rhs":[4,6,-3,5],"prec":0,"assoc":""},{"number":3,"lhs":2,"rhs":[4,6,-4,5],"prec":0,"assoc":""},{"number":4,"lhs":2,"rhs":[4,2,5],"prec":0,"assoc":""},{"number":5,"lhs":3,"rhs":[-3,-2],"prec":0,"assoc":""},{"number":6,"lhs":3,"rhs":[-2],"prec":0,"assoc":""},{"number":7,"lhs":3,"rhs":[],"prec":2,"assoc":""},{"number":8,"lhs":4,"rhs":[-5],"prec":0,"assoc":""},{"number":9,"lhs":4,"rhs":[-7],"prec":0,"assoc":""},{"number":10,"lhs":5,"rhs":[7,-6,9],"prec":0,"assoc":""},{"number":11,"lhs":6,"rhs":[8],"prec":0,"assoc":""},{"number":12,"lhs":6,"rhs":[],"prec":0,"assoc":""},{"number":13,"lhs":7,"rhs":[10,-8,18],"prec":0,"assoc":""},{"number":14,"lhs":7,"rhs":[10,2,18],"prec":0,"assoc":""},{"number":15,"lhs":8,"rhs":[-9],"prec":0,"assoc":""},{"number":16,"lhs":8,"rhs":[],"prec":0,"assoc":""},{"number":17,"lhs":9,"rhs":[-9,-10],"prec":0,"assoc":""},{"number":18,"lhs":9,"rhs":[-10],"prec":0,"assoc":""},{"number":19,"lhs":10,"rhs":[11],"prec":0,"assoc":""},{"number":20,"lhs":10,"rhs":[13],"prec":0,"assoc":""},{"number":21,"lhs":10,"rhs":[14],"prec":0,"assoc":""},{"number":22,"lhs":10,"rhs":[15],"prec":0,"assoc":""},{"number":23,"lhs":10,"rhs":[16],"prec":0,"assoc":""},{"number":24,"lhs":10,"rhs":[17],"prec":0,"assoc":""},{"number":25,"lhs":10,"rhs":[-11],"prec":0,"assoc":""},{"number":26,"lhs":11,"rhs":[12,13,15,14],"prec":0,"assoc":""}],"states":[{"number":0,"kernel":[{"production":1,"dot":0}],"shift":[{"symbol":4,"state":2}],"reduce":null,"goto":[{"symbol":2,"state":1}],"sr_conflict":[],"rr_conflict":[]},{"number":1,"kernel":[{"production":1,"dot":1}],"shift":null,"reduce":[{"look_ahead":[1],"production":1}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":2,"kernel":[{"production":2,"dot":1},{"production":3,"dot":1},{"production":4,"dot":1}],"shift":[{"symbol":2,"state":3},{"symbol":6,"state":4}],"reduce":null,"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":3,"kernel":[{"production":4,"dot":2}],"shift":[{"symbol":5,"state":5}],"reduce":null,"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":4,"kernel":[{"production":2,"dot":2},{"production":3,"dot":2}],"shift":[{"symbol":4,"state":2},{"symbol":7,"state":11},{"symbol":10,"state":12}],"reduce":[{"look_ahead":[5,1],"production":7}],"goto":[{"symbol":2,"state":6},{"symbol":3,"state":7},{"symbol":4,"state":8},{"symbol":5,"state":9},{"symbol":7,"state":10}],"sr_conflict":[{"symbol":4,"state":2,"production":7,"adopted_state":2,"adopted_production":null,"resolved_by":1}],"rr_conflict":[]},{"number":5,"kernel":[{"production":4,"dot":3}],"shift":null,"reduce":[{"look_ahead":[4,5,1],"production":4}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":6,"kernel":[{"production":6,"dot":1}],"shift":null,"reduce":[{"look_ahead":[4,5],"production":6}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":7,"kernel":[{"production":2,"dot":3},{"production":5,"dot":1}],"shift":[{"symbol":4,"state":2},{"symbol":5,"state":14}],"reduce":null,"goto":[{"symbol":2,"state":13}],"sr_conflict":[],"rr_conflict":[]},{"number":8,"kernel":[{"production":3,"dot":3}],"shift":[{"symbol":5,"state":15}],"reduce":null,"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":9,"kernel":[{"production":8,"dot":1}],"shift":null,"reduce":[{"look_ahead":[5],"production":8}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":10,"kernel":[{"production":9,"dot":1}],"shift":null,"reduce":[{"look_ahead":[5],"production":9}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":11,"kernel":[{"production":10,"dot":1}],"shift":[{"symbol":8,"state":17}],"reduce":[{"look_ahead":[4,5,9,1],"production":12}],"goto":[{"symbol":6,"state":16}],"sr_conflict":[],"rr_conflict":[]},{"number":12,"kernel":[{"production":13,"dot":1},{"production":14,"dot":1}],"shift":[{"symbol":2,"state":22},{"symbol":11,"state":23},{"symbol":12,"state":24},{"symbol":13,"state":25},{"symbol":14,"state":26},{"symbol":15,"state":27},{"symbol":16,"state":28},{"symbol":17,"state":29}],"reduce":[{"look_ahead":[4,5,18,1],"production":16}],"goto":[{"symbol":8,"state":18},{"symbol":9,"state":19},{"symbol":10,"state":20},{"symbol":11,"state":21}],"sr_conflict":[],"rr_conflict":[]},{"number":13,"kernel":[{"production":5,"dot":2}],"shift":null,"reduce":[{"look_ahead":[4,5],"production":5}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":14,"kernel":[{"production":2,"dot":4}],"shift":null,"reduce":[{"look_ahead":[4,5,1],"production":2}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":15,"kernel":[{"production":3,"dot":4}],"shift":null,"reduce":[{"look_ahead":[4,5,1],"production":3}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":16,"kernel":[{"production":10,"dot":2}],"shift":[{"symbol":9,"state":30}],"reduce":null,"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":17,"kernel":[{"production":11,"dot":1}],"shift":null,"reduce":[{"look_ahead":[9],"production":11}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":18,"kernel":[{"production":13,"dot":2}],"shift":[{"symbol":18,"state":31}],"reduce":null,"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":19,"kernel":[{"production":15,"dot":1},{"production":17,"dot":1}],"shift":[{"symbol":11,"state":23},{"symbol":12,"state":24},{"symbol":13,"state":25},{"symbol":14,"state":26},{"symbol":15,"state":27},{"symbol":16,"state":28},{"symbol":17,"state":29}],"reduce":[{"look_ahead":[18],"production":15}],"goto":[{"symbol":11,"state":21},{"symbol":10,"state":32}],"sr_conflict":[],"rr_conflict":[]},{"number":20,"kernel":[{"production":18,"dot":1}],"shift":null,"reduce":[{"look_ahead":[4,5,11,12,13,14,15,16,17,18,1],"production":18}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":21,"kernel":[{"production":25,"dot":1}],"shift":null,"reduce":[{"look_ahead":[4,5,11,12,13,14,15,16,17,18,1],"production":25}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":22,"kernel":[{"production":14,"dot":2}],"shift":[{"symbol":18,"state":33}],"reduce":null,"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":23,"kernel":[{"production":19,"dot":1}],"shift":null,"reduce":[{"look_ahead":[4,5,11,12,13,14,15,16,17,18,1],"production":19}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":24,"kernel":[{"production":26,"dot":1}],"shift":[{"symbol":13,"state":34}],"reduce":null,"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":25,"kernel":[{"production":20,"dot":1}],"shift":null,"reduce":[{"look_ahead":[4,5,11,12,13,14,15,16,17,18,1],"production":20}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":26,"kernel":[{"production":21,"dot":1}],"shift":null,"reduce":[{"look_ahead":[4,5,11,12,13,14,15,16,17,18,1],"production":21}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":27,"kernel":[{"production":22,"dot":1}],"shift":null,"reduce":[{"look_ahead":[4,5,11,12,13,14,15,16,17,18,1],"production":22}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":28,"kernel":[{"production":23,"dot":1}],"shift":null,"reduce":[{"look_ahead":[4,5,11,12,13,14,15,16,17,18,1],"production":23}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":29,"kernel":[{"production":24,"dot":1}],"shift":null,"reduce":[{"look_ahead":[4,5,11,12,13,14,15,16,17,18,1],"production":24}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":30,"kernel":[{"production":10,"dot":3}],"shift":null,"reduce":[{"look_ahead":[4,5,1],"production":10}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":31,"kernel":[{"production":13,"dot":3}],"shift":null,"reduce":[{"look_ahead":[4,5,1],"production":13}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":32,"kernel":[{"production":17,"dot":2}],"shift":null,"reduce":[{"look_ahead":[4,5,11,12,13,14,15,16,17,18,1],"production":17}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":33,"kernel":[{"production":14,"dot":3}],"shift":null,"reduce":[{"look_ahead":[4,5,1],"production":14}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":34,"kernel":[{"production":26,"dot":2}],"shift":[{"symbol":15,"state":35}],"reduce":null,"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":35,"kernel":[{"production":26,"dot":3}],"shift":[{"symbol":14,"state":36}],"reduce":null,"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":36,"kernel":[{"production":26,"dot":4}],"shift":null,"reduce":[{"look_ahead":[4,5,11,12,13,14,15,16,17,18,1],"production":26}],"goto":null,"sr_conflict":[],"rr_conflict":[]}]} +{"terminals":[null,{"number":1,"name":"\u003ceof\u003e","pattern":"","prec":0,"assoc":""},{"number":2,"name":"error","pattern":"","prec":0,"assoc":""},{"number":3,"name":"ws","pattern":"","prec":0,"assoc":""},{"number":4,"name":"l_paren","pattern":"","prec":1,"assoc":""},{"number":5,"name":"r_paren","pattern":"","prec":0,"assoc":""},{"number":6,"name":"identifier","pattern":"","prec":0,"assoc":""},{"number":7,"name":"raw_string_open","pattern":"","prec":0,"assoc":""},{"number":8,"name":"raw_string_body","pattern":"","prec":0,"assoc":""},{"number":9,"name":"raw_string_close","pattern":"","prec":0,"assoc":""},{"number":10,"name":"interpreted_string_open","pattern":"","prec":0,"assoc":""},{"number":11,"name":"interpreted_seq","pattern":"","prec":0,"assoc":""},{"number":12,"name":"codepoint_prefix","pattern":"","prec":0,"assoc":""},{"number":13,"name":"l_brace","pattern":"","prec":0,"assoc":""},{"number":14,"name":"r_brace","pattern":"","prec":0,"assoc":""},{"number":15,"name":"hex_digits","pattern":"","prec":0,"assoc":""},{"number":16,"name":"escaped_seq","pattern":"","prec":0,"assoc":""},{"number":17,"name":"escape_char","pattern":"","prec":0,"assoc":""},{"number":18,"name":"interpreted_string_close","pattern":"","prec":0,"assoc":""}],"non_terminals":[null,{"number":1,"name":"tree'"},{"number":2,"name":"tree"},{"number":3,"name":"tree_list"},{"number":4,"name":"string"},{"number":5,"name":"raw_string"},{"number":6,"name":"opt_raw_string_body"},{"number":7,"name":"interpreted_string"},{"number":8,"name":"opt_interpreted_string_body"},{"number":9,"name":"interpreted_string_body"},{"number":10,"name":"interpreted_string_elem"},{"number":11,"name":"codepoint_expr"}],"productions":[null,{"number":1,"lhs":1,"rhs":[-2],"prec":0,"assoc":""},{"number":2,"lhs":2,"rhs":[4,6,-3,5],"prec":0,"assoc":""},{"number":3,"lhs":2,"rhs":[4,6,-4,5],"prec":0,"assoc":""},{"number":4,"lhs":2,"rhs":[4,2,5],"prec":0,"assoc":""},{"number":5,"lhs":3,"rhs":[-3,-2],"prec":0,"assoc":""},{"number":6,"lhs":3,"rhs":[-2],"prec":0,"assoc":""},{"number":7,"lhs":3,"rhs":[],"prec":2,"assoc":""},{"number":8,"lhs":4,"rhs":[-5],"prec":0,"assoc":""},{"number":9,"lhs":4,"rhs":[-7],"prec":0,"assoc":""},{"number":10,"lhs":5,"rhs":[7,-6,9],"prec":0,"assoc":""},{"number":11,"lhs":6,"rhs":[8],"prec":0,"assoc":""},{"number":12,"lhs":6,"rhs":[],"prec":0,"assoc":""},{"number":13,"lhs":7,"rhs":[10,-8,18],"prec":0,"assoc":""},{"number":14,"lhs":7,"rhs":[10,2,18],"prec":0,"assoc":""},{"number":15,"lhs":8,"rhs":[-9],"prec":0,"assoc":""},{"number":16,"lhs":8,"rhs":[],"prec":0,"assoc":""},{"number":17,"lhs":9,"rhs":[-9,-10],"prec":0,"assoc":""},{"number":18,"lhs":9,"rhs":[-10],"prec":0,"assoc":""},{"number":19,"lhs":10,"rhs":[11],"prec":0,"assoc":""},{"number":20,"lhs":10,"rhs":[13],"prec":0,"assoc":""},{"number":21,"lhs":10,"rhs":[14],"prec":0,"assoc":""},{"number":22,"lhs":10,"rhs":[15],"prec":0,"assoc":""},{"number":23,"lhs":10,"rhs":[16],"prec":0,"assoc":""},{"number":24,"lhs":10,"rhs":[17],"prec":0,"assoc":""},{"number":25,"lhs":10,"rhs":[-11],"prec":0,"assoc":""},{"number":26,"lhs":11,"rhs":[12,13,15,14],"prec":0,"assoc":""}],"states":[{"number":0,"kernel":[{"production":1,"dot":0}],"shift":[{"symbol":4,"state":2}],"reduce":null,"goto":[{"symbol":2,"state":1}],"sr_conflict":[],"rr_conflict":[]},{"number":1,"kernel":[{"production":1,"dot":1}],"shift":null,"reduce":[{"look_ahead":[1],"production":1}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":2,"kernel":[{"production":2,"dot":1},{"production":3,"dot":1},{"production":4,"dot":1}],"shift":[{"symbol":2,"state":3},{"symbol":6,"state":4}],"reduce":null,"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":3,"kernel":[{"production":4,"dot":2}],"shift":[{"symbol":5,"state":5}],"reduce":null,"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":4,"kernel":[{"production":2,"dot":2},{"production":3,"dot":2}],"shift":[{"symbol":4,"state":2},{"symbol":7,"state":11},{"symbol":10,"state":12}],"reduce":[{"look_ahead":[5,1],"production":7}],"goto":[{"symbol":2,"state":6},{"symbol":3,"state":7},{"symbol":4,"state":8},{"symbol":5,"state":9},{"symbol":7,"state":10}],"sr_conflict":[{"symbol":4,"state":2,"production":7,"adopted_state":2,"adopted_production":null,"resolved_by":1}],"rr_conflict":[]},{"number":5,"kernel":[{"production":4,"dot":3}],"shift":null,"reduce":[{"look_ahead":[4,5,1],"production":4}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":6,"kernel":[{"production":6,"dot":1}],"shift":null,"reduce":[{"look_ahead":[4,5],"production":6}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":7,"kernel":[{"production":2,"dot":3},{"production":5,"dot":1}],"shift":[{"symbol":4,"state":2},{"symbol":5,"state":14}],"reduce":null,"goto":[{"symbol":2,"state":13}],"sr_conflict":[],"rr_conflict":[]},{"number":8,"kernel":[{"production":3,"dot":3}],"shift":[{"symbol":5,"state":15}],"reduce":null,"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":9,"kernel":[{"production":8,"dot":1}],"shift":null,"reduce":[{"look_ahead":[5],"production":8}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":10,"kernel":[{"production":9,"dot":1}],"shift":null,"reduce":[{"look_ahead":[5],"production":9}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":11,"kernel":[{"production":10,"dot":1}],"shift":[{"symbol":8,"state":17}],"reduce":[{"look_ahead":[4,5,9,1],"production":12}],"goto":[{"symbol":6,"state":16}],"sr_conflict":[],"rr_conflict":[]},{"number":12,"kernel":[{"production":13,"dot":1},{"production":14,"dot":1}],"shift":[{"symbol":2,"state":22},{"symbol":11,"state":23},{"symbol":12,"state":24},{"symbol":13,"state":25},{"symbol":14,"state":26},{"symbol":15,"state":27},{"symbol":16,"state":28},{"symbol":17,"state":29}],"reduce":[{"look_ahead":[4,5,18,1],"production":16}],"goto":[{"symbol":8,"state":18},{"symbol":9,"state":19},{"symbol":10,"state":20},{"symbol":11,"state":21}],"sr_conflict":[],"rr_conflict":[]},{"number":13,"kernel":[{"production":5,"dot":2}],"shift":null,"reduce":[{"look_ahead":[4,5],"production":5}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":14,"kernel":[{"production":2,"dot":4}],"shift":null,"reduce":[{"look_ahead":[4,5,1],"production":2}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":15,"kernel":[{"production":3,"dot":4}],"shift":null,"reduce":[{"look_ahead":[4,5,1],"production":3}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":16,"kernel":[{"production":10,"dot":2}],"shift":[{"symbol":9,"state":30}],"reduce":null,"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":17,"kernel":[{"production":11,"dot":1}],"shift":null,"reduce":[{"look_ahead":[9],"production":11}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":18,"kernel":[{"production":13,"dot":2}],"shift":[{"symbol":18,"state":31}],"reduce":null,"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":19,"kernel":[{"production":15,"dot":1},{"production":17,"dot":1}],"shift":[{"symbol":11,"state":23},{"symbol":12,"state":24},{"symbol":13,"state":25},{"symbol":14,"state":26},{"symbol":15,"state":27},{"symbol":16,"state":28},{"symbol":17,"state":29}],"reduce":[{"look_ahead":[18],"production":15}],"goto":[{"symbol":11,"state":21},{"symbol":10,"state":32}],"sr_conflict":[],"rr_conflict":[]},{"number":20,"kernel":[{"production":18,"dot":1}],"shift":null,"reduce":[{"look_ahead":[4,5,11,12,13,14,15,16,17,18,1],"production":18}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":21,"kernel":[{"production":25,"dot":1}],"shift":null,"reduce":[{"look_ahead":[4,5,11,12,13,14,15,16,17,18,1],"production":25}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":22,"kernel":[{"production":14,"dot":2}],"shift":[{"symbol":18,"state":33}],"reduce":null,"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":23,"kernel":[{"production":19,"dot":1}],"shift":null,"reduce":[{"look_ahead":[4,5,11,12,13,14,15,16,17,18,1],"production":19}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":24,"kernel":[{"production":26,"dot":1}],"shift":[{"symbol":13,"state":34}],"reduce":null,"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":25,"kernel":[{"production":20,"dot":1}],"shift":null,"reduce":[{"look_ahead":[4,5,11,12,13,14,15,16,17,18,1],"production":20}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":26,"kernel":[{"production":21,"dot":1}],"shift":null,"reduce":[{"look_ahead":[4,5,11,12,13,14,15,16,17,18,1],"production":21}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":27,"kernel":[{"production":22,"dot":1}],"shift":null,"reduce":[{"look_ahead":[4,5,11,12,13,14,15,16,17,18,1],"production":22}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":28,"kernel":[{"production":23,"dot":1}],"shift":null,"reduce":[{"look_ahead":[4,5,11,12,13,14,15,16,17,18,1],"production":23}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":29,"kernel":[{"production":24,"dot":1}],"shift":null,"reduce":[{"look_ahead":[4,5,11,12,13,14,15,16,17,18,1],"production":24}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":30,"kernel":[{"production":10,"dot":3}],"shift":null,"reduce":[{"look_ahead":[4,5,1],"production":10}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":31,"kernel":[{"production":13,"dot":3}],"shift":null,"reduce":[{"look_ahead":[4,5,1],"production":13}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":32,"kernel":[{"production":17,"dot":2}],"shift":null,"reduce":[{"look_ahead":[4,5,11,12,13,14,15,16,17,18,1],"production":17}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":33,"kernel":[{"production":14,"dot":3}],"shift":null,"reduce":[{"look_ahead":[4,5,1],"production":14}],"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":34,"kernel":[{"production":26,"dot":2}],"shift":[{"symbol":15,"state":35}],"reduce":null,"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":35,"kernel":[{"production":26,"dot":3}],"shift":[{"symbol":14,"state":36}],"reduce":null,"goto":null,"sr_conflict":[],"rr_conflict":[]},{"number":36,"kernel":[{"production":26,"dot":4}],"shift":null,"reduce":[{"look_ahead":[4,5,11,12,13,14,15,16,17,18,1],"production":26}],"goto":null,"sr_conflict":[],"rr_conflict":[]}]} diff --git a/spec/test/tree_semantic_action.go b/spec/test/tree_semantic_action.go index c426183..c1d5a25 100644 --- a/spec/test/tree_semantic_action.go +++ b/spec/test/tree_semantic_action.go @@ -341,11 +341,7 @@ func printTree(w io.Writer, node *Node, ruledLine string, childRuledLinePrefix s case NodeTypeError: fmt.Fprintf(w, "%v%v\n", ruledLine, node.KindName) case NodeTypeTerminal: - if node.KindName == "" { - fmt.Fprintf(w, "%v<anonymous> %v\n", ruledLine, strconv.Quote(node.Text)) - } else { - fmt.Fprintf(w, "%v%v %v\n", ruledLine, node.KindName, strconv.Quote(node.Text)) - } + fmt.Fprintf(w, "%v%v %v\n", ruledLine, node.KindName, strconv.Quote(node.Text)) case NodeTypeNonTerminal: fmt.Fprintf(w, "%v%v\n", ruledLine, node.KindName) |