Colin Cross | e32cc80 | 2016-06-07 12:28:16 -0700 | [diff] [blame] | 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 | |
Colin Cross | 1ead645 | 2016-06-09 17:40:13 -0700 | [diff] [blame] | 23 | type Node interface { |
Colin Cross | fdeaf88 | 2018-03-21 17:00:39 -0700 | [diff] [blame] | 24 | // Pos returns the position of the first token in the Node |
Colin Cross | 1ead645 | 2016-06-09 17:40:13 -0700 | [diff] [blame] | 25 | Pos() scanner.Position |
Colin Cross | fdeaf88 | 2018-03-21 17:00:39 -0700 | [diff] [blame] | 26 | // End returns the position of the character after the last token in the Node |
Colin Cross | 1ead645 | 2016-06-09 17:40:13 -0700 | [diff] [blame] | 27 | End() scanner.Position |
| 28 | } |
| 29 | |
Colin Cross | e32cc80 | 2016-06-07 12:28:16 -0700 | [diff] [blame] | 30 | // Definition is an Assignment or a Module at the top level of a Blueprints file |
| 31 | type Definition interface { |
Colin Cross | 1ead645 | 2016-06-09 17:40:13 -0700 | [diff] [blame] | 32 | Node |
Colin Cross | e32cc80 | 2016-06-07 12:28:16 -0700 | [diff] [blame] | 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 { |
Colin Cross | c32c479 | 2016-06-09 15:52:30 -0700 | [diff] [blame] | 40 | Name string |
| 41 | NamePos scanner.Position |
Colin Cross | e32cc80 | 2016-06-07 12:28:16 -0700 | [diff] [blame] | 42 | Value Expression |
| 43 | OrigValue Expression |
Colin Cross | b3d0b8d | 2016-06-09 17:03:57 -0700 | [diff] [blame] | 44 | EqualsPos scanner.Position |
Colin Cross | e32cc80 | 2016-06-07 12:28:16 -0700 | [diff] [blame] | 45 | Assigner string |
| 46 | Referenced bool |
| 47 | } |
| 48 | |
| 49 | func (a *Assignment) String() string { |
Colin Cross | b3d0b8d | 2016-06-09 17:03:57 -0700 | [diff] [blame] | 50 | return fmt.Sprintf("%s@%s %s %s (%s) %t", a.Name, a.EqualsPos, a.Assigner, a.Value, a.OrigValue, a.Referenced) |
Colin Cross | e32cc80 | 2016-06-07 12:28:16 -0700 | [diff] [blame] | 51 | } |
| 52 | |
Colin Cross | 1ead645 | 2016-06-09 17:40:13 -0700 | [diff] [blame] | 53 | func (a *Assignment) Pos() scanner.Position { return a.NamePos } |
| 54 | func (a *Assignment) End() scanner.Position { return a.Value.End() } |
| 55 | |
Colin Cross | e32cc80 | 2016-06-07 12:28:16 -0700 | [diff] [blame] | 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 { |
Colin Cross | c32c479 | 2016-06-09 15:52:30 -0700 | [diff] [blame] | 60 | Type string |
| 61 | TypePos scanner.Position |
Colin Cross | e32cc80 | 2016-06-07 12:28:16 -0700 | [diff] [blame] | 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 | |
Colin Cross | c32c479 | 2016-06-09 15:52:30 -0700 | [diff] [blame] | 86 | func (m *Module) Pos() scanner.Position { return m.TypePos } |
| 87 | func (m *Module) End() scanner.Position { return m.Map.End() } |
| 88 | |
Colin Cross | e32cc80 | 2016-06-07 12:28:16 -0700 | [diff] [blame] | 89 | // A Property is a name: value pair within a Map, which may be a top level Module. |
| 90 | type Property struct { |
Colin Cross | b3d0b8d | 2016-06-09 17:03:57 -0700 | [diff] [blame] | 91 | Name string |
| 92 | NamePos scanner.Position |
| 93 | ColonPos scanner.Position |
| 94 | Value Expression |
Colin Cross | e32cc80 | 2016-06-07 12:28:16 -0700 | [diff] [blame] | 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 { |
Colin Cross | b3d0b8d | 2016-06-09 17:03:57 -0700 | [diff] [blame] | 104 | return fmt.Sprintf("%s@%s: %s", p.Name, p.ColonPos, p.Value) |
Colin Cross | e32cc80 | 2016-06-07 12:28:16 -0700 | [diff] [blame] | 105 | } |
| 106 | |
Colin Cross | 1ead645 | 2016-06-09 17:40:13 -0700 | [diff] [blame] | 107 | func (p *Property) Pos() scanner.Position { return p.NamePos } |
| 108 | func (p *Property) End() scanner.Position { return p.Value.End() } |
| 109 | |
Colin Cross | e32cc80 | 2016-06-07 12:28:16 -0700 | [diff] [blame] | 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 { |
Colin Cross | 1ead645 | 2016-06-09 17:40:13 -0700 | [diff] [blame] | 114 | Node |
Colin Cross | e32cc80 | 2016-06-07 12:28:16 -0700 | [diff] [blame] | 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 |
Colin Cross | e32cc80 | 2016-06-07 12:28:16 -0700 | [diff] [blame] | 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 | |
Jeff Gaston | 5d4b9d8 | 2017-05-16 17:39:37 -0700 | [diff] [blame] | 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 | |
Sasha Smundak | 29fdcad | 2020-02-11 22:39:47 -0800 | [diff] [blame] | 133 | // TODO(jeffrygaston) once positions are removed from Expression structs, |
Jeff Gaston | 5d4b9d8 | 2017-05-16 17:39:37 -0700 | [diff] [blame] | 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 | |
Colin Cross | e32cc80 | 2016-06-07 12:28:16 -0700 | [diff] [blame] | 159 | type Type int |
| 160 | |
| 161 | const ( |
| 162 | BoolType Type = iota + 1 |
| 163 | StringType |
Nan Zhang | f586544 | 2017-11-01 14:03:28 -0700 | [diff] [blame] | 164 | Int64Type |
Colin Cross | e32cc80 | 2016-06-07 12:28:16 -0700 | [diff] [blame] | 165 | ListType |
| 166 | MapType |
Sasha Smundak | 77418b7 | 2020-01-21 13:31:06 -0800 | [diff] [blame] | 167 | NotEvaluatedType |
Colin Cross | e32cc80 | 2016-06-07 12:28:16 -0700 | [diff] [blame] | 168 | ) |
| 169 | |
| 170 | func (t Type) String() string { |
| 171 | switch t { |
| 172 | case BoolType: |
| 173 | return "bool" |
| 174 | case StringType: |
| 175 | return "string" |
Nan Zhang | f586544 | 2017-11-01 14:03:28 -0700 | [diff] [blame] | 176 | case Int64Type: |
| 177 | return "int64" |
Colin Cross | e32cc80 | 2016-06-07 12:28:16 -0700 | [diff] [blame] | 178 | case ListType: |
| 179 | return "list" |
| 180 | case MapType: |
| 181 | return "map" |
Sasha Smundak | 77418b7 | 2020-01-21 13:31:06 -0800 | [diff] [blame] | 182 | case NotEvaluatedType: |
| 183 | return "notevaluated" |
Colin Cross | e32cc80 | 2016-06-07 12:28:16 -0700 | [diff] [blame] | 184 | default: |
| 185 | panic(fmt.Errorf("Unknown type %d", t)) |
| 186 | } |
| 187 | } |
| 188 | |
| 189 | type Operator struct { |
| 190 | Args [2]Expression |
| 191 | Operator rune |
| 192 | OperatorPos scanner.Position |
| 193 | Value Expression |
| 194 | } |
| 195 | |
| 196 | func (x *Operator) Copy() Expression { |
| 197 | ret := *x |
| 198 | ret.Args[0] = x.Args[0].Copy() |
| 199 | ret.Args[1] = x.Args[1].Copy() |
| 200 | return &ret |
| 201 | } |
| 202 | |
| 203 | func (x *Operator) Eval() Expression { |
| 204 | return x.Value.Eval() |
| 205 | } |
| 206 | |
| 207 | func (x *Operator) Type() Type { |
| 208 | return x.Args[0].Type() |
| 209 | } |
| 210 | |
| 211 | func (x *Operator) Pos() scanner.Position { return x.Args[0].Pos() } |
| 212 | func (x *Operator) End() scanner.Position { return x.Args[1].End() } |
| 213 | |
| 214 | func (x *Operator) String() string { |
| 215 | return fmt.Sprintf("(%s %c %s = %s)@%s", x.Args[0].String(), x.Operator, x.Args[1].String(), |
| 216 | x.Value, x.OperatorPos) |
| 217 | } |
| 218 | |
| 219 | type Variable struct { |
| 220 | Name string |
Colin Cross | e32cc80 | 2016-06-07 12:28:16 -0700 | [diff] [blame] | 221 | NamePos scanner.Position |
Colin Cross | 1ead645 | 2016-06-09 17:40:13 -0700 | [diff] [blame] | 222 | Value Expression |
Colin Cross | e32cc80 | 2016-06-07 12:28:16 -0700 | [diff] [blame] | 223 | } |
| 224 | |
| 225 | func (x *Variable) Pos() scanner.Position { return x.NamePos } |
Colin Cross | fdeaf88 | 2018-03-21 17:00:39 -0700 | [diff] [blame] | 226 | func (x *Variable) End() scanner.Position { return endPos(x.NamePos, len(x.Name)) } |
Colin Cross | e32cc80 | 2016-06-07 12:28:16 -0700 | [diff] [blame] | 227 | |
| 228 | func (x *Variable) Copy() Expression { |
| 229 | ret := *x |
| 230 | return &ret |
| 231 | } |
| 232 | |
| 233 | func (x *Variable) Eval() Expression { |
| 234 | return x.Value.Eval() |
| 235 | } |
| 236 | |
| 237 | func (x *Variable) String() string { |
| 238 | return x.Name + " = " + x.Value.String() |
| 239 | } |
| 240 | |
| 241 | func (x *Variable) Type() Type { return x.Value.Type() } |
| 242 | |
| 243 | type Map struct { |
| 244 | LBracePos scanner.Position |
| 245 | RBracePos scanner.Position |
| 246 | Properties []*Property |
| 247 | } |
| 248 | |
| 249 | func (x *Map) Pos() scanner.Position { return x.LBracePos } |
Colin Cross | fdeaf88 | 2018-03-21 17:00:39 -0700 | [diff] [blame] | 250 | func (x *Map) End() scanner.Position { return endPos(x.RBracePos, 1) } |
Colin Cross | e32cc80 | 2016-06-07 12:28:16 -0700 | [diff] [blame] | 251 | |
| 252 | func (x *Map) Copy() Expression { |
| 253 | ret := *x |
| 254 | ret.Properties = make([]*Property, len(x.Properties)) |
| 255 | for i := range x.Properties { |
| 256 | ret.Properties[i] = x.Properties[i].Copy() |
| 257 | } |
| 258 | return &ret |
| 259 | } |
| 260 | |
| 261 | func (x *Map) Eval() Expression { |
| 262 | return x |
| 263 | } |
| 264 | |
| 265 | func (x *Map) String() string { |
| 266 | propertyStrings := make([]string, len(x.Properties)) |
| 267 | for i, property := range x.Properties { |
| 268 | propertyStrings[i] = property.String() |
| 269 | } |
| 270 | return fmt.Sprintf("@%s-%s{%s}", x.LBracePos, x.RBracePos, |
| 271 | strings.Join(propertyStrings, ", ")) |
| 272 | } |
| 273 | |
| 274 | func (x *Map) Type() Type { return MapType } |
| 275 | |
Jeff Gaston | 5d4b9d8 | 2017-05-16 17:39:37 -0700 | [diff] [blame] | 276 | // GetProperty looks for a property with the given name. |
| 277 | // It resembles the bracket operator of a built-in Golang map. |
| 278 | func (x *Map) GetProperty(name string) (Property *Property, found bool) { |
| 279 | prop, found, _ := x.getPropertyImpl(name) |
| 280 | return prop, found // we don't currently expose the index to callers |
| 281 | } |
| 282 | |
| 283 | func (x *Map) getPropertyImpl(name string) (Property *Property, found bool, index int) { |
| 284 | for i, prop := range x.Properties { |
| 285 | if prop.Name == name { |
| 286 | return prop, true, i |
| 287 | } |
| 288 | } |
| 289 | return nil, false, -1 |
| 290 | } |
| 291 | |
| 292 | // GetProperty removes the property with the given name, if it exists. |
| 293 | func (x *Map) RemoveProperty(propertyName string) (removed bool) { |
| 294 | _, found, index := x.getPropertyImpl(propertyName) |
| 295 | if found { |
| 296 | x.Properties = append(x.Properties[:index], x.Properties[index+1:]...) |
| 297 | } |
| 298 | return found |
| 299 | } |
| 300 | |
Colin Cross | e32cc80 | 2016-06-07 12:28:16 -0700 | [diff] [blame] | 301 | type List struct { |
| 302 | LBracePos scanner.Position |
| 303 | RBracePos scanner.Position |
| 304 | Values []Expression |
| 305 | } |
| 306 | |
| 307 | func (x *List) Pos() scanner.Position { return x.LBracePos } |
Colin Cross | fdeaf88 | 2018-03-21 17:00:39 -0700 | [diff] [blame] | 308 | func (x *List) End() scanner.Position { return endPos(x.RBracePos, 1) } |
Colin Cross | e32cc80 | 2016-06-07 12:28:16 -0700 | [diff] [blame] | 309 | |
| 310 | func (x *List) Copy() Expression { |
| 311 | ret := *x |
| 312 | ret.Values = make([]Expression, len(x.Values)) |
| 313 | for i := range ret.Values { |
| 314 | ret.Values[i] = x.Values[i].Copy() |
| 315 | } |
| 316 | return &ret |
| 317 | } |
| 318 | |
| 319 | func (x *List) Eval() Expression { |
| 320 | return x |
| 321 | } |
| 322 | |
| 323 | func (x *List) String() string { |
| 324 | valueStrings := make([]string, len(x.Values)) |
| 325 | for i, value := range x.Values { |
| 326 | valueStrings[i] = value.String() |
| 327 | } |
| 328 | return fmt.Sprintf("@%s-%s[%s]", x.LBracePos, x.RBracePos, |
| 329 | strings.Join(valueStrings, ", ")) |
| 330 | } |
| 331 | |
| 332 | func (x *List) Type() Type { return ListType } |
| 333 | |
| 334 | type String struct { |
| 335 | LiteralPos scanner.Position |
| 336 | Value string |
| 337 | } |
| 338 | |
| 339 | func (x *String) Pos() scanner.Position { return x.LiteralPos } |
Colin Cross | fdeaf88 | 2018-03-21 17:00:39 -0700 | [diff] [blame] | 340 | func (x *String) End() scanner.Position { return endPos(x.LiteralPos, len(x.Value)+2) } |
Colin Cross | e32cc80 | 2016-06-07 12:28:16 -0700 | [diff] [blame] | 341 | |
| 342 | func (x *String) Copy() Expression { |
| 343 | ret := *x |
| 344 | return &ret |
| 345 | } |
| 346 | |
| 347 | func (x *String) Eval() Expression { |
| 348 | return x |
| 349 | } |
| 350 | |
| 351 | func (x *String) String() string { |
| 352 | return fmt.Sprintf("%q@%s", x.Value, x.LiteralPos) |
| 353 | } |
| 354 | |
| 355 | func (x *String) Type() Type { |
| 356 | return StringType |
| 357 | } |
| 358 | |
Nan Zhang | f586544 | 2017-11-01 14:03:28 -0700 | [diff] [blame] | 359 | type Int64 struct { |
| 360 | LiteralPos scanner.Position |
| 361 | Value int64 |
Colin Cross | fdeaf88 | 2018-03-21 17:00:39 -0700 | [diff] [blame] | 362 | Token string |
Nan Zhang | f586544 | 2017-11-01 14:03:28 -0700 | [diff] [blame] | 363 | } |
| 364 | |
| 365 | func (x *Int64) Pos() scanner.Position { return x.LiteralPos } |
Colin Cross | fdeaf88 | 2018-03-21 17:00:39 -0700 | [diff] [blame] | 366 | func (x *Int64) End() scanner.Position { return endPos(x.LiteralPos, len(x.Token)) } |
Nan Zhang | f586544 | 2017-11-01 14:03:28 -0700 | [diff] [blame] | 367 | |
| 368 | func (x *Int64) Copy() Expression { |
| 369 | ret := *x |
| 370 | return &ret |
| 371 | } |
| 372 | |
| 373 | func (x *Int64) Eval() Expression { |
| 374 | return x |
| 375 | } |
| 376 | |
| 377 | func (x *Int64) String() string { |
| 378 | return fmt.Sprintf("%q@%s", x.Value, x.LiteralPos) |
| 379 | } |
| 380 | |
| 381 | func (x *Int64) Type() Type { |
| 382 | return Int64Type |
| 383 | } |
| 384 | |
Colin Cross | e32cc80 | 2016-06-07 12:28:16 -0700 | [diff] [blame] | 385 | type Bool struct { |
| 386 | LiteralPos scanner.Position |
| 387 | Value bool |
Colin Cross | fdeaf88 | 2018-03-21 17:00:39 -0700 | [diff] [blame] | 388 | Token string |
Colin Cross | e32cc80 | 2016-06-07 12:28:16 -0700 | [diff] [blame] | 389 | } |
| 390 | |
| 391 | func (x *Bool) Pos() scanner.Position { return x.LiteralPos } |
Colin Cross | fdeaf88 | 2018-03-21 17:00:39 -0700 | [diff] [blame] | 392 | func (x *Bool) End() scanner.Position { return endPos(x.LiteralPos, len(x.Token)) } |
Colin Cross | e32cc80 | 2016-06-07 12:28:16 -0700 | [diff] [blame] | 393 | |
| 394 | func (x *Bool) Copy() Expression { |
| 395 | ret := *x |
| 396 | return &ret |
| 397 | } |
| 398 | |
| 399 | func (x *Bool) Eval() Expression { |
| 400 | return x |
| 401 | } |
| 402 | |
| 403 | func (x *Bool) String() string { |
| 404 | return fmt.Sprintf("%t@%s", x.Value, x.LiteralPos) |
| 405 | } |
| 406 | |
| 407 | func (x *Bool) Type() Type { |
| 408 | return BoolType |
| 409 | } |
| 410 | |
Colin Cross | 1e73794 | 2016-06-10 17:27:12 -0700 | [diff] [blame] | 411 | type CommentGroup struct { |
| 412 | Comments []*Comment |
| 413 | } |
| 414 | |
| 415 | func (x *CommentGroup) Pos() scanner.Position { return x.Comments[0].Pos() } |
| 416 | func (x *CommentGroup) End() scanner.Position { return x.Comments[len(x.Comments)-1].End() } |
| 417 | |
Colin Cross | e32cc80 | 2016-06-07 12:28:16 -0700 | [diff] [blame] | 418 | type Comment struct { |
| 419 | Comment []string |
| 420 | Slash scanner.Position |
| 421 | } |
| 422 | |
| 423 | func (c Comment) Pos() scanner.Position { |
| 424 | return c.Slash |
| 425 | } |
| 426 | |
| 427 | func (c Comment) End() scanner.Position { |
| 428 | pos := c.Slash |
| 429 | for _, comment := range c.Comment { |
Colin Cross | fdeaf88 | 2018-03-21 17:00:39 -0700 | [diff] [blame] | 430 | pos.Offset += len(comment) + 1 |
| 431 | pos.Column = len(comment) + 1 |
Colin Cross | e32cc80 | 2016-06-07 12:28:16 -0700 | [diff] [blame] | 432 | } |
| 433 | pos.Line += len(c.Comment) - 1 |
| 434 | return pos |
| 435 | } |
| 436 | |
| 437 | func (c Comment) String() string { |
| 438 | l := 0 |
| 439 | for _, comment := range c.Comment { |
| 440 | l += len(comment) + 1 |
| 441 | } |
| 442 | buf := make([]byte, 0, l) |
| 443 | for _, comment := range c.Comment { |
| 444 | buf = append(buf, comment...) |
| 445 | buf = append(buf, '\n') |
| 446 | } |
| 447 | |
| 448 | return string(buf) + "@" + c.Slash.String() |
| 449 | } |
| 450 | |
| 451 | // Return the text of the comment with // or /* and */ stripped |
| 452 | func (c Comment) Text() string { |
| 453 | l := 0 |
| 454 | for _, comment := range c.Comment { |
| 455 | l += len(comment) + 1 |
| 456 | } |
| 457 | buf := make([]byte, 0, l) |
| 458 | |
| 459 | blockComment := false |
| 460 | if strings.HasPrefix(c.Comment[0], "/*") { |
| 461 | blockComment = true |
| 462 | } |
| 463 | |
| 464 | for i, comment := range c.Comment { |
| 465 | if blockComment { |
| 466 | if i == 0 { |
| 467 | comment = strings.TrimPrefix(comment, "/*") |
| 468 | } |
| 469 | if i == len(c.Comment)-1 { |
| 470 | comment = strings.TrimSuffix(comment, "*/") |
| 471 | } |
| 472 | } else { |
| 473 | comment = strings.TrimPrefix(comment, "//") |
| 474 | } |
| 475 | buf = append(buf, comment...) |
| 476 | buf = append(buf, '\n') |
| 477 | } |
| 478 | |
| 479 | return string(buf) |
| 480 | } |
Colin Cross | fdeaf88 | 2018-03-21 17:00:39 -0700 | [diff] [blame] | 481 | |
Sasha Smundak | 77418b7 | 2020-01-21 13:31:06 -0800 | [diff] [blame] | 482 | type NotEvaluated struct { |
| 483 | Position scanner.Position |
| 484 | } |
| 485 | |
| 486 | func (n NotEvaluated) Copy() Expression { |
| 487 | return NotEvaluated{Position: n.Position} |
| 488 | } |
| 489 | |
| 490 | func (n NotEvaluated) String() string { |
| 491 | return "Not Evaluated" |
| 492 | } |
| 493 | |
| 494 | func (n NotEvaluated) Type() Type { |
| 495 | return NotEvaluatedType |
| 496 | } |
| 497 | |
| 498 | func (n NotEvaluated) Eval() Expression { |
| 499 | return NotEvaluated{Position: n.Position} |
| 500 | } |
| 501 | |
| 502 | func (n NotEvaluated) Pos() scanner.Position { return n.Position } |
| 503 | func (n NotEvaluated) End() scanner.Position { return n.Position } |
| 504 | |
Colin Cross | fdeaf88 | 2018-03-21 17:00:39 -0700 | [diff] [blame] | 505 | func endPos(pos scanner.Position, n int) scanner.Position { |
| 506 | pos.Offset += n |
| 507 | pos.Column += n |
| 508 | return pos |
| 509 | } |