mirror of https://github.com/t1meshift/js.git
Compare commits
No commits in common. "5cd616ceb38d79c8bc787aba981f34ea728e6e03" and "c5048309280fdf64304b5c7e83153fa866df2b5e" have entirely different histories.
5cd616ceb3
...
c504830928
|
@ -11,7 +11,7 @@ Another JavaScript interpreter written on Python 3.
|
||||||
|
|
||||||
To run tests:
|
To run tests:
|
||||||
|
|
||||||
- pytest
|
- pylint
|
||||||
- Tox
|
- Tox
|
||||||
|
|
||||||
You can get ANTLR [here](https://www.antlr.org/), other dependencies could be installed with pip:
|
You can get ANTLR [here](https://www.antlr.org/), other dependencies could be installed with pip:
|
||||||
|
|
|
@ -37,7 +37,7 @@ options { superClass=JavaScriptBaseLexer; }
|
||||||
HashBangLine: { self.isStartOfFile()}? '#!' ~[\r\n\u2028\u2029]*; // only allowed at start
|
HashBangLine: { self.isStartOfFile()}? '#!' ~[\r\n\u2028\u2029]*; // only allowed at start
|
||||||
MultiLineComment: '/*' .*? '*/' -> channel(HIDDEN);
|
MultiLineComment: '/*' .*? '*/' -> channel(HIDDEN);
|
||||||
SingleLineComment: '//' ~[\r\n\u2028\u2029]* -> channel(HIDDEN);
|
SingleLineComment: '//' ~[\r\n\u2028\u2029]* -> channel(HIDDEN);
|
||||||
//RegularExpressionLiteral: '/' RegularExpressionFirstChar RegularExpressionChar* {self.isRegexPossible()}? '/' IdentifierPart*;
|
RegularExpressionLiteral: '/' RegularExpressionFirstChar RegularExpressionChar* {self.isRegexPossible()}? '/' IdentifierPart*;
|
||||||
|
|
||||||
OpenBracket: '[';
|
OpenBracket: '[';
|
||||||
CloseBracket: ']';
|
CloseBracket: ']';
|
||||||
|
|
|
@ -403,7 +403,7 @@ literal
|
||||||
| BooleanLiteral
|
| BooleanLiteral
|
||||||
| StringLiteral
|
| StringLiteral
|
||||||
// | TemplateStringLiteral
|
// | TemplateStringLiteral
|
||||||
// | RegularExpressionLiteral
|
| RegularExpressionLiteral
|
||||||
| numericLiteral
|
| numericLiteral
|
||||||
| bigintLiteral
|
| bigintLiteral
|
||||||
;
|
;
|
||||||
|
|
|
@ -3,7 +3,7 @@ So here it is.
|
||||||
"""
|
"""
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
__version__ = "0.0.9"
|
__version__ = "0.0.7"
|
||||||
__snake__ = r"""
|
__snake__ = r"""
|
||||||
_________ _________
|
_________ _________
|
||||||
/ \ / \
|
/ \ / \
|
||||||
|
@ -32,5 +32,4 @@ LOG_LEVELS = {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# TODO: make it usable as a module too
|
# TODO: make it usable as a module too
|
||||||
|
|
|
@ -1059,35 +1059,6 @@ class BigIntLiteral(Literal):
|
||||||
self._fields.update({"bigint": self.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
|
# "Property" block
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -6,11 +6,9 @@ Todo:
|
||||||
* Fill `source` field in SourceLocation and pass it to each `_get_source_location()` call.
|
* Fill `source` field in SourceLocation and pass it to each `_get_source_location()` call.
|
||||||
* Compare `SourceLocation` creation behavior with the one in Acorn/ESPrima
|
* Compare `SourceLocation` creation behavior with the one in Acorn/ESPrima
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from typing import Optional, List, Union
|
from typing import Optional, List, Union
|
||||||
import antlr4.ParserRuleContext
|
import antlr4.ParserRuleContext
|
||||||
from antlr4 import ErrorNode, ParserRuleContext
|
|
||||||
|
|
||||||
from ..lex.JavaScriptParser import JavaScriptParser
|
from ..lex.JavaScriptParser import JavaScriptParser
|
||||||
from ..lex.JavaScriptParserListener import JavaScriptParserListener as JSBaseListener
|
from ..lex.JavaScriptParserListener import JavaScriptParserListener as JSBaseListener
|
||||||
|
@ -33,78 +31,7 @@ def _get_source_location(
|
||||||
return nodes.SourceLocation(source=source, start=start_pos, end=end_pos)
|
return nodes.SourceLocation(source=source, start=start_pos, end=end_pos)
|
||||||
|
|
||||||
|
|
||||||
class NodeListener(JSBaseListener):
|
class AssignableListener(JSBaseListener):
|
||||||
def visitErrorNode(self, node: ErrorNode):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def enterEveryRule(self, ctx: ParserRuleContext):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class LiteralListener(JSBaseListener):
|
|
||||||
_literal: nodes.Literal
|
|
||||||
|
|
||||||
@property
|
|
||||||
def literal(self):
|
|
||||||
return self._literal
|
|
||||||
|
|
||||||
def enterLiteral(self, ctx: JavaScriptParser.LiteralContext):
|
|
||||||
loc = _get_source_location(ctx, None)
|
|
||||||
if ctx.NullLiteral() is not None:
|
|
||||||
self._literal = nodes.NullLiteral(loc)
|
|
||||||
elif ctx.BooleanLiteral() is not None:
|
|
||||||
value = ctx.BooleanLiteral().getText() == "true"
|
|
||||||
self._literal = nodes.BooleanLiteral(loc, value)
|
|
||||||
elif ctx.StringLiteral() is not None:
|
|
||||||
self._literal = nodes.StringLiteral(loc, ctx.StringLiteral().getText())
|
|
||||||
else:
|
|
||||||
ctx.getChild(0).enterRule(self)
|
|
||||||
|
|
||||||
def enterNumericLiteral(self, ctx: JavaScriptParser.NumericLiteralContext):
|
|
||||||
# Thank you, PEP-515, very cool!
|
|
||||||
loc = _get_source_location(ctx, None)
|
|
||||||
value = float(ctx.DecimalLiteral().getText())
|
|
||||||
self._literal = nodes.NumericLiteral(loc, value)
|
|
||||||
|
|
||||||
def enterBigintLiteral(self, ctx: JavaScriptParser.BigintLiteralContext):
|
|
||||||
raise NotImplementedError("Bigint literals")
|
|
||||||
|
|
||||||
|
|
||||||
class ExpressionListener(JSBaseListener):
|
|
||||||
_expr: nodes.Expression
|
|
||||||
|
|
||||||
@property
|
|
||||||
def expression(self):
|
|
||||||
return self._expr
|
|
||||||
|
|
||||||
def enterExpressionStatement(
|
|
||||||
self, ctx: JavaScriptParser.ExpressionStatementContext
|
|
||||||
):
|
|
||||||
ctx.expressionSequence().enterRule(self)
|
|
||||||
|
|
||||||
def enterExpressionSequence(self, ctx: JavaScriptParser.ExpressionSequenceContext):
|
|
||||||
expressions: List[nodes.Expression] = []
|
|
||||||
loc = _get_source_location(ctx, None)
|
|
||||||
for expr in ctx.singleExpression():
|
|
||||||
expr_listener = ExpressionListener()
|
|
||||||
expr.enterRule(expr_listener)
|
|
||||||
expressions.append(expr_listener.expression)
|
|
||||||
self._expr = nodes.SequenceExpression(loc, expressions)
|
|
||||||
|
|
||||||
def enterParenthesizedExpression(
|
|
||||||
self, ctx: JavaScriptParser.ParenthesizedExpressionContext
|
|
||||||
):
|
|
||||||
ctx.expressionSequence().enterRule(self)
|
|
||||||
|
|
||||||
def enterLiteralExpression(self, ctx: JavaScriptParser.LiteralExpressionContext):
|
|
||||||
literal_listener = LiteralListener()
|
|
||||||
ctx.literal().enterRule(literal_listener)
|
|
||||||
self._expr = literal_listener.literal
|
|
||||||
|
|
||||||
# TODO single expression
|
|
||||||
|
|
||||||
|
|
||||||
class AssignableListener(NodeListener):
|
|
||||||
_result: Union[nodes.Identifier, nodes.ObjectPattern, nodes.ArrayPattern]
|
_result: Union[nodes.Identifier, nodes.ObjectPattern, nodes.ArrayPattern]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -143,11 +70,11 @@ class VariableDeclarationListener(JSBaseListener):
|
||||||
assign_listener = AssignableListener()
|
assign_listener = AssignableListener()
|
||||||
ctx.assignable().enterRule(assign_listener)
|
ctx.assignable().enterRule(assign_listener)
|
||||||
|
|
||||||
init = None # or value from ExpressionListener
|
|
||||||
if ctx.singleExpression() is not None:
|
if ctx.singleExpression() is not None:
|
||||||
expression_listener = ExpressionListener()
|
raise NotImplementedError("VariableDeclarator initialization")
|
||||||
ctx.singleExpression().enterRule(expression_listener)
|
|
||||||
init = expression_listener.expression
|
# ctx.singleExpression().enterRule(expression_listener) # FIXME No ExpressionListener yet
|
||||||
|
init = None # value from ExpressionListener
|
||||||
|
|
||||||
self._var_decl = nodes.VariableDeclarator(loc, assign_listener.result, init)
|
self._var_decl = nodes.VariableDeclarator(loc, assign_listener.result, init)
|
||||||
|
|
||||||
|
@ -161,17 +88,6 @@ class StatementListener(JSBaseListener):
|
||||||
|
|
||||||
return self._stmt
|
return self._stmt
|
||||||
|
|
||||||
def __init__(self, in_loop: bool = False, in_func: bool = False):
|
|
||||||
"""
|
|
||||||
Statement listener. Generates a Statement.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
in_loop (bool): allow `continue` and `break` statements
|
|
||||||
in_func (bool): allow `return` statement
|
|
||||||
"""
|
|
||||||
self._in_loop = in_loop
|
|
||||||
self._in_func = in_func
|
|
||||||
|
|
||||||
def enterStatement(self, ctx: JavaScriptParser.StatementContext):
|
def enterStatement(self, ctx: JavaScriptParser.StatementContext):
|
||||||
"""Obtain an actual statement."""
|
"""Obtain an actual statement."""
|
||||||
logging.debug("Entered section Statement")
|
logging.debug("Entered section Statement")
|
||||||
|
@ -221,17 +137,17 @@ class StatementListener(JSBaseListener):
|
||||||
def enterExpressionStatement(
|
def enterExpressionStatement(
|
||||||
self, ctx: JavaScriptParser.ExpressionStatementContext
|
self, ctx: JavaScriptParser.ExpressionStatementContext
|
||||||
):
|
):
|
||||||
"""Listener for ExpressionStatement."""
|
"""Listener for ExpressionStatement.
|
||||||
|
TODO: check up expression containers.
|
||||||
|
"""
|
||||||
logging.debug("Entered section ExpressionStatement")
|
logging.debug("Entered section ExpressionStatement")
|
||||||
expr_listener = ExpressionListener()
|
raise NotImplementedError("ExpressionStatement")
|
||||||
ctx.expressionSequence().enterRule(expr_listener)
|
|
||||||
loc = _get_source_location(ctx, None)
|
|
||||||
self._stmt = nodes.ExpressionStatement(loc, expr_listener.expression)
|
|
||||||
|
|
||||||
def enterIfStatement(self, ctx: JavaScriptParser.IfStatementContext):
|
def enterIfStatement(self, ctx: JavaScriptParser.IfStatementContext):
|
||||||
"""Listener for IfStatement."""
|
"""Listener for IfStatement."""
|
||||||
logging.debug("Entered section IfStatement")
|
logging.debug("Entered section IfStatement")
|
||||||
raise NotImplementedError("IfStatement")
|
raise NotImplementedError("ExpressionStatement") # FIXME
|
||||||
|
pass
|
||||||
|
|
||||||
def enterFunctionDeclaration(
|
def enterFunctionDeclaration(
|
||||||
self, ctx: JavaScriptParser.FunctionDeclarationContext
|
self, ctx: JavaScriptParser.FunctionDeclarationContext
|
||||||
|
@ -240,54 +156,7 @@ class StatementListener(JSBaseListener):
|
||||||
logging.debug("Entered section FunctionDeclaration")
|
logging.debug("Entered section FunctionDeclaration")
|
||||||
raise NotImplementedError("FunctionDeclaration")
|
raise NotImplementedError("FunctionDeclaration")
|
||||||
|
|
||||||
def enterDoStatement(self, ctx: JavaScriptParser.DoStatementContext):
|
# TODO: import/export, ClassDeclaration, iter statements, continue. break, return
|
||||||
"""Listener for DoStatement (do-while)."""
|
|
||||||
raise NotImplementedError("DoWhileStatement")
|
|
||||||
|
|
||||||
def enterWhileStatement(self, ctx: JavaScriptParser.WhileStatementContext):
|
|
||||||
"""Listener for WhileStatement."""
|
|
||||||
logging.debug("Entered section WhileStatement")
|
|
||||||
raise NotImplementedError("WhileStatement")
|
|
||||||
|
|
||||||
def enterForStatement(self, ctx: JavaScriptParser.ForStatementContext):
|
|
||||||
"""Listener for ForStatement."""
|
|
||||||
logging.debug("Entered section ForStatement")
|
|
||||||
raise NotImplementedError("ForStatement")
|
|
||||||
|
|
||||||
def enterForInStatement(self, ctx: JavaScriptParser.ForInStatementContext):
|
|
||||||
"""Listener for ForInStatement."""
|
|
||||||
logging.debug("Entered section ForInStatement")
|
|
||||||
raise NotImplementedError("ForInStatement")
|
|
||||||
|
|
||||||
def enterContinueStatement(self, ctx: JavaScriptParser.ContinueStatementContext):
|
|
||||||
logging.debug("Entered section ContinueStatement")
|
|
||||||
raise NotImplementedError("ContinueStatement")
|
|
||||||
|
|
||||||
def enterBreakStatement(self, ctx: JavaScriptParser.BreakStatementContext):
|
|
||||||
logging.debug("Entered BreakStatement")
|
|
||||||
raise NotImplementedError("BreakStatement")
|
|
||||||
|
|
||||||
def enterReturnStatement(self, ctx: JavaScriptParser.ReturnStatementContext):
|
|
||||||
logging.debug("Entered ReturnStatement")
|
|
||||||
raise NotImplementedError("ReturnStatement")
|
|
||||||
|
|
||||||
def enterImportStatement(self, ctx: JavaScriptParser.ImportStatementContext):
|
|
||||||
logging.debug("Entered ImportStatement")
|
|
||||||
raise NotImplementedError("ImportStatement")
|
|
||||||
|
|
||||||
def enterExportDeclaration(self, ctx: JavaScriptParser.ExportDeclarationContext):
|
|
||||||
logging.debug("Entered ExportDeclaration")
|
|
||||||
raise NotImplementedError("ExportDeclaration")
|
|
||||||
|
|
||||||
def enterExportDefaultDeclaration(
|
|
||||||
self, ctx: JavaScriptParser.ExportDefaultDeclarationContext
|
|
||||||
):
|
|
||||||
logging.debug("Entered ExportDefaultDeclaration")
|
|
||||||
raise NotImplementedError("ExportDefaultDeclaration")
|
|
||||||
|
|
||||||
def enterClassDeclaration(self, ctx: JavaScriptParser.ClassDeclarationContext):
|
|
||||||
logging.debug("Entered ClassDeclaration")
|
|
||||||
raise NotImplementedError("ClassDeclaration")
|
|
||||||
|
|
||||||
|
|
||||||
class SourceElementListener(JSBaseListener):
|
class SourceElementListener(JSBaseListener):
|
||||||
|
|
|
@ -1,19 +1,15 @@
|
||||||
from antlr4.error.ErrorListener import ErrorListener
|
from antlr4.error.ErrorListener import ErrorListener
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from antlr4.error.Errors import ParseCancellationException
|
|
||||||
|
|
||||||
|
|
||||||
class LogErrorListener(ErrorListener):
|
class LogErrorListener(ErrorListener):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e):
|
def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e):
|
||||||
logging.critical("SyntaxError: %s", msg)
|
logging.debug(
|
||||||
raise ParseCancellationException("Syntax Error lol")
|
"{}\n{}\n{}\n{}\n{}".format(offendingSymbol, line, column, msg, e)
|
||||||
# logging.debug(
|
)
|
||||||
# "{}\n{}\n{}\n{}\n{}".format(offendingSymbol, line, column, msg, e)
|
|
||||||
# )
|
|
||||||
|
|
||||||
def reportAmbiguity(
|
def reportAmbiguity(
|
||||||
self, recognizer, dfa, startIndex, stopIndex, exact, ambigAlts, configs
|
self, recognizer, dfa, startIndex, stopIndex, exact, ambigAlts, configs
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
// Guess what? It should be parsable, but it's not (git rev 44d7e241)
|
|
||||||
{let a = 15, b; {1_337.2_28, false, "String"}}
|
|
|
@ -1,15 +0,0 @@
|
||||||
// The code below won't work since the grammar treat Unicode
|
|
||||||
//"\x20\x77hil\x65\x20exe\x63uting c\x6cient e\x76\145\x6et ";
|
|
||||||
|
|
||||||
//{let a = 15, b}
|
|
||||||
|
|
||||||
|
|
||||||
{{{let t = false, n = true}}}
|
|
||||||
//++a15;
|
|
||||||
var a, b=14;
|
|
||||||
let c;
|
|
||||||
;
|
|
||||||
4444444444444444444444;
|
|
||||||
//228,1444444444444;t,fnm
|
|
||||||
//if (1) 0;
|
|
||||||
//function f4444444(){}
|
|
Loading…
Reference in New Issue