Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Android/build/build/blueprint/parser/   (Android Betriebssystem Version 17©)  Datei vom 26.5.2026 mit Größe 23 kB image not shown  

Quelle  ast.go   Sprache: unbekannt

 
Spracherkennung für: .go vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

// Copyright 2016 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package parser

import (
 "fmt"
 "os"
 "strings"
 "sync/atomic"
 "text/scanner"
)

type Node interface {
 // Pos returns the position of the first token in the Node
 Pos() scanner.Position
 // End returns the position of the character after the last token in the Node
 End() scanner.Position
}

// Definition is an Assignment or a Module at the top level of a Blueprints file
type Definition interface {
 Node
 String() string
 definitionTag()
}

// An Assignment is a variable assignment at the top level of a Blueprints file, scoped to the
// file and subdirs.
type Assignment struct {
 Name       string
 NamePos    scanner.Position
 Value      Expression
 EqualsPos  scanner.Position
 Assigner   string
 Referenced atomic.Bool
}

func (a *Assignment) String() string {
 return fmt.Sprintf("%s@%s %s %s %t", a.Name, a.EqualsPos, a.Assigner, a.Value, a.Referenced.Load())
}

func (a *Assignment) Pos() scanner.Position { return a.NamePos }
func (a *Assignment) End() scanner.Position { return a.Value.End() }

func (a *Assignment) definitionTag() {}

// A Module is a module definition at the top level of a Blueprints file
type Module struct {
 Type    string
 TypePos scanner.Position
 Map
 //TODO(delmerico) make this a private field once ag/21588220 lands
 Name__internal_only *string
}

func (m *Module) Copy() *Module {
 ret := *m
 ret.Properties = make([]*Property, len(m.Properties))
 for i := range m.Properties {
  ret.Properties[i] = m.Properties[i].Copy()
 }
 return &ret
}

func (m *Module) String() string {
 propertyStrings := make([]string, len(m.Properties))
 for i, property := range m.Properties {
  propertyStrings[i] = property.String()
 }
 return fmt.Sprintf("%s@%s-%s{%s}", m.Type,
  m.LBracePos, m.RBracePos,
  strings.Join(propertyStrings, ", "))
}

func (m *Module) definitionTag() {}

func (m *Module) Pos() scanner.Position { return m.TypePos }
func (m *Module) End() scanner.Position { return m.Map.End() }

func (m *Module) Name() string {
 if m.Name__internal_only != nil {
  return *m.Name__internal_only
 }
 for _, prop := range m.Properties {
  if prop.Name == "name" {
   if stringProp, ok := prop.Value.(*String); ok {
    name := stringProp.Value
    m.Name__internal_only = &name
   } else {
    name := prop.Value.String()
    m.Name__internal_only = &name
   }
  }
 }
 if m.Name__internal_only == nil {
  name := ""
  m.Name__internal_only = &name
 }
 return *m.Name__internal_only
}

// A Property is a name: value pair within a Map, which may be a top level Module.
type Property struct {
 Name     string
 NamePos  scanner.Position
 ColonPos scanner.Position
 Value    Expression
 Deleted  bool
}

func (p *Property) Copy() *Property {
 ret := *p
 ret.Value = p.Value.Copy()
 return &ret
}

func (p *Property) String() string {
 return fmt.Sprintf("%s@%s: %s", p.Name, p.ColonPos, p.Value)
}

func (p *Property) Pos() scanner.Position { return p.NamePos }
func (p *Property) End() scanner.Position { return p.Value.End() }

func (p *Property) MarkReferencedVariables(scope *Scope) {
 p.Value.MarkReferencedVariables(scope)
}

// An Expression is a Value in a Property or Assignment.  It can be a literal (String or Bool), a
// Map, a List, an Operator that combines two expressions of the same type, or a Variable that
// references and Assignment.
type Expression interface {
 Node
 // Copy returns a copy of the Expression that will not affect the original if mutated
 Copy() Expression
 String() string
 // Type returns the underlying Type enum of the Expression if it were to be evaluated, if it's known.
 // It's possible that the type isn't known, such as when a select statement with a late-bound variable
 // is used. For that reason, Type() is mostly for use in error messages, not to make logic decisions
 // off of.
 Type() Type
 // Eval returns an expression that is fully evaluated to a simple type (List, Map, String,
 // Bool, or Select).  It will return the origional expression if possible, or allocate a
 // new one if modifications were necessary.
 Eval(scope *Scope) (Expression, error)
 // PrintfInto will substitute any %s's in string literals in the AST with the provided
 // value. It will modify the AST in-place. This is used to implement soong config value
 // variables, but should be removed when those have switched to selects.
 PrintfInto(value string) error
 // MarkReferencedVariables marks the variables in the given scope referenced if there
 // is a matching variable reference in this expression. This happens naturally during
 // Eval as well, but for selects, we need to mark variables as referenced without
 // actually evaluating the expression yet.
 MarkReferencedVariables(scope *Scope)
}

