github.phpd.cn/thought-machine/please@v12.2.0+incompatible/src/parse/asp/util.go (about)

     1  package asp
     2  
     3  import "strings"
     4  
     5  // FindTarget returns the top-level call in a BUILD file that corresponds to a target
     6  // of the given name (or nil if one does not exist).
     7  func FindTarget(statements []*Statement, name string) *Statement {
     8  	for _, statement := range statements {
     9  		if ident := statement.Ident; ident != nil && ident.Action != nil && ident.Action.Call != nil {
    10  			for _, arg := range ident.Action.Call.Arguments {
    11  				if arg.Name == "name" {
    12  					if arg.Value.Val != nil && arg.Value.Val.String != "" && strings.Trim(arg.Value.Val.String, `"`) == name {
    13  						return statement
    14  					}
    15  				}
    16  			}
    17  		}
    18  	}
    19  	return nil
    20  }
    21  
    22  // NextStatement finds the statement that follows the given one.
    23  // This is often useful to find the extent of a statement in source code.
    24  // It will return nil if there is not one following it.
    25  func NextStatement(statements []*Statement, statement *Statement) *Statement {
    26  	for i, s := range statements {
    27  		if s == statement && i < len(statements)-1 {
    28  			return statements[i+1]
    29  		}
    30  	}
    31  	return nil
    32  }
    33  
    34  // GetExtents returns the "extents" of a statement, i.e. the lines that it covers in source.
    35  // The caller must pass a value for the maximum extent of the file; we can't detect it here
    36  // because the AST only contains positions for the beginning of the statements.
    37  func GetExtents(statements []*Statement, statement *Statement, max int) (int, int) {
    38  	next := NextStatement(statements, statement)
    39  	if next == nil {
    40  		// Assume it reaches to the end of the file
    41  		return statement.Pos.Line, max
    42  	}
    43  	return statement.Pos.Line, next.Pos.Line - 1
    44  }
    45  
    46  // FindArgument finds an argument of any one of the given names, or nil if there isn't one.
    47  // The statement must be a function call (e.g. as returned by FindTarget).
    48  func FindArgument(statement *Statement, args ...string) *CallArgument {
    49  	for i, a := range statement.Ident.Action.Call.Arguments {
    50  		for _, arg := range args {
    51  			if a.Name == arg {
    52  				return &statement.Ident.Action.Call.Arguments[i]
    53  			}
    54  		}
    55  	}
    56  	return nil
    57  }