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  }