// ExpressionsAreSame tells whether the two values are the same Expression.
// This includes the symbolic representation of each Expression but not their positions in the original source tree.
// This does not apply any simplification to the expressions before comparing them
// (for example, "!!a" wouldn't be deemed equal to "a")
func ExpressionsAreSame(a Expression, b Expression) (equal bool, err error) {
 return hackyExpressionsAreSame(a, b)
}

// TODO(jeffrygaston) once positions are removed from Expression structs,
// remove this function and have callers use reflect.DeepEqual(a, b)
func hackyExpressionsAreSame(a Expression, b Expression) (equal bool, err error) {
 left, err := hackyFingerprint(a)
 if err != nil {
  return false, nil
 }
 right, err := hackyFingerprint(b)
 if err != nil {
  return false, nil
 }
 areEqual := string(left) == string(right)
 return areEqual, nil
}

func hackyFingerprint(expression Expression) (fingerprint []byte, err error) {
 assignment := &Assignment{"a", noPos, expression, noPos, "=", atomic.Bool{}}
 module := &File{}
 module.Defs = append(module.Defs, assignment)
 p := newPrinter(module)
 return p.Print()
}

type Type int

const (
 UnknownType Type = iota
 BoolType
 StringType
 Int64Type
 ListType
 MapType
 UnsetType
)

func (t Type) String() string {
 switch t {
 case UnknownType:
  return "unknown"
 case BoolType:
  return "bool"
 case StringType:
  return "string"
 case Int64Type:
  return "int64"
 case ListType:
  return "list"
 case MapType:
  return "map"
 case UnsetType:
  return "unset"
 default:
  panic(fmt.Sprintf("Unknown type %d", t))
 }
}

func ZeroExpression(t Type) Expression {
 switch t {
 case UnknownType:
  panic(fmt.Errorf("cannot create zero expression for UnknownType"))
 case BoolType:
  return &Bool{}
 case StringType:
  return &String{}
 case Int64Type:
  return &Int64{}
 case ListType:
  return &List{}
 case MapType:
  return &Map{}
 case UnsetType:
  panic(fmt.Errorf("cannot create zero expression for UnsetType"))

 default:
  panic(fmt.Errorf("Unknown type %d", t))
 }
}

type Operator struct {
 Args        [2]Expression
 Operator    rune
 OperatorPos scanner.Position
}

func (x *Operator) Copy() Expression {
 ret := *x
 ret.Args[0] = x.Args[0].Copy()
 ret.Args[1] = x.Args[1].Copy()
 return &ret
}

func (x *Operator) Type() Type {
 t1 := x.Args[0].Type()
 t2 := x.Args[1].Type()
 if t1 == UnknownType {
  return t2
 }
 if t2 == UnknownType {
  return t1
 }
 if t1 != t2 {
  return UnknownType
 }
 return t1
}

func (x *Operator) Eval(scope *Scope) (Expression, error) {
 return evaluateOperator(scope, x.Operator, x.Args[0], x.Args[1])
}

func evaluateOperator(scope *Scope, operator rune, left, right Expression) (Expression, error) {
 if operator != '+' {
  return nil, fmt.Errorf("unknown operator %c", operator)
 }
 l, err := left.Eval(scope)
 if err != nil {
  return nil, err
 }
 r, err := right.Eval(scope)
 if err != nil {
  return nil, err
 }

 if _, ok := l.(*Select); !ok {
  if _, ok := r.(*Select); ok {
   // Promote l to a select so we can add r to it
   l = &Select{
    Cases: []*SelectCase{{
     Value: l,
    }},
   }
  }
 }

 l = l.Copy()

 switch v := l.(type) {
 case *String:
  if _, ok := r.(*String); !ok {
   fmt.Fprintf(os.Stderr, "not ok")
  }
  v.Value += r.(*String).Value
 case *Int64:
  v.Value += r.(*Int64).Value
  v.Token = ""
 case *List:
  v.Values = append(v.Values, r.(*List).Values...)
 case *Map:
  var err error
  v.Properties, err = addMaps(scope, v.Properties, r.(*Map).Properties)
  if err != nil {
   return nil, err
  }
 case *Select:
  v.Append = r
 default:
  return nil, fmt.Errorf("operator %c not supported on %v", operator, v)
 }

 return l, nil
}

