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