js/jasminesnake/ast/nodes.py

1475 lines
43 KiB
Python

"""The module with AST nodes declaration. They are ESTree compliant.
The module lacks support of:
* ES5 features:
* labelled statements
* switch statements
* try-catch statements
* debugger statement
* with statement
* RegExp
* ES2015 features:
* generators/yield statement
* for-of statement
* template literals
* ES2017 features:
* async/await.
Basically, the whole standard consists of it, so no ES2017 support.
* ES2018 features:
* for-await-of statement
* template literals
* ES2019 features
* catch binding omission.
The only ES2019 feature.
More about ESTree standard:
https://github.com/estree/estree/
Todo:
* Add support for lacking features
* Make another attempt to split up this module
"""
from typing import List, Union, Optional, Literal as TypeLiteral, Any
from enum import Enum
from collections import OrderedDict
# The Lord sees I actually wanted to split it up, but ESTree hierarchy is so messed up... No. It's actually *fucked up*
# that much that I couldn't even resolve circular dependencies in the submodules. I have to reap what I've sown.
# Custom types used in the nodes
number = float
"""A type representing Number type in JavaScript."""
bigint = int
"""A type representing BigInt type in JavaScript."""
SourceTypeLiteral = TypeLiteral["script", "module"]
"""The type for the `sourceType` field."""
VarDeclKind = TypeLiteral["var", "let", "const"]
"""The type for the `kind` field of `VariableDeclaration`."""
PropKind = TypeLiteral["init", "get", "set"]
"""A type for a `kind` field of `Property`."""
MethodDefinitionKind = TypeLiteral["constructor", "method", "get", "set"]
"""A type for a `kind` field of `MethodDefinition`."""
class UnaryOperator(Enum):
"""A unary operator token."""
MINUS = "-"
PLUS = "+"
NOT_LOGIC = "!"
NOT_BIT = "~"
TYPEOF = "typeof"
VOID = "void"
DELETE = "delete"
class UpdateOperator(Enum):
"""An update (increment or decrement) operator token."""
INCREMENT = "++"
DECREMENT = "--"
class BinaryOperator(Enum):
"""A binary operator token."""
EQ = "=="
NEQ = "!="
EQ_IDENTITY = "==="
NEQ_IDENTITY = "!=="
LT = "<"
LTE = "<="
GT = ">"
GTE = ">="
SHL = "<<"
SHR = ">>"
SHR_LOGIC = ">>>"
ADD = "+"
SUB = "-"
MUL = "*"
DIV = "/"
MOD = "%"
OR = "|"
XOR = "^"
AND = "&"
IN = "in"
INSTANCEOF = "instanceof"
POW = "**"
class AssignmentOperator(Enum):
"""An assignment operator token."""
ASSIGN = "="
ADD = "+="
SUB = "-="
MUL = "*="
DIV = "/="
MOD = "%="
SHL = "<<="
SHR = ">>="
SHR_LOGIC = ">>>="
OR = "|="
XOR = "^="
AND = "&="
POW = "**="
class LogicalOperator(Enum):
"""A logical operator token."""
OR = "||"
AND = "&&"
NULLISH_COALESCING = "??"
# Nodes forward declarations
class Expression:
...
class Pattern:
...
class Directive:
...
class Statement:
...
class FunctionBody:
...
class VariableDeclaration:
...
class Property:
...
class Identifier:
...
class Literal:
...
# "Node objects" block
class Position:
"""The class for an object consisting of a line number (1-indexed) and a column number (0-indexed)."""
def __init__(self, line: int, column: int):
if line < 1 or column < 0:
raise ValueError(
"L{}:C{} is not valid ESTree position!".format(line, column)
)
self.line = line
self.column = column
def __str__(self):
return f"{self.line}:{self.column}"
class SourceLocation:
"""
The class for the source location information of a node.
Consists of a start position (the position of the first character of the parsed source region) and an end
position (the position of the first character after the parsed source region).
See Also:
Position
"""
def __init__(self, source: Optional[str], start: Position, end: Position):
self.source = source
self.start = start
self.end = end
@property
def fields(self):
return OrderedDict({"start": self.start, "end": self.end})
def __str__(self):
src = "" if self.source is None else f"{self.source}:"
return f"{src}{str(self.start)}"
class Node:
"""ESTree AST nodes are represented as Node objects, which may have any prototype inheritance but which implement
this interface.
The `type` field is a string representing the AST variant type. Each subtype of `Node` is documented below with
the specific string of its `type` field. You can use this field to determine which interface a node implements.
The `loc` field represents the source location information of the node. If the node contains no information about
the source location, the field is `None`; otherwise it contains a `SourceLocation` object.
See Also:
SourceLocation
"""
def __init__(self, node_type: str, loc: Optional[SourceLocation]):
self.type = node_type
self.loc = loc
self._fields: OrderedDict[str, Any] = OrderedDict()
self._fields.update({"type": self.type, "loc": self.loc})
def __str__(self):
return f"{self.type} at {str(self.loc)}"
@property
def fields(self):
return self._fields
# "Programs" block
class Program(Node):
"""A complete program source tree."""
def __init__(
self,
loc: Optional[SourceLocation],
source_type: SourceTypeLiteral,
body: List[Union[Directive, Statement]],
):
super().__init__("Program", loc)
self.body = body
self.source_type = source_type
self._fields.update({"sourceType": self.source_type, "body": self.body})
# "Functions" block
class Function(Node):
"""A function declaration or expression.
See Also:
FunctionDeclaration
FunctionExpression
FunctionBody
"""
def __init__(
self,
node_type: str,
loc: Optional[SourceLocation],
function_id: Optional[Identifier],
params: List[Pattern],
body: FunctionBody,
):
super().__init__(node_type, loc)
self.id = function_id
self.params = params
self.body = body
self._fields.update({"id": self.id, "params": self.params, "body": self.body})
# "Statements" block
class Statement(Node):
"""Any statement."""
def __init__(self, node_type: str, loc: Optional[SourceLocation]):
super().__init__(node_type, loc)
class EmptyStatement(Statement):
"""An empty statement, i.e., a solitary semicolon."""
def __init__(self, loc: Optional[SourceLocation]):
super().__init__("EmptyStatement", loc)
class BlockStatement(Statement):
"""A block statement, i.e., a sequence of statements surrounded by braces."""
def __init__(self, loc: Optional[SourceLocation], body: List[Statement]):
super().__init__("BlockStatement", loc)
self.body = body
self._fields.update({"body": self.body})
class ExpressionStatement(Statement):
"""An expression statement, i.e., a statement consisting of a single expression."""
def __init__(self, loc: Optional[SourceLocation], expression: Expression):
super().__init__("ExpressionStatement", loc)
self.expression = expression
self._fields.update({"expression": self.expression})
class Directive(Node):
"""A directive from the directive prologue of a script or function. The `directive` property is the raw string
source of the directive without quotes.
"""
def __init__(
self, loc: Optional[SourceLocation], expression: Literal, directive: str
):
super().__init__("Directive", loc)
self.expression = expression
self.directive = directive
self._fields.update(
{"expression": self.expression, "directive": self.directive}
)
class FunctionBody(BlockStatement):
"""The body of a function, which is a block statement that may begin with directives."""
def __init__(
self, loc: Optional[SourceLocation], body: List[Union[Directive, Statement]]
):
super().__init__(loc, body)
class ReturnStatement(Statement):
"""A `return` statement."""
def __init__(self, loc: Optional[SourceLocation], argument: Optional[Expression]):
super().__init__("ReturnStatement", loc)
self.argument = argument
self._fields.update({"argument": self.argument})
class BreakStatement(Statement):
"""A `break` statement."""
def __init__(self, loc: Optional[SourceLocation], label: Optional[Identifier]):
super().__init__("BreakStatement", loc)
self.label = label
self._fields.update({"label": self.label})
class ContinueStatement(Statement):
"""A `continue` statement."""
def __init__(self, loc: Optional[SourceLocation], label: Optional[Identifier]):
super().__init__("ContinueStatement", loc)
self.label = label
self._fields.update({"label": self.label})
class IfStatement(Statement):
"""An `if` statement."""
def __init__(
self,
loc: Optional[SourceLocation],
test: Expression,
consequent: Statement,
alternate: Optional[Statement],
):
super().__init__("IfStatement", loc)
self.test = test
self.consequent = consequent
self.alternate = alternate
self._fields.update(
{
"test": self.test,
"consequent": self.consequent,
"alternate": self.alternate,
}
)
class WhileStatement(Statement):
"""A `while` statement."""
def __init__(
self, loc: Optional[SourceLocation], test: Expression, body: Statement
):
super().__init__("WhileStatement", loc)
self.test = test
self.body = body
self._fields.update({"test": self.test, "body": self.body})
class DoWhileStatement(Statement):
"""A `do`/`while` statement."""
def __init__(
self, loc: Optional[SourceLocation], body: Statement, test: Expression
):
super().__init__("DoWhileStatement", loc)
self.body = body
self.test = test
self._fields.update({"body": self.body, "test": self.test})
class ForStatement(Statement):
"""A `for` statement."""
def __init__(
self,
loc: Optional[SourceLocation],
init: Union[VariableDeclaration, Expression, None],
test: Optional[Expression],
update: Optional[Expression],
body: Statement,
):
super().__init__("ForStatement", loc)
self.init = init
self.test = test
self.update = update
self.body = body
self._fields.update(
{
"init": self.init,
"test": self.test,
"update": self.update,
"body": self.body,
}
)
class ForInStatement(Statement):
"""A `for`/`in` statement."""
def __init__(
self,
loc: Optional[SourceLocation],
left: Union[VariableDeclaration, Pattern],
right: Expression,
body: Statement,
):
super().__init__("ForInStatement", loc)
self.left = left
self.right = right
self.body = body
self._fields.update({"left": self.left, "right": self.right, "body": self.body})
# "Declarations" block
class Declaration(Statement):
"""Any declaration node. Note that declarations are considered statements; this is because declarations can
appear in any statement context. """
def __init__(self, node_type: str, loc: Optional[SourceLocation]):
super().__init__(node_type, loc)
class FunctionDeclaration(Function, Declaration):
"""A function declaration. Note that unlike in the parent interface `Function`, the `id` cannot be `None`."""
def __init__(
self,
loc: Optional[SourceLocation],
function_id: Identifier,
params: List[Pattern],
body: FunctionBody,
):
super().__init__("FunctionDeclaration", loc, function_id, params, body)
class VariableDeclarator(Node):
"""A variable declarator."""
def __init__(
self, loc: Optional[SourceLocation], var_id: Pattern, init: Optional[Expression]
):
super().__init__("VariableDeclarator", loc)
self.id = var_id
self.init = init
self._fields.update({"id": self.id, "init": self.init})
class VariableDeclaration(Declaration):
"""A variable declaration."""
def __init__(
self,
loc: Optional[SourceLocation],
kind: VarDeclKind,
declarations: List[VariableDeclarator],
):
super().__init__("VariableDeclaration", loc)
self.declarations = declarations
self.kind = kind
self._fields.update({"kind": self.kind, "declarations": self.declarations})
# "Expressions" block
class Expression(Node):
"""Any expression node. Since the left-hand side of an assignment may be any expression in general, an expression
can also be a pattern.
See Also:
Pattern
"""
def __init__(self, node_type: str, loc: Optional[SourceLocation]):
super().__init__(node_type, loc)
class Super(Node):
"""A ``super`` pseudo-expression."""
def __init__(self, loc: Optional[SourceLocation]):
super().__init__("Super", loc)
class SpreadElement(Node):
"""Spread expression, e.g., ``[head, ...iter, tail]``, ``f(head, ...iter, ...tail)``."""
def __init__(self, loc: Optional[SourceLocation], argument: Expression):
super().__init__("SpreadElement", loc)
self.argument = argument
self._fields.update({"argument": self.argument})
class ThisExpression(Expression):
"""A `this` expression."""
def __init__(self, loc: Optional[SourceLocation]):
super().__init__("ThisExpression", loc)
class ArrayExpression(Expression):
"""An array expression. An element might be `None` if it represents a hole in a sparse array. E.g. ``[1,,2]``."""
def __init__(
self,
loc: Optional[SourceLocation],
elements: List[Union[Expression, SpreadElement, None]],
):
super().__init__("ArrayExpression", loc)
self.elements = elements
self._fields.update({"elements": self.elements})
class ObjectExpression(Expression):
"""An object expression."""
def __init__(
self,
loc: Optional[SourceLocation],
properties: List[Union[Property, SpreadElement]],
):
super().__init__("ObjectExpression", loc)
self.properties = properties
self._fields.update({"properties": self.properties})
class FunctionExpression(Function, Expression):
"""A function expression."""
def __init__(
self,
loc: Optional[SourceLocation],
function_id: Optional[Identifier],
params: List[Pattern],
body: FunctionBody,
):
super().__init__("FunctionExpression", loc, function_id, params, body)
class ArrowFunctionExpression(Function, Expression):
"""A fat arrow function expression, e.g., ``let foo = (bar) => { /* body */ }``."""
def __init__(
self,
loc: Optional[SourceLocation],
params: List[Pattern],
body: Union[FunctionBody, Expression],
expression: bool,
):
super().__init__("ArrowFunctionExpression", loc, None, params, body)
self.expression = expression
self._fields.update({"expression": self.expression})
class UnaryExpression(Expression):
"""A unary operator expression."""
def __init__(
self,
loc: Optional[SourceLocation],
operator: UnaryOperator,
prefix: bool,
argument: Expression,
):
super().__init__("UnaryExpression", loc)
self.operator = operator
self.prefix = prefix
self.argument = argument
self._fields.update(
{
"operator": self.operator,
"prefix": self.prefix,
"argument": self.argument,
}
)
class UpdateExpression(Expression):
"""An update (increment or decrement) operator expression."""
def __init__(
self,
loc: Optional[SourceLocation],
operator: UpdateOperator,
argument: Expression,
prefix: bool,
):
super().__init__("UpdateExpression", loc)
self.operator = operator
self.argument = argument
self.prefix = prefix
self._fields.update(
{
"operator": self.operator,
"argument": self.argument,
"prefix": self.prefix,
}
)
class BinaryExpression(Expression):
"""A binary operator expression."""
def __init__(
self,
loc: Optional[SourceLocation],
operator: BinaryOperator,
left: Expression,
right: Expression,
):
super().__init__("BinaryExpression", loc)
self.operator = operator
self.left = left
self.right = right
self._fields.update(
{"operator": self.operator, "left": self.left, "right": self.right}
)
class AssignmentExpression(Expression):
"""An assignment operator expression."""
def __init__(
self,
loc: Optional[SourceLocation],
operator: AssignmentOperator,
left: Union[
Pattern, Expression
], # Left for backwards compatibility with pre-ES6 code, should be `Pattern`
right: Expression,
):
super().__init__("AssignmentExpression", loc)
self.operator = operator
self.left = left
self.right = right
self._fields.update(
{"operator": self.operator, "left": self.left, "right": self.right}
)
class LogicalExpression(Expression):
"""A logical operator expression."""
def __init__(
self,
loc: Optional[SourceLocation],
operator: LogicalOperator,
left: Union[Pattern, Expression],
right: Expression,
):
super().__init__("LogicalExpression", loc)
self.operator = operator
self.left = left
self.right = right
self._fields.update(
{"operator": self.operator, "left": self.left, "right": self.right}
)
class MemberExpression(Expression, Pattern):
"""A member expression. If `computed` is ``True``, the node corresponds to a computed (``a[b]``) member
expression and `property` is an `Expression`. If `computed` is `False`, the node corresponds to a static
(``a.b``) member expression and `property` is an `Identifier`. """
def __init__(
self,
loc: Optional[SourceLocation],
member_object: Union[Expression, Super],
member_property: Expression,
computed: bool,
):
super().__init__("MemberExpression", loc)
self.object = member_object
self.property = member_property
self.computed = computed
self._fields.update(
{
"object": self.object,
"property": self.property,
"computed": self.computed,
}
)
class ConditionalExpression(Expression):
"""A conditional expression, i.e., a ternary ``?``/``:`` expression."""
def __init__(
self,
loc: Optional[SourceLocation],
test: Expression,
alternate: Expression,
consequent: Expression,
):
super().__init__("ConditionalExpression", loc)
self.test = test
self.alternate = alternate
self.consequent = consequent
self._fields.update(
{
"test": self.test,
"alternate": self.alternate,
"consequent": self.consequent,
}
)
class CallExpression(Expression):
"""A function or method call expression."""
def __init__(
self,
loc: Optional[SourceLocation],
callee: Union[Expression, Super],
arguments: List[Union[Expression, SpreadElement]],
):
super().__init__("CallExpression", loc)
self.callee = callee
self.arguments = arguments
self._fields.update({"callee": self.callee, "arguments": self.arguments})
class NewExpression(Expression):
"""A ``new`` expression."""
def __init__(
self,
loc: Optional[SourceLocation],
callee: Expression,
arguments: List[Union[Expression, SpreadElement]],
):
super().__init__("NewExpression", loc)
self.callee = callee
self.arguments = arguments
self._fields.update({"callee": self.callee, "arguments": self.arguments})
class SequenceExpression(Expression):
"""A sequence expression, i.e., a comma-separated sequence of expressions."""
def __init__(self, loc: Optional[SourceLocation], expressions: List[Expression]):
super().__init__("SequenceExpression", loc)
self.expressions = expressions
self._fields.update({"expressions": self.expressions})
def _generate_unary_expression(operator: UnaryOperator, docstring: str):
"""Internal function to generate unary expression AST node.
Implying that all UnaryExpression nodes are prefix.
"""
class Expr(UnaryExpression):
__doc__ = docstring
def __init__(self, loc: Optional[SourceLocation], argument: Expression):
super().__init__(loc, operator, True, argument)
return Expr
def _generate_update_expression(operator: UpdateOperator, prefix: bool, docstring: str):
"""Internal function to generate update expression AST node."""
class Expr(UpdateExpression):
__doc__ = docstring
def __init__(self, loc: Optional[SourceLocation], argument: Expression):
super().__init__(loc, operator, argument, prefix)
return Expr
def _generate_binary_expression(operator: BinaryOperator, docstring: str):
"""Internal function to generate binary expression AST node."""
class Expr(BinaryExpression):
__doc__ = docstring
def __init__(
self, loc: Optional[SourceLocation], left: Expression, right: Expression
):
super().__init__(loc, operator, left, right)
return Expr
def _generate_assignment_expression(operator: AssignmentOperator, docstring: str):
"""Internal function to generate assignment expression AST node."""
class Expr(AssignmentExpression):
__doc__ = docstring
def __init__(
self,
loc: Optional[SourceLocation],
left: Union[Pattern, Expression],
right: Expression,
):
super().__init__(loc, operator, left, right)
return Expr
def _generate_logical_expression(operator: LogicalOperator, docstring: str):
"""Internal function to generate logical expression AST node."""
class Expr(LogicalExpression):
__doc__ = docstring
def __init__(
self,
loc: Optional[SourceLocation],
left: Union[Pattern, Expression],
right: Expression,
):
super().__init__(loc, operator, left, right)
return Expr
UnaryMinusExpression = _generate_unary_expression(
UnaryOperator.MINUS, """A unary minus expression."""
)
UnaryPlusExpression = _generate_unary_expression(
UnaryOperator.PLUS, """A unary plus expression."""
)
UnaryLogicNotExpression = _generate_unary_expression(
UnaryOperator.NOT_LOGIC, """A unary logic "not" expression."""
)
UnaryBitNotExpression = _generate_unary_expression(
UnaryOperator.NOT_BIT, """A unary bit "not" expression."""
)
TypeofExpression = _generate_unary_expression(
UnaryOperator.TYPEOF, """A `typeof` expression."""
)
VoidExpression = _generate_unary_expression(
UnaryOperator.VOID, """A `void` expression."""
)
DeleteExpression = _generate_unary_expression(
UnaryOperator.DELETE, """A `delete` expression."""
)
PreIncrementExpression = _generate_update_expression(
UpdateOperator.INCREMENT, True, """A pre-increment expression."""
)
PostIncrementExpression = _generate_update_expression(
UpdateOperator.INCREMENT, False, """A post-increment expression."""
)
PreDecrementExpression = _generate_update_expression(
UpdateOperator.DECREMENT, True, """A pre-decrement expression."""
)
PostDecrementExpression = _generate_update_expression(
UpdateOperator.DECREMENT, False, """A post-decrement expression."""
)
EqualityExpression = _generate_binary_expression(
BinaryOperator.EQ, """An equality expression."""
)
NotEqualityExpression = _generate_binary_expression(
BinaryOperator.NEQ, """A "not equality" expression."""
)
IdentityEqualityExpression = _generate_binary_expression(
BinaryOperator.EQ_IDENTITY, """An identity equality expression."""
)
NotIdentityEqualityExpression = _generate_binary_expression(
BinaryOperator.NEQ_IDENTITY, """A "not identity equality" expression."""
)
LowerThanRelationExpression = _generate_binary_expression(
BinaryOperator.LT, """A "lower than" expression."""
)
LowerThanEqualRelationExpression = _generate_binary_expression(
BinaryOperator.LTE, """A "lower than or equal" expression."""
)
GreaterThanRelationExpression = _generate_binary_expression(
BinaryOperator.GT, """A "greater than" expression."""
)
GreaterThanEqualRelationExpression = _generate_binary_expression(
BinaryOperator.GTE, """A "greater than or equal" expression."""
)
LeftBitShiftExpression = _generate_binary_expression(
BinaryOperator.SHL, """A "left bit shift" expression."""
)
RightBitShiftExpression = _generate_binary_expression(
BinaryOperator.SHR, """A "right bit shift" expression."""
)
LogicRightBitShiftExpression = _generate_binary_expression(
BinaryOperator.SHR_LOGIC, """A "logical right bit shift" expression."""
)
AddArithmeticExpression = _generate_binary_expression(
BinaryOperator.ADD, """An addition arithmetical expression."""
)
SubArithmeticExpression = _generate_binary_expression(
BinaryOperator.SUB, """A subtraction arithmetical expression."""
)
MulArithmeticExpression = _generate_binary_expression(
BinaryOperator.MUL, """A multiplication arithmetical expression."""
)
DivArithmeticExpression = _generate_binary_expression(
BinaryOperator.DIV, """A division arithmetical expression."""
)
ModArithmeticExpression = _generate_binary_expression(
BinaryOperator.MOD, """A modulo arithmetical expression."""
)
OrBitExpression = _generate_binary_expression(
BinaryOperator.OR, """An "or" bit expression."""
)
XorBitExpression = _generate_binary_expression(
BinaryOperator.XOR, """A "xor" bit expression."""
)
AndBitExpression = _generate_binary_expression(
BinaryOperator.AND, """An "and" bit expression."""
)
InExpression = _generate_binary_expression(BinaryOperator.IN, """An "in" expression.""")
InstanceofExpression = _generate_binary_expression(
BinaryOperator.INSTANCEOF, """An "instanceof" expression."""
)
PowBinaryExpression = _generate_binary_expression(
BinaryOperator.POW, """A power expression, e.g. ``2**3``."""
)
SimpleAssignExpression = _generate_assignment_expression(
AssignmentOperator.ASSIGN, """An assignment done with operator ``=`` expression."""
)
AddAssignExpression = _generate_assignment_expression(
AssignmentOperator.ADD,
"""An addition assignment done with operator ``+=`` expression.""",
)
SubAssignExpression = _generate_assignment_expression(
AssignmentOperator.SUB,
"""A subtraction assignment done with operator ``-=`` expression.""",
)
MulAssignExpression = _generate_assignment_expression(
AssignmentOperator.MUL,
"""A multiplication assignment done with operator ``*=`` expression.""",
)
ModAssignExpression = _generate_assignment_expression(
AssignmentOperator.DIV,
"""A modulo assignment done with operator ``%=`` expression.""",
)
ShlAssignExpression = _generate_assignment_expression(
AssignmentOperator.SHL,
"""A left shift assignment done with operator ``<<=`` expression.""",
)
ShrAssignExpression = _generate_assignment_expression(
AssignmentOperator.SHR,
"""A right shift assignment done with operator ``>>=`` expression.""",
)
LogicShrAssignExpression = _generate_assignment_expression(
AssignmentOperator.SHR_LOGIC,
"""A logical right shift assignment done with operator ``>>>=`` expression.""",
)
OrAssignExpression = _generate_assignment_expression(
AssignmentOperator.OR,
"""A "bit or" assignment done with operator ``|=`` expression.""",
)
XorAssignExpression = _generate_assignment_expression(
AssignmentOperator.XOR,
"""A "bit xor" assignment done with operator ``^=`` expression.""",
)
AndAssignExpression = _generate_assignment_expression(
AssignmentOperator.AND,
"""A "bit and" assignment done with operator ``&=`` expression.""",
)
PowAssignExpression = _generate_assignment_expression(
AssignmentOperator.POW, """A power assignment expression, e.g. ``x**=2``."""
)
OrLogicExpression = _generate_logical_expression(
LogicalOperator.OR, """An "or" logical expression."""
)
AndLogicExpression = _generate_logical_expression(
LogicalOperator.AND, """An "and" logical expression."""
)
NullishCoalescingLogicExpression = _generate_logical_expression(
LogicalOperator.NULLISH_COALESCING, """A nullish coalescing logical expression."""
)
# "Literal" block
class Literal(Expression):
"""A literal token. Note that a literal can be an expression."""
def __init__(
self,
loc: Optional[SourceLocation],
value: Union[str, bool, number, bigint, None],
):
super().__init__("Literal", loc)
self.value = value
self._fields.update({"value": self.value})
class BigIntLiteral(Literal):
"""`bigint` property is the string representation of the ``BigInt`` value. It doesn't include the suffix ``n``.
In environments that don't support ``BigInt`` values, value property will be `None` as the ``BigInt`` value can't
be represented natively.
"""
def __init__(
self,
loc: Optional[SourceLocation],
value: Union[str, bool, number, bigint, None],
bigint: str,
):
super().__init__(loc, value)
self.bigint = bigint
self._fields.update({"bigint": self.bigint})
class NullLiteral(Literal):
def __init__(self, loc: Optional[SourceLocation]):
super().__init__(loc, None)
def __str__(self):
return "null"
class BooleanLiteral(Literal):
def __init__(self, loc: Optional[SourceLocation], value: bool):
super().__init__(loc, value)
def __str__(self):
return str(self.value).lower()
class StringLiteral(Literal):
def __init__(self, loc: Optional[SourceLocation], value: str):
super().__init__(loc, value)
def __str__(self):
return f'"{self.value}"'
class NumericLiteral(Literal):
def __init__(self, loc: Optional[SourceLocation], value: number):
super().__init__(loc, value)
# "Property" block
class Property(Node):
"""A literal property in an object expression can have either a string or number as its `value`. Ordinary
property initializers have a `kind` value ``"init"``; getters and setters have the kind values ``"get"`` and
``"set"``, respectively. """
def __init__(
self,
loc: Optional[SourceLocation],
key: Expression,
value: Expression,
kind: PropKind,
method: bool,
shorthand: bool,
computed: bool,
):
super().__init__("Property", loc)
self.key = key
self.value = value
self.kind = kind
self.method = method
self.shorthand = shorthand
self.computed = computed
self._fields.update(
{
"key": self.key,
"value": self.value,
"kind": self.kind,
"method": self.method,
"shorthand": self.shorthand,
"computed": self.computed,
}
)
class AssignmentProperty(Property):
def __init__(
self,
loc: Optional[SourceLocation],
key: Expression,
value: Pattern,
shorthand: bool,
computed: bool,
):
super().__init__(loc, key, value, "init", False, shorthand, computed)
# "Patterns" block
#
# Destructuring binding and assignment are not part of ES5, but all binding positions accept Pattern
# to allow for destructuring in ES6. Nevertheless, for ES5, the only Pattern subtype is Identifier.
class Pattern(Node):
"""A pattern."""
def __init__(self, node_type: str, loc: Optional[SourceLocation]):
super().__init__(node_type, loc)
class RestElement(Pattern):
def __init__(self, loc: Optional[SourceLocation], argument: Pattern):
super().__init__("RestElement", loc)
self.argument = argument
self._fields.update({"argument": self.argument})
class ObjectPattern(Pattern):
def __init__(
self,
loc: Optional[SourceLocation],
properties: List[Union[AssignmentProperty, RestElement]],
):
super().__init__("ObjectPattern", loc)
self.properties = properties
self._fields.update({"properties": self.properties})
class ArrayPattern(Pattern):
def __init__(
self, loc: Optional[SourceLocation], elements: List[Optional[Pattern]]
):
super().__init__("ArrayPattern", loc)
self.elements = elements
self._fields.update({"elements": self.elements})
class AssignmentPattern(Pattern):
def __init__(self, loc: Optional[SourceLocation], left: Pattern, right: Expression):
super().__init__("AssignmentPattern", loc)
self.left = left
self.right = right
self._fields.update({"left": self.left, "right": self.right})
# "Identifier" block
class Identifier(Expression, Pattern):
"""An identifier. Note that an identifier may be an expression or a destructuring pattern."""
def __init__(self, loc: Optional[SourceLocation], name: str):
super().__init__("Identifier", loc)
self.name = name
self._fields.update({"name": self.name})
# "Classes" block
class MethodDefinition(Node):
def __init__(
self,
loc: Optional[SourceLocation],
key: Expression,
value: FunctionExpression,
kind: MethodDefinitionKind,
computed: bool,
static: bool,
):
super().__init__("MethodDefinition", loc)
self.key = key
self.value = value
self.kind = kind
self.computed = computed
self.static = static
self._fields.update(
{
"key": self.key,
"value": self.value,
"kind": self.kind,
"computed": self.computed,
"static": self.static,
}
)
class ClassBody(Node):
def __init__(self, loc: Optional[SourceLocation], body: List[MethodDefinition]):
super().__init__("ClassBody", loc)
self.body = body
self._fields.update({"body": self.body})
class Class(Node):
def __init__(
self,
node_type: str,
loc: Optional[SourceLocation],
class_id: Optional[Identifier],
super_class: Optional[Expression],
body: ClassBody,
):
super().__init__(node_type, loc)
self.id = class_id
self.super_class = super_class
self.body = body
self._fields.update(
{"id": self.id, "superClass": self.super_class, "body": self.body}
)
class ClassDeclaration(Class, Declaration):
def __init__(
self,
loc: Optional[SourceLocation],
class_id: Identifier,
super_class: Optional[Expression],
body: ClassBody,
):
super().__init__("ClassDeclaration", loc, class_id, super_class, body)
class ClassExpression(Class, Expression):
def __init__(
self,
loc: Optional[SourceLocation],
class_id: Optional[Identifier],
super_class: Optional[Expression],
body: ClassBody,
):
super().__init__("ClassExpression", loc, class_id, super_class, body)
class MetaProperty(Expression):
"""`MetaProperty` node represents ``new.target`` meta property in ES2015.
In the future, it will represent other meta properties as well.
"""
def __init__(
self, loc: Optional[SourceLocation], meta: Identifier, meta_property: Identifier
):
super().__init__("MetaProperty", loc)
self.meta = (meta,)
self.property = meta_property
self._fields.update({"meta": self.meta, "property": self.property})
# "Modules" block
class ModuleDeclaration(Node):
"""A module ``import`` or ``export`` declaration."""
def __init__(self, node_type: str, loc: Optional[SourceLocation]):
super().__init__(node_type, loc)
class ModuleSpecifier(Node):
"""A specifier in an import or export declaration."""
def __init__(
self, node_type: str, loc: Optional[SourceLocation], local: Identifier
):
super().__init__(node_type, loc)
self.local = local
self._fields.update({"local": self.local})
class ImportSpecifier(ModuleSpecifier):
"""An imported variable binding, e.g., ``{foo}`` in ``import {foo} from "mod"``
or ``{foo as bar}`` in ``import {foo as bar} from "mod"``. The `imported` field
refers to the name of the export imported from the module. The `local` field
refers to the binding imported into the local module scope. If it is a basic named
import, such as in ``import {foo} from "mod"``, both `imported` and `local` are
equivalent `Identifier` nodes; in this case an `Identifier` node representing ``foo``.
If it is an aliased import, such as in ``import {foo as bar} from "mod"``, the
`imported` field is an `Identifier` node representing ``foo``, and the `local` field
is an `Identifier` node representing ``bar``.
"""
def __init__(
self, loc: Optional[SourceLocation], local: Identifier, imported: Identifier
):
super().__init__("ImportSpecifier", loc, local)
self.imported = imported
self._fields.update({"imported": self.imported})
class ImportDefaultSpecifier(ModuleSpecifier):
"""A default import specifier, e.g., ``foo`` in ``import foo from "mod.js"``."""
def __init__(self, loc: Optional[SourceLocation], local: Identifier):
super().__init__("ImportDefaultSpecifier", loc, local)
class ImportNamespaceSpecifier(ModuleSpecifier):
"""A namespace import specifier, e.g., ``* as foo`` in ``import * as foo from "mod.js"``."""
def __init__(self, loc: Optional[SourceLocation], local: Identifier):
super().__init__("ImportNamespaceSpecifier", loc, local)
class ImportDeclaration(ModuleDeclaration):
"""An import declaration, e.g., ``import foo from "mod";``."""
def __init__(
self,
loc: Optional[SourceLocation],
specifiers: List[
Union[ImportSpecifier, ImportDefaultSpecifier, ImportNamespaceSpecifier]
],
source: Literal,
):
super().__init__("ImportDeclaration", loc)
self.specifiers = specifiers
self.source = source
self._fields.update({"specifiers": self.specifiers, "source": self.source})
class ImportExpression(Expression):
"""`ImportExpression` node represents Dynamic Imports such as ``import(source)``.
The `source` property is the importing source as similar to ImportDeclaration node,
but it can be an arbitrary expression node.
"""
def __init__(self, loc: Optional[SourceLocation], source: Expression):
super().__init__("ImportExpression", loc)
self.source = source
self._fields.update({"source": self.source})
class ExportSpecifier(ModuleSpecifier):
"""An exported variable binding, e.g., ``{foo}`` in ``export {foo}`` or ``{bar as foo}``
in ``export {bar as foo}``. The `exported` field refers to the name exported in the module.
The `local` field refers to the binding into the local module scope. If it is a basic named
export, such as in ``export {foo}``, both `exported` and `local` are equivalent `Identifier`
nodes; in this case an `Identifier` node representing ``foo``. If it is an aliased export,
such as in ``export {bar as foo}``, the `exported` field is an `Identifier` node representing
``foo``, and the `local` field is an `Identifier` node representing ``bar``.
"""
def __init__(
self, loc: Optional[SourceLocation], local: Identifier, exported: Identifier
):
super().__init__("ExportSpecifier", loc, local)
self.exported = exported
self._fields.update({"exported": self.exported})
class ExportNamedDeclaration(ModuleDeclaration):
"""An export named declaration, e.g., ``export {foo, bar};``, ``export {foo} from "mod";``
or ``export var foo = 1;``.
Notes:
Having `declaration` populated with non-empty `specifiers` or non-null `source` results
in an invalid state.
"""
def __init__(
self,
loc: Optional[SourceLocation],
declaration: Optional[Declaration],
specifiers: List[ExportSpecifier],
source: Optional[Literal],
):
super().__init__("ExportNamedDeclaration", loc)
self.declaration = declaration
self.specifiers = specifiers
self.source = source
self._fields.update(
{
"declaration": self.declaration,
"specifiers": self.specifiers,
"source": self.source,
}
)
class AnonymousDefaultExportedFunctionDeclaration(Function):
def __init__(
self, loc: Optional[SourceLocation], params: List[Pattern], body: FunctionBody
):
super().__init__("FunctionDeclaration", loc, None, params, body)
class AnonymousDefaultExportedClassDeclaration(Class):
def __init__(
self,
loc: Optional[SourceLocation],
super_class: Optional[Expression],
body: ClassBody,
):
super().__init__("ClassDeclaration", loc, None, super_class, body)
class ExportDefaultDeclaration(ModuleDeclaration):
"""An export default declaration, e.g., ``export default function () {};`` or ``export default 1;``."""
def __init__(
self,
loc: Optional[SourceLocation],
declaration: Union[
AnonymousDefaultExportedFunctionDeclaration,
FunctionDeclaration,
AnonymousDefaultExportedClassDeclaration,
ClassDeclaration,
Expression,
],
):
super().__init__("ExportDefaultDeclaration", loc)
self.declaration = declaration
self._fields.update({"declaration": self.declaration})
class ExportAllDeclaration(ModuleDeclaration):
"""An export batch declaration, e.g., ``export * from "mod";``.
The `exported` property contains an `Identifier` when a different exported
name is specified using ``as``, e.g., ``export * as foo from "mod";``.
"""
def __init__(
self,
loc: Optional[SourceLocation],
source: Literal,
exported: Optional[Identifier],
):
super().__init__("ExportAllDeclaration", loc)
self.source = source
self.exported = exported
self._fields.update({"source": self.source, "exported": self.exported})