pulumi/pkg/pack/ast/expressions.go
joeduffy 3b0184cec3 Add a missing JSON annotation
The NewExpression AST node type was missing a JSON annotation on
its Type field, leading to decoding errors.

Now, with this, the full suite of MuJS test cases can be unmarshaled
into fully populated MuPack and MuIL structures.
2017-01-16 10:04:25 -08:00

363 lines
11 KiB
Go

// Copyright 2016 Marapongo, Inc. All rights reserved.
package ast
import (
"github.com/marapongo/mu/pkg/pack/symbols"
)
// Expression is an executable operation that usually produces a value.
type Expression interface {
Node
expression()
}
type expressionNode struct {
node
}
func (node *expressionNode) expression() {}
/* Literals */
type Literal interface {
GetRaw() *string // the raw literal, for round tripping purposes.
}
type literalNode struct {
expressionNode
Raw *string `json:"raw,omitempty"`
}
func (node *literalNode) GetRaw() *string { return node.Raw }
// NullLiteral represents the usual `null` constant.
type NullLiteral struct {
literalNode
}
var _ Node = (*NullLiteral)(nil)
var _ Expression = (*NullLiteral)(nil)
var _ Literal = (*NullLiteral)(nil)
const NullLiteralKind NodeKind = "NullLiteral"
// BoolLiteral represents the usual Boolean literal constant (`true` or `false`).
type BoolLiteral struct {
literalNode
Value bool `json:"value"`
}
var _ Node = (*BoolLiteral)(nil)
var _ Expression = (*BoolLiteral)(nil)
var _ Literal = (*BoolLiteral)(nil)
const BoolLiteralKind NodeKind = "BoolLiteral"
// NumberLiteral represents a floating point IEEE 754 literal value.
type NumberLiteral struct {
literalNode
Value float64 `json:"value"`
}
var _ Node = (*NumberLiteral)(nil)
var _ Expression = (*NumberLiteral)(nil)
var _ Literal = (*NumberLiteral)(nil)
const NumberLiteralKind NodeKind = "NumberLiteral"
// StringLiteral represents a UTF8-encoded string literal.
type StringLiteral struct {
literalNode
Value string `json:"value"`
}
var _ Node = (*StringLiteral)(nil)
var _ Expression = (*StringLiteral)(nil)
var _ Literal = (*StringLiteral)(nil)
const StringLiteralKind NodeKind = "StringLiteral"
// ArrayLiteral evaluates to a newly allocated array, with optional initialized elements.
type ArrayLiteral struct {
literalNode
Type *symbols.TypeToken `json:"type,omitempty"` // the optional type of array being produced.
Size *Expression `json:"size,omitempty"` // an optional expression for the array size.
Elements *[]Expression `json:"elements,omitempty"` // an optional array of element initializers.
}
var _ Node = (*ArrayLiteral)(nil)
var _ Expression = (*ArrayLiteral)(nil)
var _ Literal = (*ArrayLiteral)(nil)
const ArrayLiteralKind NodeKind = "ArrayLiteral"
// ObjectLiteral evaluates to a new object, with optional property initializers for primary properties.
type ObjectLiteral struct {
literalNode
Type *symbols.TypeToken `json:"type,omitempty"` // the optional type of object to produce.
Properties *[]ObjectLiteralProperty `json:"properties,omitempty"` // an optional array of property initializers.
}
var _ Node = (*ObjectLiteral)(nil)
var _ Expression = (*ObjectLiteral)(nil)
var _ Literal = (*ObjectLiteral)(nil)
const ObjectLiteralKind NodeKind = "ObjectLiteral"
// ObjectLiteralProperty initializes a single object literal property.
type ObjectLiteralProperty struct {
node
Name *Identifier `json:"name"` // the property to initialize.
Value Expression `json:"value"` // the expression whose value to store into the property.
}
var _ Node = (*ObjectLiteralProperty)(nil)
const ObjectLiteralPropertyKind NodeKind = "ObjectLiteralProperty"
/* Loads */
type LoadExpression interface {
Expression
loadExpression()
}
type loadExpressionNode struct {
expressionNode
}
func (node *loadExpressionNode) loadExpression() {}
// LoadLocationExpression loads a location's address, producing a pointer that can be dereferenced.
type LoadLocationExpression struct {
loadExpressionNode
Object *Expression `json:"object,omitempty"` // the `this` object, in the case of class properties.
Name *Identifier `json:"name"` // the name of the member to load.
}
var _ Node = (*LoadLocationExpression)(nil)
var _ Expression = (*LoadLocationExpression)(nil)
var _ LoadExpression = (*LoadLocationExpression)(nil)
const LoadLocationExpressionKind NodeKind = "LoadLocationExpression"
// LoadDynamicExpression dynamically loads either a variable or a function, by name, from an object.
type LoadDynamicExpression struct {
loadExpressionNode
Object Expression `json:"object"` // the object from which to load the property.
Name Expression `json:"name"` // the dynamically evaluated name of the property to load.
}
var _ Node = (*LoadDynamicExpression)(nil)
var _ Expression = (*LoadDynamicExpression)(nil)
var _ LoadExpression = (*LoadDynamicExpression)(nil)
const LoadDynamicExpressionKind NodeKind = "LoadDynamicExpression"
/* Functions */
type CallExpression interface {
Expression
GetArguments() *[]Expression // the list of arguments in sequential order.
}
type callExpressionNode struct {
expressionNode
Arguments *[]Expression `json:"arguments,omitempty"`
}
func (node *callExpressionNode) GetArguments() *[]Expression { return node.Arguments }
// NewExpression allocates a new object and calls its constructor.
type NewExpression struct {
callExpressionNode
Type *Identifier `json:"type"` // the object type to allocate.
}
var _ Node = (*NewExpression)(nil)
var _ Expression = (*NewExpression)(nil)
var _ CallExpression = (*NewExpression)(nil)
const NewExpressionKind NodeKind = "NewExpression"
// InvokeFunction invokes a target expression that must evaluate to a function.
type InvokeFunctionExpression struct {
callExpressionNode
Function Expression `json:"function"` // a function to invoke (of a function type).
}
var _ Node = (*InvokeFunctionExpression)(nil)
var _ Expression = (*InvokeFunctionExpression)(nil)
var _ CallExpression = (*InvokeFunctionExpression)(nil)
const InvokeFunctionExpressionKind NodeKind = "InvokeFunctionExpression"
// LambdaExpression creates a lambda, a sort of "anonymous" function, that evaluates to a function type.
type LambdaExpression struct {
expressionNode
Signature symbols.TypeToken `json:"signature"` // the function signature type.
Parameters []symbols.VariableToken `json:"parameters"` // the parameter variables.
Body *Block `json:"body"` // the lambda's body block.
}
var _ Node = (*LambdaExpression)(nil)
var _ Expression = (*LambdaExpression)(nil)
const LambdaExpressionKind NodeKind = "LambdaExpression"
/* Operators */
// UnaryOperatorExpression is the usual C-like unary operator.
type UnaryOperatorExpression struct {
expressionNode
Operator UnaryOperator `json:"operator"` // the operator type.
Operand Expression `json:"operand"` // the right hand side operand.
Postfix bool `json:"postfix"` // whether this is a postfix operator (only legal for UnaryPfixOperators).
}
var _ Node = (*UnaryOperatorExpression)(nil)
var _ Expression = (*UnaryOperatorExpression)(nil)
const UnaryOperatorExpressionKind NodeKind = "UnaryOperatorExpression"
// UnaryOperator is the full set of unary operator tokens. Note that MuIL doesn't care about precedence. The MetaMu
// compilers must present expression in the order in which they should be evaluated through an in-order AST tree walk.
type UnaryOperator string
const (
// Prefix-only operators:
OpDereference UnaryOperator = "*"
OpAddressof = "&"
OpUnaryPlus = "+"
OpUnaryMinus = "-"
OpLogicalNot = "!"
OpBitwiseNot = "~"
// These are permitted to be prefix or postfix:
OpPlusPlus = "++"
OpMinusMinus = "--"
)
// BinaryOperatorExpression is the usual C-like binary operator (assignment, logical, operator, or relational).
type BinaryOperatorExpression struct {
expressionNode
Left Expression `json:"left"` // the left hand side.
Operator BinaryOperator `json:"operator"` // the operator.
Right Expression `json:"right"` // the right hand side.
}
var _ Node = (*BinaryOperatorExpression)(nil)
var _ Expression = (*BinaryOperatorExpression)(nil)
const BinaryOperatorExpressionKind NodeKind = "BinaryOperatorExpression"
// All of the available arithmetic operators.
type BinaryOperator string
const (
// Arithmetic operators:
OpAdd BinaryOperator = "+"
OpSubtract = "-"
OpMultiply = "*"
OpDivide = "/"
OpRemainder = "%"
OpExponentiate = "**"
// Assignment operators:
OpAssign = "="
OpAssignSum = "+="
OpAssignDifference = "-="
OpAssignProduct = "*="
OpAssignQuotient = "/="
OpAssignRemainder = "%="
OpAssignExponentiation = "**="
OpAssignBitwiseShiftLeft = "<<="
OpAssignBitwiseShiftRight = ">>="
OpAssignBitwiseAnd = "&="
OpAssignBitwiseOr = "|="
OpAssignBitwiseXor = "^="
// Bitwise operators:
OpBitwiseShiftLeft = "<<"
OpBitwiseShiftRight = ">>"
OpBitwiseAnd = "&"
OpBitwiseOr = "|"
OpBitwiseXor = "^"
// Conditional operators:
OpLogicalAnd = "&&"
OpLogicalOr = "||"
// Relational operators:
OpLt = "<"
OpLtEquals = "<="
OpGt = ">"
OpGtEquals = ">="
OpEquals = "=="
OpNotEquals = "!="
)
/* Type Testing */
// CastExpression handles both nominal and structural casts, and will throw an exception upon failure.
type CastExpression struct {
expressionNode
Expression Expression `json:"expression"` // the source expression.
Type symbols.TypeToken `json:"type"` // the target type.
}
var _ Node = (*CastExpression)(nil)
var _ Expression = (*CastExpression)(nil)
const CastExpressionKind NodeKind = "CastExpression"
// IsInstExpression checks an expression for compatibility with the given type token, and evaluates to a bool.
type IsInstExpression struct {
expressionNode
Expression Expression `json:"expression"` // the source expression.
Type symbols.TypeToken `json:"type"` // the target type.
}
var _ Node = (*IsInstExpression)(nil)
var _ Expression = (*IsInstExpression)(nil)
const IsInstExpressionKind NodeKind = "IsInstExpression"
// TypeOfExpression gets the type token -- just a string -- of a particular type at runtime.
type TypeOfExpression struct {
expressionNode
Expression Expression `json:"expression"` // the source expression
}
var _ Node = (*TypeOfExpression)(nil)
var _ Expression = (*TypeOfExpression)(nil)
const TypeOfExpressionKind NodeKind = "TypeOfExpression"
/* Miscellaneous */
// ConditionalExpression evaluates to either a consequent or alternate based on a predicate condition.
type ConditionalExpression struct {
expressionNode
Condition Expression `json:"condition"` // a `bool` conditional expression.
Consequent Expression `json:"consequent"` // the expression to evaluate to if `true`.
Alternate Expression `json:"alternate"` // the expression to evaluate to if `false`.
}
var _ Node = (*ConditionalExpression)(nil)
var _ Expression = (*ConditionalExpression)(nil)
const ConditionalExpressionKind NodeKind = "ConditionalExpression"
// SequenceExpression allows composition of multiple expressions into one. It evaluates to the last one.
type SequenceExpression struct {
expressionNode
Expressions []Expression `json:"expressions"`
}
var _ Node = (*SequenceExpression)(nil)
var _ Expression = (*SequenceExpression)(nil)
const SequenceExpressionKind NodeKind = "SequenceExpression"