• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2016 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
15package parser
16
17import (
18	"fmt"
19	"strings"
20	"text/scanner"
21)
22
23type Node interface {
24	// Pos returns the position of the first token in the Node
25	Pos() scanner.Position
26	// End returns the position of the character after the last token in the Node
27	End() scanner.Position
28}
29
30// Definition is an Assignment or a Module at the top level of a Blueprints file
31type Definition interface {
32	Node
33	String() string
34	definitionTag()
35}
36
37// An Assignment is a variable assignment at the top level of a Blueprints file, scoped to the
38// file and subdirs.
39type Assignment struct {
40	Name       string
41	NamePos    scanner.Position
42	Value      Expression
43	OrigValue  Expression
44	EqualsPos  scanner.Position
45	Assigner   string
46	Referenced bool
47}
48
49func (a *Assignment) String() string {
50	return fmt.Sprintf("%s@%s %s %s (%s) %t", a.Name, a.EqualsPos, a.Assigner, a.Value, a.OrigValue, a.Referenced)
51}
52
53func (a *Assignment) Pos() scanner.Position { return a.NamePos }
54func (a *Assignment) End() scanner.Position { return a.Value.End() }
55
56func (a *Assignment) definitionTag() {}
57
58// A Module is a module definition at the top level of a Blueprints file
59type Module struct {
60	Type    string
61	TypePos scanner.Position
62	Map
63}
64
65func (m *Module) Copy() *Module {
66	ret := *m
67	ret.Properties = make([]*Property, len(m.Properties))
68	for i := range m.Properties {
69		ret.Properties[i] = m.Properties[i].Copy()
70	}
71	return &ret
72}
73
74func (m *Module) String() string {
75	propertyStrings := make([]string, len(m.Properties))
76	for i, property := range m.Properties {
77		propertyStrings[i] = property.String()
78	}
79	return fmt.Sprintf("%s@%s-%s{%s}", m.Type,
80		m.LBracePos, m.RBracePos,
81		strings.Join(propertyStrings, ", "))
82}
83
84func (m *Module) definitionTag() {}
85
86func (m *Module) Pos() scanner.Position { return m.TypePos }
87func (m *Module) End() scanner.Position { return m.Map.End() }
88
89// A Property is a name: value pair within a Map, which may be a top level Module.
90type Property struct {
91	Name     string
92	NamePos  scanner.Position
93	ColonPos scanner.Position
94	Value    Expression
95}
96
97func (p *Property) Copy() *Property {
98	ret := *p
99	ret.Value = p.Value.Copy()
100	return &ret
101}
102
103func (p *Property) String() string {
104	return fmt.Sprintf("%s@%s: %s", p.Name, p.ColonPos, p.Value)
105}
106
107func (p *Property) Pos() scanner.Position { return p.NamePos }
108func (p *Property) End() scanner.Position { return p.Value.End() }
109
110// A MapItem is a key: value pair within a Map, corresponding to map type, rather than a struct.
111type MapItem struct {
112	ColonPos scanner.Position
113	Key      *String
114	Value    Expression
115}
116
117func (m *MapItem) Copy() *MapItem {
118	ret := MapItem{
119		ColonPos: m.ColonPos,
120		Key:      m.Key.Copy().(*String),
121		Value:    m.Value.Copy(),
122	}
123	return &ret
124}
125
126func (m *MapItem) String() string {
127	return fmt.Sprintf("%s@%s: %s", m.Key, m.ColonPos, m.Value)
128}
129
130func (m *MapItem) Pos() scanner.Position { return m.Key.Pos() }
131func (m *MapItem) End() scanner.Position { return m.Value.End() }
132
133// An Expression is a Value in a Property or Assignment.  It can be a literal (String or Bool), a
134// Map, a List, an Operator that combines two expressions of the same type, or a Variable that
135// references and Assignment.
136type Expression interface {
137	Node
138	// Copy returns a copy of the Expression that will not affect the original if mutated
139	Copy() Expression
140	String() string
141	// Type returns the underlying Type enum of the Expression if it were to be evalutated
142	Type() Type
143	// Eval returns an expression that is fully evaluated to a simple type (List, Map, String, or
144	// Bool).  It will return the same object for every call to Eval().
145	Eval() Expression
146}
147
148// ExpressionsAreSame tells whether the two values are the same Expression.
149// This includes the symbolic representation of each Expression but not their positions in the original source tree.
150// This does not apply any simplification to the expressions before comparing them
151// (for example, "!!a" wouldn't be deemed equal to "a")
152func ExpressionsAreSame(a Expression, b Expression) (equal bool, err error) {
153	return hackyExpressionsAreSame(a, b)
154}
155
156// TODO(jeffrygaston) once positions are removed from Expression structs,
157// remove this function and have callers use reflect.DeepEqual(a, b)
158func hackyExpressionsAreSame(a Expression, b Expression) (equal bool, err error) {
159	if a.Type() != b.Type() {
160		return false, nil
161	}
162	left, err := hackyFingerprint(a)
163	if err != nil {
164		return false, nil
165	}
166	right, err := hackyFingerprint(b)
167	if err != nil {
168		return false, nil
169	}
170	areEqual := string(left) == string(right)
171	return areEqual, nil
172}
173
174func hackyFingerprint(expression Expression) (fingerprint []byte, err error) {
175	assignment := &Assignment{"a", noPos, expression, expression, noPos, "=", false}
176	module := &File{}
177	module.Defs = append(module.Defs, assignment)
178	p := newPrinter(module)
179	return p.Print()
180}
181
182type Type int
183
184const (
185	BoolType Type = iota + 1
186	StringType
187	Int64Type
188	ListType
189	MapType
190	NotEvaluatedType
191)
192
193func (t Type) String() string {
194	switch t {
195	case BoolType:
196		return "bool"
197	case StringType:
198		return "string"
199	case Int64Type:
200		return "int64"
201	case ListType:
202		return "list"
203	case MapType:
204		return "map"
205	case NotEvaluatedType:
206		return "notevaluated"
207	default:
208		panic(fmt.Errorf("Unknown type %d", t))
209	}
210}
211
212type Operator struct {
213	Args        [2]Expression
214	Operator    rune
215	OperatorPos scanner.Position
216	Value       Expression
217}
218
219func (x *Operator) Copy() Expression {
220	ret := *x
221	ret.Args[0] = x.Args[0].Copy()
222	ret.Args[1] = x.Args[1].Copy()
223	return &ret
224}
225
226func (x *Operator) Eval() Expression {
227	return x.Value.Eval()
228}
229
230func (x *Operator) Type() Type {
231	return x.Args[0].Type()
232}
233
234func (x *Operator) Pos() scanner.Position { return x.Args[0].Pos() }
235func (x *Operator) End() scanner.Position { return x.Args[1].End() }
236
237func (x *Operator) String() string {
238	return fmt.Sprintf("(%s %c %s = %s)@%s", x.Args[0].String(), x.Operator, x.Args[1].String(),
239		x.Value, x.OperatorPos)
240}
241
242type Variable struct {
243	Name    string
244	NamePos scanner.Position
245	Value   Expression
246}
247
248func (x *Variable) Pos() scanner.Position { return x.NamePos }
249func (x *Variable) End() scanner.Position { return endPos(x.NamePos, len(x.Name)) }
250
251func (x *Variable) Copy() Expression {
252	ret := *x
253	return &ret
254}
255
256func (x *Variable) Eval() Expression {
257	return x.Value.Eval()
258}
259
260func (x *Variable) String() string {
261	return x.Name + " = " + x.Value.String()
262}
263
264func (x *Variable) Type() Type { return x.Value.Type() }
265
266type Map struct {
267	LBracePos  scanner.Position
268	RBracePos  scanner.Position
269	Properties []*Property
270	MapItems   []*MapItem
271}
272
273func (x *Map) Pos() scanner.Position { return x.LBracePos }
274func (x *Map) End() scanner.Position { return endPos(x.RBracePos, 1) }
275
276func (x *Map) Copy() Expression {
277	ret := *x
278	ret.Properties = make([]*Property, len(x.Properties))
279	for i := range x.Properties {
280		ret.Properties[i] = x.Properties[i].Copy()
281	}
282	ret.MapItems = make([]*MapItem, len(x.MapItems))
283	for i := range x.MapItems {
284		ret.MapItems[i] = x.MapItems[i].Copy()
285	}
286	return &ret
287}
288
289func (x *Map) Eval() Expression {
290	if len(x.Properties) > 0 && len(x.MapItems) > 0 {
291		panic("Cannot support both Properties and MapItems")
292	}
293	return x
294}
295
296func (x *Map) String() string {
297	var s string
298	if len(x.MapItems) > 0 {
299		mapStrings := make([]string, len(x.MapItems))
300		for i, mapItem := range x.MapItems {
301			mapStrings[i] = mapItem.String()
302		}
303		s = strings.Join(mapStrings, ", ")
304	} else {
305		propertyStrings := make([]string, len(x.Properties))
306		for i, property := range x.Properties {
307			propertyStrings[i] = property.String()
308		}
309		s = strings.Join(propertyStrings, ", ")
310	}
311	return fmt.Sprintf("@%s-%s{%s}", x.LBracePos, x.RBracePos, s)
312}
313
314func (x *Map) Type() Type { return MapType }
315
316// GetProperty looks for a property with the given name.
317// It resembles the bracket operator of a built-in Golang map.
318func (x *Map) GetProperty(name string) (Property *Property, found bool) {
319	prop, found, _ := x.getPropertyImpl(name)
320	return prop, found // we don't currently expose the index to callers
321}
322
323func (x *Map) getPropertyImpl(name string) (Property *Property, found bool, index int) {
324	for i, prop := range x.Properties {
325		if prop.Name == name {
326			return prop, true, i
327		}
328	}
329	return nil, false, -1
330}
331
332// RemoveProperty removes the property with the given name, if it exists.
333func (x *Map) RemoveProperty(propertyName string) (removed bool) {
334	_, found, index := x.getPropertyImpl(propertyName)
335	if found {
336		x.Properties = append(x.Properties[:index], x.Properties[index+1:]...)
337	}
338	return found
339}
340
341type List struct {
342	LBracePos scanner.Position
343	RBracePos scanner.Position
344	Values    []Expression
345}
346
347func (x *List) Pos() scanner.Position { return x.LBracePos }
348func (x *List) End() scanner.Position { return endPos(x.RBracePos, 1) }
349
350func (x *List) Copy() Expression {
351	ret := *x
352	ret.Values = make([]Expression, len(x.Values))
353	for i := range ret.Values {
354		ret.Values[i] = x.Values[i].Copy()
355	}
356	return &ret
357}
358
359func (x *List) Eval() Expression {
360	return x
361}
362
363func (x *List) String() string {
364	valueStrings := make([]string, len(x.Values))
365	for i, value := range x.Values {
366		valueStrings[i] = value.String()
367	}
368	return fmt.Sprintf("@%s-%s[%s]", x.LBracePos, x.RBracePos,
369		strings.Join(valueStrings, ", "))
370}
371
372func (x *List) Type() Type { return ListType }
373
374type String struct {
375	LiteralPos scanner.Position
376	Value      string
377}
378
379func (x *String) Pos() scanner.Position { return x.LiteralPos }
380func (x *String) End() scanner.Position { return endPos(x.LiteralPos, len(x.Value)+2) }
381
382func (x *String) Copy() Expression {
383	ret := *x
384	return &ret
385}
386
387func (x *String) Eval() Expression {
388	return x
389}
390
391func (x *String) String() string {
392	return fmt.Sprintf("%q@%s", x.Value, x.LiteralPos)
393}
394
395func (x *String) Type() Type {
396	return StringType
397}
398
399type Int64 struct {
400	LiteralPos scanner.Position
401	Value      int64
402	Token      string
403}
404
405func (x *Int64) Pos() scanner.Position { return x.LiteralPos }
406func (x *Int64) End() scanner.Position { return endPos(x.LiteralPos, len(x.Token)) }
407
408func (x *Int64) Copy() Expression {
409	ret := *x
410	return &ret
411}
412
413func (x *Int64) Eval() Expression {
414	return x
415}
416
417func (x *Int64) String() string {
418	return fmt.Sprintf("%q@%s", x.Value, x.LiteralPos)
419}
420
421func (x *Int64) Type() Type {
422	return Int64Type
423}
424
425type Bool struct {
426	LiteralPos scanner.Position
427	Value      bool
428	Token      string
429}
430
431func (x *Bool) Pos() scanner.Position { return x.LiteralPos }
432func (x *Bool) End() scanner.Position { return endPos(x.LiteralPos, len(x.Token)) }
433
434func (x *Bool) Copy() Expression {
435	ret := *x
436	return &ret
437}
438
439func (x *Bool) Eval() Expression {
440	return x
441}
442
443func (x *Bool) String() string {
444	return fmt.Sprintf("%t@%s", x.Value, x.LiteralPos)
445}
446
447func (x *Bool) Type() Type {
448	return BoolType
449}
450
451type CommentGroup struct {
452	Comments []*Comment
453}
454
455func (x *CommentGroup) Pos() scanner.Position { return x.Comments[0].Pos() }
456func (x *CommentGroup) End() scanner.Position { return x.Comments[len(x.Comments)-1].End() }
457
458type Comment struct {
459	Comment []string
460	Slash   scanner.Position
461}
462
463func (c Comment) Pos() scanner.Position {
464	return c.Slash
465}
466
467func (c Comment) End() scanner.Position {
468	pos := c.Slash
469	for _, comment := range c.Comment {
470		pos.Offset += len(comment) + 1
471		pos.Column = len(comment) + 1
472	}
473	pos.Line += len(c.Comment) - 1
474	return pos
475}
476
477func (c Comment) String() string {
478	l := 0
479	for _, comment := range c.Comment {
480		l += len(comment) + 1
481	}
482	buf := make([]byte, 0, l)
483	for _, comment := range c.Comment {
484		buf = append(buf, comment...)
485		buf = append(buf, '\n')
486	}
487
488	return string(buf) + "@" + c.Slash.String()
489}
490
491// Return the text of the comment with // or /* and */ stripped
492func (c Comment) Text() string {
493	l := 0
494	for _, comment := range c.Comment {
495		l += len(comment) + 1
496	}
497	buf := make([]byte, 0, l)
498
499	blockComment := false
500	if strings.HasPrefix(c.Comment[0], "/*") {
501		blockComment = true
502	}
503
504	for i, comment := range c.Comment {
505		if blockComment {
506			if i == 0 {
507				comment = strings.TrimPrefix(comment, "/*")
508			}
509			if i == len(c.Comment)-1 {
510				comment = strings.TrimSuffix(comment, "*/")
511			}
512		} else {
513			comment = strings.TrimPrefix(comment, "//")
514		}
515		buf = append(buf, comment...)
516		buf = append(buf, '\n')
517	}
518
519	return string(buf)
520}
521
522type NotEvaluated struct {
523	Position scanner.Position
524}
525
526func (n NotEvaluated) Copy() Expression {
527	return NotEvaluated{Position: n.Position}
528}
529
530func (n NotEvaluated) String() string {
531	return "Not Evaluated"
532}
533
534func (n NotEvaluated) Type() Type {
535	return NotEvaluatedType
536}
537
538func (n NotEvaluated) Eval() Expression {
539	return NotEvaluated{Position: n.Position}
540}
541
542func (n NotEvaluated) Pos() scanner.Position { return n.Position }
543func (n NotEvaluated) End() scanner.Position { return n.Position }
544
545func endPos(pos scanner.Position, n int) scanner.Position {
546	pos.Offset += n
547	pos.Column += n
548	return pos
549}
550