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