1*1fa6dee9SAndroid Build Coastguard Worker// Copyright 2016 Google Inc. All rights reserved. 2*1fa6dee9SAndroid Build Coastguard Worker// 3*1fa6dee9SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*1fa6dee9SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*1fa6dee9SAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*1fa6dee9SAndroid Build Coastguard Worker// 7*1fa6dee9SAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*1fa6dee9SAndroid Build Coastguard Worker// 9*1fa6dee9SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*1fa6dee9SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*1fa6dee9SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*1fa6dee9SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*1fa6dee9SAndroid Build Coastguard Worker// limitations under the License. 14*1fa6dee9SAndroid Build Coastguard Worker 15*1fa6dee9SAndroid Build Coastguard Workerpackage parser 16*1fa6dee9SAndroid Build Coastguard Worker 17*1fa6dee9SAndroid Build Coastguard Workerimport ( 18*1fa6dee9SAndroid Build Coastguard Worker "fmt" 19*1fa6dee9SAndroid Build Coastguard Worker "os" 20*1fa6dee9SAndroid Build Coastguard Worker "strings" 21*1fa6dee9SAndroid Build Coastguard Worker "text/scanner" 22*1fa6dee9SAndroid Build Coastguard Worker) 23*1fa6dee9SAndroid Build Coastguard Worker 24*1fa6dee9SAndroid Build Coastguard Workertype Node interface { 25*1fa6dee9SAndroid Build Coastguard Worker // Pos returns the position of the first token in the Node 26*1fa6dee9SAndroid Build Coastguard Worker Pos() scanner.Position 27*1fa6dee9SAndroid Build Coastguard Worker // End returns the position of the character after the last token in the Node 28*1fa6dee9SAndroid Build Coastguard Worker End() scanner.Position 29*1fa6dee9SAndroid Build Coastguard Worker} 30*1fa6dee9SAndroid Build Coastguard Worker 31*1fa6dee9SAndroid Build Coastguard Worker// Definition is an Assignment or a Module at the top level of a Blueprints file 32*1fa6dee9SAndroid Build Coastguard Workertype Definition interface { 33*1fa6dee9SAndroid Build Coastguard Worker Node 34*1fa6dee9SAndroid Build Coastguard Worker String() string 35*1fa6dee9SAndroid Build Coastguard Worker definitionTag() 36*1fa6dee9SAndroid Build Coastguard Worker} 37*1fa6dee9SAndroid Build Coastguard Worker 38*1fa6dee9SAndroid Build Coastguard Worker// An Assignment is a variable assignment at the top level of a Blueprints file, scoped to the 39*1fa6dee9SAndroid Build Coastguard Worker// file and subdirs. 40*1fa6dee9SAndroid Build Coastguard Workertype Assignment struct { 41*1fa6dee9SAndroid Build Coastguard Worker Name string 42*1fa6dee9SAndroid Build Coastguard Worker NamePos scanner.Position 43*1fa6dee9SAndroid Build Coastguard Worker Value Expression 44*1fa6dee9SAndroid Build Coastguard Worker EqualsPos scanner.Position 45*1fa6dee9SAndroid Build Coastguard Worker Assigner string 46*1fa6dee9SAndroid Build Coastguard Worker Referenced bool 47*1fa6dee9SAndroid Build Coastguard Worker} 48*1fa6dee9SAndroid Build Coastguard Worker 49*1fa6dee9SAndroid Build Coastguard Workerfunc (a *Assignment) String() string { 50*1fa6dee9SAndroid Build Coastguard Worker return fmt.Sprintf("%s@%s %s %s %t", a.Name, a.EqualsPos, a.Assigner, a.Value, a.Referenced) 51*1fa6dee9SAndroid Build Coastguard Worker} 52*1fa6dee9SAndroid Build Coastguard Worker 53*1fa6dee9SAndroid Build Coastguard Workerfunc (a *Assignment) Pos() scanner.Position { return a.NamePos } 54*1fa6dee9SAndroid Build Coastguard Workerfunc (a *Assignment) End() scanner.Position { return a.Value.End() } 55*1fa6dee9SAndroid Build Coastguard Worker 56*1fa6dee9SAndroid Build Coastguard Workerfunc (a *Assignment) definitionTag() {} 57*1fa6dee9SAndroid Build Coastguard Worker 58*1fa6dee9SAndroid Build Coastguard Worker// A Module is a module definition at the top level of a Blueprints file 59*1fa6dee9SAndroid Build Coastguard Workertype Module struct { 60*1fa6dee9SAndroid Build Coastguard Worker Type string 61*1fa6dee9SAndroid Build Coastguard Worker TypePos scanner.Position 62*1fa6dee9SAndroid Build Coastguard Worker Map 63*1fa6dee9SAndroid Build Coastguard Worker //TODO(delmerico) make this a private field once ag/21588220 lands 64*1fa6dee9SAndroid Build Coastguard Worker Name__internal_only *string 65*1fa6dee9SAndroid Build Coastguard Worker} 66*1fa6dee9SAndroid Build Coastguard Worker 67*1fa6dee9SAndroid Build Coastguard Workerfunc (m *Module) Copy() *Module { 68*1fa6dee9SAndroid Build Coastguard Worker ret := *m 69*1fa6dee9SAndroid Build Coastguard Worker ret.Properties = make([]*Property, len(m.Properties)) 70*1fa6dee9SAndroid Build Coastguard Worker for i := range m.Properties { 71*1fa6dee9SAndroid Build Coastguard Worker ret.Properties[i] = m.Properties[i].Copy() 72*1fa6dee9SAndroid Build Coastguard Worker } 73*1fa6dee9SAndroid Build Coastguard Worker return &ret 74*1fa6dee9SAndroid Build Coastguard Worker} 75*1fa6dee9SAndroid Build Coastguard Worker 76*1fa6dee9SAndroid Build Coastguard Workerfunc (m *Module) String() string { 77*1fa6dee9SAndroid Build Coastguard Worker propertyStrings := make([]string, len(m.Properties)) 78*1fa6dee9SAndroid Build Coastguard Worker for i, property := range m.Properties { 79*1fa6dee9SAndroid Build Coastguard Worker propertyStrings[i] = property.String() 80*1fa6dee9SAndroid Build Coastguard Worker } 81*1fa6dee9SAndroid Build Coastguard Worker return fmt.Sprintf("%s@%s-%s{%s}", m.Type, 82*1fa6dee9SAndroid Build Coastguard Worker m.LBracePos, m.RBracePos, 83*1fa6dee9SAndroid Build Coastguard Worker strings.Join(propertyStrings, ", ")) 84*1fa6dee9SAndroid Build Coastguard Worker} 85*1fa6dee9SAndroid Build Coastguard Worker 86*1fa6dee9SAndroid Build Coastguard Workerfunc (m *Module) definitionTag() {} 87*1fa6dee9SAndroid Build Coastguard Worker 88*1fa6dee9SAndroid Build Coastguard Workerfunc (m *Module) Pos() scanner.Position { return m.TypePos } 89*1fa6dee9SAndroid Build Coastguard Workerfunc (m *Module) End() scanner.Position { return m.Map.End() } 90*1fa6dee9SAndroid Build Coastguard Worker 91*1fa6dee9SAndroid Build Coastguard Workerfunc (m *Module) Name() string { 92*1fa6dee9SAndroid Build Coastguard Worker if m.Name__internal_only != nil { 93*1fa6dee9SAndroid Build Coastguard Worker return *m.Name__internal_only 94*1fa6dee9SAndroid Build Coastguard Worker } 95*1fa6dee9SAndroid Build Coastguard Worker for _, prop := range m.Properties { 96*1fa6dee9SAndroid Build Coastguard Worker if prop.Name == "name" { 97*1fa6dee9SAndroid Build Coastguard Worker if stringProp, ok := prop.Value.(*String); ok { 98*1fa6dee9SAndroid Build Coastguard Worker name := stringProp.Value 99*1fa6dee9SAndroid Build Coastguard Worker m.Name__internal_only = &name 100*1fa6dee9SAndroid Build Coastguard Worker } else { 101*1fa6dee9SAndroid Build Coastguard Worker name := prop.Value.String() 102*1fa6dee9SAndroid Build Coastguard Worker m.Name__internal_only = &name 103*1fa6dee9SAndroid Build Coastguard Worker } 104*1fa6dee9SAndroid Build Coastguard Worker } 105*1fa6dee9SAndroid Build Coastguard Worker } 106*1fa6dee9SAndroid Build Coastguard Worker if m.Name__internal_only == nil { 107*1fa6dee9SAndroid Build Coastguard Worker name := "" 108*1fa6dee9SAndroid Build Coastguard Worker m.Name__internal_only = &name 109*1fa6dee9SAndroid Build Coastguard Worker } 110*1fa6dee9SAndroid Build Coastguard Worker return *m.Name__internal_only 111*1fa6dee9SAndroid Build Coastguard Worker} 112*1fa6dee9SAndroid Build Coastguard Worker 113*1fa6dee9SAndroid Build Coastguard Worker// A Property is a name: value pair within a Map, which may be a top level Module. 114*1fa6dee9SAndroid Build Coastguard Workertype Property struct { 115*1fa6dee9SAndroid Build Coastguard Worker Name string 116*1fa6dee9SAndroid Build Coastguard Worker NamePos scanner.Position 117*1fa6dee9SAndroid Build Coastguard Worker ColonPos scanner.Position 118*1fa6dee9SAndroid Build Coastguard Worker Value Expression 119*1fa6dee9SAndroid Build Coastguard Worker} 120*1fa6dee9SAndroid Build Coastguard Worker 121*1fa6dee9SAndroid Build Coastguard Workerfunc (p *Property) Copy() *Property { 122*1fa6dee9SAndroid Build Coastguard Worker ret := *p 123*1fa6dee9SAndroid Build Coastguard Worker ret.Value = p.Value.Copy() 124*1fa6dee9SAndroid Build Coastguard Worker return &ret 125*1fa6dee9SAndroid Build Coastguard Worker} 126*1fa6dee9SAndroid Build Coastguard Worker 127*1fa6dee9SAndroid Build Coastguard Workerfunc (p *Property) String() string { 128*1fa6dee9SAndroid Build Coastguard Worker return fmt.Sprintf("%s@%s: %s", p.Name, p.ColonPos, p.Value) 129*1fa6dee9SAndroid Build Coastguard Worker} 130*1fa6dee9SAndroid Build Coastguard Worker 131*1fa6dee9SAndroid Build Coastguard Workerfunc (p *Property) Pos() scanner.Position { return p.NamePos } 132*1fa6dee9SAndroid Build Coastguard Workerfunc (p *Property) End() scanner.Position { return p.Value.End() } 133*1fa6dee9SAndroid Build Coastguard Worker 134*1fa6dee9SAndroid Build Coastguard Workerfunc (p *Property) MarkReferencedVariables(scope *Scope) { 135*1fa6dee9SAndroid Build Coastguard Worker p.Value.MarkReferencedVariables(scope) 136*1fa6dee9SAndroid Build Coastguard Worker} 137*1fa6dee9SAndroid Build Coastguard Worker 138*1fa6dee9SAndroid Build Coastguard Worker// An Expression is a Value in a Property or Assignment. It can be a literal (String or Bool), a 139*1fa6dee9SAndroid Build Coastguard Worker// Map, a List, an Operator that combines two expressions of the same type, or a Variable that 140*1fa6dee9SAndroid Build Coastguard Worker// references and Assignment. 141*1fa6dee9SAndroid Build Coastguard Workertype Expression interface { 142*1fa6dee9SAndroid Build Coastguard Worker Node 143*1fa6dee9SAndroid Build Coastguard Worker // Copy returns a copy of the Expression that will not affect the original if mutated 144*1fa6dee9SAndroid Build Coastguard Worker Copy() Expression 145*1fa6dee9SAndroid Build Coastguard Worker String() string 146*1fa6dee9SAndroid Build Coastguard Worker // Type returns the underlying Type enum of the Expression if it were to be evaluated, if it's known. 147*1fa6dee9SAndroid Build Coastguard Worker // It's possible that the type isn't known, such as when a select statement with a late-bound variable 148*1fa6dee9SAndroid Build Coastguard Worker // is used. For that reason, Type() is mostly for use in error messages, not to make logic decisions 149*1fa6dee9SAndroid Build Coastguard Worker // off of. 150*1fa6dee9SAndroid Build Coastguard Worker Type() Type 151*1fa6dee9SAndroid Build Coastguard Worker // Eval returns an expression that is fully evaluated to a simple type (List, Map, String, 152*1fa6dee9SAndroid Build Coastguard Worker // Bool, or Select). It will return the origional expression if possible, or allocate a 153*1fa6dee9SAndroid Build Coastguard Worker // new one if modifications were necessary. 154*1fa6dee9SAndroid Build Coastguard Worker Eval(scope *Scope) (Expression, error) 155*1fa6dee9SAndroid Build Coastguard Worker // PrintfInto will substitute any %s's in string literals in the AST with the provided 156*1fa6dee9SAndroid Build Coastguard Worker // value. It will modify the AST in-place. This is used to implement soong config value 157*1fa6dee9SAndroid Build Coastguard Worker // variables, but should be removed when those have switched to selects. 158*1fa6dee9SAndroid Build Coastguard Worker PrintfInto(value string) error 159*1fa6dee9SAndroid Build Coastguard Worker // MarkReferencedVariables marks the variables in the given scope referenced if there 160*1fa6dee9SAndroid Build Coastguard Worker // is a matching variable reference in this expression. This happens naturally during 161*1fa6dee9SAndroid Build Coastguard Worker // Eval as well, but for selects, we need to mark variables as referenced without 162*1fa6dee9SAndroid Build Coastguard Worker // actually evaluating the expression yet. 163*1fa6dee9SAndroid Build Coastguard Worker MarkReferencedVariables(scope *Scope) 164*1fa6dee9SAndroid Build Coastguard Worker} 165*1fa6dee9SAndroid Build Coastguard Worker 166*1fa6dee9SAndroid Build Coastguard Worker// ExpressionsAreSame tells whether the two values are the same Expression. 167*1fa6dee9SAndroid Build Coastguard Worker// This includes the symbolic representation of each Expression but not their positions in the original source tree. 168*1fa6dee9SAndroid Build Coastguard Worker// This does not apply any simplification to the expressions before comparing them 169*1fa6dee9SAndroid Build Coastguard Worker// (for example, "!!a" wouldn't be deemed equal to "a") 170*1fa6dee9SAndroid Build Coastguard Workerfunc ExpressionsAreSame(a Expression, b Expression) (equal bool, err error) { 171*1fa6dee9SAndroid Build Coastguard Worker return hackyExpressionsAreSame(a, b) 172*1fa6dee9SAndroid Build Coastguard Worker} 173*1fa6dee9SAndroid Build Coastguard Worker 174*1fa6dee9SAndroid Build Coastguard Worker// TODO(jeffrygaston) once positions are removed from Expression structs, 175*1fa6dee9SAndroid Build Coastguard Worker// remove this function and have callers use reflect.DeepEqual(a, b) 176*1fa6dee9SAndroid Build Coastguard Workerfunc hackyExpressionsAreSame(a Expression, b Expression) (equal bool, err error) { 177*1fa6dee9SAndroid Build Coastguard Worker left, err := hackyFingerprint(a) 178*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 179*1fa6dee9SAndroid Build Coastguard Worker return false, nil 180*1fa6dee9SAndroid Build Coastguard Worker } 181*1fa6dee9SAndroid Build Coastguard Worker right, err := hackyFingerprint(b) 182*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 183*1fa6dee9SAndroid Build Coastguard Worker return false, nil 184*1fa6dee9SAndroid Build Coastguard Worker } 185*1fa6dee9SAndroid Build Coastguard Worker areEqual := string(left) == string(right) 186*1fa6dee9SAndroid Build Coastguard Worker return areEqual, nil 187*1fa6dee9SAndroid Build Coastguard Worker} 188*1fa6dee9SAndroid Build Coastguard Worker 189*1fa6dee9SAndroid Build Coastguard Workerfunc hackyFingerprint(expression Expression) (fingerprint []byte, err error) { 190*1fa6dee9SAndroid Build Coastguard Worker assignment := &Assignment{"a", noPos, expression, noPos, "=", false} 191*1fa6dee9SAndroid Build Coastguard Worker module := &File{} 192*1fa6dee9SAndroid Build Coastguard Worker module.Defs = append(module.Defs, assignment) 193*1fa6dee9SAndroid Build Coastguard Worker p := newPrinter(module) 194*1fa6dee9SAndroid Build Coastguard Worker return p.Print() 195*1fa6dee9SAndroid Build Coastguard Worker} 196*1fa6dee9SAndroid Build Coastguard Worker 197*1fa6dee9SAndroid Build Coastguard Workertype Type int 198*1fa6dee9SAndroid Build Coastguard Worker 199*1fa6dee9SAndroid Build Coastguard Workerconst ( 200*1fa6dee9SAndroid Build Coastguard Worker UnknownType Type = iota 201*1fa6dee9SAndroid Build Coastguard Worker BoolType 202*1fa6dee9SAndroid Build Coastguard Worker StringType 203*1fa6dee9SAndroid Build Coastguard Worker Int64Type 204*1fa6dee9SAndroid Build Coastguard Worker ListType 205*1fa6dee9SAndroid Build Coastguard Worker MapType 206*1fa6dee9SAndroid Build Coastguard Worker UnsetType 207*1fa6dee9SAndroid Build Coastguard Worker) 208*1fa6dee9SAndroid Build Coastguard Worker 209*1fa6dee9SAndroid Build Coastguard Workerfunc (t Type) String() string { 210*1fa6dee9SAndroid Build Coastguard Worker switch t { 211*1fa6dee9SAndroid Build Coastguard Worker case UnknownType: 212*1fa6dee9SAndroid Build Coastguard Worker return "unknown" 213*1fa6dee9SAndroid Build Coastguard Worker case BoolType: 214*1fa6dee9SAndroid Build Coastguard Worker return "bool" 215*1fa6dee9SAndroid Build Coastguard Worker case StringType: 216*1fa6dee9SAndroid Build Coastguard Worker return "string" 217*1fa6dee9SAndroid Build Coastguard Worker case Int64Type: 218*1fa6dee9SAndroid Build Coastguard Worker return "int64" 219*1fa6dee9SAndroid Build Coastguard Worker case ListType: 220*1fa6dee9SAndroid Build Coastguard Worker return "list" 221*1fa6dee9SAndroid Build Coastguard Worker case MapType: 222*1fa6dee9SAndroid Build Coastguard Worker return "map" 223*1fa6dee9SAndroid Build Coastguard Worker case UnsetType: 224*1fa6dee9SAndroid Build Coastguard Worker return "unset" 225*1fa6dee9SAndroid Build Coastguard Worker default: 226*1fa6dee9SAndroid Build Coastguard Worker panic(fmt.Sprintf("Unknown type %d", t)) 227*1fa6dee9SAndroid Build Coastguard Worker } 228*1fa6dee9SAndroid Build Coastguard Worker} 229*1fa6dee9SAndroid Build Coastguard Worker 230*1fa6dee9SAndroid Build Coastguard Workerfunc ZeroExpression(t Type) Expression { 231*1fa6dee9SAndroid Build Coastguard Worker switch t { 232*1fa6dee9SAndroid Build Coastguard Worker case UnknownType: 233*1fa6dee9SAndroid Build Coastguard Worker panic(fmt.Errorf("cannot create zero expression for UnknownType")) 234*1fa6dee9SAndroid Build Coastguard Worker case BoolType: 235*1fa6dee9SAndroid Build Coastguard Worker return &Bool{} 236*1fa6dee9SAndroid Build Coastguard Worker case StringType: 237*1fa6dee9SAndroid Build Coastguard Worker return &String{} 238*1fa6dee9SAndroid Build Coastguard Worker case Int64Type: 239*1fa6dee9SAndroid Build Coastguard Worker return &Int64{} 240*1fa6dee9SAndroid Build Coastguard Worker case ListType: 241*1fa6dee9SAndroid Build Coastguard Worker return &List{} 242*1fa6dee9SAndroid Build Coastguard Worker case MapType: 243*1fa6dee9SAndroid Build Coastguard Worker return &Map{} 244*1fa6dee9SAndroid Build Coastguard Worker case UnsetType: 245*1fa6dee9SAndroid Build Coastguard Worker panic(fmt.Errorf("cannot create zero expression for UnsetType")) 246*1fa6dee9SAndroid Build Coastguard Worker 247*1fa6dee9SAndroid Build Coastguard Worker default: 248*1fa6dee9SAndroid Build Coastguard Worker panic(fmt.Errorf("Unknown type %d", t)) 249*1fa6dee9SAndroid Build Coastguard Worker } 250*1fa6dee9SAndroid Build Coastguard Worker} 251*1fa6dee9SAndroid Build Coastguard Worker 252*1fa6dee9SAndroid Build Coastguard Workertype Operator struct { 253*1fa6dee9SAndroid Build Coastguard Worker Args [2]Expression 254*1fa6dee9SAndroid Build Coastguard Worker Operator rune 255*1fa6dee9SAndroid Build Coastguard Worker OperatorPos scanner.Position 256*1fa6dee9SAndroid Build Coastguard Worker} 257*1fa6dee9SAndroid Build Coastguard Worker 258*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Operator) Copy() Expression { 259*1fa6dee9SAndroid Build Coastguard Worker ret := *x 260*1fa6dee9SAndroid Build Coastguard Worker ret.Args[0] = x.Args[0].Copy() 261*1fa6dee9SAndroid Build Coastguard Worker ret.Args[1] = x.Args[1].Copy() 262*1fa6dee9SAndroid Build Coastguard Worker return &ret 263*1fa6dee9SAndroid Build Coastguard Worker} 264*1fa6dee9SAndroid Build Coastguard Worker 265*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Operator) Type() Type { 266*1fa6dee9SAndroid Build Coastguard Worker t1 := x.Args[0].Type() 267*1fa6dee9SAndroid Build Coastguard Worker t2 := x.Args[1].Type() 268*1fa6dee9SAndroid Build Coastguard Worker if t1 == UnknownType { 269*1fa6dee9SAndroid Build Coastguard Worker return t2 270*1fa6dee9SAndroid Build Coastguard Worker } 271*1fa6dee9SAndroid Build Coastguard Worker if t2 == UnknownType { 272*1fa6dee9SAndroid Build Coastguard Worker return t1 273*1fa6dee9SAndroid Build Coastguard Worker } 274*1fa6dee9SAndroid Build Coastguard Worker if t1 != t2 { 275*1fa6dee9SAndroid Build Coastguard Worker return UnknownType 276*1fa6dee9SAndroid Build Coastguard Worker } 277*1fa6dee9SAndroid Build Coastguard Worker return t1 278*1fa6dee9SAndroid Build Coastguard Worker} 279*1fa6dee9SAndroid Build Coastguard Worker 280*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Operator) Eval(scope *Scope) (Expression, error) { 281*1fa6dee9SAndroid Build Coastguard Worker return evaluateOperator(scope, x.Operator, x.Args[0], x.Args[1]) 282*1fa6dee9SAndroid Build Coastguard Worker} 283*1fa6dee9SAndroid Build Coastguard Worker 284*1fa6dee9SAndroid Build Coastguard Workerfunc evaluateOperator(scope *Scope, operator rune, left, right Expression) (Expression, error) { 285*1fa6dee9SAndroid Build Coastguard Worker if operator != '+' { 286*1fa6dee9SAndroid Build Coastguard Worker return nil, fmt.Errorf("unknown operator %c", operator) 287*1fa6dee9SAndroid Build Coastguard Worker } 288*1fa6dee9SAndroid Build Coastguard Worker l, err := left.Eval(scope) 289*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 290*1fa6dee9SAndroid Build Coastguard Worker return nil, err 291*1fa6dee9SAndroid Build Coastguard Worker } 292*1fa6dee9SAndroid Build Coastguard Worker r, err := right.Eval(scope) 293*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 294*1fa6dee9SAndroid Build Coastguard Worker return nil, err 295*1fa6dee9SAndroid Build Coastguard Worker } 296*1fa6dee9SAndroid Build Coastguard Worker 297*1fa6dee9SAndroid Build Coastguard Worker if _, ok := l.(*Select); !ok { 298*1fa6dee9SAndroid Build Coastguard Worker if _, ok := r.(*Select); ok { 299*1fa6dee9SAndroid Build Coastguard Worker // Promote l to a select so we can add r to it 300*1fa6dee9SAndroid Build Coastguard Worker l = &Select{ 301*1fa6dee9SAndroid Build Coastguard Worker Cases: []*SelectCase{{ 302*1fa6dee9SAndroid Build Coastguard Worker Value: l, 303*1fa6dee9SAndroid Build Coastguard Worker }}, 304*1fa6dee9SAndroid Build Coastguard Worker } 305*1fa6dee9SAndroid Build Coastguard Worker } 306*1fa6dee9SAndroid Build Coastguard Worker } 307*1fa6dee9SAndroid Build Coastguard Worker 308*1fa6dee9SAndroid Build Coastguard Worker l = l.Copy() 309*1fa6dee9SAndroid Build Coastguard Worker 310*1fa6dee9SAndroid Build Coastguard Worker switch v := l.(type) { 311*1fa6dee9SAndroid Build Coastguard Worker case *String: 312*1fa6dee9SAndroid Build Coastguard Worker if _, ok := r.(*String); !ok { 313*1fa6dee9SAndroid Build Coastguard Worker fmt.Fprintf(os.Stderr, "not ok") 314*1fa6dee9SAndroid Build Coastguard Worker } 315*1fa6dee9SAndroid Build Coastguard Worker v.Value += r.(*String).Value 316*1fa6dee9SAndroid Build Coastguard Worker case *Int64: 317*1fa6dee9SAndroid Build Coastguard Worker v.Value += r.(*Int64).Value 318*1fa6dee9SAndroid Build Coastguard Worker v.Token = "" 319*1fa6dee9SAndroid Build Coastguard Worker case *List: 320*1fa6dee9SAndroid Build Coastguard Worker v.Values = append(v.Values, r.(*List).Values...) 321*1fa6dee9SAndroid Build Coastguard Worker case *Map: 322*1fa6dee9SAndroid Build Coastguard Worker var err error 323*1fa6dee9SAndroid Build Coastguard Worker v.Properties, err = addMaps(scope, v.Properties, r.(*Map).Properties) 324*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 325*1fa6dee9SAndroid Build Coastguard Worker return nil, err 326*1fa6dee9SAndroid Build Coastguard Worker } 327*1fa6dee9SAndroid Build Coastguard Worker case *Select: 328*1fa6dee9SAndroid Build Coastguard Worker v.Append = r 329*1fa6dee9SAndroid Build Coastguard Worker default: 330*1fa6dee9SAndroid Build Coastguard Worker return nil, fmt.Errorf("operator %c not supported on %v", operator, v) 331*1fa6dee9SAndroid Build Coastguard Worker } 332*1fa6dee9SAndroid Build Coastguard Worker 333*1fa6dee9SAndroid Build Coastguard Worker return l, nil 334*1fa6dee9SAndroid Build Coastguard Worker} 335*1fa6dee9SAndroid Build Coastguard Worker 336*1fa6dee9SAndroid Build Coastguard Workerfunc addMaps(scope *Scope, map1, map2 []*Property) ([]*Property, error) { 337*1fa6dee9SAndroid Build Coastguard Worker ret := make([]*Property, 0, len(map1)) 338*1fa6dee9SAndroid Build Coastguard Worker 339*1fa6dee9SAndroid Build Coastguard Worker inMap1 := make(map[string]*Property) 340*1fa6dee9SAndroid Build Coastguard Worker inMap2 := make(map[string]*Property) 341*1fa6dee9SAndroid Build Coastguard Worker inBoth := make(map[string]*Property) 342*1fa6dee9SAndroid Build Coastguard Worker 343*1fa6dee9SAndroid Build Coastguard Worker for _, prop1 := range map1 { 344*1fa6dee9SAndroid Build Coastguard Worker inMap1[prop1.Name] = prop1 345*1fa6dee9SAndroid Build Coastguard Worker } 346*1fa6dee9SAndroid Build Coastguard Worker 347*1fa6dee9SAndroid Build Coastguard Worker for _, prop2 := range map2 { 348*1fa6dee9SAndroid Build Coastguard Worker inMap2[prop2.Name] = prop2 349*1fa6dee9SAndroid Build Coastguard Worker if _, ok := inMap1[prop2.Name]; ok { 350*1fa6dee9SAndroid Build Coastguard Worker inBoth[prop2.Name] = prop2 351*1fa6dee9SAndroid Build Coastguard Worker } 352*1fa6dee9SAndroid Build Coastguard Worker } 353*1fa6dee9SAndroid Build Coastguard Worker 354*1fa6dee9SAndroid Build Coastguard Worker for _, prop1 := range map1 { 355*1fa6dee9SAndroid Build Coastguard Worker if prop2, ok := inBoth[prop1.Name]; ok { 356*1fa6dee9SAndroid Build Coastguard Worker var err error 357*1fa6dee9SAndroid Build Coastguard Worker newProp := *prop1 358*1fa6dee9SAndroid Build Coastguard Worker newProp.Value, err = evaluateOperator(scope, '+', prop1.Value, prop2.Value) 359*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 360*1fa6dee9SAndroid Build Coastguard Worker return nil, err 361*1fa6dee9SAndroid Build Coastguard Worker } 362*1fa6dee9SAndroid Build Coastguard Worker ret = append(ret, &newProp) 363*1fa6dee9SAndroid Build Coastguard Worker } else { 364*1fa6dee9SAndroid Build Coastguard Worker ret = append(ret, prop1) 365*1fa6dee9SAndroid Build Coastguard Worker } 366*1fa6dee9SAndroid Build Coastguard Worker } 367*1fa6dee9SAndroid Build Coastguard Worker 368*1fa6dee9SAndroid Build Coastguard Worker for _, prop2 := range map2 { 369*1fa6dee9SAndroid Build Coastguard Worker if _, ok := inBoth[prop2.Name]; !ok { 370*1fa6dee9SAndroid Build Coastguard Worker ret = append(ret, prop2) 371*1fa6dee9SAndroid Build Coastguard Worker } 372*1fa6dee9SAndroid Build Coastguard Worker } 373*1fa6dee9SAndroid Build Coastguard Worker 374*1fa6dee9SAndroid Build Coastguard Worker return ret, nil 375*1fa6dee9SAndroid Build Coastguard Worker} 376*1fa6dee9SAndroid Build Coastguard Worker 377*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Operator) PrintfInto(value string) error { 378*1fa6dee9SAndroid Build Coastguard Worker if err := x.Args[0].PrintfInto(value); err != nil { 379*1fa6dee9SAndroid Build Coastguard Worker return err 380*1fa6dee9SAndroid Build Coastguard Worker } 381*1fa6dee9SAndroid Build Coastguard Worker return x.Args[1].PrintfInto(value) 382*1fa6dee9SAndroid Build Coastguard Worker} 383*1fa6dee9SAndroid Build Coastguard Worker 384*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Operator) MarkReferencedVariables(scope *Scope) { 385*1fa6dee9SAndroid Build Coastguard Worker x.Args[0].MarkReferencedVariables(scope) 386*1fa6dee9SAndroid Build Coastguard Worker x.Args[1].MarkReferencedVariables(scope) 387*1fa6dee9SAndroid Build Coastguard Worker} 388*1fa6dee9SAndroid Build Coastguard Worker 389*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Operator) Pos() scanner.Position { return x.Args[0].Pos() } 390*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Operator) End() scanner.Position { return x.Args[1].End() } 391*1fa6dee9SAndroid Build Coastguard Worker 392*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Operator) String() string { 393*1fa6dee9SAndroid Build Coastguard Worker return fmt.Sprintf("(%s %c %s)@%s", x.Args[0].String(), x.Operator, x.Args[1].String(), 394*1fa6dee9SAndroid Build Coastguard Worker x.OperatorPos) 395*1fa6dee9SAndroid Build Coastguard Worker} 396*1fa6dee9SAndroid Build Coastguard Worker 397*1fa6dee9SAndroid Build Coastguard Workertype Variable struct { 398*1fa6dee9SAndroid Build Coastguard Worker Name string 399*1fa6dee9SAndroid Build Coastguard Worker NamePos scanner.Position 400*1fa6dee9SAndroid Build Coastguard Worker Type_ Type 401*1fa6dee9SAndroid Build Coastguard Worker} 402*1fa6dee9SAndroid Build Coastguard Worker 403*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Variable) Pos() scanner.Position { return x.NamePos } 404*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Variable) End() scanner.Position { return endPos(x.NamePos, len(x.Name)) } 405*1fa6dee9SAndroid Build Coastguard Worker 406*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Variable) Copy() Expression { 407*1fa6dee9SAndroid Build Coastguard Worker ret := *x 408*1fa6dee9SAndroid Build Coastguard Worker return &ret 409*1fa6dee9SAndroid Build Coastguard Worker} 410*1fa6dee9SAndroid Build Coastguard Worker 411*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Variable) Eval(scope *Scope) (Expression, error) { 412*1fa6dee9SAndroid Build Coastguard Worker if assignment := scope.Get(x.Name); assignment != nil { 413*1fa6dee9SAndroid Build Coastguard Worker assignment.Referenced = true 414*1fa6dee9SAndroid Build Coastguard Worker return assignment.Value, nil 415*1fa6dee9SAndroid Build Coastguard Worker } 416*1fa6dee9SAndroid Build Coastguard Worker return nil, fmt.Errorf("undefined variable %s", x.Name) 417*1fa6dee9SAndroid Build Coastguard Worker} 418*1fa6dee9SAndroid Build Coastguard Worker 419*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Variable) PrintfInto(value string) error { 420*1fa6dee9SAndroid Build Coastguard Worker return nil 421*1fa6dee9SAndroid Build Coastguard Worker} 422*1fa6dee9SAndroid Build Coastguard Worker 423*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Variable) MarkReferencedVariables(scope *Scope) { 424*1fa6dee9SAndroid Build Coastguard Worker if assignment := scope.Get(x.Name); assignment != nil { 425*1fa6dee9SAndroid Build Coastguard Worker assignment.Referenced = true 426*1fa6dee9SAndroid Build Coastguard Worker } 427*1fa6dee9SAndroid Build Coastguard Worker} 428*1fa6dee9SAndroid Build Coastguard Worker 429*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Variable) String() string { 430*1fa6dee9SAndroid Build Coastguard Worker return x.Name 431*1fa6dee9SAndroid Build Coastguard Worker} 432*1fa6dee9SAndroid Build Coastguard Worker 433*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Variable) Type() Type { 434*1fa6dee9SAndroid Build Coastguard Worker // Variables do not normally have a type associated with them, this is only 435*1fa6dee9SAndroid Build Coastguard Worker // filled out in the androidmk tool 436*1fa6dee9SAndroid Build Coastguard Worker return x.Type_ 437*1fa6dee9SAndroid Build Coastguard Worker} 438*1fa6dee9SAndroid Build Coastguard Worker 439*1fa6dee9SAndroid Build Coastguard Workertype Map struct { 440*1fa6dee9SAndroid Build Coastguard Worker LBracePos scanner.Position 441*1fa6dee9SAndroid Build Coastguard Worker RBracePos scanner.Position 442*1fa6dee9SAndroid Build Coastguard Worker Properties []*Property 443*1fa6dee9SAndroid Build Coastguard Worker} 444*1fa6dee9SAndroid Build Coastguard Worker 445*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Map) Pos() scanner.Position { return x.LBracePos } 446*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Map) End() scanner.Position { return endPos(x.RBracePos, 1) } 447*1fa6dee9SAndroid Build Coastguard Worker 448*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Map) Copy() Expression { 449*1fa6dee9SAndroid Build Coastguard Worker ret := *x 450*1fa6dee9SAndroid Build Coastguard Worker ret.Properties = make([]*Property, len(x.Properties)) 451*1fa6dee9SAndroid Build Coastguard Worker for i := range x.Properties { 452*1fa6dee9SAndroid Build Coastguard Worker ret.Properties[i] = x.Properties[i].Copy() 453*1fa6dee9SAndroid Build Coastguard Worker } 454*1fa6dee9SAndroid Build Coastguard Worker return &ret 455*1fa6dee9SAndroid Build Coastguard Worker} 456*1fa6dee9SAndroid Build Coastguard Worker 457*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Map) Eval(scope *Scope) (Expression, error) { 458*1fa6dee9SAndroid Build Coastguard Worker newProps := make([]*Property, len(x.Properties)) 459*1fa6dee9SAndroid Build Coastguard Worker for i, prop := range x.Properties { 460*1fa6dee9SAndroid Build Coastguard Worker newVal, err := prop.Value.Eval(scope) 461*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 462*1fa6dee9SAndroid Build Coastguard Worker return nil, err 463*1fa6dee9SAndroid Build Coastguard Worker } 464*1fa6dee9SAndroid Build Coastguard Worker newProps[i] = &Property{ 465*1fa6dee9SAndroid Build Coastguard Worker Name: prop.Name, 466*1fa6dee9SAndroid Build Coastguard Worker NamePos: prop.NamePos, 467*1fa6dee9SAndroid Build Coastguard Worker ColonPos: prop.ColonPos, 468*1fa6dee9SAndroid Build Coastguard Worker Value: newVal, 469*1fa6dee9SAndroid Build Coastguard Worker } 470*1fa6dee9SAndroid Build Coastguard Worker } 471*1fa6dee9SAndroid Build Coastguard Worker return &Map{ 472*1fa6dee9SAndroid Build Coastguard Worker LBracePos: x.LBracePos, 473*1fa6dee9SAndroid Build Coastguard Worker RBracePos: x.RBracePos, 474*1fa6dee9SAndroid Build Coastguard Worker Properties: newProps, 475*1fa6dee9SAndroid Build Coastguard Worker }, nil 476*1fa6dee9SAndroid Build Coastguard Worker} 477*1fa6dee9SAndroid Build Coastguard Worker 478*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Map) PrintfInto(value string) error { 479*1fa6dee9SAndroid Build Coastguard Worker // We should never reach this because selects cannot hold maps 480*1fa6dee9SAndroid Build Coastguard Worker panic("printfinto() is unsupported on maps") 481*1fa6dee9SAndroid Build Coastguard Worker} 482*1fa6dee9SAndroid Build Coastguard Worker 483*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Map) MarkReferencedVariables(scope *Scope) { 484*1fa6dee9SAndroid Build Coastguard Worker for _, prop := range x.Properties { 485*1fa6dee9SAndroid Build Coastguard Worker prop.MarkReferencedVariables(scope) 486*1fa6dee9SAndroid Build Coastguard Worker } 487*1fa6dee9SAndroid Build Coastguard Worker} 488*1fa6dee9SAndroid Build Coastguard Worker 489*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Map) String() string { 490*1fa6dee9SAndroid Build Coastguard Worker propertyStrings := make([]string, len(x.Properties)) 491*1fa6dee9SAndroid Build Coastguard Worker for i, property := range x.Properties { 492*1fa6dee9SAndroid Build Coastguard Worker propertyStrings[i] = property.String() 493*1fa6dee9SAndroid Build Coastguard Worker } 494*1fa6dee9SAndroid Build Coastguard Worker return fmt.Sprintf("@%s-%s{%s}", x.LBracePos, x.RBracePos, 495*1fa6dee9SAndroid Build Coastguard Worker strings.Join(propertyStrings, ", ")) 496*1fa6dee9SAndroid Build Coastguard Worker} 497*1fa6dee9SAndroid Build Coastguard Worker 498*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Map) Type() Type { return MapType } 499*1fa6dee9SAndroid Build Coastguard Worker 500*1fa6dee9SAndroid Build Coastguard Worker// GetProperty looks for a property with the given name. 501*1fa6dee9SAndroid Build Coastguard Worker// It resembles the bracket operator of a built-in Golang map. 502*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Map) GetProperty(name string) (Property *Property, found bool) { 503*1fa6dee9SAndroid Build Coastguard Worker prop, found, _ := x.getPropertyImpl(name) 504*1fa6dee9SAndroid Build Coastguard Worker return prop, found // we don't currently expose the index to callers 505*1fa6dee9SAndroid Build Coastguard Worker} 506*1fa6dee9SAndroid Build Coastguard Worker 507*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Map) getPropertyImpl(name string) (Property *Property, found bool, index int) { 508*1fa6dee9SAndroid Build Coastguard Worker for i, prop := range x.Properties { 509*1fa6dee9SAndroid Build Coastguard Worker if prop.Name == name { 510*1fa6dee9SAndroid Build Coastguard Worker return prop, true, i 511*1fa6dee9SAndroid Build Coastguard Worker } 512*1fa6dee9SAndroid Build Coastguard Worker } 513*1fa6dee9SAndroid Build Coastguard Worker return nil, false, -1 514*1fa6dee9SAndroid Build Coastguard Worker} 515*1fa6dee9SAndroid Build Coastguard Worker 516*1fa6dee9SAndroid Build Coastguard Worker// RemoveProperty removes the property with the given name, if it exists. 517*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Map) RemoveProperty(propertyName string) (removed bool) { 518*1fa6dee9SAndroid Build Coastguard Worker _, found, index := x.getPropertyImpl(propertyName) 519*1fa6dee9SAndroid Build Coastguard Worker if found { 520*1fa6dee9SAndroid Build Coastguard Worker x.Properties = append(x.Properties[:index], x.Properties[index+1:]...) 521*1fa6dee9SAndroid Build Coastguard Worker } 522*1fa6dee9SAndroid Build Coastguard Worker return found 523*1fa6dee9SAndroid Build Coastguard Worker} 524*1fa6dee9SAndroid Build Coastguard Worker 525*1fa6dee9SAndroid Build Coastguard Worker// MovePropertyContents moves the contents of propertyName into property newLocation 526*1fa6dee9SAndroid Build Coastguard Worker// If property newLocation doesn't exist, MovePropertyContents renames propertyName as newLocation. 527*1fa6dee9SAndroid Build Coastguard Worker// Otherwise, MovePropertyContents only supports moving contents that are a List of String. 528*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Map) MovePropertyContents(propertyName string, newLocation string) (removed bool) { 529*1fa6dee9SAndroid Build Coastguard Worker oldProp, oldFound, _ := x.getPropertyImpl(propertyName) 530*1fa6dee9SAndroid Build Coastguard Worker newProp, newFound, _ := x.getPropertyImpl(newLocation) 531*1fa6dee9SAndroid Build Coastguard Worker 532*1fa6dee9SAndroid Build Coastguard Worker // newLoc doesn't exist, simply renaming property 533*1fa6dee9SAndroid Build Coastguard Worker if oldFound && !newFound { 534*1fa6dee9SAndroid Build Coastguard Worker oldProp.Name = newLocation 535*1fa6dee9SAndroid Build Coastguard Worker return oldFound 536*1fa6dee9SAndroid Build Coastguard Worker } 537*1fa6dee9SAndroid Build Coastguard Worker 538*1fa6dee9SAndroid Build Coastguard Worker if oldFound { 539*1fa6dee9SAndroid Build Coastguard Worker old, oldOk := oldProp.Value.(*List) 540*1fa6dee9SAndroid Build Coastguard Worker new, newOk := newProp.Value.(*List) 541*1fa6dee9SAndroid Build Coastguard Worker if oldOk && newOk { 542*1fa6dee9SAndroid Build Coastguard Worker toBeMoved := make([]string, len(old.Values)) // 543*1fa6dee9SAndroid Build Coastguard Worker for i, p := range old.Values { 544*1fa6dee9SAndroid Build Coastguard Worker toBeMoved[i] = p.(*String).Value 545*1fa6dee9SAndroid Build Coastguard Worker } 546*1fa6dee9SAndroid Build Coastguard Worker 547*1fa6dee9SAndroid Build Coastguard Worker for _, moved := range toBeMoved { 548*1fa6dee9SAndroid Build Coastguard Worker RemoveStringFromList(old, moved) 549*1fa6dee9SAndroid Build Coastguard Worker AddStringToList(new, moved) 550*1fa6dee9SAndroid Build Coastguard Worker } 551*1fa6dee9SAndroid Build Coastguard Worker // oldProp should now be empty and needs to be deleted 552*1fa6dee9SAndroid Build Coastguard Worker x.RemoveProperty(oldProp.Name) 553*1fa6dee9SAndroid Build Coastguard Worker } else { 554*1fa6dee9SAndroid Build Coastguard Worker print(`MovePropertyContents currently only supports moving PropertyName 555*1fa6dee9SAndroid Build Coastguard Worker with List of Strings into an existing newLocation with List of Strings\n`) 556*1fa6dee9SAndroid Build Coastguard Worker } 557*1fa6dee9SAndroid Build Coastguard Worker } 558*1fa6dee9SAndroid Build Coastguard Worker return oldFound 559*1fa6dee9SAndroid Build Coastguard Worker} 560*1fa6dee9SAndroid Build Coastguard Worker 561*1fa6dee9SAndroid Build Coastguard Workertype List struct { 562*1fa6dee9SAndroid Build Coastguard Worker LBracePos scanner.Position 563*1fa6dee9SAndroid Build Coastguard Worker RBracePos scanner.Position 564*1fa6dee9SAndroid Build Coastguard Worker Values []Expression 565*1fa6dee9SAndroid Build Coastguard Worker} 566*1fa6dee9SAndroid Build Coastguard Worker 567*1fa6dee9SAndroid Build Coastguard Workerfunc (x *List) Pos() scanner.Position { return x.LBracePos } 568*1fa6dee9SAndroid Build Coastguard Workerfunc (x *List) End() scanner.Position { return endPos(x.RBracePos, 1) } 569*1fa6dee9SAndroid Build Coastguard Worker 570*1fa6dee9SAndroid Build Coastguard Workerfunc (x *List) Copy() Expression { 571*1fa6dee9SAndroid Build Coastguard Worker ret := *x 572*1fa6dee9SAndroid Build Coastguard Worker ret.Values = make([]Expression, len(x.Values)) 573*1fa6dee9SAndroid Build Coastguard Worker for i := range ret.Values { 574*1fa6dee9SAndroid Build Coastguard Worker ret.Values[i] = x.Values[i].Copy() 575*1fa6dee9SAndroid Build Coastguard Worker } 576*1fa6dee9SAndroid Build Coastguard Worker return &ret 577*1fa6dee9SAndroid Build Coastguard Worker} 578*1fa6dee9SAndroid Build Coastguard Worker 579*1fa6dee9SAndroid Build Coastguard Workerfunc (x *List) Eval(scope *Scope) (Expression, error) { 580*1fa6dee9SAndroid Build Coastguard Worker newValues := make([]Expression, len(x.Values)) 581*1fa6dee9SAndroid Build Coastguard Worker for i, val := range x.Values { 582*1fa6dee9SAndroid Build Coastguard Worker newVal, err := val.Eval(scope) 583*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 584*1fa6dee9SAndroid Build Coastguard Worker return nil, err 585*1fa6dee9SAndroid Build Coastguard Worker } 586*1fa6dee9SAndroid Build Coastguard Worker newValues[i] = newVal 587*1fa6dee9SAndroid Build Coastguard Worker } 588*1fa6dee9SAndroid Build Coastguard Worker return &List{ 589*1fa6dee9SAndroid Build Coastguard Worker LBracePos: x.LBracePos, 590*1fa6dee9SAndroid Build Coastguard Worker RBracePos: x.RBracePos, 591*1fa6dee9SAndroid Build Coastguard Worker Values: newValues, 592*1fa6dee9SAndroid Build Coastguard Worker }, nil 593*1fa6dee9SAndroid Build Coastguard Worker} 594*1fa6dee9SAndroid Build Coastguard Worker 595*1fa6dee9SAndroid Build Coastguard Workerfunc (x *List) PrintfInto(value string) error { 596*1fa6dee9SAndroid Build Coastguard Worker for _, val := range x.Values { 597*1fa6dee9SAndroid Build Coastguard Worker if err := val.PrintfInto(value); err != nil { 598*1fa6dee9SAndroid Build Coastguard Worker return err 599*1fa6dee9SAndroid Build Coastguard Worker } 600*1fa6dee9SAndroid Build Coastguard Worker } 601*1fa6dee9SAndroid Build Coastguard Worker return nil 602*1fa6dee9SAndroid Build Coastguard Worker} 603*1fa6dee9SAndroid Build Coastguard Worker 604*1fa6dee9SAndroid Build Coastguard Workerfunc (x *List) MarkReferencedVariables(scope *Scope) { 605*1fa6dee9SAndroid Build Coastguard Worker for _, val := range x.Values { 606*1fa6dee9SAndroid Build Coastguard Worker val.MarkReferencedVariables(scope) 607*1fa6dee9SAndroid Build Coastguard Worker } 608*1fa6dee9SAndroid Build Coastguard Worker} 609*1fa6dee9SAndroid Build Coastguard Worker 610*1fa6dee9SAndroid Build Coastguard Workerfunc (x *List) String() string { 611*1fa6dee9SAndroid Build Coastguard Worker valueStrings := make([]string, len(x.Values)) 612*1fa6dee9SAndroid Build Coastguard Worker for i, value := range x.Values { 613*1fa6dee9SAndroid Build Coastguard Worker valueStrings[i] = value.String() 614*1fa6dee9SAndroid Build Coastguard Worker } 615*1fa6dee9SAndroid Build Coastguard Worker return fmt.Sprintf("@%s-%s[%s]", x.LBracePos, x.RBracePos, 616*1fa6dee9SAndroid Build Coastguard Worker strings.Join(valueStrings, ", ")) 617*1fa6dee9SAndroid Build Coastguard Worker} 618*1fa6dee9SAndroid Build Coastguard Worker 619*1fa6dee9SAndroid Build Coastguard Workerfunc (x *List) Type() Type { return ListType } 620*1fa6dee9SAndroid Build Coastguard Worker 621*1fa6dee9SAndroid Build Coastguard Workertype String struct { 622*1fa6dee9SAndroid Build Coastguard Worker LiteralPos scanner.Position 623*1fa6dee9SAndroid Build Coastguard Worker Value string 624*1fa6dee9SAndroid Build Coastguard Worker} 625*1fa6dee9SAndroid Build Coastguard Worker 626*1fa6dee9SAndroid Build Coastguard Workerfunc (x *String) Pos() scanner.Position { return x.LiteralPos } 627*1fa6dee9SAndroid Build Coastguard Workerfunc (x *String) End() scanner.Position { return endPos(x.LiteralPos, len(x.Value)+2) } 628*1fa6dee9SAndroid Build Coastguard Worker 629*1fa6dee9SAndroid Build Coastguard Workerfunc (x *String) Copy() Expression { 630*1fa6dee9SAndroid Build Coastguard Worker ret := *x 631*1fa6dee9SAndroid Build Coastguard Worker return &ret 632*1fa6dee9SAndroid Build Coastguard Worker} 633*1fa6dee9SAndroid Build Coastguard Worker 634*1fa6dee9SAndroid Build Coastguard Workerfunc (x *String) Eval(scope *Scope) (Expression, error) { 635*1fa6dee9SAndroid Build Coastguard Worker return x, nil 636*1fa6dee9SAndroid Build Coastguard Worker} 637*1fa6dee9SAndroid Build Coastguard Worker 638*1fa6dee9SAndroid Build Coastguard Workerfunc (x *String) PrintfInto(value string) error { 639*1fa6dee9SAndroid Build Coastguard Worker count := strings.Count(x.Value, "%") 640*1fa6dee9SAndroid Build Coastguard Worker if count == 0 { 641*1fa6dee9SAndroid Build Coastguard Worker return nil 642*1fa6dee9SAndroid Build Coastguard Worker } 643*1fa6dee9SAndroid Build Coastguard Worker 644*1fa6dee9SAndroid Build Coastguard Worker if count > 1 { 645*1fa6dee9SAndroid Build Coastguard Worker return fmt.Errorf("list/value variable properties only support a single '%%'") 646*1fa6dee9SAndroid Build Coastguard Worker } 647*1fa6dee9SAndroid Build Coastguard Worker 648*1fa6dee9SAndroid Build Coastguard Worker if !strings.Contains(x.Value, "%s") { 649*1fa6dee9SAndroid Build Coastguard Worker return fmt.Errorf("unsupported %% in value variable property") 650*1fa6dee9SAndroid Build Coastguard Worker } 651*1fa6dee9SAndroid Build Coastguard Worker 652*1fa6dee9SAndroid Build Coastguard Worker x.Value = fmt.Sprintf(x.Value, value) 653*1fa6dee9SAndroid Build Coastguard Worker return nil 654*1fa6dee9SAndroid Build Coastguard Worker} 655*1fa6dee9SAndroid Build Coastguard Worker 656*1fa6dee9SAndroid Build Coastguard Workerfunc (x *String) MarkReferencedVariables(scope *Scope) { 657*1fa6dee9SAndroid Build Coastguard Worker} 658*1fa6dee9SAndroid Build Coastguard Worker 659*1fa6dee9SAndroid Build Coastguard Workerfunc (x *String) String() string { 660*1fa6dee9SAndroid Build Coastguard Worker return fmt.Sprintf("%q@%s", x.Value, x.LiteralPos) 661*1fa6dee9SAndroid Build Coastguard Worker} 662*1fa6dee9SAndroid Build Coastguard Worker 663*1fa6dee9SAndroid Build Coastguard Workerfunc (x *String) Type() Type { 664*1fa6dee9SAndroid Build Coastguard Worker return StringType 665*1fa6dee9SAndroid Build Coastguard Worker} 666*1fa6dee9SAndroid Build Coastguard Worker 667*1fa6dee9SAndroid Build Coastguard Workertype Int64 struct { 668*1fa6dee9SAndroid Build Coastguard Worker LiteralPos scanner.Position 669*1fa6dee9SAndroid Build Coastguard Worker Value int64 670*1fa6dee9SAndroid Build Coastguard Worker Token string 671*1fa6dee9SAndroid Build Coastguard Worker} 672*1fa6dee9SAndroid Build Coastguard Worker 673*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Int64) Pos() scanner.Position { return x.LiteralPos } 674*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Int64) End() scanner.Position { return endPos(x.LiteralPos, len(x.Token)) } 675*1fa6dee9SAndroid Build Coastguard Worker 676*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Int64) Copy() Expression { 677*1fa6dee9SAndroid Build Coastguard Worker ret := *x 678*1fa6dee9SAndroid Build Coastguard Worker return &ret 679*1fa6dee9SAndroid Build Coastguard Worker} 680*1fa6dee9SAndroid Build Coastguard Worker 681*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Int64) Eval(scope *Scope) (Expression, error) { 682*1fa6dee9SAndroid Build Coastguard Worker return x, nil 683*1fa6dee9SAndroid Build Coastguard Worker} 684*1fa6dee9SAndroid Build Coastguard Worker 685*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Int64) PrintfInto(value string) error { 686*1fa6dee9SAndroid Build Coastguard Worker return nil 687*1fa6dee9SAndroid Build Coastguard Worker} 688*1fa6dee9SAndroid Build Coastguard Worker 689*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Int64) MarkReferencedVariables(scope *Scope) { 690*1fa6dee9SAndroid Build Coastguard Worker} 691*1fa6dee9SAndroid Build Coastguard Worker 692*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Int64) String() string { 693*1fa6dee9SAndroid Build Coastguard Worker return fmt.Sprintf("%q@%s", x.Value, x.LiteralPos) 694*1fa6dee9SAndroid Build Coastguard Worker} 695*1fa6dee9SAndroid Build Coastguard Worker 696*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Int64) Type() Type { 697*1fa6dee9SAndroid Build Coastguard Worker return Int64Type 698*1fa6dee9SAndroid Build Coastguard Worker} 699*1fa6dee9SAndroid Build Coastguard Worker 700*1fa6dee9SAndroid Build Coastguard Workertype Bool struct { 701*1fa6dee9SAndroid Build Coastguard Worker LiteralPos scanner.Position 702*1fa6dee9SAndroid Build Coastguard Worker Value bool 703*1fa6dee9SAndroid Build Coastguard Worker Token string 704*1fa6dee9SAndroid Build Coastguard Worker} 705*1fa6dee9SAndroid Build Coastguard Worker 706*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Bool) Pos() scanner.Position { return x.LiteralPos } 707*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Bool) End() scanner.Position { return endPos(x.LiteralPos, len(x.Token)) } 708*1fa6dee9SAndroid Build Coastguard Worker 709*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Bool) Copy() Expression { 710*1fa6dee9SAndroid Build Coastguard Worker ret := *x 711*1fa6dee9SAndroid Build Coastguard Worker return &ret 712*1fa6dee9SAndroid Build Coastguard Worker} 713*1fa6dee9SAndroid Build Coastguard Worker 714*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Bool) Eval(scope *Scope) (Expression, error) { 715*1fa6dee9SAndroid Build Coastguard Worker return x, nil 716*1fa6dee9SAndroid Build Coastguard Worker} 717*1fa6dee9SAndroid Build Coastguard Worker 718*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Bool) PrintfInto(value string) error { 719*1fa6dee9SAndroid Build Coastguard Worker return nil 720*1fa6dee9SAndroid Build Coastguard Worker} 721*1fa6dee9SAndroid Build Coastguard Worker 722*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Bool) MarkReferencedVariables(scope *Scope) { 723*1fa6dee9SAndroid Build Coastguard Worker} 724*1fa6dee9SAndroid Build Coastguard Worker 725*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Bool) String() string { 726*1fa6dee9SAndroid Build Coastguard Worker return fmt.Sprintf("%t@%s", x.Value, x.LiteralPos) 727*1fa6dee9SAndroid Build Coastguard Worker} 728*1fa6dee9SAndroid Build Coastguard Worker 729*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Bool) Type() Type { 730*1fa6dee9SAndroid Build Coastguard Worker return BoolType 731*1fa6dee9SAndroid Build Coastguard Worker} 732*1fa6dee9SAndroid Build Coastguard Worker 733*1fa6dee9SAndroid Build Coastguard Workertype CommentGroup struct { 734*1fa6dee9SAndroid Build Coastguard Worker Comments []*Comment 735*1fa6dee9SAndroid Build Coastguard Worker} 736*1fa6dee9SAndroid Build Coastguard Worker 737*1fa6dee9SAndroid Build Coastguard Workerfunc (x *CommentGroup) Pos() scanner.Position { return x.Comments[0].Pos() } 738*1fa6dee9SAndroid Build Coastguard Workerfunc (x *CommentGroup) End() scanner.Position { return x.Comments[len(x.Comments)-1].End() } 739*1fa6dee9SAndroid Build Coastguard Worker 740*1fa6dee9SAndroid Build Coastguard Workertype Comment struct { 741*1fa6dee9SAndroid Build Coastguard Worker Comment []string 742*1fa6dee9SAndroid Build Coastguard Worker Slash scanner.Position 743*1fa6dee9SAndroid Build Coastguard Worker} 744*1fa6dee9SAndroid Build Coastguard Worker 745*1fa6dee9SAndroid Build Coastguard Workerfunc (c Comment) Pos() scanner.Position { 746*1fa6dee9SAndroid Build Coastguard Worker return c.Slash 747*1fa6dee9SAndroid Build Coastguard Worker} 748*1fa6dee9SAndroid Build Coastguard Worker 749*1fa6dee9SAndroid Build Coastguard Workerfunc (c Comment) End() scanner.Position { 750*1fa6dee9SAndroid Build Coastguard Worker pos := c.Slash 751*1fa6dee9SAndroid Build Coastguard Worker for _, comment := range c.Comment { 752*1fa6dee9SAndroid Build Coastguard Worker pos.Offset += len(comment) + 1 753*1fa6dee9SAndroid Build Coastguard Worker pos.Column = len(comment) + 1 754*1fa6dee9SAndroid Build Coastguard Worker } 755*1fa6dee9SAndroid Build Coastguard Worker pos.Line += len(c.Comment) - 1 756*1fa6dee9SAndroid Build Coastguard Worker return pos 757*1fa6dee9SAndroid Build Coastguard Worker} 758*1fa6dee9SAndroid Build Coastguard Worker 759*1fa6dee9SAndroid Build Coastguard Workerfunc (c Comment) String() string { 760*1fa6dee9SAndroid Build Coastguard Worker l := 0 761*1fa6dee9SAndroid Build Coastguard Worker for _, comment := range c.Comment { 762*1fa6dee9SAndroid Build Coastguard Worker l += len(comment) + 1 763*1fa6dee9SAndroid Build Coastguard Worker } 764*1fa6dee9SAndroid Build Coastguard Worker buf := make([]byte, 0, l) 765*1fa6dee9SAndroid Build Coastguard Worker for _, comment := range c.Comment { 766*1fa6dee9SAndroid Build Coastguard Worker buf = append(buf, comment...) 767*1fa6dee9SAndroid Build Coastguard Worker buf = append(buf, '\n') 768*1fa6dee9SAndroid Build Coastguard Worker } 769*1fa6dee9SAndroid Build Coastguard Worker 770*1fa6dee9SAndroid Build Coastguard Worker return string(buf) + "@" + c.Slash.String() 771*1fa6dee9SAndroid Build Coastguard Worker} 772*1fa6dee9SAndroid Build Coastguard Worker 773*1fa6dee9SAndroid Build Coastguard Worker// Return the text of the comment with // or /* and */ stripped 774*1fa6dee9SAndroid Build Coastguard Workerfunc (c Comment) Text() string { 775*1fa6dee9SAndroid Build Coastguard Worker l := 0 776*1fa6dee9SAndroid Build Coastguard Worker for _, comment := range c.Comment { 777*1fa6dee9SAndroid Build Coastguard Worker l += len(comment) + 1 778*1fa6dee9SAndroid Build Coastguard Worker } 779*1fa6dee9SAndroid Build Coastguard Worker buf := make([]byte, 0, l) 780*1fa6dee9SAndroid Build Coastguard Worker 781*1fa6dee9SAndroid Build Coastguard Worker blockComment := false 782*1fa6dee9SAndroid Build Coastguard Worker if strings.HasPrefix(c.Comment[0], "/*") { 783*1fa6dee9SAndroid Build Coastguard Worker blockComment = true 784*1fa6dee9SAndroid Build Coastguard Worker } 785*1fa6dee9SAndroid Build Coastguard Worker 786*1fa6dee9SAndroid Build Coastguard Worker for i, comment := range c.Comment { 787*1fa6dee9SAndroid Build Coastguard Worker if blockComment { 788*1fa6dee9SAndroid Build Coastguard Worker if i == 0 { 789*1fa6dee9SAndroid Build Coastguard Worker comment = strings.TrimPrefix(comment, "/*") 790*1fa6dee9SAndroid Build Coastguard Worker } 791*1fa6dee9SAndroid Build Coastguard Worker if i == len(c.Comment)-1 { 792*1fa6dee9SAndroid Build Coastguard Worker comment = strings.TrimSuffix(comment, "*/") 793*1fa6dee9SAndroid Build Coastguard Worker } 794*1fa6dee9SAndroid Build Coastguard Worker } else { 795*1fa6dee9SAndroid Build Coastguard Worker comment = strings.TrimPrefix(comment, "//") 796*1fa6dee9SAndroid Build Coastguard Worker } 797*1fa6dee9SAndroid Build Coastguard Worker buf = append(buf, comment...) 798*1fa6dee9SAndroid Build Coastguard Worker buf = append(buf, '\n') 799*1fa6dee9SAndroid Build Coastguard Worker } 800*1fa6dee9SAndroid Build Coastguard Worker 801*1fa6dee9SAndroid Build Coastguard Worker return string(buf) 802*1fa6dee9SAndroid Build Coastguard Worker} 803*1fa6dee9SAndroid Build Coastguard Worker 804*1fa6dee9SAndroid Build Coastguard Workerfunc endPos(pos scanner.Position, n int) scanner.Position { 805*1fa6dee9SAndroid Build Coastguard Worker pos.Offset += n 806*1fa6dee9SAndroid Build Coastguard Worker pos.Column += n 807*1fa6dee9SAndroid Build Coastguard Worker return pos 808*1fa6dee9SAndroid Build Coastguard Worker} 809*1fa6dee9SAndroid Build Coastguard Worker 810*1fa6dee9SAndroid Build Coastguard Workertype ConfigurableCondition struct { 811*1fa6dee9SAndroid Build Coastguard Worker position scanner.Position 812*1fa6dee9SAndroid Build Coastguard Worker FunctionName string 813*1fa6dee9SAndroid Build Coastguard Worker Args []String 814*1fa6dee9SAndroid Build Coastguard Worker} 815*1fa6dee9SAndroid Build Coastguard Worker 816*1fa6dee9SAndroid Build Coastguard Workerfunc (c *ConfigurableCondition) Equals(other ConfigurableCondition) bool { 817*1fa6dee9SAndroid Build Coastguard Worker if c.FunctionName != other.FunctionName { 818*1fa6dee9SAndroid Build Coastguard Worker return false 819*1fa6dee9SAndroid Build Coastguard Worker } 820*1fa6dee9SAndroid Build Coastguard Worker if len(c.Args) != len(other.Args) { 821*1fa6dee9SAndroid Build Coastguard Worker return false 822*1fa6dee9SAndroid Build Coastguard Worker } 823*1fa6dee9SAndroid Build Coastguard Worker for i := range c.Args { 824*1fa6dee9SAndroid Build Coastguard Worker if c.Args[i] != other.Args[i] { 825*1fa6dee9SAndroid Build Coastguard Worker return false 826*1fa6dee9SAndroid Build Coastguard Worker } 827*1fa6dee9SAndroid Build Coastguard Worker } 828*1fa6dee9SAndroid Build Coastguard Worker return true 829*1fa6dee9SAndroid Build Coastguard Worker} 830*1fa6dee9SAndroid Build Coastguard Worker 831*1fa6dee9SAndroid Build Coastguard Workerfunc (c *ConfigurableCondition) String() string { 832*1fa6dee9SAndroid Build Coastguard Worker var sb strings.Builder 833*1fa6dee9SAndroid Build Coastguard Worker sb.WriteString(c.FunctionName) 834*1fa6dee9SAndroid Build Coastguard Worker sb.WriteRune('(') 835*1fa6dee9SAndroid Build Coastguard Worker for i, arg := range c.Args { 836*1fa6dee9SAndroid Build Coastguard Worker sb.WriteRune('"') 837*1fa6dee9SAndroid Build Coastguard Worker sb.WriteString(arg.Value) 838*1fa6dee9SAndroid Build Coastguard Worker sb.WriteRune('"') 839*1fa6dee9SAndroid Build Coastguard Worker if i < len(c.Args)-1 { 840*1fa6dee9SAndroid Build Coastguard Worker sb.WriteString(", ") 841*1fa6dee9SAndroid Build Coastguard Worker } 842*1fa6dee9SAndroid Build Coastguard Worker } 843*1fa6dee9SAndroid Build Coastguard Worker sb.WriteRune(')') 844*1fa6dee9SAndroid Build Coastguard Worker return sb.String() 845*1fa6dee9SAndroid Build Coastguard Worker} 846*1fa6dee9SAndroid Build Coastguard Worker 847*1fa6dee9SAndroid Build Coastguard Workertype Select struct { 848*1fa6dee9SAndroid Build Coastguard Worker Scope *Scope // scope used to evaluate the body of the select later on 849*1fa6dee9SAndroid Build Coastguard Worker KeywordPos scanner.Position // the keyword "select" 850*1fa6dee9SAndroid Build Coastguard Worker Conditions []ConfigurableCondition 851*1fa6dee9SAndroid Build Coastguard Worker LBracePos scanner.Position 852*1fa6dee9SAndroid Build Coastguard Worker RBracePos scanner.Position 853*1fa6dee9SAndroid Build Coastguard Worker Cases []*SelectCase // the case statements 854*1fa6dee9SAndroid Build Coastguard Worker Append Expression 855*1fa6dee9SAndroid Build Coastguard Worker} 856*1fa6dee9SAndroid Build Coastguard Worker 857*1fa6dee9SAndroid Build Coastguard Workerfunc (s *Select) Pos() scanner.Position { return s.KeywordPos } 858*1fa6dee9SAndroid Build Coastguard Workerfunc (s *Select) End() scanner.Position { return endPos(s.RBracePos, 1) } 859*1fa6dee9SAndroid Build Coastguard Worker 860*1fa6dee9SAndroid Build Coastguard Workerfunc (s *Select) Copy() Expression { 861*1fa6dee9SAndroid Build Coastguard Worker ret := *s 862*1fa6dee9SAndroid Build Coastguard Worker ret.Cases = make([]*SelectCase, len(ret.Cases)) 863*1fa6dee9SAndroid Build Coastguard Worker for i, selectCase := range s.Cases { 864*1fa6dee9SAndroid Build Coastguard Worker ret.Cases[i] = selectCase.Copy() 865*1fa6dee9SAndroid Build Coastguard Worker } 866*1fa6dee9SAndroid Build Coastguard Worker if s.Append != nil { 867*1fa6dee9SAndroid Build Coastguard Worker ret.Append = s.Append.Copy() 868*1fa6dee9SAndroid Build Coastguard Worker } 869*1fa6dee9SAndroid Build Coastguard Worker return &ret 870*1fa6dee9SAndroid Build Coastguard Worker} 871*1fa6dee9SAndroid Build Coastguard Worker 872*1fa6dee9SAndroid Build Coastguard Workerfunc (s *Select) Eval(scope *Scope) (Expression, error) { 873*1fa6dee9SAndroid Build Coastguard Worker s.Scope = scope 874*1fa6dee9SAndroid Build Coastguard Worker s.MarkReferencedVariables(scope) 875*1fa6dee9SAndroid Build Coastguard Worker return s, nil 876*1fa6dee9SAndroid Build Coastguard Worker} 877*1fa6dee9SAndroid Build Coastguard Worker 878*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Select) PrintfInto(value string) error { 879*1fa6dee9SAndroid Build Coastguard Worker // PrintfInto will be handled at the Configurable object level 880*1fa6dee9SAndroid Build Coastguard Worker panic("Cannot call PrintfInto on a select expression") 881*1fa6dee9SAndroid Build Coastguard Worker} 882*1fa6dee9SAndroid Build Coastguard Worker 883*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Select) MarkReferencedVariables(scope *Scope) { 884*1fa6dee9SAndroid Build Coastguard Worker for _, c := range x.Cases { 885*1fa6dee9SAndroid Build Coastguard Worker c.MarkReferencedVariables(scope) 886*1fa6dee9SAndroid Build Coastguard Worker } 887*1fa6dee9SAndroid Build Coastguard Worker if x.Append != nil { 888*1fa6dee9SAndroid Build Coastguard Worker x.Append.MarkReferencedVariables(scope) 889*1fa6dee9SAndroid Build Coastguard Worker } 890*1fa6dee9SAndroid Build Coastguard Worker} 891*1fa6dee9SAndroid Build Coastguard Worker 892*1fa6dee9SAndroid Build Coastguard Workerfunc (s *Select) String() string { 893*1fa6dee9SAndroid Build Coastguard Worker return "<select>" 894*1fa6dee9SAndroid Build Coastguard Worker} 895*1fa6dee9SAndroid Build Coastguard Worker 896*1fa6dee9SAndroid Build Coastguard Workerfunc (s *Select) Type() Type { 897*1fa6dee9SAndroid Build Coastguard Worker if len(s.Cases) == 0 { 898*1fa6dee9SAndroid Build Coastguard Worker return UnsetType 899*1fa6dee9SAndroid Build Coastguard Worker } 900*1fa6dee9SAndroid Build Coastguard Worker return UnknownType 901*1fa6dee9SAndroid Build Coastguard Worker} 902*1fa6dee9SAndroid Build Coastguard Worker 903*1fa6dee9SAndroid Build Coastguard Workertype SelectPattern struct { 904*1fa6dee9SAndroid Build Coastguard Worker Value Expression 905*1fa6dee9SAndroid Build Coastguard Worker Binding Variable 906*1fa6dee9SAndroid Build Coastguard Worker} 907*1fa6dee9SAndroid Build Coastguard Worker 908*1fa6dee9SAndroid Build Coastguard Workerfunc (c *SelectPattern) Pos() scanner.Position { return c.Value.Pos() } 909*1fa6dee9SAndroid Build Coastguard Workerfunc (c *SelectPattern) End() scanner.Position { 910*1fa6dee9SAndroid Build Coastguard Worker if c.Binding.NamePos.IsValid() { 911*1fa6dee9SAndroid Build Coastguard Worker return c.Binding.End() 912*1fa6dee9SAndroid Build Coastguard Worker } 913*1fa6dee9SAndroid Build Coastguard Worker return c.Value.End() 914*1fa6dee9SAndroid Build Coastguard Worker} 915*1fa6dee9SAndroid Build Coastguard Worker 916*1fa6dee9SAndroid Build Coastguard Workertype SelectCase struct { 917*1fa6dee9SAndroid Build Coastguard Worker Patterns []SelectPattern 918*1fa6dee9SAndroid Build Coastguard Worker ColonPos scanner.Position 919*1fa6dee9SAndroid Build Coastguard Worker Value Expression 920*1fa6dee9SAndroid Build Coastguard Worker} 921*1fa6dee9SAndroid Build Coastguard Worker 922*1fa6dee9SAndroid Build Coastguard Workerfunc (x *SelectCase) MarkReferencedVariables(scope *Scope) { 923*1fa6dee9SAndroid Build Coastguard Worker x.Value.MarkReferencedVariables(scope) 924*1fa6dee9SAndroid Build Coastguard Worker} 925*1fa6dee9SAndroid Build Coastguard Worker 926*1fa6dee9SAndroid Build Coastguard Workerfunc (c *SelectCase) Copy() *SelectCase { 927*1fa6dee9SAndroid Build Coastguard Worker ret := *c 928*1fa6dee9SAndroid Build Coastguard Worker ret.Value = c.Value.Copy() 929*1fa6dee9SAndroid Build Coastguard Worker return &ret 930*1fa6dee9SAndroid Build Coastguard Worker} 931*1fa6dee9SAndroid Build Coastguard Worker 932*1fa6dee9SAndroid Build Coastguard Workerfunc (c *SelectCase) String() string { 933*1fa6dee9SAndroid Build Coastguard Worker return "<select case>" 934*1fa6dee9SAndroid Build Coastguard Worker} 935*1fa6dee9SAndroid Build Coastguard Worker 936*1fa6dee9SAndroid Build Coastguard Workerfunc (c *SelectCase) Pos() scanner.Position { return c.Patterns[0].Pos() } 937*1fa6dee9SAndroid Build Coastguard Workerfunc (c *SelectCase) End() scanner.Position { return c.Value.End() } 938*1fa6dee9SAndroid Build Coastguard Worker 939*1fa6dee9SAndroid Build Coastguard Worker// UnsetProperty is the expression type of the "unset" keyword that can be 940*1fa6dee9SAndroid Build Coastguard Worker// used in select statements to make the property unset. For example: 941*1fa6dee9SAndroid Build Coastguard Worker// 942*1fa6dee9SAndroid Build Coastguard Worker// my_module_type { 943*1fa6dee9SAndroid Build Coastguard Worker// name: "foo", 944*1fa6dee9SAndroid Build Coastguard Worker// some_prop: select(soong_config_variable("my_namespace", "my_var"), { 945*1fa6dee9SAndroid Build Coastguard Worker// "foo": unset, 946*1fa6dee9SAndroid Build Coastguard Worker// "default": "bar", 947*1fa6dee9SAndroid Build Coastguard Worker// }) 948*1fa6dee9SAndroid Build Coastguard Worker// } 949*1fa6dee9SAndroid Build Coastguard Workertype UnsetProperty struct { 950*1fa6dee9SAndroid Build Coastguard Worker Position scanner.Position 951*1fa6dee9SAndroid Build Coastguard Worker} 952*1fa6dee9SAndroid Build Coastguard Worker 953*1fa6dee9SAndroid Build Coastguard Workerfunc (n *UnsetProperty) Copy() Expression { 954*1fa6dee9SAndroid Build Coastguard Worker return &UnsetProperty{Position: n.Position} 955*1fa6dee9SAndroid Build Coastguard Worker} 956*1fa6dee9SAndroid Build Coastguard Worker 957*1fa6dee9SAndroid Build Coastguard Workerfunc (n *UnsetProperty) String() string { 958*1fa6dee9SAndroid Build Coastguard Worker return "unset" 959*1fa6dee9SAndroid Build Coastguard Worker} 960*1fa6dee9SAndroid Build Coastguard Worker 961*1fa6dee9SAndroid Build Coastguard Workerfunc (n *UnsetProperty) Type() Type { 962*1fa6dee9SAndroid Build Coastguard Worker return UnsetType 963*1fa6dee9SAndroid Build Coastguard Worker} 964*1fa6dee9SAndroid Build Coastguard Worker 965*1fa6dee9SAndroid Build Coastguard Workerfunc (n *UnsetProperty) Eval(scope *Scope) (Expression, error) { 966*1fa6dee9SAndroid Build Coastguard Worker return n, nil 967*1fa6dee9SAndroid Build Coastguard Worker} 968*1fa6dee9SAndroid Build Coastguard Worker 969*1fa6dee9SAndroid Build Coastguard Workerfunc (x *UnsetProperty) PrintfInto(value string) error { 970*1fa6dee9SAndroid Build Coastguard Worker return nil 971*1fa6dee9SAndroid Build Coastguard Worker} 972*1fa6dee9SAndroid Build Coastguard Worker 973*1fa6dee9SAndroid Build Coastguard Workerfunc (x *UnsetProperty) MarkReferencedVariables(scope *Scope) { 974*1fa6dee9SAndroid Build Coastguard Worker} 975*1fa6dee9SAndroid Build Coastguard Worker 976*1fa6dee9SAndroid Build Coastguard Workerfunc (n *UnsetProperty) Pos() scanner.Position { return n.Position } 977*1fa6dee9SAndroid Build Coastguard Workerfunc (n *UnsetProperty) End() scanner.Position { return n.Position } 978