Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  parser.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 parser

import (
 "errors"
 "fmt"
 "io"
 "sort"
 "strconv"
 "strings"
 "text/scanner"
)

var errTooManyErrors = errors.New("too many errors")

const maxErrors = 1

const default_select_branch_name = "__soong_conditions_default__"
const any_select_branch_name = "__soong_conditions_any__"

type ParseError struct {
 Err error
 Pos scanner.Position
}

func (e *ParseError) Error() string {
 return fmt.Sprintf("%s: %s", e.Pos, e.Err)
}

type File struct {
 Name     string
 Defs     []Definition
 Comments []*CommentGroup
}

func parse(p *parser) (file *File, errs []error) {
 defer func() {
  if r := recover(); r != nil {
   if r == errTooManyErrors {
    errs = p.errors
    return
   }
   panic(r)
  }
 }()

 p.next()
 defs := p.parseDefinitions()
 p.accept(scanner.EOF)
 errs = p.errors
 comments := p.comments

 return &File{
  Name:     p.scanner.Filename,
  Defs:     defs,
  Comments: comments,
 }, errs

}

func ParseAndEval(filename string, r io.Reader, scope *Scope) (file *File, errs []error) {
 file, errs = Parse(filename, r)
 if len(errs) > 0 {
  return nil, errs
 }

 // evaluate all module properties
 var newDefs []Definition
 for _, def := range file.Defs {
  switch d := def.(type) {
  case *Module:
   for _, prop := range d.Map.Properties {
    newval, err := prop.Value.Eval(scope)
    if err != nil {
     return nil, []error{err}
    }
    switch newval.(type) {
    case *String, *Bool, *Int64, *Select, *Map, *List:
     // ok
    default:
     panic(fmt.Sprintf("Evaled but got %#v\n", newval))
    }
    prop.Value = newval
   }
   newDefs = append(newDefs, d)
  case *Assignment:
   if err := scope.HandleAssignment(d); err != nil {
    return nil, []error{err}
   }
  }
 }

 // This is not strictly necessary, but removing the assignments from
 // the result makes it clearer that this is an evaluated file.
 // We could also consider adding a "EvaluatedFile" type to return.
 file.Defs = newDefs

 return file, nil
}

func Parse(filename string, r io.Reader) (file *File, errs []error) {
 p := newParser(r)
 p.scanner.Filename = filename

 return parse(p)
}

func ParseExpression(r io.Reader) (value Expression, errs []error) {
 p := newParser(r)
 p.next()
 value = p.parseExpression()
 p.accept(scanner.EOF)
 errs = p.errors
 return
}

type parser struct {
 scanner  scanner.Scanner
 tok      rune
 errors   []error
 comments []*CommentGroup
}

func newParser(r io.Reader) *parser {
 p := &parser{}
 p.scanner.Init(r)
 p.scanner.Error = func(sc *scanner.Scanner, msg string) {
  p.errorf(msg)
 }
 p.scanner.Mode = scanner.ScanIdents | scanner.ScanInts | scanner.ScanStrings |
  scanner.ScanRawStrings | scanner.ScanComments
 return p
}

func (p *parser) error(err error) {
 pos := p.scanner.Position
 if !pos.IsValid() {
  pos = p.scanner.Pos()
 }
 err = &ParseError{
  Err: err,
  Pos: pos,
 }
 p.errors = append(p.errors, err)
 if len(p.errors) >= maxErrors {
  panic(errTooManyErrors)
 }
}

func (p *parser) errorf(format string, args ...interface{}) {
 p.error(fmt.Errorf(format, args...))
}

func (p *parser) accept(toks ...rune) bool {
 for _, tok := range toks {
  if p.tok != tok {
   p.errorf("expected %s, found %s", scanner.TokenString(tok),
    scanner.TokenString(p.tok))
   return false
  }
  p.next()
 }
 return true
}

func (p *parser) next() {
 if p.tok != scanner.EOF {
  p.tok = p.scanner.Scan()
  if p.tok == scanner.Comment {
   var comments []*Comment
   for p.tok == scanner.Comment {
    lines := strings.Split(p.scanner.TokenText(), "\n")
    if len(comments) > 0 && p.scanner.Position.Line > comments[len(comments)-1].End().Line+1 {
     p.comments = append(p.comments, &CommentGroup{Comments: comments})
     comments = nil
    }
    comments = append(comments, &Comment{lines, p.scanner.Position})
    p.tok = p.scanner.Scan()
   }
   p.comments = append(p.comments, &CommentGroup{Comments: comments})
  }
 }
}

