diff options
author | Ryo Nihei <nihei.dev@gmail.com> | 2022-05-07 20:41:33 +0900 |
---|---|---|
committer | Ryo Nihei <nihei.dev@gmail.com> | 2022-05-10 23:14:41 +0900 |
commit | 3eb0e88f911386a4e6eca991c1471070596c5554 (patch) | |
tree | 4c3ea445a804d781b846739d70392ceb1353ea6d /spec/parser.go | |
parent | Make #prec directive change only precedence and not associativity (diff) | |
download | urubu-3eb0e88f911386a4e6eca991c1471070596c5554.tar.gz urubu-3eb0e88f911386a4e6eca991c1471070596c5554.tar.xz |
Change syntax for top-level directives
%name changes to:
#name example;
%left and %right change to:
#prec (
#left a b
#right c d
);
Diffstat (limited to 'spec/parser.go')
-rw-r--r-- | spec/parser.go | 69 |
1 files changed, 41 insertions, 28 deletions
diff --git a/spec/parser.go b/spec/parser.go index a1d23f0..3b5907e 100644 --- a/spec/parser.go +++ b/spec/parser.go @@ -9,7 +9,7 @@ import ( ) type RootNode struct { - MetaData []*DirectiveNode + Directives []*DirectiveNode Productions []*ProductionNode LexProductions []*ProductionNode Fragments []*FragmentNode @@ -58,6 +58,7 @@ type ParameterNode struct { ID string Pattern string String string + Group []*DirectiveNode Expansion bool Pos Position } @@ -134,14 +135,14 @@ func (p *parser) parseRoot() *RootNode { } }() - var metadata []*DirectiveNode + var dirs []*DirectiveNode var prods []*ProductionNode var lexProds []*ProductionNode var fragments []*FragmentNode for { - md := p.parseMetaData() - if md != nil { - metadata = append(metadata, md) + dir := p.parseTopLevelDirective() + if dir != nil { + dirs = append(dirs, dir) continue } @@ -167,14 +168,14 @@ func (p *parser) parseRoot() *RootNode { } return &RootNode{ - MetaData: metadata, + Directives: dirs, Productions: prods, LexProductions: lexProds, Fragments: fragments, } } -func (p *parser) parseMetaData() *DirectiveNode { +func (p *parser) parseTopLevelDirective() *DirectiveNode { defer func() { err := recover() if err == nil { @@ -187,35 +188,21 @@ func (p *parser) parseMetaData() *DirectiveNode { } p.errs = append(p.errs, specErr) - p.skipOverTo(tokenKindNewline) + p.skipOverTo(tokenKindSemicolon) }() - p.consume(tokenKindNewline) - - if !p.consume(tokenKindMetaDataMarker) { + dir := p.parseDirective() + if dir == nil { return nil } - mdPos := p.lastTok.pos - if !p.consume(tokenKindID) { - raiseSyntaxError(p.pos.Row, synErrNoMDName) - } - name := p.lastTok.text + p.consume(tokenKindNewline) - var params []*ParameterNode - for { - param := p.parseParameter() - if param == nil { - break - } - params = append(params, param) + if !p.consume(tokenKindSemicolon) { + raiseSyntaxError(p.pos.Row, synErrTopLevelDirNoSemicolon) } - return &DirectiveNode{ - Name: name, - Parameters: params, - Pos: mdPos, - } + return dir } func (p *parser) parseFragment() *FragmentNode { @@ -428,6 +415,8 @@ func (p *parser) parseElement() *ElementNode { } func (p *parser) parseDirective() *DirectiveNode { + p.consume(tokenKindNewline) + if !p.consume(tokenKindDirectiveMarker) { return nil } @@ -472,6 +461,30 @@ func (p *parser) parseParameter() *ParameterNode { String: p.lastTok.text, Pos: p.lastTok.pos, } + case p.consume(tokenKindLParen): + pos := p.lastTok.pos + var g []*DirectiveNode + for { + dir := p.parseDirective() + if dir == nil { + break + } + g = append(g, dir) + } + if !p.consume(tokenKindRParen) { + raiseSyntaxError(p.pos.Row, synErrUnclosedDirGroup) + } + if len(g) == 0 { + // Set an empty slice representing an empty directive group to distinguish between the following two cases. + // + // - #prec (); // vartan allows this case. + // - #prec; // This case will raise an error. + g = []*DirectiveNode{} + } + param = &ParameterNode{ + Group: g, + Pos: pos, + } default: return nil } |