func addMaps(scope *Scope, map1, map2 []*Property) ([]*Property, error) {
 ret := make([]*Property, 0, len(map1))

 inMap1 := make(map[string]*Property)
 inMap2 := make(map[string]*Property)
 inBoth := make(map[string]*Property)

 for _, prop1 := range map1 {
  inMap1[prop1.Name] = prop1
 }

 for _, prop2 := range map2 {
  inMap2[prop2.Name] = prop2
  if _, ok := inMap1[prop2.Name]; ok {
   inBoth[prop2.Name] = prop2
  }
 }

 for _, prop1 := range map1 {
  if prop2, ok := inBoth[prop1.Name]; ok {
   var err error
   newProp := *prop1
   newProp.Value, err = evaluateOperator(scope, '+', prop1.Value, prop2.Value)
   if err != nil {
    return nil, err
   }
   ret = append(ret, &newProp)
  } else {
   ret = append(ret, prop1)
  }
 }

 for _, prop2 := range map2 {
  if _, ok := inBoth[prop2.Name]; !ok {
   ret = append(ret, prop2)
  }
 }

 return ret, nil
}

func (x *Operator) PrintfInto(value string) error {
 if err := x.Args[0].PrintfInto(value); err != nil {
  return err
 }
 return x.Args[1].PrintfInto(value)
}

func (x *Operator) MarkReferencedVariables(scope *Scope) {
 x.Args[0].MarkReferencedVariables(scope)
 x.Args[1].MarkReferencedVariables(scope)
}

func (x *Operator) Pos() scanner.Position { return x.Args[0].Pos() }
func (x *Operator) End() scanner.Position { return x.Args[1].End() }

func (x *Operator) String() string {
 return fmt.Sprintf("(%s %c %s)@%s", x.Args[0].String(), x.Operator, x.Args[1].String(),
  x.OperatorPos)
}

type Variable struct {
 Name    string
 NamePos scanner.Position
 Type_   Type
}

func (x *Variable) Pos() scanner.Position { return x.NamePos }
func (x *Variable) End() scanner.Position { return endPos(x.NamePos, len(x.Name)) }

func (x *Variable) Copy() Expression {
 ret := *x
 return &ret
}

func (x *Variable) Eval(scope *Scope) (Expression, error) {
 if assignment := scope.Get(x.Name); assignment != nil {
  assignment.Referenced.Store(true)
  return assignment.Value, nil
 }
 return nil, fmt.Errorf("undefined variable %s", x.Name)
}

func (x *Variable) PrintfInto(value string) error {
 return nil
}

func (x *Variable) MarkReferencedVariables(scope *Scope) {
 if assignment := scope.Get(x.Name); assignment != nil {
  assignment.Referenced.Store(true)
 }
}

func (x *Variable) String() string {
 return x.Name
}

func (x *Variable) Type() Type {
 // Variables do not normally have a type associated with them, this is only
 // filled out in the androidmk tool
 return x.Type_
}

type Map struct {
 LBracePos  scanner.Position
 RBracePos  scanner.Position
 Properties []*Property
}

func (x *Map) Pos() scanner.Position { return x.LBracePos }
func (x *Map) End() scanner.Position { return endPos(x.RBracePos, 1) }

func (x *Map) Copy() Expression {
 ret := *x
 ret.Properties = make([]*Property, len(x.Properties))
 for i := range x.Properties {
  ret.Properties[i] = x.Properties[i].Copy()
 }
 return &ret
}

func (x *Map) Eval(scope *Scope) (Expression, error) {
 newProps := make([]*Property, len(x.Properties))
 for i, prop := range x.Properties {
  newVal, err := prop.Value.Eval(scope)
  if err != nil {
   return nil, err
  }
  newProps[i] = &Property{
   Name:     prop.Name,
   NamePos:  prop.NamePos,
   ColonPos: prop.ColonPos,
   Value:    newVal,
  }
 }
 return &Map{
  LBracePos:  x.LBracePos,
  RBracePos:  x.RBracePos,
  Properties: newProps,
 }, nil
}