func (p *parser) parseDefinitions() (defs []Definition) {
 for {
  switch p.tok {
  case scanner.Ident:
   ident := p.scanner.TokenText()
   pos := p.scanner.Position

   p.accept(scanner.Ident)

   switch p.tok {
   case '+':
    p.accept('+')
    defs = append(defs, p.parseAssignment(ident, pos, "+="))
   case '=':
    defs = append(defs, p.parseAssignment(ident, pos, "="))
   case '{', '(':
    defs = append(defs, p.parseModule(ident, pos))
   default:
    p.errorf("expected \"=\" or \"+=\" or \"{\" or \"(\", found %s",
     scanner.TokenString(p.tok))
   }
  case scanner.EOF:
   return
  default:
   p.errorf("expected assignment or module definition, found %s",
    scanner.TokenString(p.tok))
   return
  }
 }
}

func (p *parser) parseAssignment(name string, namePos scanner.Position,
 assigner string) (assignment *Assignment) {

 // These are used as keywords in select statements, prevent making variables
 // with the same name to avoid any confusion.
 switch name {
 case "default", "unset":
  p.errorf("'default' and 'unset' are reserved keywords, and cannot be used as variable names")
  return nil
 }

 assignment = new(Assignment)

 pos := p.scanner.Position
 if !p.accept('=') {
  return
 }
 value := p.parseExpression()

 assignment.Name = name
 assignment.NamePos = namePos
 assignment.Value = value
 assignment.EqualsPos = pos
 assignment.Assigner = assigner

 return
}

func (p *parser) parseModule(typ string, typPos scanner.Position) *Module {

 compat := false
 lbracePos := p.scanner.Position
 if p.tok == '{' {
  compat = true
 }

 if !p.accept(p.tok) {
  return nil
 }
 properties := p.parsePropertyList(true, compat)
 rbracePos := p.scanner.Position
 if !compat {
  p.accept(')')
 } else {
  p.accept('}')
 }

 return &Module{
  Type:    typ,
  TypePos: typPos,
  Map: Map{
   Properties: properties,
   LBracePos:  lbracePos,
   RBracePos:  rbracePos,
  },
 }
}

func (p *parser) parsePropertyList(isModule, compat bool) (properties []*Property) {
 for p.tok == scanner.Ident {
  properties = append(properties, p.parseProperty(isModule, compat))

  if p.tok != ',' {
   // There was no comma, so the list is done.
   break
  }

  p.accept(',')
 }

 return
}

func (p *parser) parseProperty(isModule, compat bool) (property *Property) {
 property = new(Property)

 name := p.scanner.TokenText()
 namePos := p.scanner.Position
 p.accept(scanner.Ident)
 pos := p.scanner.Position

 if isModule {
  if compat {
   if !p.accept(':') {
    return
   }
  } else {
   if !p.accept('=') {
    return
   }
  }
 } else {
  if !p.accept(':') {
   return
  }
 }

 value := p.parseExpression()

 property.Name = name
 property.NamePos = namePos
 property.Value = value
 property.ColonPos = pos

 return
}

func (p *parser) parseExpression() (value Expression) {
 value = p.parseValue()
 switch p.tok {
 case '+':
  return p.parseOperator(value)
 case '-':
  p.errorf("subtraction not supported: %s", p.scanner.String())
  return value
 default:
  return value
 }
}

func (p *parser) parseOperator(value1 Expression) Expression {
 operator := p.tok
 pos := p.scanner.Position
 p.accept(operator)

 value2 := p.parseExpression()

 return &Operator{
  Args:        [2]Expression{value1, value2},
  Operator:    operator,
  OperatorPos: pos,
 }
}

func (p *parser) parseValue() (value Expression) {
 switch p.tok {
 case scanner.Ident:
  switch text := p.scanner.TokenText(); text {
  case "true", "false":
   return p.parseBoolean()
  case "select":
   return p.parseSelect()
  default:
   return p.parseVariable()
  }
 case '-', scanner.Int: // Integer might have '-' sign ahead ('+' is only treated as operator now)
  return p.parseIntValue()
 case scanner.String, scanner.RawString:
  return p.parseStringValue()
 case '[':
  return p.parseListValue()
 case '{':
  return p.parseMapValue()
 default:
  p.errorf("expected bool, list, or string value; found %s",
   scanner.TokenString(p.tok))
  return
 }
}

