...
1
2
3
4
5 package godoc
6
7
8
9
10
11
12
13 import (
14 "bytes"
15 "fmt"
16 "io"
17 "text/scanner"
18 )
19
20 type ebnfParser struct {
21 out io.Writer
22 src []byte
23 scanner scanner.Scanner
24 prev int
25 pos int
26 tok rune
27 lit string
28 }
29
30 func (p *ebnfParser) flush() {
31 p.out.Write(p.src[p.prev:p.pos])
32 p.prev = p.pos
33 }
34
35 func (p *ebnfParser) next() {
36 p.tok = p.scanner.Scan()
37 p.pos = p.scanner.Position.Offset
38 p.lit = p.scanner.TokenText()
39 }
40
41 func (p *ebnfParser) printf(format string, args ...interface{}) {
42 p.flush()
43 fmt.Fprintf(p.out, format, args...)
44 }
45
46 func (p *ebnfParser) errorExpected(msg string) {
47 p.printf(`<span class="highlight">error: expected %s, found %s</span>`, msg, scanner.TokenString(p.tok))
48 }
49
50 func (p *ebnfParser) expect(tok rune) {
51 if p.tok != tok {
52 p.errorExpected(scanner.TokenString(tok))
53 }
54 p.next()
55 }
56
57 func (p *ebnfParser) parseIdentifier(def bool) {
58 if p.tok == scanner.Ident {
59 name := p.lit
60 if def {
61 p.printf(`<a id="%s">%s</a>`, name, name)
62 } else {
63 p.printf(`<a href="#%s" class="noline">%s</a>`, name, name)
64 }
65 p.prev += len(name)
66 p.next()
67 } else {
68 p.expect(scanner.Ident)
69 }
70 }
71
72 func (p *ebnfParser) parseTerm() bool {
73 switch p.tok {
74 case scanner.Ident:
75 p.parseIdentifier(false)
76
77 case scanner.String, scanner.RawString:
78 p.next()
79 const ellipsis = '…'
80 if p.tok == ellipsis {
81 p.next()
82 p.expect(scanner.String)
83 }
84
85 case '(':
86 p.next()
87 p.parseExpression()
88 p.expect(')')
89
90 case '[':
91 p.next()
92 p.parseExpression()
93 p.expect(']')
94
95 case '{':
96 p.next()
97 p.parseExpression()
98 p.expect('}')
99
100 default:
101 return false
102 }
103
104 return true
105 }
106
107 func (p *ebnfParser) parseSequence() {
108 if !p.parseTerm() {
109 p.errorExpected("term")
110 }
111 for p.parseTerm() {
112 }
113 }
114
115 func (p *ebnfParser) parseExpression() {
116 for {
117 p.parseSequence()
118 if p.tok != '|' {
119 break
120 }
121 p.next()
122 }
123 }
124
125 func (p *ebnfParser) parseProduction() {
126 p.parseIdentifier(true)
127 p.expect('=')
128 if p.tok != '.' {
129 p.parseExpression()
130 }
131 p.expect('.')
132 }
133
134 func (p *ebnfParser) parse(out io.Writer, src []byte) {
135
136 p.out = out
137 p.src = src
138 p.scanner.Init(bytes.NewBuffer(src))
139 p.next()
140
141
142 for p.tok != scanner.EOF {
143 p.parseProduction()
144 }
145 p.flush()
146 }
147
148
149 var (
150 openTag = []byte(`<pre class="ebnf">`)
151 closeTag = []byte(`</pre>`)
152 )
153
154 func Linkify(out io.Writer, src []byte) {
155 for len(src) > 0 {
156
157 i := bytes.Index(src, openTag)
158 if i < 0 {
159 i = len(src) - len(openTag)
160 }
161 i += len(openTag)
162
163
164 j := bytes.Index(src[i:], closeTag)
165 if j < 0 {
166 j = len(src) - i
167 }
168 j += i
169
170
171 out.Write(src[0:i])
172
173 var p ebnfParser
174 p.parse(out, src[i:j])
175
176
177 src = src[j:]
178 }
179 }
180
View as plain text