func (x *Map) PrintfInto(value string) error {
 // We should never reach this because selects cannot hold maps
 panic("printfinto() is unsupported on maps")
}

func (x *Map) MarkReferencedVariables(scope *Scope) {
 for _, prop := range x.Properties {
  prop.MarkReferencedVariables(scope)
 }
}

func (x *Map) String() string {
 propertyStrings := make([]string, len(x.Properties))
 for i, property := range x.Properties {
  propertyStrings[i] = property.String()
 }
 return fmt.Sprintf("@%s-%s{%s}", x.LBracePos, x.RBracePos,
  strings.Join(propertyStrings, ", "))
}

func (x *Map) Type() Type { return MapType }

// GetProperty looks for a property with the given name.
// It resembles the bracket operator of a built-in Golang map.
func (x *Map) GetProperty(name string) (Property *Property, found bool) {
 prop, found, _ := x.getPropertyImpl(name)
 return prop, found // we don't currently expose the index to callers
}

func (x *Map) getPropertyImpl(name string) (Property *Property, found bool, index int) {
 for i, prop := range x.Properties {
  if prop.Name == name {
   return prop, true, i
  }
 }
 return nil, false, -1
}

// RemoveProperty removes the property with the given name, if it exists.
func (x *Map) RemoveProperty(propertyName string) (removed bool) {
 _, found, index := x.getPropertyImpl(propertyName)
 if found {
  x.Properties[index].Deleted = true
 }
 return found
}

// MovePropertyContents moves the contents of propertyName into property newLocation
// If property newLocation doesn't exist, MovePropertyContents renames propertyName as newLocation.
// Otherwise, MovePropertyContents only supports moving contents that are a List of String.
func (x *Map) MovePropertyContents(propertyName string, newLocation string) (removed bool) {
 oldProp, oldFound, _ := x.getPropertyImpl(propertyName)
 newProp, newFound, _ := x.getPropertyImpl(newLocation)

 // newLoc doesn't exist, simply renaming property
 if oldFound && !newFound {
  oldProp.Name = newLocation
  return oldFound
 }

 if oldFound {
  old, oldOk := oldProp.Value.(*List)
  new, newOk := newProp.Value.(*List)
  if oldOk && newOk {
   toBeMoved := make([]string, len(old.Values)) //
   for i, p := range old.Values {
    toBeMoved[i] = p.(*String).Value
   }

   for _, moved := range toBeMoved {
    RemoveStringFromList(old, moved)
    AddStringToList(new, moved)
   }
   // oldProp should now be empty and needs to be deleted
   x.RemoveProperty(oldProp.Name)
  } else {
   print(`MovePropertyContents currently only supports moving PropertyName
     with List of Strings into an existing newLocation with List of Strings\n`)
  }
 }
 return oldFound
}

type List struct {
 LBracePos scanner.Position
 RBracePos scanner.Position
 Values    []Expression
}

func (x *List) Pos() scanner.Position { return x.LBracePos }
func (x *List) End() scanner.Position { return endPos(x.RBracePos, 1) }

func (x *List) Copy() Expression {
 ret := *x
 ret.Values = make([]Expression, len(x.Values))
 for i := range ret.Values {
  ret.Values[i] = x.Values[i].Copy()
 }
 return &ret
}

func (x *List) Eval(scope *Scope) (Expression, error) {
 newValues := make([]Expression, len(x.Values))
 for i, val := range x.Values {
  newVal, err := val.Eval(scope)
  if err != nil {
   return nil, err
  }
  newValues[i] = newVal
 }
 return &List{
  LBracePos: x.LBracePos,
  RBracePos: x.RBracePos,
  Values:    newValues,
 }, nil
}

func (x *List) PrintfInto(value string) error {
 for _, val := range x.Values {
  if err := val.PrintfInto(value); err != nil {
   return err
  }
 }
 return nil
}

func (x *List) MarkReferencedVariables(scope *Scope) {
 for _, val := range x.Values {
  val.MarkReferencedVariables(scope)
 }
}

func (x *List) String() string {
 valueStrings := make([]string, len(x.Values))
 for i, value := range x.Values {
  valueStrings[i] = value.String()
 }
 return fmt.Sprintf("@%s-%s[%s]", x.LBracePos, x.RBracePos,
  strings.Join(valueStrings, ", "))
}

func (x *List) Type() Type { return ListType }

type String struct {
 LiteralPos scanner.Position
 Value      string
 Deleted    bool
}