func (p *parser) parseBoolean() Expression {
 switch text := p.scanner.TokenText(); text {
 case "true", "false":
  result := &Bool{
   LiteralPos: p.scanner.Position,
   Value:      text == "true",
   Token:      text,
  }
  p.accept(scanner.Ident)
  return result
 default:
  p.errorf("Expected true/false, got %q", text)
  return nil
 }
}

func (p *parser) parseVariable() Expression {
 var value Expression

 text := p.scanner.TokenText()
 value = &Variable{
  Name:    text,
  NamePos: p.scanner.Position,
 }

 p.accept(scanner.Ident)
 return value
}

func (p *parser) parseSelect() Expression {
 result := &Select{
  KeywordPos: p.scanner.Position,
 }
 // Read the "select("
 p.accept(scanner.Ident)
 if !p.accept('(') {
  return nil
 }

 // If we see another '(', there's probably multiple conditions and there must
 // be a ')' after. Set the multipleConditions variable to remind us to check for
 // the ')' after.
 multipleConditions := false
 if p.tok == '(' {
  multipleConditions = true
  p.accept('(')
 }

 // Read all individual conditions
 conditions := []ConfigurableCondition{}
 for first := true; first || multipleConditions; first = false {
  condition := ConfigurableCondition{
   position:     p.scanner.Position,
   FunctionName: p.scanner.TokenText(),
  }
  if !p.accept(scanner.Ident) {
   return nil
  }
  if !p.accept('(') {
   return nil
  }

  for p.tok != ')' {
   if s := p.parseStringValue(); s != nil {
    condition.Args = append(condition.Args, *s)
   } else {
    return nil
   }
   if p.tok == ')' {
    break
   }
   if !p.accept(',') {
    return nil
   }
  }
  p.accept(')')

  for _, c := range conditions {
   if c.Equals(condition) {
    p.errorf("Duplicate select condition found: %s", c.String())
   }
  }

  conditions = append(conditions, condition)

  if multipleConditions {
   if p.tok == ')' {
    p.next()
    break
   }
   if !p.accept(',') {
    return nil
   }
   // Retry the closing parent to allow for a trailing comma
   if p.tok == ')' {
    p.next()
    break
   }
  }
 }

 if multipleConditions && len(conditions) < 2 {
  p.errorf("Expected multiple select conditions due to the extra parenthesis, but only found 1. Please remove the extra parenthesis.")
  return nil
 }

 result.Conditions = conditions

 if !p.accept(',') {
  return nil
 }

 result.LBracePos = p.scanner.Position
 if !p.accept('{') {
  return nil
 }

 maybeParseBinding := func() (Variable, bool) {
  if p.scanner.TokenText() != "@" {
   return Variable{}, false
  }
  p.next()
  value := Variable{
   Name:    p.scanner.TokenText(),
   NamePos: p.scanner.Position,
  }
  p.accept(scanner.Ident)
  return value, true
 }

 parseOnePattern := func() SelectPattern {
  var result SelectPattern
  switch p.tok {
  case scanner.Ident:
   switch p.scanner.TokenText() {
   case "any":
    result.Value = &String{
     LiteralPos: p.scanner.Position,
     Value:      any_select_branch_name,
    }
    p.next()
    if binding, exists := maybeParseBinding(); exists {
     result.Binding = binding
    }
    return result
   case "default":
    result.Value = &String{
     LiteralPos: p.scanner.Position,
     Value:      default_select_branch_name,
    }
    p.next()
    return result
   case "true":
    result.Value = &Bool{
     LiteralPos: p.scanner.Position,
     Value:      true,
    }
    p.next()
    return result
   case "false":
    result.Value = &Bool{
     LiteralPos: p.scanner.Position,
     Value:      false,
    }
    p.next()
    return result
   default:
    p.errorf("Expected a string, true, false, or default, got %s", p.scanner.TokenText())
   }
  case scanner.Int:
   if i := p.parseIntValue(); i != nil {
    result.Value = i
    return result
   }
   p.errorf("Expected a string, int, true, false, or default, got %s", p.scanner.TokenText())
  case scanner.String:
   if s := p.parseStringValue(); s != nil {
    if strings.HasPrefix(s.Value, "__soong") {
     p.errorf("select branch patterns starting with __soong are reserved for internal use")
     return result
    }
    result.Value = s
    return result
   }
   fallthrough
  default:
   p.errorf("Expected a string, int, true, false, or default, got %s", p.scanner.TokenText())
  }
  return result
 }

 hasNonUnsetValue := false
 for p.tok != '}' {
  c := &SelectCase{}

  if multipleConditions {
   if !p.accept('(') {
    return nil
   }
   for i := 0; i < len(conditions); i++ {
    c.Patterns = append(c.Patterns, parseOnePattern())
    if i < len(conditions)-1 {
     if !p.accept(',') {
      return nil
     }
    } else if p.tok == ',' {
     // allow optional trailing comma
     p.next()
    }
   }
   if !p.accept(')') {
    return nil
   }
  } else {
   c.Patterns = append(c.Patterns, parseOnePattern())
  }
  c.ColonPos = p.scanner.Position
  if !p.accept(':') {
   return nil
  }
  if p.tok == scanner.Ident && p.scanner.TokenText() == "unset" {
   c.Value = &UnsetProperty{Position: p.scanner.Position}
   p.accept(scanner.Ident)
  } else {
   hasNonUnsetValue = true
   c.Value = p.parseExpression()
  }
  // allow trailing comma, require it if not seeing a }
  if p.tok != '}' {
   if !p.accept(',') {
    return nil
   }
  }
  result.Cases = append(result.Cases, c)
 }

 // If all branches have the value "unset", then this is equivalent
 // to an empty select.
 if !hasNonUnsetValue {
  p.errorf("This select statement is empty, remove it")
  return nil
 }

 patternsEqual := func(a, b SelectPattern) bool {
  // We can ignore the bindings, they don't affect which pattern is matched
  switch a2 := a.Value.(type) {
  case *String:
   if b2, ok := b.Value.(*String); ok {
    return a2.Value == b2.Value
   } else {
    return false
   }
  case *Bool:
   if b2, ok := b.Value.(*Bool); ok {
    return a2.Value == b2.Value
   } else {
    return false
   }
  case *Int64:
   if b2, ok := b.Value.(*Int64); ok {
    return a2.Value == b2.Value
   } else {
    return false
   }
  default:
   // true so that we produce an error in this unexpected scenario
   return true
  }
 }

 patternListsEqual := func(a, b []SelectPattern) bool {
  if len(a) != len(b) {
   return false
  }
  for i := range a {
   if !patternsEqual(a[i], b[i]) {
    return false
   }
  }
  return true
 }

 for i, c := range result.Cases {
  // Check for duplicate patterns across different branches
  for _, d := range result.Cases[i+1:] {
   if patternListsEqual(c.Patterns, d.Patterns) {
    p.errorf("Found duplicate select patterns: %v", c.Patterns)
    return nil
   }
  }
  // check for duplicate bindings within this branch
  for i := range c.Patterns {
   if c.Patterns[i].Binding.Name != "" {
    for j := i + 1; j < len(c.Patterns); j++ {
     if c.Patterns[i].Binding.Name == c.Patterns[j].Binding.Name {
      p.errorf("Found duplicate select pattern binding: %s", c.Patterns[i].Binding.Name)
      return nil
     }
    }
   }
  }
  // Check that the only all-default cases is the last one
  if i < len(result.Cases)-1 {
   isAllDefault := true
   for _, x := range c.Patterns {
    if x2, ok := x.Value.(*String); !ok || x2.Value != default_select_branch_name {
     isAllDefault = false
     break
    }
   }
   if isAllDefault {
    p.errorf("Found a default select branch at index %d, expected it to be last (index %d)", i, len(result.Cases)-1)
    return nil
   }
  }
 }

 result.RBracePos = p.scanner.Position
 if !p.accept('}') {
  return nil
 }
 if !p.accept(')') {
  return nil
 }
 return result
}

