Documentation ¶
Overview ¶
Package asp implements an experimental BUILD-language parser. Parsing is doing using Participle (github.com/alecthomas/participle) in native Go, with a custom and also native partial Python interpreter.
Index ¶
- Constants
- Variables
- func AddReader(err error, r io.ReadSeeker) error
- func AddStackFrame(pos lexer.Position, err interface{}) error
- func GetExtents(statements []*Statement, statement *Statement, max int) (int, int)
- func NewLexer() lexer.Definition
- func RequiresSubinclude(err error) (bool, core.BuildLabel)
- type Argument
- type Call
- type CallArgument
- type Comprehension
- type Dict
- type DictItem
- type Environment
- type Expression
- type FileInput
- type ForStatement
- type FuncDef
- type Function
- type FunctionArg
- type IdentExpr
- type IdentStatement
- type IdentStatementAction
- type IfStatement
- type InlineIf
- type Lambda
- type LambdaArgument
- type List
- type Operator
- type Parser
- func (p *Parser) Environment() *Environment
- func (p *Parser) LoadBuiltins(filename string, contents, encoded []byte) error
- func (p *Parser) MustLoadBuiltins(filename string, contents, encoded []byte)
- func (p *Parser) ParseFile(state *core.BuildState, pkg *core.Package, filename string) error
- func (p *Parser) ParseFileOnly(filename string) ([]*Statement, error)
- func (p *Parser) ParseToFile(input, output string) error
- type ReturnStatement
- type Slice
- type Statement
- type UnaryOp
- type ValueExpression
Constants ¶
const ( EOF = -(iota + 1) Ident Int String EOL Unindent Colon // Would prefer not to have this but literal colons seem to deeply upset the parser. LexOperator // Similarly this, it doesn't seem to be able to handle == otherwise. )
Token types.
Variables ¶
var ( True pyBool = 1 False pyBool None pyBool = -1 FileNotFound pyBool = -2 )
True, False and None are the singletons representing those values in Python. None isn't really a bool of course, but it's easier to use an instance of bool than another custom type.
Functions ¶
func AddReader ¶
func AddReader(err error, r io.ReadSeeker) error
AddReader adds an io.Reader to an errStack, which will allow it to recover more information from that file.
func AddStackFrame ¶
AddStackFrame adds a new stack frame to the given errorStack, or wraps an existing error if not.
func GetExtents ¶
GetExtents returns the "extents" of a statement, i.e. the lines that it covers in source. The caller must pass a value for the maximum extent of the file; we can't detect it here because the AST only contains positions for the beginning of the statements.
func NewLexer ¶
func NewLexer() lexer.Definition
NewLexer is a slightly nicer interface to creating a new lexer definition.
func RequiresSubinclude ¶
func RequiresSubinclude(err error) (bool, core.BuildLabel)
RequiresSubinclude returns true if the error requires another target to be built, along with the target in question.
Types ¶
type Argument ¶
type Argument struct { Name string `@Ident` Type []string `[ ":" @( { ( "bool" | "str" | "int" | "list" | "dict" | "function" ) [ "|" ] } ) ]` Value *Expression `[ "=" @@ ]` }
An Argument represents an argument to a function definition.
type Call ¶
type Call struct {
Arguments []CallArgument `[ @@ ] { "," [ @@ ] }`
}
A Call represents a call site of a function.
type CallArgument ¶
type CallArgument struct { Expr *Expression `@@` Value *Expression `[ "=" @@ ]` // contains filtered or unexported fields }
A CallArgument represents a single argument at a call site of a function.
type Comprehension ¶
type Comprehension struct { Names []string `"for" @Ident [ { "," @Ident } ] "in"` Expr *Expression `@@` Second *struct { Names []string `"for" @Ident [ { "," @Ident } ] "in"` Expr *Expression `@@` } `[ @@ ]` If *Expression `[ "if" @@ ]` }
A Comprehension represents a list or dict comprehension clause.
type Dict ¶
type Dict struct { Items []*DictItem `[ @@ ] { "," [ @@ ] }` Comprehension *Comprehension `[ @@ ]` }
A Dict represents a dict literal, either with or without a comprehension clause.
type DictItem ¶
type DictItem struct { Key string `@( Ident | String ) ":"` Value Expression `@@` }
A DictItem represents a single key-value pair in a dict literal.
type Environment ¶
An Environment describes the global environment of the parser. TODO(peterebden): We may refactor this out in favour of exposing the AST instead.
type Expression ¶
type Expression struct { Pos lexer.Position UnaryOp *UnaryOp `( @@` Val *ValueExpression `| @@ )` Op *struct { Op Operator `@("+" | "-" | "%" | "<" | ">" | "and" | "or" | "is" | "in" | "not" "in" | "==" | "!=" | ">=" | "<=")` Expr *Expression `@@` } `[ @@ ]` If *InlineIf `[ @@ ]` // contains filtered or unexported fields }
An Expression is a generalised Python expression, i.e. anything that can appear where an expression is allowed (including the extra parts like inline if-then-else, operators, etc).
type FileInput ¶
type FileInput struct {
Statements []*Statement `{ @@ } EOF`
}
A FileInput is the top-level structure of a BUILD file.
type ForStatement ¶
type ForStatement struct { Names []string `"for" @Ident [ { "," @Ident } ] "in"` Expr Expression `@@ Colon EOL` Statements []*Statement `{ @@ } Unindent` }
A ForStatement implements the 'for' statement. Note that it does not support Python's "for-else" construction.
type FuncDef ¶
type FuncDef struct { Name string `"def" @Ident` Arguments []*Argument `"(" [ @@ { "," @@ } ] ")" Colon EOL` Docstring string `[ @String EOL ]` Statements []*Statement `{ @@ } Unindent` }
A FuncDef implements definition of a new function.
type Function ¶
type Function struct { Args []FunctionArg `json:"args"` Comment string `json:"comment,omitempty"` Docstring string `json:"docstring,omitempty"` Language string `json:"language,omitempty"` }
A Function describes a function within the global environment
type FunctionArg ¶
type FunctionArg struct { Comment string `json:"comment,omitempty"` Deprecated bool `json:"deprecated,omitempty"` Name string `json:"name"` Required bool `json:"required,omitempty"` Types []string `json:"types"` }
A FunctionArg represents a single argument to a function.
type IdentExpr ¶
type IdentExpr struct { Name string `@Ident` Action []struct { Property *IdentExpr ` "." @@` Call *Call `| "(" @@ ")"` } `{ @@ }` }
An IdentExpr implements parts of an expression that begin with an identifier (i.e. anything that might be a variable name).
type IdentStatement ¶
type IdentStatement struct { Name string `@Ident` Unpack *struct { Names []string `@Ident { "," @Ident }` Expr *Expression `"=" @@` } `( "," @@ ` Index *struct { Expr *Expression `@@ "]"` Assign *Expression `( "=" @@` AugAssign *Expression `| "+=" @@ )` } `| "[" @@` Action *IdentStatementAction `| @@ )` }
An IdentStatement implements a statement that begins with an identifier (i.e. anything that starts off with a variable name). It is a little fiddly due to parser limitations.
type IdentStatementAction ¶
type IdentStatementAction struct { Property *IdentExpr ` "." @@` Call *Call `| "(" @@ ")"` Assign *Expression `| "=" @@` AugAssign *Expression `| "+=" @@` }
An IdentStatementAction implements actions on an IdentStatement.
type IfStatement ¶
type IfStatement struct { Condition Expression `"if" @@ Colon EOL` Statements []*Statement `{ @@ } Unindent` Elif []struct { Condition *Expression `"elif" @@ Colon EOL` Statements []*Statement `{ @@ } Unindent` } `{ @@ }` ElseStatements []*Statement `[ "else" Colon EOL { @@ } Unindent ]` }
An IfStatement implements the if-elif-else statement.
type InlineIf ¶
type InlineIf struct { Condition *Expression `"if" @@` Else *Expression `[ "else" @@ ]` }
An InlineIf implements the single-line if-then-else construction
type Lambda ¶
type Lambda struct { Arguments []LambdaArgument `[ @@ { "," @@ } ] Colon` Expr Expression `@@` }
A Lambda is the inline lambda function.
type LambdaArgument ¶
type LambdaArgument struct { Name string `@Ident` Value *Expression `[ "=" @@ ]` }
A LambdaArgument represents an argument to a lambda function. Vexingly these can't be normal function arguments any more, because the : for type annotations gets preferentially consumed to the one that ends the lambda itself :(
type List ¶
type List struct { Values []*Expression `[ @@ ] { "," [ @@ ] }` Comprehension *Comprehension `[ @@ ]` }
A List represents a list literal, either with or without a comprehension clause.
type Operator ¶
type Operator int
An Operator wraps up a Python binary operator to be faster to switch on and to add some useful extra methods.
const ( // ComparisonOperator is used to mark comparison operators ComparisonOperator Operator = 0x100 // LogicalOperator is used to mark logical operators. LogicalOperator Operator = 0x200 // Add etc are arithmetic operators - these are implemented on a per-type basis Add Operator = iota // Subtract implements binary - (only works on integers) Subtract // Modulo implements % (including string interpolation) Modulo // LessThan implements < LessThan // GreaterThan implements > GreaterThan // LessThanOrEqual implements <= LessThanOrEqual // GreaterThanOrEqual implements >= GreaterThanOrEqual // Equal etc are comparison operators - also on a per-type basis but have slightly different rules. Equal = iota | ComparisonOperator // NotEqual implements != NotEqual // In implements the in operator In // NotIn implements "not in" as a single operator. NotIn // And etc are logical operators - these are implemented type-independently And Operator = iota | LogicalOperator // Or implements the or operator Or // Is implements type identity. Is // Index is used in the parser, but not when parsing code. Index = -iota )
func (Operator) IsComparison ¶
IsComparison returns true if this operator is a comparison operator.
type Parser ¶
type Parser struct {
// contains filtered or unexported fields
}
A Parser implements parsing of BUILD files.
func NewParser ¶
func NewParser(state *core.BuildState) *Parser
NewParser creates a new parser instance. One is normally sufficient for a process lifetime.
func (*Parser) Environment ¶
func (p *Parser) Environment() *Environment
Environment returns the current global environment of the parser.
func (*Parser) LoadBuiltins ¶
LoadBuiltins instructs the parser to load rules from this file as built-ins. Optionally the file contents can be supplied directly. Also optionally a previously parsed form (acquired from ParseToFile) can be supplied.
func (*Parser) MustLoadBuiltins ¶
MustLoadBuiltins calls LoadBuiltins, and dies on any errors.
func (*Parser) ParseFileOnly ¶
ParseFileOnly parses the given file but does not interpret it.
func (*Parser) ParseToFile ¶
ParseToFile parses the given file and writes a binary form of the result to the output file.
type ReturnStatement ¶
type ReturnStatement struct {
Values []*Expression `[ @@ { "," @@ } ]`
}
A ReturnStatement implements the Python 'return' statement.
type Slice ¶
type Slice struct { Start *Expression `"[" [ @@ ]` Colon string `[ @":" ]` End *Expression `[ @@ ] "]"` }
A Slice represents a slice or index expression (e.g. [1], [1:2], [2:], [:], etc).
type Statement ¶
type Statement struct { Pos lexer.Position Pass string `( @"pass" EOL` Continue string `| @"continue" EOL` FuncDef *FuncDef `| @@` For *ForStatement `| @@` If *IfStatement `| @@` Return *ReturnStatement `| "return" @@ EOL` Raise *Expression `| "raise" @@ EOL` Assert *struct { Expr *Expression `@@` Message string `["," @String]` } `| "assert" @@ EOL` Ident *IdentStatement `| @@ EOL` Literal *Expression `| @@ EOL)` }
A Statement is the type we work with externally the most; it's a single Python statement. Note that some mildly excessive fiddling is needed since the parser we're using doesn't support backoff (i.e. if an earlier entry matches to its completion but can't consume following tokens, it doesn't then make another choice :( )
func FindTarget ¶
FindTarget returns the top-level call in a BUILD file that corresponds to a target of the given name (or nil if one does not exist).
func NextStatement ¶
NextStatement finds the statement that follows the given one. This is often useful to find the extent of a statement in source code. It will return nil if there is not one following it.
type UnaryOp ¶
type UnaryOp struct { Op string `@( "-" | "not" )` Expr ValueExpression `@@` }
A UnaryOp represents a unary operation - in our case the only ones we support are negation and not.
type ValueExpression ¶
type ValueExpression struct { String string `( @String` Int *struct { Int int `@Int` } `| @@` // Should just be *int, but https://github.com/golang/go/issues/23498 :( Bool string `| @( "True" | "False" | "None" )` List *List `| "[" @@ "]"` Dict *Dict `| "{" @@ "}"` Tuple *List `| "(" @@ ")"` Lambda *Lambda `| "lambda" @@` Ident *IdentExpr `| @@ )` Slice *Slice `[ @@ ]` Property *IdentExpr `[ ( "." @@` Call *Call `| "(" @@ ")" ) ]` }
A ValueExpression is the value part of an expression, i.e. without surrounding operators.