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

Quelle  scope.go   Sprache: unbekannt

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

// Copyright 2014 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 blueprint

import (
 "fmt"
 "strings"
 "unicode"
 "unicode/utf8"
)

// A Variable represents a global Ninja variable definition that will be written
// to the output .ninja file.  A variable may contain references to other global
// Ninja variables, but circular variable references are not allowed.
type Variable interface {
 packageContext() *packageContext
 name() string                                        // "foo"
 fullName(pkgNames map[*packageContext]string) string // "pkg.foo" or "path.to.pkg.foo"
 value(ctx VariableFuncContext, config interface{}) (*ninjaString, error)
 String() string
}

// A Pool represents a Ninja pool that will be written to the output .ninja
// file.
type Pool interface {
 packageContext() *packageContext
 name() string                                        // "foo"
 fullName(pkgNames map[*packageContext]string) string // "pkg.foo" or "path.to.pkg.foo"
 def(config interface{}) (*poolDef, error)
 String() string
}

// A Rule represents a Ninja build rule that will be written to the output
// .ninja file.
type Rule interface {
 packageContext() *packageContext
 name() string                                        // "foo"
 fullName(pkgNames map[*packageContext]string) string // "pkg.foo" or "path.to.pkg.foo"
 def(config interface{}) (*ruleDef, error)
 scope() *basicScope
 isArg(argName string) bool
 String() string
}

type basicScope struct {
 parent    *basicScope
 variables map[string]Variable
 pools     map[string]Pool
 rules     map[string]Rule
 imports   map[string]*basicScope
}

func newScope(parent *basicScope) *basicScope {
 return &basicScope{
  parent:    parent,
  variables: make(map[string]Variable),
  pools:     make(map[string]Pool),
  rules:     make(map[string]Rule),
  imports:   make(map[string]*basicScope),
 }
}

func makeRuleScope(parent *basicScope, argNames map[string]bool) *basicScope {
 scope := newScope(parent)
 for argName := range argNames {
  _, err := scope.LookupVariable(argName)
  if err != nil {
   arg := &argVariable{argName}
   err = scope.AddVariable(arg)
   if err != nil {
    // This should not happen.  We should have already checked that
    // the name is valid and that the scope doesn't have a variable
    // with this name.
    panic(err)
   }
  }
 }

 // We treat built-in variables like arguments for the purpose of this scope.
 for _, builtin := range builtinRuleArgs {
  arg := &argVariable{builtin}
  err := scope.AddVariable(arg)
  if err != nil {
   panic(err)
  }
 }

 return scope
}

func (s *basicScope) LookupVariable(name string) (Variable, error) {
 dotIndex := strings.IndexRune(name, '.')
 if dotIndex >= 0 {
  // The variable name looks like "pkg.var"
  if dotIndex+1 == len(name) {
   return nil, fmt.Errorf("variable name %q ends with a '.'", name)
  }
  if strings.ContainsRune(name[dotIndex+1:], '.') {
   return nil, fmt.Errorf("variable name %q contains multiple '.' "+
    "characters", name)
  }

  pkgName := name[:dotIndex]
  varName := name[dotIndex+1:]

  first, _ := utf8.DecodeRuneInString(varName)
  if !unicode.IsUpper(first) {
   return nil, fmt.Errorf("cannot refer to unexported name %q", name)
  }

  importedScope, err := s.lookupImportedScope(pkgName)
  if err != nil {
   return nil, err
  }

  v, ok := importedScope.variables[varName]
  if !ok {
   return nil, fmt.Errorf("package %q does not contain variable %q",
    pkgName, varName)
  }

  return v, nil
 } else {
  // The variable name has no package part; just "var"
  for ; s != nil; s = s.parent {
   v, ok := s.variables[name]
   if ok {
    return v, nil
   }
  }
  return nil, fmt.Errorf("undefined variable %q", name)
 }
}

func (s *basicScope) IsRuleVisible(rule Rule) bool {
 _, isBuiltin := rule.(*builtinRule)
 if isBuiltin {
  return true
 }

 name := rule.name()

 for s != nil {
  if s.rules[name] == rule {
   return true
  }

  for _, import_ := range s.imports {
   if import_.rules[name] == rule {
    return true
   }
  }

  s = s.parent
 }

 return false
}

func (s *basicScope) IsPoolVisible(pool Pool) bool {
 _, isBuiltin := pool.(*builtinPool)
 if isBuiltin {
  return true
 }

 name := pool.name()

 for s != nil {
  if s.pools[name] == pool {
   return true
  }

  for _, import_ := range s.imports {
   if import_.pools[name] == pool {
    return true
   }
  }

  s = s.parent
 }

 return false
}

func (s *basicScope) lookupImportedScope(pkgName string) (*basicScope, error) {
 for ; s != nil; s = s.parent {
  importedScope, ok := s.imports[pkgName]
  if ok {
   return importedScope, nil
  }
 }
 return nil, fmt.Errorf("unknown imported package %q (missing call to "+
  "blueprint.Import()?)", pkgName)
}

func (s *basicScope) AddImport(name string, importedScope *basicScope) error {
 _, present := s.imports[name]
 if present {
  return fmt.Errorf("import %q is already defined in this scope", name)
 }
 s.imports[name] = importedScope
 return nil
}