func (p *parser) parseStringValue() *String {
 str, err := strconv.Unquote(p.scanner.TokenText())
 if err != nil {
  p.errorf("couldn't parse string: %s", err)
  return nil
 }

 value := &String{
  LiteralPos: p.scanner.Position,
  Value:      str,
 }
 p.accept(p.tok)
 return value
}

func (p *parser) parseIntValue() *Int64 {
 var str string
 literalPos := p.scanner.Position
 if p.tok == '-' {
  str += string(p.tok)
  p.accept(p.tok)
  if p.tok != scanner.Int {
   p.errorf("expected int; found %s", scanner.TokenString(p.tok))
   return nil
  }
 }
 str += p.scanner.TokenText()
 i, err := strconv.ParseInt(str, 1064)
 if err != nil {
  p.errorf("couldn't parse int: %s", err)
  return nil
 }

 value := &Int64{
  LiteralPos: literalPos,
  Value:      i,
  Token:      str,
 }
 p.accept(scanner.Int)
 return value
}

func (p *parser) parseListValue() *List {
 lBracePos := p.scanner.Position
 if !p.accept('[') {
  return nil
 }

 var elements []Expression
 for p.tok != ']' {
  element := p.parseExpression()
  elements = append(elements, element)

  if p.tok != ',' {
   // There was no comma, so the list is done.
   break
  }

  p.accept(',')
 }

 rBracePos := p.scanner.Position
 p.accept(']')

 return &List{
  LBracePos: lBracePos,
  RBracePos: rBracePos,
  Values:    elements,
 }
}