func (x *String) Pos() scanner.Position { return x.LiteralPos }
func (x *String) End() scanner.Position { return endPos(x.LiteralPos, len(x.Value)+2) }

func (x *String) Copy() Expression {
 ret := *x
 return &ret
}

func (x *String) Eval(scope *Scope) (Expression, error) {
 return x, nil
}

func (x *String) PrintfInto(value string) error {
 count := strings.Count(x.Value, "%")
 if count == 0 {
  return nil
 }

 if count > 1 {
  return fmt.Errorf("list/value variable properties only support a single '%%'")
 }

 if !strings.Contains(x.Value, "%s") {
  return fmt.Errorf("unsupported %% in value variable property")
 }

 x.Value = fmt.Sprintf(x.Value, value)
 return nil
}

func (x *String) MarkReferencedVariables(scope *Scope) {
}

func (x *String) String() string {
 return fmt.Sprintf("%q@%s", x.Value, x.LiteralPos)
}

func (x *String) Type() Type {
 return StringType
}

type Int64 struct {
 LiteralPos scanner.Position
 Value      int64
 Token      string
}

func (x *Int64) Pos() scanner.Position { return x.LiteralPos }
func (x *Int64) End() scanner.Position { return endPos(x.LiteralPos, len(x.Token)) }

func (x *Int64) Copy() Expression {
 ret := *x
 return &ret
}

func (x *Int64) Eval(scope *Scope) (Expression, error) {
 return x, nil
}

func (x *Int64) PrintfInto(value string) error {
 return nil
}

func (x *Int64) MarkReferencedVariables(scope *Scope) {
}

func (x *Int64) String() string {
 return fmt.Sprintf("%q@%s", x.Value, x.LiteralPos)
}

func (x *Int64) Type() Type {
 return Int64Type
}

type Bool struct {
 LiteralPos scanner.Position
 Value      bool
 Token      string
}

func (x *Bool) Pos() scanner.Position { return x.LiteralPos }
func (x *Bool) End() scanner.Position { return endPos(x.LiteralPos, len(x.Token)) }

func (x *Bool) Copy() Expression {
 ret := *x
 return &ret
}

func (x *Bool) Eval(scope *Scope) (Expression, error) {
 return x, nil
}

func (x *Bool) PrintfInto(value string) error {
 return nil
}

func (x *Bool) MarkReferencedVariables(scope *Scope) {
}

func (x *Bool) String() string {
 return fmt.Sprintf("%t@%s", x.Value, x.LiteralPos)
}

func (x *Bool) Type() Type {
 return BoolType
}

type CommentGroup struct {
 Comments []*Comment
}

func (x *CommentGroup) Pos() scanner.Position { return x.Comments[0].Pos() }
func (x *CommentGroup) End() scanner.Position { return x.Comments[len(x.Comments)-1].End() }

type Comment struct {
 Comment []string
 Slash   scanner.Position
}

func (c Comment) Pos() scanner.Position {
 return c.Slash
}

func (c Comment) End() scanner.Position {
 pos := c.Slash
 for _, comment := range c.Comment {
  pos.Offset += len(comment) + 1
  pos.Column = len(comment) + 1
 }
 pos.Line += len(c.Comment) - 1
 return pos
}

func (c Comment) String() string {
 l := 0
 for _, comment := range c.Comment {
  l += len(comment) + 1
 }
 buf := make([]byte, 0, l)
 for _, comment := range c.Comment {
  buf = append(buf, comment...)
  buf = append(buf, '\n')
 }

 return string(buf) + "@" + c.Slash.String()
}

// Return the text of the comment with // or /* and */ stripped
func (c Comment) Text() string {
 l := 0
 for _, comment := range c.Comment {
  l += len(comment) + 1
 }
 buf := make([]byte, 0, l)

 blockComment := false
 if strings.HasPrefix(c.Comment[0], "/*") {
  blockComment = true
 }

 for i, comment := range c.Comment {
  if blockComment {
   if i == 0 {
    comment = strings.TrimPrefix(comment, "/*")
   }
   if i == len(c.Comment)-1 {
    comment = strings.TrimSuffix(comment, "*/")
   }
  } else {
   comment = strings.TrimPrefix(comment, "//")
  }
  buf = append(buf, comment...)
  buf = append(buf, '\n')
 }

 return string(buf)
}

func endPos(pos scanner.Position, n int) scanner.Position {
 pos.Offset += n
 pos.Column += n
 return pos
}

type ConfigurableCondition struct {
 position     scanner.Position
 FunctionName string
 Args         []String
}

