blob: 9b6aa1862f76462e30eb28f623cdd988700ea492 [file] [log] [blame]
Colin Cross8e0c5112015-01-23 14:15:10 -08001// Copyright 2014 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Jamie Gennis1bc967e2014-05-27 16:34:41 -070015package parser
16
17import (
18 "errors"
19 "fmt"
20 "io"
Colin Crossc0dbc552015-01-02 15:19:28 -080021 "sort"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070022 "strconv"
23 "strings"
24 "text/scanner"
25)
26
27var errTooManyErrors = errors.New("too many errors")
28
29const maxErrors = 1
30
31type ParseError struct {
32 Err error
33 Pos scanner.Position
34}
35
36func (e *ParseError) Error() string {
37 return fmt.Sprintf("%s: %s", e.Pos, e.Err)
38}
39
Colin Crossd1facc12015-01-08 14:56:03 -080040type File struct {
Colin Cross23d7aa12015-06-30 16:05:22 -070041 Name string
Colin Crossd1facc12015-01-08 14:56:03 -080042 Defs []Definition
Colin Cross1e737942016-06-10 17:27:12 -070043 Comments []*CommentGroup
Colin Cross1ead6452016-06-09 17:40:13 -070044}
45
46func (f *File) Pos() scanner.Position {
47 return scanner.Position{
48 Filename: f.Name,
49 Line: 1,
50 Column: 1,
51 Offset: 0,
52 }
53}
54
55func (f *File) End() scanner.Position {
56 if len(f.Defs) > 0 {
57 return f.Defs[len(f.Defs)-1].End()
58 }
59 return noPos
Colin Crossd1facc12015-01-08 14:56:03 -080060}
61
Colin Cross96e56702015-03-19 17:28:06 -070062func parse(p *parser) (file *File, errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -070063 defer func() {
64 if r := recover(); r != nil {
65 if r == errTooManyErrors {
Jamie Gennis1bc967e2014-05-27 16:34:41 -070066 errs = p.errors
67 return
68 }
69 panic(r)
70 }
71 }()
72
Colin Crossd1facc12015-01-08 14:56:03 -080073 defs := p.parseDefinitions()
Jamie Gennis1bc967e2014-05-27 16:34:41 -070074 p.accept(scanner.EOF)
75 errs = p.errors
Colin Crossd1facc12015-01-08 14:56:03 -080076 comments := p.comments
Jamie Gennis1bc967e2014-05-27 16:34:41 -070077
Colin Crossd1facc12015-01-08 14:56:03 -080078 return &File{
Colin Cross23d7aa12015-06-30 16:05:22 -070079 Name: p.scanner.Filename,
Colin Crossd1facc12015-01-08 14:56:03 -080080 Defs: defs,
81 Comments: comments,
82 }, errs
Colin Cross96e56702015-03-19 17:28:06 -070083
84}
85
86func ParseAndEval(filename string, r io.Reader, scope *Scope) (file *File, errs []error) {
87 p := newParser(r, scope)
88 p.eval = true
89 p.scanner.Filename = filename
90
91 return parse(p)
92}
93
94func Parse(filename string, r io.Reader, scope *Scope) (file *File, errs []error) {
95 p := newParser(r, scope)
96 p.scanner.Filename = filename
97
98 return parse(p)
Jamie Gennis1bc967e2014-05-27 16:34:41 -070099}
100
101type parser struct {
Colin Cross96e56702015-03-19 17:28:06 -0700102 scanner scanner.Scanner
103 tok rune
104 errors []error
105 scope *Scope
Colin Cross1e737942016-06-10 17:27:12 -0700106 comments []*CommentGroup
Colin Cross96e56702015-03-19 17:28:06 -0700107 eval bool
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700108}
109
Colin Crossc0dbc552015-01-02 15:19:28 -0800110func newParser(r io.Reader, scope *Scope) *parser {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700111 p := &parser{}
Colin Crossc0dbc552015-01-02 15:19:28 -0800112 p.scope = scope
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700113 p.scanner.Init(r)
114 p.scanner.Error = func(sc *scanner.Scanner, msg string) {
115 p.errorf(msg)
116 }
Nan Zhangf5865442017-11-01 14:03:28 -0700117 p.scanner.Mode = scanner.ScanIdents | scanner.ScanInts | scanner.ScanStrings |
Colin Crossd1facc12015-01-08 14:56:03 -0800118 scanner.ScanRawStrings | scanner.ScanComments
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700119 p.next()
120 return p
121}
122
Colin Cross6d8780f2015-07-10 17:51:55 -0700123func (p *parser) error(err error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700124 pos := p.scanner.Position
125 if !pos.IsValid() {
126 pos = p.scanner.Pos()
127 }
Colin Cross6d8780f2015-07-10 17:51:55 -0700128 err = &ParseError{
129 Err: err,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700130 Pos: pos,
131 }
132 p.errors = append(p.errors, err)
133 if len(p.errors) >= maxErrors {
134 panic(errTooManyErrors)
135 }
136}
137
Colin Cross6d8780f2015-07-10 17:51:55 -0700138func (p *parser) errorf(format string, args ...interface{}) {
139 p.error(fmt.Errorf(format, args...))
140}
141
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700142func (p *parser) accept(toks ...rune) bool {
143 for _, tok := range toks {
144 if p.tok != tok {
145 p.errorf("expected %s, found %s", scanner.TokenString(tok),
146 scanner.TokenString(p.tok))
147 return false
148 }
Colin Crossd1facc12015-01-08 14:56:03 -0800149 p.next()
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700150 }
151 return true
152}
153
154func (p *parser) next() {
155 if p.tok != scanner.EOF {
156 p.tok = p.scanner.Scan()
Colin Cross1e737942016-06-10 17:27:12 -0700157 if p.tok == scanner.Comment {
158 var comments []*Comment
159 for p.tok == scanner.Comment {
160 lines := strings.Split(p.scanner.TokenText(), "\n")
161 if len(comments) > 0 && p.scanner.Position.Line > comments[len(comments)-1].End().Line+1 {
162 p.comments = append(p.comments, &CommentGroup{Comments: comments})
163 comments = nil
164 }
165 comments = append(comments, &Comment{lines, p.scanner.Position})
166 p.tok = p.scanner.Scan()
167 }
168 p.comments = append(p.comments, &CommentGroup{Comments: comments})
Colin Crossd1facc12015-01-08 14:56:03 -0800169 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700170 }
171 return
172}
173
174func (p *parser) parseDefinitions() (defs []Definition) {
175 for {
176 switch p.tok {
177 case scanner.Ident:
178 ident := p.scanner.TokenText()
179 pos := p.scanner.Position
180
181 p.accept(scanner.Ident)
182
183 switch p.tok {
Colin Crossb274e6c2015-02-04 10:50:22 -0800184 case '+':
185 p.accept('+')
186 defs = append(defs, p.parseAssignment(ident, pos, "+="))
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700187 case '=':
Colin Crossb274e6c2015-02-04 10:50:22 -0800188 defs = append(defs, p.parseAssignment(ident, pos, "="))
Colin Cross6bb4af92015-01-14 17:04:13 -0800189 case '{', '(':
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700190 defs = append(defs, p.parseModule(ident, pos))
191 default:
Colin Crossb274e6c2015-02-04 10:50:22 -0800192 p.errorf("expected \"=\" or \"+=\" or \"{\" or \"(\", found %s",
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700193 scanner.TokenString(p.tok))
194 }
195 case scanner.EOF:
196 return
197 default:
198 p.errorf("expected assignment or module definition, found %s",
199 scanner.TokenString(p.tok))
200 return
201 }
202 }
203}
204
Colin Crosse32cc802016-06-07 12:28:16 -0700205func (p *parser) parseAssignment(name string, namePos scanner.Position,
206 assigner string) (assignment *Assignment) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700207
208 assignment = new(Assignment)
209
Colin Crossd1facc12015-01-08 14:56:03 -0800210 pos := p.scanner.Position
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700211 if !p.accept('=') {
212 return
213 }
Colin Cross82b7d512015-01-02 15:47:54 -0800214 value := p.parseExpression()
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700215
Colin Crossc32c4792016-06-09 15:52:30 -0700216 assignment.Name = name
217 assignment.NamePos = namePos
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700218 assignment.Value = value
Colin Crossb274e6c2015-02-04 10:50:22 -0800219 assignment.OrigValue = value
Colin Crossb3d0b8d2016-06-09 17:03:57 -0700220 assignment.EqualsPos = pos
Colin Crossb274e6c2015-02-04 10:50:22 -0800221 assignment.Assigner = assigner
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700222
Colin Crossc0dbc552015-01-02 15:19:28 -0800223 if p.scope != nil {
Colin Crossb274e6c2015-02-04 10:50:22 -0800224 if assigner == "+=" {
Colin Crossc32c4792016-06-09 15:52:30 -0700225 if old, local := p.scope.Get(assignment.Name); old == nil {
226 p.errorf("modified non-existent variable %q with +=", assignment.Name)
Colin Cross6d8780f2015-07-10 17:51:55 -0700227 } else if !local {
Colin Crossc32c4792016-06-09 15:52:30 -0700228 p.errorf("modified non-local variable %q with +=", assignment.Name)
Colin Cross6d8780f2015-07-10 17:51:55 -0700229 } else if old.Referenced {
Colin Crossc32c4792016-06-09 15:52:30 -0700230 p.errorf("modified variable %q with += after referencing", assignment.Name)
Colin Cross6d8780f2015-07-10 17:51:55 -0700231 } else {
Colin Crossb3d0b8d2016-06-09 17:03:57 -0700232 val, err := p.evaluateOperator(old.Value, assignment.Value, '+', assignment.EqualsPos)
Colin Cross6d8780f2015-07-10 17:51:55 -0700233 if err != nil {
234 p.error(err)
235 } else {
236 old.Value = val
Colin Cross96e56702015-03-19 17:28:06 -0700237 }
Colin Crossb274e6c2015-02-04 10:50:22 -0800238 }
Colin Cross6d8780f2015-07-10 17:51:55 -0700239 } else {
240 err := p.scope.Add(assignment)
241 if err != nil {
242 p.error(err)
243 }
Colin Cross96e56702015-03-19 17:28:06 -0700244 }
Colin Crossc0dbc552015-01-02 15:19:28 -0800245 }
246
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700247 return
248}
249
Colin Crosse32cc802016-06-07 12:28:16 -0700250func (p *parser) parseModule(typ string, typPos scanner.Position) *Module {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700251
Colin Cross6bb4af92015-01-14 17:04:13 -0800252 compat := false
Colin Crossd1facc12015-01-08 14:56:03 -0800253 lbracePos := p.scanner.Position
Colin Cross6bb4af92015-01-14 17:04:13 -0800254 if p.tok == '{' {
255 compat = true
256 }
257
258 if !p.accept(p.tok) {
Colin Crosse32cc802016-06-07 12:28:16 -0700259 return nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700260 }
Colin Cross6bb4af92015-01-14 17:04:13 -0800261 properties := p.parsePropertyList(true, compat)
Colin Crossd1facc12015-01-08 14:56:03 -0800262 rbracePos := p.scanner.Position
Colin Cross6bb4af92015-01-14 17:04:13 -0800263 if !compat {
264 p.accept(')')
265 } else {
266 p.accept('}')
267 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700268
Colin Crosse32cc802016-06-07 12:28:16 -0700269 return &Module{
Colin Crossc32c4792016-06-09 15:52:30 -0700270 Type: typ,
271 TypePos: typPos,
Colin Crosse32cc802016-06-07 12:28:16 -0700272 Map: Map{
273 Properties: properties,
274 LBracePos: lbracePos,
275 RBracePos: rbracePos,
276 },
277 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700278}
279
Colin Cross6bb4af92015-01-14 17:04:13 -0800280func (p *parser) parsePropertyList(isModule, compat bool) (properties []*Property) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700281 for p.tok == scanner.Ident {
Colin Cross6bb4af92015-01-14 17:04:13 -0800282 property := p.parseProperty(isModule, compat)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700283 properties = append(properties, property)
284
285 if p.tok != ',' {
286 // There was no comma, so the list is done.
287 break
288 }
289
290 p.accept(',')
291 }
292
293 return
294}
295
Colin Cross6bb4af92015-01-14 17:04:13 -0800296func (p *parser) parseProperty(isModule, compat bool) (property *Property) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700297 property = new(Property)
298
299 name := p.scanner.TokenText()
Colin Crossd1facc12015-01-08 14:56:03 -0800300 namePos := p.scanner.Position
301 p.accept(scanner.Ident)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700302 pos := p.scanner.Position
Colin Cross6bb4af92015-01-14 17:04:13 -0800303
304 if isModule {
Logan Chien3deba3d2018-06-25 11:52:48 +0800305 if compat {
306 if !p.accept(':') {
307 return
308 }
Colin Cross6bb4af92015-01-14 17:04:13 -0800309 } else {
310 if !p.accept('=') {
311 return
312 }
313 }
314 } else {
315 if !p.accept(':') {
316 return
317 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700318 }
Colin Crossd1facc12015-01-08 14:56:03 -0800319
Colin Cross82b7d512015-01-02 15:47:54 -0800320 value := p.parseExpression()
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700321
Colin Crossc32c4792016-06-09 15:52:30 -0700322 property.Name = name
323 property.NamePos = namePos
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700324 property.Value = value
Colin Crossb3d0b8d2016-06-09 17:03:57 -0700325 property.ColonPos = pos
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700326
327 return
328}
329
Colin Crosse32cc802016-06-07 12:28:16 -0700330func (p *parser) parseExpression() (value Expression) {
Colin Cross82b7d512015-01-02 15:47:54 -0800331 value = p.parseValue()
332 switch p.tok {
333 case '+':
334 return p.parseOperator(value)
Nan Zhangf5865442017-11-01 14:03:28 -0700335 case '-':
336 p.errorf("subtraction not supported: %s", p.scanner.String())
337 return value
Colin Cross82b7d512015-01-02 15:47:54 -0800338 default:
339 return value
340 }
341}
342
Colin Crosse32cc802016-06-07 12:28:16 -0700343func (p *parser) evaluateOperator(value1, value2 Expression, operator rune,
344 pos scanner.Position) (*Operator, error) {
Colin Cross82b7d512015-01-02 15:47:54 -0800345
Colin Crosse32cc802016-06-07 12:28:16 -0700346 value := value1
Colin Crossd1facc12015-01-08 14:56:03 -0800347
Colin Cross96e56702015-03-19 17:28:06 -0700348 if p.eval {
Colin Crosse32cc802016-06-07 12:28:16 -0700349 e1 := value1.Eval()
350 e2 := value2.Eval()
351 if e1.Type() != e2.Type() {
352 return nil, fmt.Errorf("mismatched type in operator %c: %s != %s", operator,
353 e1.Type(), e2.Type())
Colin Cross96e56702015-03-19 17:28:06 -0700354 }
355
Colin Crosse32cc802016-06-07 12:28:16 -0700356 value = e1.Copy()
Colin Cross96e56702015-03-19 17:28:06 -0700357
358 switch operator {
359 case '+':
Colin Crosse32cc802016-06-07 12:28:16 -0700360 switch v := value.(type) {
361 case *String:
362 v.Value += e2.(*String).Value
Nan Zhangf5865442017-11-01 14:03:28 -0700363 case *Int64:
364 v.Value += e2.(*Int64).Value
Colin Crossfdeaf882018-03-21 17:00:39 -0700365 v.Token = ""
Colin Crosse32cc802016-06-07 12:28:16 -0700366 case *List:
367 v.Values = append(v.Values, e2.(*List).Values...)
368 case *Map:
Colin Cross96e56702015-03-19 17:28:06 -0700369 var err error
Colin Crosse32cc802016-06-07 12:28:16 -0700370 v.Properties, err = p.addMaps(v.Properties, e2.(*Map).Properties, pos)
Colin Cross96e56702015-03-19 17:28:06 -0700371 if err != nil {
Colin Crosse32cc802016-06-07 12:28:16 -0700372 return nil, err
Colin Cross96e56702015-03-19 17:28:06 -0700373 }
374 default:
Colin Crosse32cc802016-06-07 12:28:16 -0700375 return nil, fmt.Errorf("operator %c not supported on type %s", operator, v.Type())
Colin Cross542fd552015-02-12 10:12:10 -0800376 }
Colin Cross82b7d512015-01-02 15:47:54 -0800377 default:
Colin Cross96e56702015-03-19 17:28:06 -0700378 panic("unknown operator " + string(operator))
Colin Cross82b7d512015-01-02 15:47:54 -0800379 }
Colin Cross82b7d512015-01-02 15:47:54 -0800380 }
381
Colin Crosse32cc802016-06-07 12:28:16 -0700382 return &Operator{
383 Args: [2]Expression{value1, value2},
384 Operator: operator,
385 OperatorPos: pos,
386 Value: value,
387 }, nil
Colin Crossb274e6c2015-02-04 10:50:22 -0800388}
389
Colin Cross96e56702015-03-19 17:28:06 -0700390func (p *parser) addMaps(map1, map2 []*Property, pos scanner.Position) ([]*Property, error) {
Colin Cross542fd552015-02-12 10:12:10 -0800391 ret := make([]*Property, 0, len(map1))
Colin Cross969c7032015-03-10 14:37:27 -0700392
Colin Cross542fd552015-02-12 10:12:10 -0800393 inMap1 := make(map[string]*Property)
394 inMap2 := make(map[string]*Property)
395 inBoth := make(map[string]*Property)
Colin Cross969c7032015-03-10 14:37:27 -0700396
Colin Cross542fd552015-02-12 10:12:10 -0800397 for _, prop1 := range map1 {
Colin Crossc32c4792016-06-09 15:52:30 -0700398 inMap1[prop1.Name] = prop1
Colin Cross542fd552015-02-12 10:12:10 -0800399 }
400
401 for _, prop2 := range map2 {
Colin Crossc32c4792016-06-09 15:52:30 -0700402 inMap2[prop2.Name] = prop2
403 if _, ok := inMap1[prop2.Name]; ok {
404 inBoth[prop2.Name] = prop2
Colin Cross542fd552015-02-12 10:12:10 -0800405 }
406 }
Colin Cross969c7032015-03-10 14:37:27 -0700407
Colin Cross542fd552015-02-12 10:12:10 -0800408 for _, prop1 := range map1 {
Colin Crossc32c4792016-06-09 15:52:30 -0700409 if prop2, ok := inBoth[prop1.Name]; ok {
Colin Cross542fd552015-02-12 10:12:10 -0800410 var err error
411 newProp := *prop1
Colin Cross96e56702015-03-19 17:28:06 -0700412 newProp.Value, err = p.evaluateOperator(prop1.Value, prop2.Value, '+', pos)
Colin Cross542fd552015-02-12 10:12:10 -0800413 if err != nil {
414 return nil, err
415 }
416 ret = append(ret, &newProp)
417 } else {
418 ret = append(ret, prop1)
419 }
420 }
421
422 for _, prop2 := range map2 {
Colin Crossc32c4792016-06-09 15:52:30 -0700423 if _, ok := inBoth[prop2.Name]; !ok {
Colin Cross542fd552015-02-12 10:12:10 -0800424 ret = append(ret, prop2)
425 }
426 }
Colin Cross969c7032015-03-10 14:37:27 -0700427
Colin Cross542fd552015-02-12 10:12:10 -0800428 return ret, nil
429}
430
Colin Crosse32cc802016-06-07 12:28:16 -0700431func (p *parser) parseOperator(value1 Expression) *Operator {
Colin Crossb274e6c2015-02-04 10:50:22 -0800432 operator := p.tok
433 pos := p.scanner.Position
434 p.accept(operator)
435
436 value2 := p.parseExpression()
437
Colin Cross96e56702015-03-19 17:28:06 -0700438 value, err := p.evaluateOperator(value1, value2, operator, pos)
Colin Crossb274e6c2015-02-04 10:50:22 -0800439 if err != nil {
Colin Cross6d8780f2015-07-10 17:51:55 -0700440 p.error(err)
Colin Crosse32cc802016-06-07 12:28:16 -0700441 return nil
Colin Crossb274e6c2015-02-04 10:50:22 -0800442 }
443
Colin Crossd1facc12015-01-08 14:56:03 -0800444 return value
Colin Crosse32cc802016-06-07 12:28:16 -0700445
Colin Cross82b7d512015-01-02 15:47:54 -0800446}
447
Colin Crosse32cc802016-06-07 12:28:16 -0700448func (p *parser) parseValue() (value Expression) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700449 switch p.tok {
450 case scanner.Ident:
Colin Crossc0dbc552015-01-02 15:19:28 -0800451 return p.parseVariable()
Nan Zhangf5865442017-11-01 14:03:28 -0700452 case '-', scanner.Int: // Integer might have '-' sign ahead ('+' is only treated as operator now)
453 return p.parseIntValue()
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700454 case scanner.String:
455 return p.parseStringValue()
456 case '[':
457 return p.parseListValue()
Romain Guy2476f812014-07-25 17:01:20 -0700458 case '{':
459 return p.parseMapValue()
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700460 default:
461 p.errorf("expected bool, list, or string value; found %s",
462 scanner.TokenString(p.tok))
463 return
464 }
465}
466
Colin Crosse32cc802016-06-07 12:28:16 -0700467func (p *parser) parseVariable() Expression {
468 var value Expression
469
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700470 switch text := p.scanner.TokenText(); text {
Colin Crosse32cc802016-06-07 12:28:16 -0700471 case "true", "false":
472 value = &Bool{
473 LiteralPos: p.scanner.Position,
474 Value: text == "true",
Colin Crossfdeaf882018-03-21 17:00:39 -0700475 Token: text,
Colin Crosse32cc802016-06-07 12:28:16 -0700476 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700477 default:
Colin Cross96e56702015-03-19 17:28:06 -0700478 if p.eval {
Colin Crosse32cc802016-06-07 12:28:16 -0700479 if assignment, local := p.scope.Get(text); assignment == nil {
480 p.errorf("variable %q is not set", text)
Colin Cross6d8780f2015-07-10 17:51:55 -0700481 } else {
482 if local {
483 assignment.Referenced = true
484 }
485 value = assignment.Value
Colin Cross96e56702015-03-19 17:28:06 -0700486 }
Sasha Smundak77418b72020-01-21 13:31:06 -0800487 } else {
488 value = &NotEvaluated{}
Colin Crossc0dbc552015-01-02 15:19:28 -0800489 }
Colin Crosse32cc802016-06-07 12:28:16 -0700490 value = &Variable{
491 Name: text,
492 NamePos: p.scanner.Position,
493 Value: value,
494 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700495 }
Colin Crossc0dbc552015-01-02 15:19:28 -0800496
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700497 p.accept(scanner.Ident)
Colin Crosse32cc802016-06-07 12:28:16 -0700498 return value
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700499}
500
Colin Crosse32cc802016-06-07 12:28:16 -0700501func (p *parser) parseStringValue() *String {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700502 str, err := strconv.Unquote(p.scanner.TokenText())
503 if err != nil {
504 p.errorf("couldn't parse string: %s", err)
Colin Crosse32cc802016-06-07 12:28:16 -0700505 return nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700506 }
Colin Crosse32cc802016-06-07 12:28:16 -0700507
508 value := &String{
509 LiteralPos: p.scanner.Position,
510 Value: str,
511 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700512 p.accept(scanner.String)
Colin Crosse32cc802016-06-07 12:28:16 -0700513 return value
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700514}
515
Nan Zhangf5865442017-11-01 14:03:28 -0700516func (p *parser) parseIntValue() *Int64 {
517 var str string
518 literalPos := p.scanner.Position
519 if p.tok == '-' {
520 str += string(p.tok)
521 p.accept(p.tok)
522 if p.tok != scanner.Int {
523 p.errorf("expected int; found %s", scanner.TokenString(p.tok))
524 return nil
525 }
526 }
527 str += p.scanner.TokenText()
528 i, err := strconv.ParseInt(str, 10, 64)
529 if err != nil {
530 p.errorf("couldn't parse int: %s", err)
531 return nil
532 }
533
534 value := &Int64{
535 LiteralPos: literalPos,
536 Value: i,
Colin Crossfdeaf882018-03-21 17:00:39 -0700537 Token: str,
Nan Zhangf5865442017-11-01 14:03:28 -0700538 }
539 p.accept(scanner.Int)
540 return value
541}
542
Colin Crosse32cc802016-06-07 12:28:16 -0700543func (p *parser) parseListValue() *List {
544 lBracePos := p.scanner.Position
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700545 if !p.accept('[') {
Colin Crosse32cc802016-06-07 12:28:16 -0700546 return nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700547 }
548
Colin Crosse32cc802016-06-07 12:28:16 -0700549 var elements []Expression
Colin Crossc0dbc552015-01-02 15:19:28 -0800550 for p.tok != ']' {
Colin Cross82b7d512015-01-02 15:47:54 -0800551 element := p.parseExpression()
Colin Crossc0dbc552015-01-02 15:19:28 -0800552 elements = append(elements, element)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700553
554 if p.tok != ',' {
555 // There was no comma, so the list is done.
556 break
557 }
558
559 p.accept(',')
560 }
561
Colin Crosse32cc802016-06-07 12:28:16 -0700562 rBracePos := p.scanner.Position
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700563 p.accept(']')
Colin Crosse32cc802016-06-07 12:28:16 -0700564
565 return &List{
566 LBracePos: lBracePos,
567 RBracePos: rBracePos,
568 Values: elements,
569 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700570}
571
Colin Crosse32cc802016-06-07 12:28:16 -0700572func (p *parser) parseMapValue() *Map {
573 lBracePos := p.scanner.Position
Romain Guy2476f812014-07-25 17:01:20 -0700574 if !p.accept('{') {
Colin Crosse32cc802016-06-07 12:28:16 -0700575 return nil
Romain Guy2476f812014-07-25 17:01:20 -0700576 }
577
Colin Cross6bb4af92015-01-14 17:04:13 -0800578 properties := p.parsePropertyList(false, false)
Romain Guy2476f812014-07-25 17:01:20 -0700579
Colin Crosse32cc802016-06-07 12:28:16 -0700580 rBracePos := p.scanner.Position
Romain Guy2476f812014-07-25 17:01:20 -0700581 p.accept('}')
Romain Guy2476f812014-07-25 17:01:20 -0700582
Colin Crosse32cc802016-06-07 12:28:16 -0700583 return &Map{
584 LBracePos: lBracePos,
585 RBracePos: rBracePos,
586 Properties: properties,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700587 }
588}
589
Colin Crossc0dbc552015-01-02 15:19:28 -0800590type Scope struct {
Colin Cross6d8780f2015-07-10 17:51:55 -0700591 vars map[string]*Assignment
592 inheritedVars map[string]*Assignment
Colin Crossc0dbc552015-01-02 15:19:28 -0800593}
594
595func NewScope(s *Scope) *Scope {
596 newScope := &Scope{
Colin Cross6d8780f2015-07-10 17:51:55 -0700597 vars: make(map[string]*Assignment),
598 inheritedVars: make(map[string]*Assignment),
Colin Crossc0dbc552015-01-02 15:19:28 -0800599 }
600
601 if s != nil {
602 for k, v := range s.vars {
Colin Cross6d8780f2015-07-10 17:51:55 -0700603 newScope.inheritedVars[k] = v
604 }
605 for k, v := range s.inheritedVars {
606 newScope.inheritedVars[k] = v
Colin Crossc0dbc552015-01-02 15:19:28 -0800607 }
608 }
609
610 return newScope
611}
612
613func (s *Scope) Add(assignment *Assignment) error {
Colin Crossc32c4792016-06-09 15:52:30 -0700614 if old, ok := s.vars[assignment.Name]; ok {
Colin Crossc0dbc552015-01-02 15:19:28 -0800615 return fmt.Errorf("variable already set, previous assignment: %s", old)
616 }
617
Colin Crossc32c4792016-06-09 15:52:30 -0700618 if old, ok := s.inheritedVars[assignment.Name]; ok {
Colin Cross6d8780f2015-07-10 17:51:55 -0700619 return fmt.Errorf("variable already set in inherited scope, previous assignment: %s", old)
620 }
621
Colin Crossc32c4792016-06-09 15:52:30 -0700622 s.vars[assignment.Name] = assignment
Colin Crossc0dbc552015-01-02 15:19:28 -0800623
624 return nil
625}
626
627func (s *Scope) Remove(name string) {
628 delete(s.vars, name)
Colin Cross6d8780f2015-07-10 17:51:55 -0700629 delete(s.inheritedVars, name)
Colin Crossc0dbc552015-01-02 15:19:28 -0800630}
631
Colin Cross6d8780f2015-07-10 17:51:55 -0700632func (s *Scope) Get(name string) (*Assignment, bool) {
Colin Crossc0dbc552015-01-02 15:19:28 -0800633 if a, ok := s.vars[name]; ok {
Colin Cross6d8780f2015-07-10 17:51:55 -0700634 return a, true
Colin Crossc0dbc552015-01-02 15:19:28 -0800635 }
636
Colin Cross6d8780f2015-07-10 17:51:55 -0700637 if a, ok := s.inheritedVars[name]; ok {
638 return a, false
639 }
640
641 return nil, false
Colin Crossc0dbc552015-01-02 15:19:28 -0800642}
643
644func (s *Scope) String() string {
645 vars := []string{}
646
647 for k := range s.vars {
648 vars = append(vars, k)
649 }
Colin Cross6d8780f2015-07-10 17:51:55 -0700650 for k := range s.inheritedVars {
651 vars = append(vars, k)
652 }
Colin Crossc0dbc552015-01-02 15:19:28 -0800653
654 sort.Strings(vars)
655
656 ret := []string{}
657 for _, v := range vars {
Colin Cross6d8780f2015-07-10 17:51:55 -0700658 if assignment, ok := s.vars[v]; ok {
659 ret = append(ret, assignment.String())
660 } else {
661 ret = append(ret, s.inheritedVars[v].String())
662 }
Colin Crossc0dbc552015-01-02 15:19:28 -0800663 }
664
665 return strings.Join(ret, "\n")
666}