func (p *parser) parseMapValue() *Map {
 lBracePos := p.scanner.Position
 if !p.accept('{') {
  return nil
 }

 properties := p.parsePropertyList(false, false)

 rBracePos := p.scanner.Position
 p.accept('}')

 return &Map{
  LBracePos:  lBracePos,
  RBracePos:  rBracePos,
  Properties: properties,
 }
}

type Scope struct {
 vars              map[string]*Assignment
 preventInheriting map[string]bool
 parentScope       *Scope
}

func NewScope(s *Scope) *Scope {
 return &Scope{
  vars:              make(map[string]*Assignment),
  preventInheriting: make(map[string]bool),
  parentScope:       s,
 }
}

func (s *Scope) HandleAssignment(assignment *Assignment) error {
 switch assignment.Assigner {
 case "+=":
  if !s.preventInheriting[assignment.Name] && s.parentScope.Get(assignment.Name) != nil {
   return fmt.Errorf("modified non-local variable %q with +=", assignment.Name)
  }
  if old, ok := s.vars[assignment.Name]; !ok {
   return fmt.Errorf("modified non-existent variable %q with +=", assignment.Name)
  } else if old.Referenced.Load() {
   return fmt.Errorf("modified variable %q with += after referencing", assignment.Name)
  } else {
   newValue, err := evaluateOperator(s, '+', old.Value, assignment.Value)
   if err != nil {
    return err
   }
   old.Value = newValue
  }
 case "=":
  if old, ok := s.vars[assignment.Name]; ok {
   return fmt.Errorf("variable already set, previous assignment: %s", old)
  }

  if old := s.parentScope.Get(assignment.Name); old != nil && !s.preventInheriting[assignment.Name] {
   return fmt.Errorf("variable already set in inherited scope, previous assignment: %s", old)
  }

  if newValue, err := assignment.Value.Eval(s); err != nil {
   return err
  } else {
   assignment.Value = newValue
  }
  s.vars[assignment.Name] = assignment
 default:
  return fmt.Errorf("Unknown assigner '%s'", assignment.Assigner)
 }
 return nil
}

func (s *Scope) Get(name string) *Assignment {
 if s == nil {
  return nil
 }
 if a, ok := s.vars[name]; ok {
  return a
 }
 if s.preventInheriting[name] {
  return nil
 }
 return s.parentScope.Get(name)
}

func (s *Scope) GetLocal(name string) *Assignment {
 if s == nil {
  return nil
 }
 if a, ok := s.vars[name]; ok {
  return a
 }
 return nil
}

// DontInherit prevents this scope from inheriting the given variable from its
// parent scope.
func (s *Scope) DontInherit(name string) {
 s.preventInheriting[name] = true
}

func (s *Scope) String() string {
 var sb strings.Builder
 s.stringInner(&sb)
 return sb.String()
}

func (s *Scope) stringInner(sb *strings.Builder) {
 if s == nil {
  return
 }
 vars := make([]string, 0, len(s.vars))
 for k := range s.vars {
  vars = append(vars, k)
 }

 sort.Strings(vars)

 for _, v := range vars {
  sb.WriteString(s.vars[v].String())
  sb.WriteRune('\n')
 }

 s.parentScope.stringInner(sb)
}

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

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik