mirror of https://github.com/t1meshift/js.git
Add AST to ASCII converter
parent
c09b52638c
commit
6414fecbfe
|
@ -1,7 +1,8 @@
|
|||
"""AST module."""
|
||||
|
||||
from enum import Enum
|
||||
from typing import Union
|
||||
from antlr4 import ParseTreeWalker
|
||||
from tree_format import format_tree
|
||||
|
||||
import lex.JavaScriptParser as Parser
|
||||
import ast.nodes
|
||||
|
@ -24,6 +25,46 @@ def from_parse_tree(tree: JSP.ProgramContext) -> ast.nodes.Program:
|
|||
return ast_listener.program_node
|
||||
|
||||
|
||||
def to_ascii_tree(
|
||||
node: Union[ast.nodes.Position, ast.nodes.SourceLocation, ast.nodes.Node],
|
||||
name_prefix: str = "",
|
||||
nesting_lvl: int = 0,
|
||||
):
|
||||
if nesting_lvl < 0:
|
||||
raise ValueError("Nesting level can't be below 0")
|
||||
|
||||
FORK = "+"
|
||||
VERTICAL = "|"
|
||||
HORIZONTAL = "-"
|
||||
|
||||
SUBENTRY_PREFIX = f"{FORK}{HORIZONTAL}{HORIZONTAL} "
|
||||
NESTED_PREFIX = f"{VERTICAL} "
|
||||
|
||||
value = str(node)
|
||||
children = None
|
||||
|
||||
if isinstance(node, Enum):
|
||||
value = str(node.value)
|
||||
|
||||
if isinstance(node, list):
|
||||
value = ""
|
||||
children = [(index, val) for index, val in enumerate(node)]
|
||||
|
||||
if hasattr(node, "fields"):
|
||||
children = [(k, node.fields[k]) for k in node.fields.keys()]
|
||||
|
||||
result = f"{NESTED_PREFIX * (nesting_lvl - 1)}{SUBENTRY_PREFIX * (nesting_lvl > 0)}"
|
||||
result += f"{name_prefix}{value}\n"
|
||||
|
||||
if children is not None:
|
||||
for (child_name, child_value) in children:
|
||||
result += to_ascii_tree(child_value, f"{child_name}: ", nesting_lvl + 1)
|
||||
|
||||
# result += "\n"
|
||||
|
||||
return result
|
||||
|
||||
|
||||
# Delete temporary imports
|
||||
del JSP
|
||||
del Parser
|
||||
|
|
|
@ -21,8 +21,9 @@ Todo:
|
|||
* Add support for lacking features
|
||||
"""
|
||||
|
||||
from typing import List, Union, Optional, Literal as TypeLiteral, TypedDict
|
||||
from typing import List, Union, Optional, Literal as TypeLiteral, TypedDict, 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.
|
||||
|
@ -140,6 +141,10 @@ class Property:
|
|||
...
|
||||
|
||||
|
||||
class Identifier:
|
||||
...
|
||||
|
||||
|
||||
# "Node objects" block
|
||||
|
||||
|
||||
|
@ -155,6 +160,9 @@ class Position:
|
|||
self.line = line
|
||||
self.column = column
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.line}:{self.column}"
|
||||
|
||||
|
||||
class SourceLocation:
|
||||
"""
|
||||
|
@ -172,6 +180,10 @@ class SourceLocation:
|
|||
self.start = start
|
||||
self.end = 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
|
||||
|
@ -191,16 +203,15 @@ class Node:
|
|||
self.type = node_type
|
||||
self.loc = loc
|
||||
|
||||
self._fields: OrderedDict[str, Any] = OrderedDict()
|
||||
self._fields.update({"type": self.type, "loc": self.loc})
|
||||
|
||||
# "Identifier" block
|
||||
def __str__(self):
|
||||
return f"{self.type} at {str(self.loc)}"
|
||||
|
||||
|
||||
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(Identifier, self).__init__("Identifier", loc)
|
||||
self.name = name
|
||||
@property
|
||||
def fields(self):
|
||||
return self._fields
|
||||
|
||||
|
||||
# "Literal" block
|
||||
|
@ -214,6 +225,7 @@ class Literal(Expression):
|
|||
):
|
||||
super().__init__("Literal", loc)
|
||||
self.value = value
|
||||
self._fields.update({"value": self.value})
|
||||
|
||||
|
||||
# "Programs" block
|
||||
|
@ -231,6 +243,7 @@ class Program(Node):
|
|||
super().__init__("Program", loc)
|
||||
self.body = body
|
||||
self.source_type = source_type
|
||||
self._fields.update({"sourceType": self.source_type, "body": self.body})
|
||||
|
||||
|
||||
# "Functions" block
|
||||
|
@ -257,6 +270,7 @@ class Function(Node):
|
|||
self.id = function_id
|
||||
self.params = params
|
||||
self.body = body
|
||||
self._fields.update({"id": self.id, "params": self.params, "body": self.body})
|
||||
|
||||
|
||||
# "Statements" block
|
||||
|
@ -282,6 +296,7 @@ class BlockStatement(Statement):
|
|||
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):
|
||||
|
@ -290,6 +305,7 @@ class ExpressionStatement(Statement):
|
|||
def __init__(self, loc: Optional[SourceLocation], expression: Expression):
|
||||
super().__init__("ExpressionStatement", loc)
|
||||
self.expression = expression
|
||||
self._fields.update({"expression": self.expression})
|
||||
|
||||
|
||||
class Directive(Node):
|
||||
|
@ -303,6 +319,9 @@ class Directive(Node):
|
|||
super().__init__("Directive", loc)
|
||||
self.expression = expression
|
||||
self.directive = directive
|
||||
self._fields.update(
|
||||
{"expression": self.expression, "directive": self.directive}
|
||||
)
|
||||
|
||||
|
||||
class FunctionBody(BlockStatement):
|
||||
|
@ -320,6 +339,7 @@ class ReturnStatement(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):
|
||||
|
@ -328,6 +348,7 @@ class BreakStatement(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):
|
||||
|
@ -336,6 +357,7 @@ class ContinueStatement(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):
|
||||
|
@ -352,6 +374,13 @@ class IfStatement(Statement):
|
|||
self.test = test
|
||||
self.consequent = consequent
|
||||
self.alternate = alternate
|
||||
self._fields.update(
|
||||
{
|
||||
"test": self.test,
|
||||
"consequent": self.consequent,
|
||||
"alternate": self.alternate,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class WhileStatement(Statement):
|
||||
|
@ -363,6 +392,7 @@ class WhileStatement(Statement):
|
|||
super().__init__("WhileStatement", loc)
|
||||
self.test = test
|
||||
self.body = body
|
||||
self._fields.update({"test": self.test, "body": self.body})
|
||||
|
||||
|
||||
class DoWhileStatement(Statement):
|
||||
|
@ -374,6 +404,7 @@ class DoWhileStatement(Statement):
|
|||
super().__init__("DoWhileStatement", loc)
|
||||
self.body = body
|
||||
self.test = test
|
||||
self._fields.update({"body": self.body, "test": self.test})
|
||||
|
||||
|
||||
class ForStatement(Statement):
|
||||
|
@ -392,6 +423,14 @@ class ForStatement(Statement):
|
|||
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):
|
||||
|
@ -408,6 +447,7 @@ class ForInStatement(Statement):
|
|||
self.left = left
|
||||
self.right = right
|
||||
self.body = body
|
||||
self._fields.update({"left": self.left, "right": self.right, "body": self.body})
|
||||
|
||||
|
||||
# "Declarations" block
|
||||
|
@ -443,6 +483,7 @@ class VariableDeclarator(Node):
|
|||
super().__init__("VariableDeclarator", loc)
|
||||
self.id = var_id
|
||||
self.init = init
|
||||
self._fields.update({"id": self.id, "init": self.init})
|
||||
|
||||
|
||||
class VariableDeclaration(Declaration):
|
||||
|
@ -457,6 +498,7 @@ class VariableDeclaration(Declaration):
|
|||
super().__init__("VariableDeclaration", loc)
|
||||
self.declarations = declarations
|
||||
self.kind = kind
|
||||
self._fields.update({"kind": self.kind, "declarations": self.declarations})
|
||||
|
||||
|
||||
# "Expressions" block
|
||||
|
@ -487,6 +529,7 @@ class SpreadElement(Node):
|
|||
def __init__(self, loc: Optional[SourceLocation], argument: Expression):
|
||||
super().__init__("SpreadElement", loc)
|
||||
self.argument = argument
|
||||
self._fields.update({"argument": self.argument})
|
||||
|
||||
|
||||
class ThisExpression(Expression):
|
||||
|
@ -506,6 +549,7 @@ class ArrayExpression(Expression):
|
|||
):
|
||||
super().__init__("ArrayExpression", loc)
|
||||
self.elements = elements
|
||||
self._fields.update({"elements": self.elements})
|
||||
|
||||
|
||||
class ObjectExpression(Expression):
|
||||
|
@ -514,6 +558,7 @@ class ObjectExpression(Expression):
|
|||
def __init__(self, loc: Optional[SourceLocation], properties: List[Property]):
|
||||
super().__init__("ObjectExpression", loc)
|
||||
self.properties = properties
|
||||
self._fields.update({"properties": self.properties})
|
||||
|
||||
|
||||
class FunctionExpression(Function, Expression):
|
||||
|
@ -541,6 +586,7 @@ class ArrowFunctionExpression(Function, Expression):
|
|||
):
|
||||
super().__init__("ArrowFunctionExpression", loc, None, params, body)
|
||||
self.expression = expression
|
||||
self._fields.update({"expression": self.expression})
|
||||
|
||||
|
||||
class UnaryExpression(Expression):
|
||||
|
@ -557,6 +603,13 @@ class UnaryExpression(Expression):
|
|||
self.operator = operator
|
||||
self.prefix = prefix
|
||||
self.argument = argument
|
||||
self._fields.update(
|
||||
{
|
||||
"operator": self.operator,
|
||||
"prefix": self.prefix,
|
||||
"argument": self.argument,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class UpdateExpression(Expression):
|
||||
|
@ -573,6 +626,13 @@ class UpdateExpression(Expression):
|
|||
self.operator = operator
|
||||
self.argument = argument
|
||||
self.prefix = prefix
|
||||
self._fields.update(
|
||||
{
|
||||
"operator": self.operator,
|
||||
"argument": self.argument,
|
||||
"prefix": self.prefix,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class BinaryExpression(Expression):
|
||||
|
@ -589,6 +649,9 @@ class BinaryExpression(Expression):
|
|||
self.operator = operator
|
||||
self.left = left
|
||||
self.right = right
|
||||
self._fields.update(
|
||||
{"operator": self.operator, "left": self.left, "right": self.right}
|
||||
)
|
||||
|
||||
|
||||
class AssignmentExpression(Expression):
|
||||
|
@ -607,6 +670,9 @@ class AssignmentExpression(Expression):
|
|||
self.operator = operator
|
||||
self.left = left
|
||||
self.right = right
|
||||
self._fields.update(
|
||||
{"operator": self.operator, "left": self.left, "right": self.right}
|
||||
)
|
||||
|
||||
|
||||
class LogicalExpression(Expression):
|
||||
|
@ -623,6 +689,9 @@ class LogicalExpression(Expression):
|
|||
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):
|
||||
|
@ -641,6 +710,13 @@ class MemberExpression(Expression, Pattern):
|
|||
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):
|
||||
|
@ -657,6 +733,13 @@ class ConditionalExpression(Expression):
|
|||
self.test = test
|
||||
self.alternate = alternate
|
||||
self.consequent = consequent
|
||||
self._fields.update(
|
||||
{
|
||||
"test": self.test,
|
||||
"alternate": self.alternate,
|
||||
"consequent": self.consequent,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class CallExpression(Expression):
|
||||
|
@ -671,6 +754,7 @@ class CallExpression(Expression):
|
|||
super().__init__("CallExpression", loc)
|
||||
self.callee = callee
|
||||
self.arguments = arguments
|
||||
self._fields.update({"callee": self.callee, "arguments": self.arguments})
|
||||
|
||||
|
||||
class NewExpression(Expression):
|
||||
|
@ -685,6 +769,7 @@ class NewExpression(Expression):
|
|||
super().__init__("NewExpression", loc)
|
||||
self.callee = callee
|
||||
self.arguments = arguments
|
||||
self._fields.update({"callee": self.callee, "arguments": self.arguments})
|
||||
|
||||
|
||||
class SequenceExpression(Expression):
|
||||
|
@ -693,6 +778,7 @@ class SequenceExpression(Expression):
|
|||
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):
|
||||
|
@ -940,6 +1026,16 @@ class Property(Node):
|
|||
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):
|
||||
|
@ -978,6 +1074,7 @@ class ObjectPattern(Pattern):
|
|||
):
|
||||
super().__init__("ObjectPattern", loc)
|
||||
self.properties = properties
|
||||
self._fields.update({"properties": self.properties})
|
||||
|
||||
|
||||
class ArrayPattern(Pattern):
|
||||
|
@ -986,3 +1083,15 @@ class ArrayPattern(Pattern):
|
|||
):
|
||||
super().__init__("ArrayPattern", loc)
|
||||
self.elements = elements
|
||||
self._fields.update({"elements": self.elements})
|
||||
|
||||
|
||||
# "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
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
antlr4-python3-runtime==4.8
|
||||
colorama==0.4.3
|
||||
coloredlogs==14.0
|
||||
tree_format==0.1.2
|
||||
coloredlogs==14.0
|
Loading…
Reference in New Issue