func (c *ConfigurableCondition) Equals(other ConfigurableCondition) bool {
 if c.FunctionName != other.FunctionName {
  return false
 }
 if len(c.Args) != len(other.Args) {
  return false
 }
 for i := range c.Args {
  if c.Args[i] != other.Args[i] {
   return false
  }
 }
 return true
}

func (c *ConfigurableCondition) String() string {
 var sb strings.Builder
 sb.WriteString(c.FunctionName)
 sb.WriteRune('(')
 for i, arg := range c.Args {
  sb.WriteRune('"')
  sb.WriteString(arg.Value)
  sb.WriteRune('"')
  if i < len(c.Args)-1 {
   sb.WriteString(", ")
  }
 }
 sb.WriteRune(')')
 return sb.String()
}

type Select struct {
 Scope      *Scope           // scope used to evaluate the body of the select later on
 KeywordPos scanner.Position // the keyword "select"
 Conditions []ConfigurableCondition
 LBracePos  scanner.Position
 RBracePos  scanner.Position
 Cases      []*SelectCase // the case statements
 Append     Expression
}

func (s *Select) Pos() scanner.Position { return s.KeywordPos }
func (s *Select) End() scanner.Position { return endPos(s.RBracePos, 1) }

func (s *Select) Copy() Expression {
 ret := *s
 ret.Cases = make([]*SelectCase, len(ret.Cases))
 for i, selectCase := range s.Cases {
  ret.Cases[i] = selectCase.Copy()
 }
 if s.Append != nil {
  ret.Append = s.Append.Copy()
 }
 return &ret
}

func (s *Select) Eval(scope *Scope) (Expression, error) {
 s.Scope = scope
 s.MarkReferencedVariables(scope)
 return s, nil
}

func (x *Select) PrintfInto(value string) error {
 // PrintfInto will be handled at the Configurable object level
 panic("Cannot call PrintfInto on a select expression")
}

func (x *Select) MarkReferencedVariables(scope *Scope) {
 for _, c := range x.Cases {
  c.MarkReferencedVariables(scope)
 }
 if x.Append != nil {
  x.Append.MarkReferencedVariables(scope)
 }
}

func (s *Select) String() string {
 return "<select>"
}

func (s *Select) Type() Type {
 if len(s.Cases) == 0 {
  return UnsetType
 }
 return UnknownType
}

type SelectPattern struct {
 Value   Expression
 Binding Variable
}

func (c *SelectPattern) Pos() scanner.Position { return c.Value.Pos() }
func (c *SelectPattern) End() scanner.Position {
 if c.Binding.NamePos.IsValid() {
  return c.Binding.End()
 }
 return c.Value.End()
}

type SelectCase struct {
 Patterns []SelectPattern
 ColonPos scanner.Position
 Value    Expression
}

func (x *SelectCase) MarkReferencedVariables(scope *Scope) {
 x.Value.MarkReferencedVariables(scope)
}

func (c *SelectCase) Copy() *SelectCase {
 ret := *c
 ret.Value = c.Value.Copy()
 return &ret
}

func (c *SelectCase) String() string {
 return "<select case>"
}

func (c *SelectCase) Pos() scanner.Position { return c.Patterns[0].Pos() }
func (c *SelectCase) End() scanner.Position { return c.Value.End() }

// UnsetProperty is the expression type of the "unset" keyword that can be
// used in select statements to make the property unset. For example:
//
// my_module_type {
//   name: "foo",
//   some_prop: select(soong_config_variable("my_namespace", "my_var"), {
//     "foo": unset,
//     "default": "bar",
//   })
// }
type UnsetProperty struct {
 Position scanner.Position
}

func (n *UnsetProperty) Copy() Expression {
 return &UnsetProperty{Position: n.Position}
}

func (n *UnsetProperty) String() string {
 return "unset"
}

func (n *UnsetProperty) Type() Type {
 return UnsetType
}

func (n *UnsetProperty) Eval(scope *Scope) (Expression, error) {
 return n, nil
}

func (x *UnsetProperty) PrintfInto(value string) error {
 return nil
}

func (x *UnsetProperty) MarkReferencedVariables(scope *Scope) {
}

func (n *UnsetProperty) Pos() scanner.Position { return n.Position }
func (n *UnsetProperty) End() scanner.Position { return n.Position }

[Dauer der Verarbeitung: 0.24 Sekunden, vorverarbeitet 2026-06-28]