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 }