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