aboutsummaryrefslogtreecommitdiff
path: root/spec/parser.go
diff options
context:
space:
mode:
authorRyo Nihei <nihei.dev@gmail.com>2022-05-07 20:41:33 +0900
committerRyo Nihei <nihei.dev@gmail.com>2022-05-10 23:14:41 +0900
commit3eb0e88f911386a4e6eca991c1471070596c5554 (patch)
tree4c3ea445a804d781b846739d70392ceb1353ea6d /spec/parser.go
parentMake #prec directive change only precedence and not associativity (diff)
downloadurubu-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.go69
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
}