Source file
src/cmd/dist/buildtag.go
1
2
3
4
5 package main
6
7 import (
8 "fmt"
9 "strings"
10 )
11
12
13
14
15 type exprParser struct {
16 x string
17 t exprToken
18 }
19
20
21
22 type val bool
23
24
25
26
27
28
29 type exprToken struct {
30 tok string
31 prec int
32 prefix func(*exprParser) val
33 infix func(val, val) val
34 }
35
36 var exprTokens []exprToken
37
38 func init() {
39 exprTokens = []exprToken{
40 {tok: "&&", prec: 1, infix: func(x, y val) val { return x && y }},
41 {tok: "||", prec: 2, infix: func(x, y val) val { return x || y }},
42 {tok: "!", prec: 3, prefix: (*exprParser).not},
43 {tok: "(", prec: 3, prefix: (*exprParser).paren},
44 {tok: ")"},
45 }
46 }
47
48
49 func matchexpr(x string) (matched bool, err error) {
50 defer func() {
51 if e := recover(); e != nil {
52 matched = false
53 err = fmt.Errorf("parsing //go:build line: %v", e)
54 }
55 }()
56
57 p := &exprParser{x: x}
58 p.next()
59 v := p.parse(0)
60 if p.t.tok != "end of expression" {
61 panic("unexpected " + p.t.tok)
62 }
63 return bool(v), nil
64 }
65
66
67 func (p *exprParser) parse(prec int) val {
68 if p.t.prefix == nil {
69 panic("unexpected " + p.t.tok)
70 }
71 v := p.t.prefix(p)
72 for p.t.prec >= prec && p.t.infix != nil {
73 t := p.t
74 p.next()
75 v = t.infix(v, p.parse(t.prec+1))
76 }
77 return v
78 }
79
80
81 func (p *exprParser) not() val {
82 p.next()
83 return !p.parse(100)
84 }
85
86
87 func (p *exprParser) paren() val {
88 p.next()
89 v := p.parse(0)
90 if p.t.tok != ")" {
91 panic("missing )")
92 }
93 p.next()
94 return v
95 }
96
97
98
99 func (p *exprParser) next() {
100 p.x = strings.TrimSpace(p.x)
101 if p.x == "" {
102 p.t = exprToken{tok: "end of expression"}
103 return
104 }
105 for _, t := range exprTokens {
106 if strings.HasPrefix(p.x, t.tok) {
107 p.x = p.x[len(t.tok):]
108 p.t = t
109 return
110 }
111 }
112
113 i := 0
114 for i < len(p.x) && validtag(p.x[i]) {
115 i++
116 }
117 if i == 0 {
118 panic(fmt.Sprintf("syntax error near %#q", rune(p.x[i])))
119 }
120 tag := p.x[:i]
121 p.x = p.x[i:]
122 p.t = exprToken{
123 tok: "tag",
124 prefix: func(p *exprParser) val {
125 p.next()
126 return val(matchtag(tag))
127 },
128 }
129 }
130
131 func validtag(c byte) bool {
132 return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '.' || c == '_'
133 }
134
View as plain text