mirror of https://github.com/t1meshift/js.git
Compare commits
6 Commits
c09b52638c
...
041f4c31fb
Author | SHA1 | Date |
---|---|---|
Yury Kurlykov | 041f4c31fb | |
Yury Kurlykov | 6b4865af8d | |
Yury Kurlykov | eea056550c | |
Yury Kurlykov | 494ed06f28 | |
Yury Kurlykov | 47d6d31239 | |
Yury Kurlykov | 6414fecbfe |
|
@ -3,7 +3,7 @@ So here it is.
|
|||
"""
|
||||
import logging
|
||||
|
||||
__version__ = "0.0.2"
|
||||
__version__ = "0.0.7"
|
||||
__snake__ = r"""
|
||||
_________ _________
|
||||
/ \ / \
|
||||
|
|
|
@ -10,7 +10,7 @@ import coloredlogs
|
|||
from jasminesnake import __version__, __snake__, LOG_LEVELS
|
||||
from .js_stream import JSBaseStream, JSStringStream, JSFileStream
|
||||
from .lex.ErrorListeners import LogErrorListener
|
||||
import ast
|
||||
from ast import nodes, to_ascii_tree, from_parse_tree
|
||||
|
||||
|
||||
def create_argument_parser():
|
||||
|
@ -70,8 +70,11 @@ def main():
|
|||
stream = JSFileStream(args.infile, LogErrorListener())
|
||||
|
||||
tree = stream.parse()
|
||||
ast_tree = ast.from_parse_tree(tree)
|
||||
|
||||
ast_tree = from_parse_tree(tree)
|
||||
ascii_ast = to_ascii_tree(ast_tree)
|
||||
|
||||
logging.info("Got an AST!\n%s", ascii_ast)
|
||||
# TODO: run logic
|
||||
sys.exit(0)
|
||||
|
||||
|
@ -92,7 +95,11 @@ def main():
|
|||
tree = stream.parse()
|
||||
logging.debug("Got tree %s", tree.toStringTree(stream.parser.ruleNames))
|
||||
|
||||
ast_tree = ast.from_parse_tree(tree)
|
||||
ast_tree = from_parse_tree(tree)
|
||||
ascii_ast = to_ascii_tree(ast_tree)
|
||||
|
||||
logging.info("Got an AST!")
|
||||
logging.info(ascii_ast)
|
||||
# TODO: run logic
|
||||
except EOFError:
|
||||
print("Ctrl-D received, shutting down...")
|
||||
|
|
|
@ -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,14 @@ class SourceLocation:
|
|||
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
|
||||
|
@ -191,16 +207,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 +229,7 @@ class Literal(Expression):
|
|||
):
|
||||
super().__init__("Literal", loc)
|
||||
self.value = value
|
||||
self._fields.update({"value": self.value})
|
||||
|
||||
|
||||
# "Programs" block
|
||||
|
@ -231,6 +247,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 +274,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 +300,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 +309,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 +323,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 +343,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 +352,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 +361,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 +378,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 +396,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 +408,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 +427,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 +451,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
|
||||
|
@ -438,11 +482,12 @@ class VariableDeclarator(Node):
|
|||
"""A variable declarator."""
|
||||
|
||||
def __init__(
|
||||
self, loc: Optional[SourceLocation], var_id: Pattern, init: Optional[Exception]
|
||||
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):
|
||||
|
@ -457,6 +502,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 +533,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 +553,7 @@ class ArrayExpression(Expression):
|
|||
):
|
||||
super().__init__("ArrayExpression", loc)
|
||||
self.elements = elements
|
||||
self._fields.update({"elements": self.elements})
|
||||
|
||||
|
||||
class ObjectExpression(Expression):
|
||||
|
@ -514,6 +562,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 +590,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 +607,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 +630,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 +653,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 +674,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 +693,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 +714,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 +737,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 +758,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 +773,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 +782,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 +1030,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 +1078,7 @@ class ObjectPattern(Pattern):
|
|||
):
|
||||
super().__init__("ObjectPattern", loc)
|
||||
self.properties = properties
|
||||
self._fields.update({"properties": self.properties})
|
||||
|
||||
|
||||
class ArrayPattern(Pattern):
|
||||
|
@ -986,3 +1087,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,5 +1,5 @@
|
|||
import logging
|
||||
from typing import Optional, List
|
||||
from typing import Optional, List, Union
|
||||
import antlr4.ParserRuleContext
|
||||
|
||||
from lex.JavaScriptParser import JavaScriptParser
|
||||
|
@ -23,6 +23,52 @@ def _get_source_location(
|
|||
return ast.nodes.SourceLocation(source=source, start=start_pos, end=end_pos)
|
||||
|
||||
|
||||
class AssignableListener(JSBaseListener):
|
||||
_result: Union[
|
||||
ast.nodes.Identifier, ast.nodes.ObjectPattern, ast.nodes.ArrayPattern
|
||||
]
|
||||
|
||||
@property
|
||||
def result(self):
|
||||
return self._result
|
||||
|
||||
def enterAssignable(self, ctx: JavaScriptParser.AssignableContext):
|
||||
logging.debug("Entered section Assignable")
|
||||
ctx.getChild(0).enterRule(self)
|
||||
|
||||
def enterIdentifier(self, ctx: JavaScriptParser.IdentifierContext):
|
||||
logging.debug("Entered section Identifier")
|
||||
loc = _get_source_location(ctx, None)
|
||||
self._result = ast.nodes.Identifier(loc, ctx.getText())
|
||||
|
||||
def enterArrayLiteral(self, ctx: JavaScriptParser.ArrayLiteralContext):
|
||||
logging.debug("Entered section ArrayLiteral")
|
||||
pass # TODO
|
||||
|
||||
def enterObjectLiteral(self, ctx: JavaScriptParser.ObjectLiteralContext):
|
||||
logging.debug("Entered section ObjectLiteral")
|
||||
pass # TODO
|
||||
|
||||
|
||||
class VariableDeclarationListener(JSBaseListener):
|
||||
_var_decl: ast.nodes.VariableDeclarator
|
||||
|
||||
@property
|
||||
def var_declarator(self):
|
||||
return self._var_decl
|
||||
|
||||
def enterVariableDeclaration(
|
||||
self, ctx: JavaScriptParser.VariableDeclarationContext
|
||||
):
|
||||
loc = _get_source_location(ctx, None)
|
||||
assign_listener = AssignableListener()
|
||||
ctx.assignable().enterRule(assign_listener)
|
||||
# ctx.singleExpression().enterRule(expression_listener) # FIXME No ExpressionListener yet
|
||||
self._var_decl = ast.nodes.VariableDeclarator(
|
||||
loc, assign_listener.result, None
|
||||
) # FIXME
|
||||
|
||||
|
||||
class StatementListener(JSBaseListener):
|
||||
_stmt: ast.nodes.Statement
|
||||
|
||||
|
@ -50,12 +96,26 @@ class StatementListener(JSBaseListener):
|
|||
loc = _get_source_location(ctx, None) # FIXME source param is None
|
||||
self._stmt = ast.nodes.BlockStatement(loc, stmt_list)
|
||||
|
||||
def enterVariableStatement(self, ctx: JavaScriptParser.VariableStatementContext):
|
||||
logging.debug("Entered section VariableStatement")
|
||||
ctx.variableDeclarationList().enterRule(self)
|
||||
|
||||
def enterVariableDeclarationList(
|
||||
self, ctx: JavaScriptParser.VariableDeclarationListContext
|
||||
):
|
||||
"""Listener for VariableDeclaration."""
|
||||
logging.debug("Entered section VariableDeclaration")
|
||||
pass
|
||||
|
||||
var_modifier: ast.nodes.VarDeclKind = ctx.varModifier().getText()
|
||||
var_decls: List[ast.nodes.VariableDeclarator] = []
|
||||
|
||||
for var_decl in ctx.variableDeclaration():
|
||||
var_decl_listener = VariableDeclarationListener()
|
||||
var_decl.enterRule(var_decl_listener)
|
||||
var_decls.append(var_decl_listener.var_declarator)
|
||||
|
||||
loc = _get_source_location(ctx, None)
|
||||
self._stmt = ast.nodes.VariableDeclaration(loc, var_modifier, var_decls)
|
||||
|
||||
def enterEmptyStatement(self, ctx: JavaScriptParser.EmptyStatementContext):
|
||||
"""Listener for EmptyStatement."""
|
||||
|
|
|
@ -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