func (s *basicScope) AddVariable(v Variable) error {
 name := v.name()
 _, present := s.variables[name]
 if present {
  return fmt.Errorf("variable %q is already defined in this scope", name)
 }
 s.variables[name] = v
 return nil
}

func (s *basicScope) AddPool(p Pool) error {
 name := p.name()
 _, present := s.pools[name]
 if present {
  return fmt.Errorf("pool %q is already defined in this scope", name)
 }
 s.pools[name] = p
 return nil
}

func (s *basicScope) AddRule(r Rule) error {
 name := r.name()
 _, present := s.rules[name]
 if present {
  return fmt.Errorf("rule %q is already defined in this scope", name)
 }
 s.rules[name] = r
 return nil
}

type localScope struct {
 namePrefix string
 scope      *basicScope
}

func newLocalScope(parent *basicScope, namePrefix string) *localScope {
 return &localScope{
  namePrefix: namePrefix,
  scope:      newScope(parent),
 }
}

// ReparentTo sets the localScope's parent scope to the scope of the given
// package context.  This allows a ModuleContext and SingletonContext to call
// a function defined in a different Go package and have that function retain
// access to all of the package-scoped variables of its own package.
func (s *localScope) ReparentTo(pctx PackageContext) {
 s.scope.parent = pctx.getScope()
}

func (s *localScope) LookupVariable(name string) (Variable, error) {
 return s.scope.LookupVariable(name)
}

func (s *localScope) IsRuleVisible(rule Rule) bool {
 return s.scope.IsRuleVisible(rule)
}

func (s *localScope) IsPoolVisible(pool Pool) bool {
 return s.scope.IsPoolVisible(pool)
}

func (s *localScope) AddLocalVariable(name, value string) (*localVariable,
 error) {

 err := validateNinjaName(name)
 if err != nil {
  return nil, err
 }

 if strings.ContainsRune(name, '.') {
  return nil, fmt.Errorf("local variable name %q contains '.'", name)
 }

 ninjaValue, err := parseNinjaString(s.scope, value)
 if err != nil {
  return nil, err
 }

 v := &localVariable{
  fullName_: s.namePrefix + name,
  name_:     name,
  value_:    ninjaValue,
 }

 err = s.scope.AddVariable(v)
 if err != nil {
  return nil, err
 }

 return v, nil
}

func (s *localScope) AddLocalRule(config any, name string, params *RuleParams,
 argNames ...string) (*localRule, error) {

 err := validateNinjaName(name)
 if err != nil {
  return nil, err
 }

 err = validateArgNames(argNames)
 if err != nil {
  return nil, fmt.Errorf("invalid argument name: %s", err)
 }

 argNamesSet := make(map[string]bool)
 for _, argName := range argNames {
  argNamesSet[argName] = true
 }

 ruleScope := makeRuleScope(s.scope, argNamesSet)

 def, err := parseRuleParams(config, ruleScope, params)
 if err != nil {
  return nil, err
 }

 r := &localRule{
  fullName_: s.namePrefix + name,
  name_:     name,
  def_:      def,
  argNames:  argNamesSet,
  scope_:    ruleScope,
 }

 err = s.scope.AddRule(r)
 if err != nil {
  return nil, err
 }

 return r, nil
}

type localVariable struct {
 fullName_ string
 name_     string
 value_    *ninjaString
}

func (l *localVariable) packageContext() *packageContext {
 return nil
}

func (l *localVariable) name() string {
 return l.name_
}

func (l *localVariable) fullName(pkgNames map[*packageContext]string) string {
 return l.fullName_
}

func (l *localVariable) value(VariableFuncContext, interface{}) (*ninjaString, error) {
 return l.value_, nil
}

func (l *localVariable) String() string {
 return "<local var>:" + l.fullName_
}

type localRule struct {
 fullName_ string
 name_     string
 def_      *ruleDef
 argNames  map[string]bool
 scope_    *basicScope
}

func (l *localRule) packageContext() *packageContext {
 return nil
}

func (l *localRule) name() string {
 return l.name_
}

func (l *localRule) fullName(pkgNames map[*packageContext]string) string {
 return l.fullName_
}

func (l *localRule) def(interface{}) (*ruleDef, error) {
 return l.def_, nil
}

func (r *localRule) scope() *basicScope {
 return r.scope_
}

func (r *localRule) isArg(argName string) bool {
 return r.argNames[argName]
}

func (r *localRule) String() string {
 return "<local rule>:" + r.fullName_
}

type nameTracker struct {
 variables map[Variable]string
 rules     map[Rule]string
 pools     map[Pool]string

 pkgNames map[*packageContext]string
}

func (m *nameTracker) Variable(v Variable) string {
 if m == nil {
  return v.fullName(nil)
 }
 if name, ok := m.variables[v]; ok {
  return name
 }
 return v.fullName(m.pkgNames)
}

func (m *nameTracker) Rule(r Rule) string {
 if m == nil {
  return r.fullName(nil)
 }
 if name, ok := m.rules[r]; ok {
  return name
 }
 return r.fullName(m.pkgNames)
}

func (m *nameTracker) Pool(p Pool) string {
 if m == nil {
  return p.fullName(nil)
 }
 if name, ok := m.pools[p]; ok {
  return name
 }
 return p.fullName(m.pkgNames)
}

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