GoPLS Viewer

Home|gopls/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
5package 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
13import (
14    "bytes"
15    "fmt"
16    "io"
17    "text/scanner"
18)
19
20type 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
30func (p *ebnfParserflush() {
31    p.out.Write(p.src[p.prev:p.pos])
32    p.prev = p.pos
33}
34
35func (p *ebnfParsernext() {
36    p.tok = p.scanner.Scan()
37    p.pos = p.scanner.Position.Offset
38    p.lit = p.scanner.TokenText()
39}
40
41func (p *ebnfParserprintf(format stringargs ...interface{}) {
42    p.flush()
43    fmt.Fprintf(p.outformatargs...)
44}
45
46func (p *ebnfParsererrorExpected(msg string) {
47    p.printf(`<span class="highlight">error: expected %s, found %s</span>`msgscanner.TokenString(p.tok))
48}
49
50func (p *ebnfParserexpect(tok rune) {
51    if p.tok != tok {
52        p.errorExpected(scanner.TokenString(tok))
53    }
54    p.next() // make progress in any case
55}
56
57func (p *ebnfParserparseIdentifier(def bool) {
58    if p.tok == scanner.Ident {
59        name := p.lit
60        if def {
61            p.printf(`<a id="%s">%s</a>`namename)
62        } else {
63            p.printf(`<a href="#%s" class="noline">%s</a>`namename)
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
72func (p *ebnfParserparseTerm() bool {
73    switch p.tok {
74    case scanner.Ident:
75        p.parseIdentifier(false)
76
77    case scanner.Stringscanner.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
107func (p *ebnfParserparseSequence() {
108    if !p.parseTerm() {
109        p.errorExpected("term")
110    }
111    for p.parseTerm() {
112    }
113}
114
115func (p *ebnfParserparseExpression() {
116    for {
117        p.parseSequence()
118        if p.tok != '|' {
119            break
120        }
121        p.next()
122    }
123}
124
125func (p *ebnfParserparseProduction() {
126    p.parseIdentifier(true)
127    p.expect('=')
128    if p.tok != '.' {
129        p.parseExpression()
130    }
131    p.expect('.')
132}
133
134func (p *ebnfParserparse(out io.Writersrc []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
149var (
150    openTag  = []byte(`<pre class="ebnf">`)
151    closeTag = []byte(`</pre>`)
152)
153
154func Linkify(out io.Writersrc []byte) {
155    for len(src) > 0 {
156        // i: beginning of EBNF text (or end of source)
157        i := bytes.Index(srcopenTag)
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(outsrc[i:j])
175
176        // advance
177        src = src[j:]
178    }
179}
180
MembersX
Linkify.src
ebnfParser.tok
ebnfParser.next.p
ebnfParser.parseIdentifier
ebnfParser.parseTerm.BlockStmt.ellipsis
ebnfParser.parseExpression
ebnfParser
ebnfParser.scanner
ebnfParser.parseIdentifier.p
ebnfParser.parseExpression.p
ebnfParser.parseSequence.p
ebnfParser.parse
ebnfParser.pos
ebnfParser.printf.format
ebnfParser.expect.p
ebnfParser.parseIdentifier.def
ebnfParser.parseProduction
ebnfParser.src
ebnfParser.printf.args
ebnfParser.errorExpected
ebnfParser.expect.tok
ebnfParser.printf.p
ebnfParser.errorExpected.p
ebnfParser.expect
ebnfParser.parseIdentifier.BlockStmt.name
ebnfParser.parseTerm.p
ebnfParser.parseSequence
ebnfParser.parseProduction.p
ebnfParser.parse.out
ebnfParser.lit
ebnfParser.flush.p
ebnfParser.next
ebnfParser.printf
Linkify
Linkify.out
Linkify.BlockStmt.j
Linkify.BlockStmt.p
ebnfParser.parseTerm
ebnfParser.parse.p
ebnfParser.parse.src
Linkify.BlockStmt.i
ebnfParser.out
ebnfParser.prev
ebnfParser.flush
ebnfParser.errorExpected.msg
Members
X