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

     1  package asp
     2  
     3  // A FileInput is the top-level structure of a BUILD file.
     4  type FileInput struct {
     5  	Statements []*Statement `{ @@ } EOF`
     6  }
     7  
     8  // A Statement is the type we work with externally the most; it's a single Python statement.
     9  // Note that some mildly excessive fiddling is needed since the parser we're using doesn't
    10  // support backoff (i.e. if an earlier entry matches to its completion but can't consume
    11  // following tokens, it doesn't then make another choice :( )
    12  type Statement struct {
    13  	Pos     Position
    14  	FuncDef *FuncDef         `| @@`
    15  	For     *ForStatement    `| @@`
    16  	If      *IfStatement     `| @@`
    17  	Return  *ReturnStatement `| "return" @@ EOL`
    18  	Raise   *Expression      `| "raise" @@ EOL`
    19  	Assert  *struct {
    20  		Expr    *Expression `@@`
    21  		Message string      `["," @String]`
    22  	} `| "assert" @@ EOL`
    23  	Ident    *IdentStatement `| @@ EOL`
    24  	Literal  *Expression     `| @@ EOL)`
    25  	Pass     bool            `( @"pass" EOL`
    26  	Continue bool            `| @"continue" EOL`
    27  }
    28  
    29  // A ReturnStatement implements the Python 'return' statement.
    30  type ReturnStatement struct {
    31  	Values []*Expression `[ @@ { "," @@ } ]`
    32  }
    33  
    34  // A FuncDef implements definition of a new function.
    35  type FuncDef struct {
    36  	Name       string       `"def" @Ident`
    37  	Arguments  []Argument   `"(" [ @@ { "," @@ } ] ")" Colon EOL`
    38  	Docstring  string       `[ @String EOL ]`
    39  	Statements []*Statement `{ @@ } Unindent`
    40  	// Not part of the grammar. Used to indicate internal targets that can only
    41  	// be called using keyword arguments.
    42  	KeywordsOnly bool
    43  }
    44  
    45  // A ForStatement implements the 'for' statement.
    46  // Note that it does not support Python's "for-else" construction.
    47  type ForStatement struct {
    48  	Names      []string     `"for" @Ident [ { "," @Ident } ] "in"`
    49  	Expr       Expression   `@@ Colon EOL`
    50  	Statements []*Statement `{ @@ } Unindent`
    51  }
    52  
    53  // An IfStatement implements the if-elif-else statement.
    54  type IfStatement struct {
    55  	Condition  Expression   `"if" @@ Colon EOL`
    56  	Statements []*Statement `{ @@ } Unindent`
    57  	Elif       []struct {
    58  		Condition  Expression   `"elif" @@ Colon EOL`
    59  		Statements []*Statement `{ @@ } Unindent`
    60  	} `{ @@ }`
    61  	ElseStatements []*Statement `[ "else" Colon EOL { @@ } Unindent ]`
    62  }
    63  
    64  // An Argument represents an argument to a function definition.
    65  type Argument struct {
    66  	Name string   `@Ident`
    67  	Type []string `[ ":" @( { ( "bool" | "str" | "int" | "list" | "dict" | "function" ) [ "|" ] } ) ]`
    68  	// Aliases are an experimental non-Python concept where function arguments can be aliased to different names.
    69  	// We use this to support compatibility with Bazel & Buck etc in some cases.
    70  	Aliases []string    `[ "&" ( { @Ident [ "&" ] } ) ]`
    71  	Value   *Expression `[ "=" @@ ]`
    72  }
    73  
    74  // An Expression is a generalised Python expression, i.e. anything that can appear where an
    75  // expression is allowed (including the extra parts like inline if-then-else, operators, etc).
    76  type Expression struct {
    77  	Pos     Position
    78  	UnaryOp *UnaryOp         `( @@`
    79  	Val     *ValueExpression `| @@ )`
    80  	Op      []OpExpression   `{ @@ }`
    81  	If      *InlineIf        `[ @@ ]`
    82  	// For internal optimisation - do not use outside this package.
    83  	Optimised *OptimisedExpression
    84  }
    85  
    86  // An OptimisedExpression contains information to optimise certain aspects of execution of
    87  // an expression. It must be public for serialisation but shouldn't be used outside this package.
    88  type OptimisedExpression struct {
    89  	// Used to optimise constant expressions.
    90  	Constant pyObject
    91  	// Similarly applied to optimise simple lookups of local variables.
    92  	Local string
    93  	// And similarly applied to optimise lookups into configuration.
    94  	Config string
    95  }
    96  
    97  // An OpExpression is a operator combined with its following expression.
    98  type OpExpression struct {
    99  	Op   Operator    `@("+" | "-" | "%" | "<" | ">" | "and" | "or" | "is" | "in" | "not" "in" | "==" | "!=" | ">=" | "<=")`
   100  	Expr *Expression `@@`
   101  }
   102  
   103  // A ValueExpression is the value part of an expression, i.e. without surrounding operators.
   104  type ValueExpression struct {
   105  	String string `( @String`
   106  	Int    *struct {
   107  		Int int `@Int`
   108  	} `| @@` // Should just be *int, but https://github.com/golang/go/issues/23498 :(
   109  	Bool     string     `| @( "True" | "False" | "None" )`
   110  	List     *List      `| "[" @@ "]"`
   111  	Dict     *Dict      `| "{" @@ "}"`
   112  	Tuple    *List      `| "(" @@ ")"`
   113  	Lambda   *Lambda    `| "lambda" @@`
   114  	Ident    *IdentExpr `| @@ )`
   115  	Slice    *Slice     `[ @@ ]`
   116  	Property *IdentExpr `[ ( "." @@`
   117  	Call     *Call      `| "(" @@ ")" ) ]`
   118  }
   119  
   120  // A UnaryOp represents a unary operation - in our case the only ones we support are negation and not.
   121  type UnaryOp struct {
   122  	Op   string          `@( "-" | "not" )`
   123  	Expr ValueExpression `@@`
   124  }
   125  
   126  // An IdentStatement implements a statement that begins with an identifier (i.e. anything that
   127  // starts off with a variable name). It is a little fiddly due to parser limitations.
   128  type IdentStatement struct {
   129  	Name   string `@Ident`
   130  	Unpack *struct {
   131  		Names []string    `@Ident { "," @Ident }`
   132  		Expr  *Expression `"=" @@`
   133  	} `( "," @@ `
   134  	Index *struct {
   135  		Expr      *Expression `@@ "]"`
   136  		Assign    *Expression `( "=" @@`
   137  		AugAssign *Expression `| "+=" @@ )`
   138  	} `| "[" @@`
   139  	Action *IdentStatementAction `| @@ )`
   140  }
   141  
   142  // An IdentStatementAction implements actions on an IdentStatement.
   143  type IdentStatementAction struct {
   144  	Property  *IdentExpr  `  "." @@`
   145  	Call      *Call       `| "(" @@ ")"`
   146  	Assign    *Expression `| "=" @@`
   147  	AugAssign *Expression `| "+=" @@`
   148  }
   149  
   150  // An IdentExpr implements parts of an expression that begin with an identifier (i.e. anything
   151  // that might be a variable name).
   152  type IdentExpr struct {
   153  	Name   string `@Ident`
   154  	Action []struct {
   155  		Property *IdentExpr `  "." @@`
   156  		Call     *Call      `| "(" @@ ")"`
   157  	} `{ @@ }`
   158  }
   159  
   160  // A Call represents a call site of a function.
   161  type Call struct {
   162  	Arguments []CallArgument `[ @@ ] { "," [ @@ ] }`
   163  }
   164  
   165  // A CallArgument represents a single argument at a call site of a function.
   166  type CallArgument struct {
   167  	Name  string     `[ @@ "=" ]`
   168  	Value Expression `@@`
   169  }
   170  
   171  // A List represents a list literal, either with or without a comprehension clause.
   172  type List struct {
   173  	Values        []*Expression  `[ @@ ] { "," [ @@ ] }`
   174  	Comprehension *Comprehension `[ @@ ]`
   175  }
   176  
   177  // A Dict represents a dict literal, either with or without a comprehension clause.
   178  type Dict struct {
   179  	Items         []*DictItem    `[ @@ ] { "," [ @@ ] }`
   180  	Comprehension *Comprehension `[ @@ ]`
   181  }
   182  
   183  // A DictItem represents a single key-value pair in a dict literal.
   184  type DictItem struct {
   185  	Key   Expression `@( Ident | String ) ":"`
   186  	Value Expression `@@`
   187  }
   188  
   189  // A Slice represents a slice or index expression (e.g. [1], [1:2], [2:], [:], etc).
   190  type Slice struct {
   191  	Start *Expression `"[" [ @@ ]`
   192  	Colon string      `[ @":" ]`
   193  	End   *Expression `[ @@ ] "]"`
   194  }
   195  
   196  // An InlineIf implements the single-line if-then-else construction
   197  type InlineIf struct {
   198  	Condition *Expression `"if" @@`
   199  	Else      *Expression `[ "else" @@ ]`
   200  }
   201  
   202  // A Comprehension represents a list or dict comprehension clause.
   203  type Comprehension struct {
   204  	Names  []string    `"for" @Ident [ { "," @Ident } ] "in"`
   205  	Expr   *Expression `@@`
   206  	Second *struct {
   207  		Names []string    `"for" @Ident [ { "," @Ident } ] "in"`
   208  		Expr  *Expression `@@`
   209  	} `[ @@ ]`
   210  	If *Expression `[ "if" @@ ]`
   211  }
   212  
   213  // A Lambda is the inline lambda function.
   214  type Lambda struct {
   215  	Arguments []Argument `[ @@ { "," @@ } ] Colon`
   216  	Expr      Expression `@@`
   217  }
   218  
   219  // An Operator defines a unary or binary operator.
   220  type Operator rune
   221  
   222  const (
   223  	// Add etc are arithmetic operators - these are implemented on a per-type basis
   224  	Add Operator = '+'
   225  	// Subtract implements binary - (only works on integers)
   226  	Subtract = '-'
   227  	// Modulo implements % (including string interpolation)
   228  	Modulo = '%'
   229  	// LessThan implements <
   230  	LessThan = '<'
   231  	// GreaterThan implements >
   232  	GreaterThan = '>'
   233  	// LessThanOrEqual implements <=
   234  	LessThanOrEqual = '≤'
   235  	// GreaterThanOrEqual implements >=
   236  	GreaterThanOrEqual = '≥'
   237  	// Equal etc are comparison operators - also on a per-type basis but have slightly different rules.
   238  	Equal = '='
   239  	// NotEqual implements !=
   240  	NotEqual = '≠'
   241  	// In implements the in operator
   242  	In = '∈'
   243  	// NotIn implements "not in" as a single operator.
   244  	NotIn = '∉'
   245  	// And etc are logical operators - these are implemented type-independently
   246  	And Operator = '&'
   247  	// Or implements the or operator
   248  	Or = '|'
   249  	// Is implements type identity.
   250  	Is = '≡'
   251  	// Index is used in the parser, but not when parsing code.
   252  	Index = '['
   253  )
   254  
   255  // String implements the fmt.Stringer interface. It is not especially efficient and is
   256  // normally only used for errors & debugging.
   257  func (o Operator) String() string {
   258  	for k, v := range operators {
   259  		if o == v {
   260  			return k
   261  		}
   262  	}
   263  	return "unknown"
   264  }
   265  
   266  var operators = map[string]Operator{
   267  	"+":      Add,
   268  	"-":      Subtract,
   269  	"%":      Modulo,
   270  	"<":      LessThan,
   271  	">":      GreaterThan,
   272  	"and":    And,
   273  	"or":     Or,
   274  	"is":     Is,
   275  	"in":     In,
   276  	"not in": NotIn,
   277  	"==":     Equal,
   278  	"!=":     NotEqual,
   279  	">=":     GreaterThanOrEqual,
   280  	"<=":     LessThanOrEqual,
   281  }