Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201028153306-37f0764111ff / godoc / spec.go
1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package godoc
6
7 // This file contains the mechanism to "linkify" html source
8 // text containing EBNF sections (as found in go_spec.html).
9 // The result is the input source text with the EBNF sections
10 // modified such that identifiers are linked to the respective
11 // definitions.
12
13 import (
14         "bytes"
15         "fmt"
16         "io"
17         "text/scanner"
18 )
19
20 type ebnfParser struct {
21         out     io.Writer // parser output
22         src     []byte    // parser input
23         scanner scanner.Scanner
24         prev    int    // offset of previous token
25         pos     int    // offset of current token
26         tok     rune   // one token look-ahead
27         lit     string // token literal
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() // make progress in any case
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) // skip identifier when printing next time
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 = '…' // U+2026, the horizontal ellipsis character
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 // no term found
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         // initialize ebnfParser
136         p.out = out
137         p.src = src
138         p.scanner.Init(bytes.NewBuffer(src))
139         p.next() // initializes pos, tok, lit
140
141         // process source
142         for p.tok != scanner.EOF {
143                 p.parseProduction()
144         }
145         p.flush()
146 }
147
148 // Markers around EBNF sections
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                 // i: beginning of EBNF text (or end of source)
157                 i := bytes.Index(src, openTag)
158                 if i < 0 {
159                         i = len(src) - len(openTag)
160                 }
161                 i += len(openTag)
162
163                 // j: end of EBNF text (or end of source)
164                 j := bytes.Index(src[i:], closeTag) // close marker
165                 if j < 0 {
166                         j = len(src) - i
167                 }
168                 j += i
169
170                 // write text before EBNF
171                 out.Write(src[0:i])
172                 // process EBNF
173                 var p ebnfParser
174                 p.parse(out, src[i:j])
175
176                 // advance
177                 src = src[j:]
178         }
179 }