mirror of https://github.com/t1meshift/js.git
Compare commits
10 Commits
5cd616ceb3
...
8bba41bd45
Author | SHA1 | Date |
---|---|---|
Yury Kurlykov | 8bba41bd45 | |
Yury Kurlykov | ff8341e20c | |
Yury Kurlykov | 897207a11d | |
Yury Kurlykov | 6e910b77b2 | |
Yury Kurlykov | 26dbd6ee10 | |
Yury Kurlykov | 3641570e4b | |
Yury Kurlykov | e7f1cc89b9 | |
Yury Kurlykov | 9f0646c6f0 | |
Yury Kurlykov | 5be6f96098 | |
Yury Kurlykov | 5024ca003b |
|
@ -0,0 +1,43 @@
|
||||||
|
# This is a basic workflow to help you get started with Actions
|
||||||
|
|
||||||
|
name: Testing
|
||||||
|
|
||||||
|
# Controls when the action will run. Triggers the workflow on push or pull request
|
||||||
|
# events but only for the master branch
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ master ]
|
||||||
|
|
||||||
|
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
||||||
|
jobs:
|
||||||
|
# This workflow contains a single job called "build"
|
||||||
|
build:
|
||||||
|
# The type of runner that the job will run on
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||||
|
steps:
|
||||||
|
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Install Python 3
|
||||||
|
uses: actions/setup-python@v2
|
||||||
|
with:
|
||||||
|
python-version: 3.8
|
||||||
|
|
||||||
|
- name: Setup ANTLR 4 tool
|
||||||
|
uses: NiccoMlt/setup-antlr4@v0.0.5
|
||||||
|
|
||||||
|
# Runs a set of commands using the runners shell
|
||||||
|
- name: Build ANTLR lexer and parser
|
||||||
|
run: |
|
||||||
|
$JAVA_EXEC -jar $Antlr4ToolPath -Xexact-output-dir -o jasminesnake/lex -package lex -Dlanguage=Python3 -listener grammars/*.g4
|
||||||
|
|
||||||
|
- name: Install deps from pip
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade -rrequirements-dev.txt
|
||||||
|
|
||||||
|
- name: Run Tox
|
||||||
|
run: tox
|
|
@ -3,6 +3,7 @@ Another JavaScript interpreter written on Python 3.
|
||||||
|
|
||||||
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
|
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
|
||||||
[![SemVer: 2.0.0](https://img.shields.io/badge/SemVer-2.0.0-F8DE7E?labelColor=23261D)](https://semver.org/spec/v2.0.0.html)
|
[![SemVer: 2.0.0](https://img.shields.io/badge/SemVer-2.0.0-F8DE7E?labelColor=23261D)](https://semver.org/spec/v2.0.0.html)
|
||||||
|
![Testing status](https://github.com/t1meshift/js/workflows/Testing/badge.svg)
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
|
@ -12,7 +13,6 @@ Another JavaScript interpreter written on Python 3.
|
||||||
To run tests:
|
To run tests:
|
||||||
|
|
||||||
- pytest
|
- pytest
|
||||||
- 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:
|
||||||
```bash
|
```bash
|
||||||
|
@ -26,6 +26,12 @@ antlr4 -Xexact-output-dir -o jasminesnake/lex -package lex -Dlanguage=Python3 -l
|
||||||
python -m jasminesnake
|
python -m jasminesnake
|
||||||
```
|
```
|
||||||
|
|
||||||
|
# Testing
|
||||||
|
```bash
|
||||||
|
# Running with -s is optional
|
||||||
|
python -m pytest -s
|
||||||
|
```
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
ESTree specification:
|
ESTree specification:
|
||||||
|
|
|
@ -20,6 +20,9 @@ def create_argument_parser():
|
||||||
)
|
)
|
||||||
|
|
||||||
_arg_parser.add_argument("--snake", action="store_true", help="print a snake")
|
_arg_parser.add_argument("--snake", action="store_true", help="print a snake")
|
||||||
|
_arg_parser.add_argument(
|
||||||
|
"--ast", choices=["full", "short", "none"], default="none", help="print AST"
|
||||||
|
)
|
||||||
_arg_parser.add_argument(
|
_arg_parser.add_argument(
|
||||||
"--verbose",
|
"--verbose",
|
||||||
"-v",
|
"-v",
|
||||||
|
@ -72,9 +75,12 @@ def main():
|
||||||
tree = stream.parse()
|
tree = stream.parse()
|
||||||
|
|
||||||
ast_tree = 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)
|
logging.info("Got an AST!\n")
|
||||||
|
if args.ast != "none":
|
||||||
|
ascii_ast = to_ascii_tree(ast_tree, ast_format=args.ast)
|
||||||
|
print(ascii_ast)
|
||||||
|
|
||||||
# TODO: run logic
|
# TODO: run logic
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
|
@ -29,10 +29,13 @@ def to_ascii_tree(
|
||||||
node: Union[nodes.Position, nodes.SourceLocation, nodes.Node],
|
node: Union[nodes.Position, nodes.SourceLocation, nodes.Node],
|
||||||
name_prefix: str = "",
|
name_prefix: str = "",
|
||||||
nesting_lvl: int = 0,
|
nesting_lvl: int = 0,
|
||||||
|
ast_format: str = "full",
|
||||||
):
|
):
|
||||||
if nesting_lvl < 0:
|
if nesting_lvl < 0:
|
||||||
raise ValueError("Nesting level can't be below 0")
|
raise ValueError("Nesting level can't be below 0")
|
||||||
|
|
||||||
|
NODE_BLACKLIST = ["loc", "type"] if ast_format == "short" else []
|
||||||
|
|
||||||
FORK = "+"
|
FORK = "+"
|
||||||
VERTICAL = "|"
|
VERTICAL = "|"
|
||||||
HORIZONTAL = "-"
|
HORIZONTAL = "-"
|
||||||
|
@ -40,25 +43,30 @@ def to_ascii_tree(
|
||||||
SUBENTRY_PREFIX = f"{FORK}{HORIZONTAL}{HORIZONTAL} "
|
SUBENTRY_PREFIX = f"{FORK}{HORIZONTAL}{HORIZONTAL} "
|
||||||
NESTED_PREFIX = f"{VERTICAL} "
|
NESTED_PREFIX = f"{VERTICAL} "
|
||||||
|
|
||||||
value = str(node)
|
value = str(node) if not isinstance(node, list) else ""
|
||||||
children = None
|
children = None
|
||||||
|
|
||||||
if isinstance(node, Enum):
|
if isinstance(node, Enum):
|
||||||
value = str(node.value)
|
value = str(node.value)
|
||||||
|
|
||||||
if isinstance(node, list):
|
if isinstance(node, list):
|
||||||
value = ""
|
|
||||||
children = [(index, val) for index, val in enumerate(node)]
|
children = [(index, val) for index, val in enumerate(node)]
|
||||||
|
|
||||||
if hasattr(node, "fields"):
|
if hasattr(node, "fields"):
|
||||||
children = [(k, node.fields[k]) for k in node.fields.keys()]
|
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"{NESTED_PREFIX * (nesting_lvl - 1)}{SUBENTRY_PREFIX * (nesting_lvl > 0)}"
|
||||||
result += f"{name_prefix}{value}\n"
|
result += f"{name_prefix + ' '*(value!='' and name_prefix!='')}{value}\n"
|
||||||
|
|
||||||
if children is not None:
|
if children is not None:
|
||||||
for (child_name, child_value) in children:
|
for (child_name, child_value) in children:
|
||||||
result += to_ascii_tree(child_value, f"{child_name}: ", nesting_lvl + 1)
|
if child_name not in NODE_BLACKLIST:
|
||||||
|
result += to_ascii_tree(
|
||||||
|
child_value,
|
||||||
|
f"{child_name}:",
|
||||||
|
nesting_lvl + 1,
|
||||||
|
ast_format=ast_format,
|
||||||
|
)
|
||||||
|
|
||||||
# result += "\n"
|
# result += "\n"
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,36 @@ class NodeListener(JSBaseListener):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class AssignmentOperatorListener(JSBaseListener):
|
||||||
|
_op: nodes.AssignmentOperator
|
||||||
|
|
||||||
|
@property
|
||||||
|
def oper(self):
|
||||||
|
return self._op
|
||||||
|
|
||||||
|
def enterAssignmentOperator(self, ctx: JavaScriptParser.AssignmentOperatorContext):
|
||||||
|
ops = nodes.AssignmentOperator
|
||||||
|
ops_list = [
|
||||||
|
(ctx.MultiplyAssign(), ops.MUL),
|
||||||
|
(ctx.DivideAssign(), ops.DIV),
|
||||||
|
(ctx.ModulusAssign(), ops.MOD),
|
||||||
|
(ctx.PlusAssign(), ops.ADD),
|
||||||
|
(ctx.MinusAssign(), ops.SUB),
|
||||||
|
(ctx.LeftShiftArithmeticAssign(), ops.SHL),
|
||||||
|
(ctx.RightShiftArithmeticAssign(), ops.SHR),
|
||||||
|
(ctx.RightShiftLogicalAssign(), ops.SHR_LOGIC),
|
||||||
|
(ctx.BitAndAssign(), ops.AND),
|
||||||
|
(ctx.BitXorAssign(), ops.XOR),
|
||||||
|
(ctx.BitOrAssign(), ops.OR),
|
||||||
|
(ctx.PowerAssign(), ops.POW),
|
||||||
|
]
|
||||||
|
|
||||||
|
for (op_cond, op) in ops_list:
|
||||||
|
if op_cond is not None:
|
||||||
|
self._op = op
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
class LiteralListener(JSBaseListener):
|
class LiteralListener(JSBaseListener):
|
||||||
_literal: nodes.Literal
|
_literal: nodes.Literal
|
||||||
|
|
||||||
|
@ -56,7 +86,8 @@ class LiteralListener(JSBaseListener):
|
||||||
value = ctx.BooleanLiteral().getText() == "true"
|
value = ctx.BooleanLiteral().getText() == "true"
|
||||||
self._literal = nodes.BooleanLiteral(loc, value)
|
self._literal = nodes.BooleanLiteral(loc, value)
|
||||||
elif ctx.StringLiteral() is not None:
|
elif ctx.StringLiteral() is not None:
|
||||||
self._literal = nodes.StringLiteral(loc, ctx.StringLiteral().getText())
|
value = ctx.StringLiteral().getText()[1:-1] # Strip quotes
|
||||||
|
self._literal = nodes.StringLiteral(loc, value)
|
||||||
else:
|
else:
|
||||||
ctx.getChild(0).enterRule(self)
|
ctx.getChild(0).enterRule(self)
|
||||||
|
|
||||||
|
@ -70,6 +101,34 @@ class LiteralListener(JSBaseListener):
|
||||||
raise NotImplementedError("Bigint literals")
|
raise NotImplementedError("Bigint literals")
|
||||||
|
|
||||||
|
|
||||||
|
class ArrayLiteralExpandListener(JSBaseListener):
|
||||||
|
_exprs: List[Union[nodes.Expression, nodes.SpreadElement]]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def expressions(self):
|
||||||
|
return self._exprs
|
||||||
|
|
||||||
|
def enterArrayLiteral(self, ctx: JavaScriptParser.ArrayLiteralContext):
|
||||||
|
logging.debug("Entered section ArrayLiteral")
|
||||||
|
ctx.elementList().enterRule(self)
|
||||||
|
|
||||||
|
def enterElementList(self, ctx: JavaScriptParser.ElementListContext):
|
||||||
|
logging.debug("Entered section ElementList")
|
||||||
|
self._exprs = []
|
||||||
|
for expr in ctx.arrayElement():
|
||||||
|
expr.enterRule(self)
|
||||||
|
|
||||||
|
def enterArrayElement(self, ctx: JavaScriptParser.ArrayElementContext):
|
||||||
|
logging.debug("Entered section ArrayElement")
|
||||||
|
expr_listener = ExpressionListener()
|
||||||
|
ctx.singleExpression().enterRule(expr_listener)
|
||||||
|
if ctx.Ellipsis() is not None:
|
||||||
|
loc = _get_source_location(ctx, None)
|
||||||
|
self._exprs.append(nodes.SpreadElement(loc, expr_listener.expression))
|
||||||
|
else:
|
||||||
|
self._exprs.append(expr_listener.expression)
|
||||||
|
|
||||||
|
|
||||||
class ExpressionListener(JSBaseListener):
|
class ExpressionListener(JSBaseListener):
|
||||||
_expr: nodes.Expression
|
_expr: nodes.Expression
|
||||||
|
|
||||||
|
@ -81,6 +140,7 @@ class ExpressionListener(JSBaseListener):
|
||||||
self, ctx: JavaScriptParser.ExpressionStatementContext
|
self, ctx: JavaScriptParser.ExpressionStatementContext
|
||||||
):
|
):
|
||||||
ctx.expressionSequence().enterRule(self)
|
ctx.expressionSequence().enterRule(self)
|
||||||
|
raise NotImplementedError("ExpressionStatement")
|
||||||
|
|
||||||
def enterExpressionSequence(self, ctx: JavaScriptParser.ExpressionSequenceContext):
|
def enterExpressionSequence(self, ctx: JavaScriptParser.ExpressionSequenceContext):
|
||||||
expressions: List[nodes.Expression] = []
|
expressions: List[nodes.Expression] = []
|
||||||
|
@ -95,13 +155,365 @@ class ExpressionListener(JSBaseListener):
|
||||||
self, ctx: JavaScriptParser.ParenthesizedExpressionContext
|
self, ctx: JavaScriptParser.ParenthesizedExpressionContext
|
||||||
):
|
):
|
||||||
ctx.expressionSequence().enterRule(self)
|
ctx.expressionSequence().enterRule(self)
|
||||||
|
raise NotImplementedError("ParenthesizedExpression")
|
||||||
|
|
||||||
def enterLiteralExpression(self, ctx: JavaScriptParser.LiteralExpressionContext):
|
def enterLiteralExpression(self, ctx: JavaScriptParser.LiteralExpressionContext):
|
||||||
literal_listener = LiteralListener()
|
literal_listener = LiteralListener()
|
||||||
ctx.literal().enterRule(literal_listener)
|
ctx.literal().enterRule(literal_listener)
|
||||||
self._expr = literal_listener.literal
|
self._expr = literal_listener.literal
|
||||||
|
|
||||||
# TODO single expression
|
def enterFunctionExpression(self, ctx: JavaScriptParser.FunctionExpressionContext):
|
||||||
|
logging.debug("Entered section FunctionExpression")
|
||||||
|
raise NotImplementedError("FunctionExpression") # TODO
|
||||||
|
|
||||||
|
def enterClassExpression(self, ctx: JavaScriptParser.ClassExpressionContext):
|
||||||
|
logging.debug("Entered section ClassExpression")
|
||||||
|
raise NotImplementedError("ClassExpression") # TODO
|
||||||
|
|
||||||
|
def enterMemberIndexExpression(
|
||||||
|
self, ctx: JavaScriptParser.MemberIndexExpressionContext
|
||||||
|
):
|
||||||
|
logging.debug("Entered section MemberIndexExpression")
|
||||||
|
raise NotImplementedError("MemberIndexExpression") # TODO
|
||||||
|
|
||||||
|
def enterMemberDotExpression(
|
||||||
|
self, ctx: JavaScriptParser.MemberDotExpressionContext
|
||||||
|
):
|
||||||
|
logging.debug("Entered section MemberDotExpression")
|
||||||
|
raise NotImplementedError("MemberDotExpression") # TODO
|
||||||
|
|
||||||
|
def enterArgumentsExpression(
|
||||||
|
self, ctx: JavaScriptParser.ArgumentsExpressionContext
|
||||||
|
):
|
||||||
|
logging.debug("Entered section ArgumentsExpression")
|
||||||
|
raise NotImplementedError("ArgumentsExpression") # TODO
|
||||||
|
|
||||||
|
def enterNewExpression(self, ctx: JavaScriptParser.NewExpressionContext):
|
||||||
|
logging.debug("Entered section NewExpression")
|
||||||
|
raise NotImplementedError("NewExpression") # TODO
|
||||||
|
|
||||||
|
def enterMetaExpression(self, ctx: JavaScriptParser.MetaExpressionContext):
|
||||||
|
logging.debug("Entered section MetaExpression")
|
||||||
|
raise NotImplementedError("MetaExpression") # TODO
|
||||||
|
|
||||||
|
def enterPostIncrementExpression(
|
||||||
|
self, ctx: JavaScriptParser.PostIncrementExpressionContext
|
||||||
|
):
|
||||||
|
logging.debug("Entered section PostIncrementExpression")
|
||||||
|
arg_lst = ExpressionListener()
|
||||||
|
ctx.singleExpression().enterRule(arg_lst)
|
||||||
|
loc = _get_source_location(ctx, None)
|
||||||
|
self._expr = nodes.PostIncrementExpression(loc, arg_lst.expression)
|
||||||
|
|
||||||
|
def enterPostDecreaseExpression(
|
||||||
|
self, ctx: JavaScriptParser.PostDecreaseExpressionContext
|
||||||
|
):
|
||||||
|
logging.debug("Entered section PostDecreaseExpression")
|
||||||
|
arg_lst = ExpressionListener()
|
||||||
|
ctx.singleExpression().enterRule(arg_lst)
|
||||||
|
loc = _get_source_location(ctx, None)
|
||||||
|
self._expr = nodes.PostDecrementExpression(loc, arg_lst.expression)
|
||||||
|
|
||||||
|
def enterDeleteExpression(self, ctx: JavaScriptParser.DeleteExpressionContext):
|
||||||
|
logging.debug("Entered section DeleteExpression")
|
||||||
|
arg_lst = ExpressionListener()
|
||||||
|
ctx.singleExpression().enterRule(arg_lst)
|
||||||
|
loc = _get_source_location(ctx, None)
|
||||||
|
self._expr = nodes.DeleteExpression(loc, arg_lst.expression)
|
||||||
|
|
||||||
|
def enterVoidExpression(self, ctx: JavaScriptParser.VoidExpressionContext):
|
||||||
|
logging.debug("Entered section VoidExpression")
|
||||||
|
arg_lst = ExpressionListener()
|
||||||
|
ctx.singleExpression().enterRule(arg_lst)
|
||||||
|
loc = _get_source_location(ctx, None)
|
||||||
|
self._expr = nodes.VoidExpression(loc, arg_lst.expression)
|
||||||
|
|
||||||
|
def enterTypeofExpression(self, ctx: JavaScriptParser.TypeofExpressionContext):
|
||||||
|
logging.debug("Entered section TypeofExpression")
|
||||||
|
arg_lst = ExpressionListener()
|
||||||
|
ctx.singleExpression().enterRule(arg_lst)
|
||||||
|
loc = _get_source_location(ctx, None)
|
||||||
|
self._expr = nodes.TypeofExpression(loc, arg_lst.expression)
|
||||||
|
|
||||||
|
def enterPreIncrementExpression(
|
||||||
|
self, ctx: JavaScriptParser.PreIncrementExpressionContext
|
||||||
|
):
|
||||||
|
logging.debug("Entered section PreIncrementExpression")
|
||||||
|
arg_lst = ExpressionListener()
|
||||||
|
ctx.singleExpression().enterRule(arg_lst)
|
||||||
|
loc = _get_source_location(ctx, None)
|
||||||
|
self._expr = nodes.PreIncrementExpression(loc, arg_lst.expression)
|
||||||
|
|
||||||
|
def enterPreDecreaseExpression(
|
||||||
|
self, ctx: JavaScriptParser.PreDecreaseExpressionContext
|
||||||
|
):
|
||||||
|
logging.debug("Entered section PreDecreaseExpression")
|
||||||
|
arg_lst = ExpressionListener()
|
||||||
|
ctx.singleExpression().enterRule(arg_lst)
|
||||||
|
loc = _get_source_location(ctx, None)
|
||||||
|
self._expr = nodes.PreDecrementExpression(loc, arg_lst.expression)
|
||||||
|
|
||||||
|
def enterUnaryPlusExpression(
|
||||||
|
self, ctx: JavaScriptParser.UnaryPlusExpressionContext
|
||||||
|
):
|
||||||
|
logging.debug("Entered section UnaryPlusExpression")
|
||||||
|
arg_lst = ExpressionListener()
|
||||||
|
ctx.singleExpression().enterRule(arg_lst)
|
||||||
|
loc = _get_source_location(ctx, None)
|
||||||
|
self._expr = nodes.UnaryPlusExpression(loc, arg_lst.expression)
|
||||||
|
|
||||||
|
def enterUnaryMinusExpression(
|
||||||
|
self, ctx: JavaScriptParser.UnaryMinusExpressionContext
|
||||||
|
):
|
||||||
|
logging.debug("Entered section UnaryMinusExpression")
|
||||||
|
arg_lst = ExpressionListener()
|
||||||
|
ctx.singleExpression().enterRule(arg_lst)
|
||||||
|
loc = _get_source_location(ctx, None)
|
||||||
|
self._expr = nodes.UnaryMinusExpression(loc, arg_lst.expression)
|
||||||
|
|
||||||
|
def enterBitNotExpression(self, ctx: JavaScriptParser.BitNotExpressionContext):
|
||||||
|
logging.debug("Entered section BitNotExpression")
|
||||||
|
arg_lst = ExpressionListener()
|
||||||
|
ctx.singleExpression().enterRule(arg_lst)
|
||||||
|
loc = _get_source_location(ctx, None)
|
||||||
|
self._expr = nodes.UnaryBitNotExpression(loc, arg_lst.expression)
|
||||||
|
|
||||||
|
def enterNotExpression(self, ctx: JavaScriptParser.NotExpressionContext):
|
||||||
|
logging.debug("Entered section NotExpression")
|
||||||
|
arg_lst = ExpressionListener()
|
||||||
|
ctx.singleExpression().enterRule(arg_lst)
|
||||||
|
loc = _get_source_location(ctx, None)
|
||||||
|
self._expr = nodes.UnaryLogicNotExpression(loc, arg_lst.expression)
|
||||||
|
|
||||||
|
def enterPowerExpression(self, ctx: JavaScriptParser.PowerExpressionContext):
|
||||||
|
logging.debug("Entered section PowerExpression")
|
||||||
|
arg_l_lst = ExpressionListener()
|
||||||
|
arg_r_lst = ExpressionListener()
|
||||||
|
ctx.singleExpression(0).enterRule(arg_l_lst)
|
||||||
|
ctx.singleExpression(1).enterRule(arg_r_lst)
|
||||||
|
loc = _get_source_location(ctx, None)
|
||||||
|
self._expr = nodes.PowBinaryExpression(
|
||||||
|
loc, arg_l_lst.expression, arg_r_lst.expression
|
||||||
|
)
|
||||||
|
|
||||||
|
def enterMultiplicativeExpression(
|
||||||
|
self, ctx: JavaScriptParser.MultiplicativeExpressionContext
|
||||||
|
):
|
||||||
|
logging.debug("Entered section MultiplicativeExpression")
|
||||||
|
|
||||||
|
ops_list = [
|
||||||
|
(ctx.Multiply(), nodes.MulArithmeticExpression),
|
||||||
|
(ctx.Divide(), nodes.DivArithmeticExpression),
|
||||||
|
(ctx.Modulus(), nodes.ModArithmeticExpression),
|
||||||
|
]
|
||||||
|
|
||||||
|
arg_l_lst = ExpressionListener()
|
||||||
|
arg_r_lst = ExpressionListener()
|
||||||
|
ctx.singleExpression(0).enterRule(arg_l_lst)
|
||||||
|
ctx.singleExpression(1).enterRule(arg_r_lst)
|
||||||
|
|
||||||
|
loc = _get_source_location(ctx, None)
|
||||||
|
|
||||||
|
for (op_cond, op) in ops_list:
|
||||||
|
if op_cond is not None:
|
||||||
|
self._expr = op(loc, arg_l_lst.expression, arg_r_lst.expression)
|
||||||
|
break
|
||||||
|
|
||||||
|
def enterAdditiveExpression(self, ctx: JavaScriptParser.AdditiveExpressionContext):
|
||||||
|
logging.debug("Entered section AdditiveExpression")
|
||||||
|
|
||||||
|
ops_list = [
|
||||||
|
(ctx.Plus(), nodes.AddArithmeticExpression),
|
||||||
|
(ctx.Minus(), nodes.SubArithmeticExpression),
|
||||||
|
]
|
||||||
|
|
||||||
|
arg_l_lst = ExpressionListener()
|
||||||
|
arg_r_lst = ExpressionListener()
|
||||||
|
ctx.singleExpression(0).enterRule(arg_l_lst)
|
||||||
|
ctx.singleExpression(1).enterRule(arg_r_lst)
|
||||||
|
|
||||||
|
loc = _get_source_location(ctx, None)
|
||||||
|
|
||||||
|
for (op_cond, op) in ops_list:
|
||||||
|
if op_cond is not None:
|
||||||
|
self._expr = op(loc, arg_l_lst.expression, arg_r_lst.expression)
|
||||||
|
break
|
||||||
|
|
||||||
|
def enterCoalesceExpression(self, ctx: JavaScriptParser.CoalesceExpressionContext):
|
||||||
|
logging.debug("Entered section CoalesceExpression")
|
||||||
|
raise NotImplementedError("CoalesceExpression") # TODO
|
||||||
|
|
||||||
|
def enterBitShiftExpression(self, ctx: JavaScriptParser.BitShiftExpressionContext):
|
||||||
|
logging.debug("Entered section BitShiftExpression")
|
||||||
|
|
||||||
|
ops_list = [
|
||||||
|
(ctx.LeftShiftArithmetic(), nodes.LeftBitShiftExpression),
|
||||||
|
(ctx.RightShiftArithmetic(), nodes.RightBitShiftExpression),
|
||||||
|
(ctx.RightShiftLogical(), nodes.LogicRightBitShiftExpression),
|
||||||
|
]
|
||||||
|
|
||||||
|
arg_l_lst = ExpressionListener()
|
||||||
|
arg_r_lst = ExpressionListener()
|
||||||
|
ctx.singleExpression(0).enterRule(arg_l_lst)
|
||||||
|
ctx.singleExpression(1).enterRule(arg_r_lst)
|
||||||
|
|
||||||
|
loc = _get_source_location(ctx, None)
|
||||||
|
|
||||||
|
for (op_cond, op) in ops_list:
|
||||||
|
if op_cond is not None:
|
||||||
|
self._expr = op(loc, arg_l_lst.expression, arg_r_lst.expression)
|
||||||
|
break
|
||||||
|
|
||||||
|
def enterRelationalExpression(
|
||||||
|
self, ctx: JavaScriptParser.RelationalExpressionContext
|
||||||
|
):
|
||||||
|
logging.debug("Entered section RelationalExpression")
|
||||||
|
|
||||||
|
ops_list = [
|
||||||
|
(ctx.LessThan(), nodes.LowerThanRelationExpression),
|
||||||
|
(ctx.LessThanEquals(), nodes.LowerThanEqualRelationExpression),
|
||||||
|
(ctx.MoreThan(), nodes.GreaterThanRelationExpression),
|
||||||
|
(ctx.GreaterThanEquals(), nodes.GreaterThanEqualRelationExpression),
|
||||||
|
]
|
||||||
|
|
||||||
|
arg_l_lst = ExpressionListener()
|
||||||
|
arg_r_lst = ExpressionListener()
|
||||||
|
ctx.singleExpression(0).enterRule(arg_l_lst)
|
||||||
|
ctx.singleExpression(1).enterRule(arg_r_lst)
|
||||||
|
|
||||||
|
loc = _get_source_location(ctx, None)
|
||||||
|
|
||||||
|
for (op_cond, op) in ops_list:
|
||||||
|
if op_cond is not None:
|
||||||
|
self._expr = op(loc, arg_l_lst.expression, arg_r_lst.expression)
|
||||||
|
break
|
||||||
|
|
||||||
|
def enterInExpression(self, ctx: JavaScriptParser.InExpressionContext):
|
||||||
|
logging.debug("Entered section InExpression")
|
||||||
|
raise NotImplementedError("InExpression") # TODO
|
||||||
|
|
||||||
|
def enterEqualityExpression(self, ctx: JavaScriptParser.EqualityExpressionContext):
|
||||||
|
logging.debug("Entered section EqualityExpression")
|
||||||
|
|
||||||
|
ops_list = [
|
||||||
|
(ctx.Equals_(), nodes.EqualityExpression),
|
||||||
|
(ctx.NotEquals(), nodes.NotEqualityExpression),
|
||||||
|
(ctx.IdentityEquals(), nodes.IdentityEqualityExpression),
|
||||||
|
(ctx.IdentityNotEquals(), nodes.NotIdentityEqualityExpression),
|
||||||
|
]
|
||||||
|
|
||||||
|
arg_l_lst = ExpressionListener()
|
||||||
|
arg_r_lst = ExpressionListener()
|
||||||
|
ctx.singleExpression(0).enterRule(arg_l_lst)
|
||||||
|
ctx.singleExpression(1).enterRule(arg_r_lst)
|
||||||
|
|
||||||
|
loc = _get_source_location(ctx, None)
|
||||||
|
|
||||||
|
for (op_cond, op) in ops_list:
|
||||||
|
if op_cond is not None:
|
||||||
|
self._expr = op(loc, arg_l_lst.expression, arg_r_lst.expression)
|
||||||
|
break
|
||||||
|
|
||||||
|
def enterBitAndExpression(self, ctx: JavaScriptParser.BitAndExpressionContext):
|
||||||
|
logging.debug("Entered section BitAndExpression")
|
||||||
|
raise NotImplementedError("BitAndExpression") # TODO
|
||||||
|
|
||||||
|
def enterBitOrExpression(self, ctx: JavaScriptParser.BitOrExpressionContext):
|
||||||
|
logging.debug("Entered section BitOrExpression")
|
||||||
|
raise NotImplementedError("BitOrExpression") # TODO
|
||||||
|
|
||||||
|
def enterBitXOrExpression(self, ctx: JavaScriptParser.BitXOrExpressionContext):
|
||||||
|
logging.debug("Entered section BitXOrExpression")
|
||||||
|
raise NotImplementedError("BitXOrExpression") # TODO
|
||||||
|
|
||||||
|
def enterLogicalAndExpression(
|
||||||
|
self, ctx: JavaScriptParser.LogicalAndExpressionContext
|
||||||
|
):
|
||||||
|
logging.debug("Entered section LogicalAndExpression")
|
||||||
|
raise NotImplementedError("LogicalAndExpression") # TODO
|
||||||
|
|
||||||
|
def enterLogicalOrExpression(
|
||||||
|
self, ctx: JavaScriptParser.LogicalOrExpressionContext
|
||||||
|
):
|
||||||
|
logging.debug("Entered section LogicalOrExpression")
|
||||||
|
raise NotImplementedError("LogicalOrExpression") # TODO
|
||||||
|
|
||||||
|
def enterTernaryExpression(self, ctx: JavaScriptParser.TernaryExpressionContext):
|
||||||
|
logging.debug("Entered section TernaryExpression")
|
||||||
|
raise NotImplementedError("TernaryExpression") # TODO
|
||||||
|
|
||||||
|
def enterAssignmentExpression(
|
||||||
|
self, ctx: JavaScriptParser.AssignmentExpressionContext
|
||||||
|
):
|
||||||
|
logging.debug("Entered section AssignmentExpression")
|
||||||
|
left_lst = ExpressionListener()
|
||||||
|
right_lst = ExpressionListener()
|
||||||
|
ctx.singleExpression(0).enterRule(left_lst)
|
||||||
|
ctx.singleExpression(1).enterRule(right_lst)
|
||||||
|
|
||||||
|
loc = _get_source_location(ctx, None)
|
||||||
|
left = left_lst.expression
|
||||||
|
right = right_lst.expression
|
||||||
|
self._expr = nodes.AssignmentExpression(
|
||||||
|
loc, nodes.AssignmentOperator.ASSIGN, left, right
|
||||||
|
)
|
||||||
|
|
||||||
|
def enterAssignmentOperatorExpression(
|
||||||
|
self, ctx: JavaScriptParser.AssignmentOperatorExpressionContext
|
||||||
|
):
|
||||||
|
logging.debug("Entered section AssignmentOperatorExpression")
|
||||||
|
left_lst = ExpressionListener()
|
||||||
|
right_lst = ExpressionListener()
|
||||||
|
op_lst = AssignmentOperatorListener()
|
||||||
|
ctx.singleExpression(0).enterRule(left_lst)
|
||||||
|
ctx.singleExpression(1).enterRule(right_lst)
|
||||||
|
ctx.assignmentOperator().enterRule(op_lst)
|
||||||
|
|
||||||
|
loc = _get_source_location(ctx, None)
|
||||||
|
left = left_lst.expression
|
||||||
|
right = right_lst.expression
|
||||||
|
op = op_lst.oper
|
||||||
|
self._expr = nodes.AssignmentExpression(loc, op, left, right)
|
||||||
|
|
||||||
|
def enterImportExpression(self, ctx: JavaScriptParser.ImportExpressionContext):
|
||||||
|
logging.debug("Entered section ImportExpression")
|
||||||
|
raise NotImplementedError("ImportExpression") # TODO
|
||||||
|
|
||||||
|
def enterThisExpression(self, ctx: JavaScriptParser.ThisExpressionContext):
|
||||||
|
logging.debug("Entered section ThisExpression")
|
||||||
|
loc = _get_source_location(ctx, None)
|
||||||
|
self._expr = nodes.ThisExpression(loc)
|
||||||
|
|
||||||
|
def enterIdentifierExpression(
|
||||||
|
self, ctx: JavaScriptParser.IdentifierExpressionContext
|
||||||
|
):
|
||||||
|
logging.debug("Entered section IdentifierExpression")
|
||||||
|
ctx.identifier().enterRule(self)
|
||||||
|
|
||||||
|
def enterIdentifier(self, ctx: JavaScriptParser.IdentifierContext):
|
||||||
|
logging.debug("Entered section Identifier")
|
||||||
|
loc = _get_source_location(ctx, None)
|
||||||
|
self._expr = nodes.Identifier(loc, ctx.getText())
|
||||||
|
|
||||||
|
def enterSuperExpression(self, ctx: JavaScriptParser.SuperExpressionContext):
|
||||||
|
logging.debug("Entered section SuperExpression")
|
||||||
|
loc = _get_source_location(ctx, None)
|
||||||
|
self._expr = nodes.Super(loc)
|
||||||
|
|
||||||
|
def enterArrayLiteralExpression(
|
||||||
|
self, ctx: JavaScriptParser.ArrayLiteralExpressionContext
|
||||||
|
):
|
||||||
|
logging.debug("Entered section ArrayLiteralExpression")
|
||||||
|
arr_expand_lst = ArrayLiteralExpandListener()
|
||||||
|
ctx.arrayLiteral().enterRule(arr_expand_lst)
|
||||||
|
loc = _get_source_location(ctx, None)
|
||||||
|
self._expr = nodes.ArrayExpression(loc, arr_expand_lst.expressions)
|
||||||
|
|
||||||
|
def enterObjectLiteralExpression(
|
||||||
|
self, ctx: JavaScriptParser.ObjectLiteralExpressionContext
|
||||||
|
):
|
||||||
|
logging.debug("Entered section ObjectLiteralExpression")
|
||||||
|
raise NotImplementedError("ObjectLiteralExpression") # TODO
|
||||||
|
|
||||||
|
|
||||||
class AssignableListener(NodeListener):
|
class AssignableListener(NodeListener):
|
||||||
|
@ -122,7 +534,15 @@ class AssignableListener(NodeListener):
|
||||||
|
|
||||||
def enterArrayLiteral(self, ctx: JavaScriptParser.ArrayLiteralContext):
|
def enterArrayLiteral(self, ctx: JavaScriptParser.ArrayLiteralContext):
|
||||||
logging.debug("Entered section ArrayLiteral")
|
logging.debug("Entered section ArrayLiteral")
|
||||||
raise NotImplementedError("ArrayLiteral assignment") # TODO
|
loc = _get_source_location(ctx, None)
|
||||||
|
|
||||||
|
elems = []
|
||||||
|
if ctx.elementList() is not None:
|
||||||
|
arr_exp_lst = ArrayLiteralExpandListener()
|
||||||
|
ctx.elementList().enterRule(arr_exp_lst)
|
||||||
|
elems += arr_exp_lst.expressions
|
||||||
|
|
||||||
|
self._result = nodes.ArrayPattern(loc, elems)
|
||||||
|
|
||||||
def enterObjectLiteral(self, ctx: JavaScriptParser.ObjectLiteralContext):
|
def enterObjectLiteral(self, ctx: JavaScriptParser.ObjectLiteralContext):
|
||||||
logging.debug("Entered section ObjectLiteral")
|
logging.debug("Entered section ObjectLiteral")
|
||||||
|
@ -293,7 +713,10 @@ class StatementListener(JSBaseListener):
|
||||||
class SourceElementListener(JSBaseListener):
|
class SourceElementListener(JSBaseListener):
|
||||||
"""The proxy between Program and Statement."""
|
"""The proxy between Program and Statement."""
|
||||||
|
|
||||||
_elems: List[nodes.Statement] = []
|
_elems: List[nodes.Statement]
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._elems = []
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def source_elements(self) -> List[nodes.Statement]:
|
def source_elements(self) -> List[nodes.Statement]:
|
||||||
|
@ -312,9 +735,12 @@ class SourceElementListener(JSBaseListener):
|
||||||
class ASTListener(JSBaseListener):
|
class ASTListener(JSBaseListener):
|
||||||
"""AST listener."""
|
"""AST listener."""
|
||||||
|
|
||||||
_program_node: Optional[nodes.Program] = None
|
_program_node: Optional[nodes.Program]
|
||||||
_source_type: nodes.SourceTypeLiteral
|
_source_type: nodes.SourceTypeLiteral
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._program_node = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def program_node(self) -> nodes.Program:
|
def program_node(self) -> nodes.Program:
|
||||||
"""The `Program` AST node generated after parse tree walking."""
|
"""The `Program` AST node generated after parse tree walking."""
|
||||||
|
|
|
@ -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"}}
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
Program at 1:0
|
||||||
|
+-- sourceType: script
|
||||||
|
+-- body:
|
||||||
|
| +-- 0: ExpressionStatement at 1:0
|
||||||
|
| | +-- expression: SequenceExpression at 1:0
|
||||||
|
| | | +-- expressions:
|
||||||
|
| | | | +-- 0: " while executing client event 1"
|
||||||
|
| | | | | +-- value: while executing client event 1
|
|
@ -0,0 +1,2 @@
|
||||||
|
// The code below won't work since the grammar treat Unicode
|
||||||
|
"\x20\x77hil\x65\x20exe\x63uting c\x6cient e\x76\145\x6et 1";
|
|
@ -0,0 +1,120 @@
|
||||||
|
Program at 1:0
|
||||||
|
+-- sourceType: script
|
||||||
|
+-- body:
|
||||||
|
| +-- 0: ExpressionStatement at 1:0
|
||||||
|
| | +-- expression: SequenceExpression at 1:0
|
||||||
|
| | | +-- expressions:
|
||||||
|
| | | | +-- 0: AssignmentExpression at 1:0
|
||||||
|
| | | | | +-- operator: =
|
||||||
|
| | | | | +-- left: Identifier at 1:0
|
||||||
|
| | | | | | +-- name: a
|
||||||
|
| | | | | +-- right: Literal at 1:4
|
||||||
|
| | | | | | +-- value: 1.0
|
||||||
|
| +-- 1: ExpressionStatement at 2:0
|
||||||
|
| | +-- expression: SequenceExpression at 2:0
|
||||||
|
| | | +-- expressions:
|
||||||
|
| | | | +-- 0: AssignmentExpression at 2:0
|
||||||
|
| | | | | +-- operator: *=
|
||||||
|
| | | | | +-- left: Identifier at 2:0
|
||||||
|
| | | | | | +-- name: q
|
||||||
|
| | | | | +-- right: Literal at 2:5
|
||||||
|
| | | | | | +-- value: 2.0
|
||||||
|
| +-- 2: ExpressionStatement at 3:0
|
||||||
|
| | +-- expression: SequenceExpression at 3:0
|
||||||
|
| | | +-- expressions:
|
||||||
|
| | | | +-- 0: AssignmentExpression at 3:0
|
||||||
|
| | | | | +-- operator: /=
|
||||||
|
| | | | | +-- left: Identifier at 3:0
|
||||||
|
| | | | | | +-- name: d
|
||||||
|
| | | | | +-- right: Literal at 3:5
|
||||||
|
| | | | | | +-- value: 2.0
|
||||||
|
| +-- 3: ExpressionStatement at 4:0
|
||||||
|
| | +-- expression: SequenceExpression at 4:0
|
||||||
|
| | | +-- expressions:
|
||||||
|
| | | | +-- 0: AssignmentExpression at 4:0
|
||||||
|
| | | | | +-- operator: %=
|
||||||
|
| | | | | +-- left: Identifier at 4:0
|
||||||
|
| | | | | | +-- name: w
|
||||||
|
| | | | | +-- right: Literal at 4:5
|
||||||
|
| | | | | | +-- value: 15.0
|
||||||
|
| +-- 4: ExpressionStatement at 5:0
|
||||||
|
| | +-- expression: SequenceExpression at 5:0
|
||||||
|
| | | +-- expressions:
|
||||||
|
| | | | +-- 0: AssignmentExpression at 5:0
|
||||||
|
| | | | | +-- operator: +=
|
||||||
|
| | | | | +-- left: Identifier at 5:0
|
||||||
|
| | | | | | +-- name: b
|
||||||
|
| | | | | +-- right: Literal at 5:5
|
||||||
|
| | | | | | +-- value: 12.0
|
||||||
|
| +-- 5: ExpressionStatement at 6:0
|
||||||
|
| | +-- expression: SequenceExpression at 6:0
|
||||||
|
| | | +-- expressions:
|
||||||
|
| | | | +-- 0: AssignmentExpression at 6:0
|
||||||
|
| | | | | +-- operator: -=
|
||||||
|
| | | | | +-- left: Identifier at 6:0
|
||||||
|
| | | | | | +-- name: c
|
||||||
|
| | | | | +-- right: Literal at 6:5
|
||||||
|
| | | | | | +-- value: 14.0
|
||||||
|
| +-- 6: ExpressionStatement at 7:0
|
||||||
|
| | +-- expression: SequenceExpression at 7:0
|
||||||
|
| | | +-- expressions:
|
||||||
|
| | | | +-- 0: AssignmentExpression at 7:0
|
||||||
|
| | | | | +-- operator: <<=
|
||||||
|
| | | | | +-- left: Identifier at 7:0
|
||||||
|
| | | | | | +-- name: a
|
||||||
|
| | | | | +-- right: Literal at 7:6
|
||||||
|
| | | | | | +-- value: 1.0
|
||||||
|
| +-- 7: ExpressionStatement at 8:0
|
||||||
|
| | +-- expression: SequenceExpression at 8:0
|
||||||
|
| | | +-- expressions:
|
||||||
|
| | | | +-- 0: AssignmentExpression at 8:0
|
||||||
|
| | | | | +-- operator: >>=
|
||||||
|
| | | | | +-- left: Identifier at 8:0
|
||||||
|
| | | | | | +-- name: b
|
||||||
|
| | | | | +-- right: Literal at 8:6
|
||||||
|
| | | | | | +-- value: 2.0
|
||||||
|
| +-- 8: ExpressionStatement at 9:0
|
||||||
|
| | +-- expression: SequenceExpression at 9:0
|
||||||
|
| | | +-- expressions:
|
||||||
|
| | | | +-- 0: AssignmentExpression at 9:0
|
||||||
|
| | | | | +-- operator: >>>=
|
||||||
|
| | | | | +-- left: Identifier at 9:0
|
||||||
|
| | | | | | +-- name: z
|
||||||
|
| | | | | +-- right: Literal at 9:7
|
||||||
|
| | | | | | +-- value: 2.0
|
||||||
|
| +-- 9: ExpressionStatement at 10:0
|
||||||
|
| | +-- expression: SequenceExpression at 10:0
|
||||||
|
| | | +-- expressions:
|
||||||
|
| | | | +-- 0: AssignmentExpression at 10:0
|
||||||
|
| | | | | +-- operator: &=
|
||||||
|
| | | | | +-- left: Identifier at 10:0
|
||||||
|
| | | | | | +-- name: v
|
||||||
|
| | | | | +-- right: Literal at 10:5
|
||||||
|
| | | | | | +-- value: 1.0
|
||||||
|
| +-- 10: ExpressionStatement at 11:0
|
||||||
|
| | +-- expression: SequenceExpression at 11:0
|
||||||
|
| | | +-- expressions:
|
||||||
|
| | | | +-- 0: AssignmentExpression at 11:0
|
||||||
|
| | | | | +-- operator: ^=
|
||||||
|
| | | | | +-- left: Identifier at 11:0
|
||||||
|
| | | | | | +-- name: cc
|
||||||
|
| | | | | +-- right: Identifier at 11:6
|
||||||
|
| | | | | | +-- name: cc
|
||||||
|
| +-- 11: ExpressionStatement at 12:0
|
||||||
|
| | +-- expression: SequenceExpression at 12:0
|
||||||
|
| | | +-- expressions:
|
||||||
|
| | | | +-- 0: AssignmentExpression at 12:0
|
||||||
|
| | | | | +-- operator: |=
|
||||||
|
| | | | | +-- left: Identifier at 12:0
|
||||||
|
| | | | | | +-- name: vv
|
||||||
|
| | | | | +-- right: Identifier at 12:5
|
||||||
|
| | | | | | +-- name: a
|
||||||
|
| +-- 12: ExpressionStatement at 13:0
|
||||||
|
| | +-- expression: SequenceExpression at 13:0
|
||||||
|
| | | +-- expressions:
|
||||||
|
| | | | +-- 0: AssignmentExpression at 13:0
|
||||||
|
| | | | | +-- operator: **=
|
||||||
|
| | | | | +-- left: Identifier at 13:0
|
||||||
|
| | | | | | +-- name: x
|
||||||
|
| | | | | +-- right: Literal at 13:6
|
||||||
|
| | | | | | +-- value: 2.0
|
|
@ -0,0 +1,42 @@
|
||||||
|
Program at 1:0
|
||||||
|
+-- sourceType: script
|
||||||
|
+-- body:
|
||||||
|
| +-- 0: ExpressionStatement at 1:0
|
||||||
|
| | +-- expression: SequenceExpression at 1:0
|
||||||
|
| | | +-- expressions:
|
||||||
|
| | | | +-- 0: BinaryExpression at 1:0
|
||||||
|
| | | | | +-- operator: +
|
||||||
|
| | | | | +-- left: Literal at 1:0
|
||||||
|
| | | | | | +-- value: 2.0
|
||||||
|
| | | | | +-- right: BinaryExpression at 1:2
|
||||||
|
| | | | | | +-- operator: *
|
||||||
|
| | | | | | +-- left: Literal at 1:2
|
||||||
|
| | | | | | | +-- value: 2.0
|
||||||
|
| | | | | | +-- right: Literal at 1:4
|
||||||
|
| | | | | | | +-- value: 2.0
|
||||||
|
| +-- 1: ExpressionStatement at 2:0
|
||||||
|
| | +-- expression: SequenceExpression at 2:0
|
||||||
|
| | | +-- expressions:
|
||||||
|
| | | | +-- 0: BinaryExpression at 2:0
|
||||||
|
| | | | | +-- operator: ==
|
||||||
|
| | | | | +-- left: BinaryExpression at 2:0
|
||||||
|
| | | | | | +-- operator: +
|
||||||
|
| | | | | | +-- left: Literal at 2:0
|
||||||
|
| | | | | | | +-- value: 2.0
|
||||||
|
| | | | | | +-- right: Literal at 2:6
|
||||||
|
| | | | | | | +-- value: 2.0
|
||||||
|
| | | | | +-- right: Literal at 2:11
|
||||||
|
| | | | | | +-- value: 5.0
|
||||||
|
| +-- 2: ExpressionStatement at 3:0
|
||||||
|
| | +-- expression: SequenceExpression at 3:0
|
||||||
|
| | | +-- expressions:
|
||||||
|
| | | | +-- 0: BinaryExpression at 3:0
|
||||||
|
| | | | | +-- operator: !==
|
||||||
|
| | | | | +-- left: BinaryExpression at 3:0
|
||||||
|
| | | | | | +-- operator: /
|
||||||
|
| | | | | | +-- left: Literal at 3:0
|
||||||
|
| | | | | | | +-- value: 1.0
|
||||||
|
| | | | | | +-- right: Literal at 3:2
|
||||||
|
| | | | | | | +-- value: 0.0
|
||||||
|
| | | | | +-- right: Identifier at 3:8
|
||||||
|
| | | | | | +-- name: infty
|
|
@ -0,0 +1,7 @@
|
||||||
|
Program at 1:1
|
||||||
|
+-- sourceType: script
|
||||||
|
+-- body:
|
||||||
|
| +-- 0: EmptyStatement at 1:1
|
||||||
|
| +-- 1: EmptyStatement at 2:0
|
||||||
|
| +-- 2: EmptyStatement at 2:2
|
||||||
|
| +-- 3: EmptyStatement at 3:1
|
|
@ -0,0 +1,32 @@
|
||||||
|
Program at 1:0
|
||||||
|
+-- sourceType: script
|
||||||
|
+-- body:
|
||||||
|
| +-- 0: ExpressionStatement at 1:0
|
||||||
|
| | +-- expression: SequenceExpression at 1:0
|
||||||
|
| | | +-- expressions:
|
||||||
|
| | | | +-- 0: UpdateExpression at 1:0
|
||||||
|
| | | | | +-- operator: ++
|
||||||
|
| | | | | +-- argument: Identifier at 1:2
|
||||||
|
| | | | | | +-- name: a
|
||||||
|
| | | | | +-- prefix: True
|
||||||
|
| +-- 1: ExpressionStatement at 1:5
|
||||||
|
| | +-- expression: SequenceExpression at 1:5
|
||||||
|
| | | +-- expressions:
|
||||||
|
| | | | +-- 0: UpdateExpression at 1:5
|
||||||
|
| | | | | +-- operator: ++
|
||||||
|
| | | | | +-- argument: Identifier at 1:5
|
||||||
|
| | | | | | +-- name: b
|
||||||
|
| | | | | +-- prefix: False
|
||||||
|
| +-- 2: ExpressionStatement at 2:0
|
||||||
|
| | +-- expression: SequenceExpression at 2:0
|
||||||
|
| | | +-- expressions:
|
||||||
|
| | | | +-- 0: UpdateExpression at 2:0
|
||||||
|
| | | | | +-- operator: --
|
||||||
|
| | | | | +-- argument: Identifier at 2:0
|
||||||
|
| | | | | | +-- name: a
|
||||||
|
| | | | | +-- prefix: False
|
||||||
|
| | | | +-- 1: UpdateExpression at 2:5
|
||||||
|
| | | | | +-- operator: --
|
||||||
|
| | | | | +-- argument: Identifier at 2:7
|
||||||
|
| | | | | | +-- name: b
|
||||||
|
| | | | | +-- prefix: True
|
|
@ -0,0 +1,13 @@
|
||||||
|
a = 1;
|
||||||
|
q *= 2;
|
||||||
|
d /= 2;
|
||||||
|
w %= 15;
|
||||||
|
b += 12;
|
||||||
|
c -= 14;
|
||||||
|
a <<= 1;
|
||||||
|
b >>= 2;
|
||||||
|
z >>>= 2;
|
||||||
|
v &= 1;
|
||||||
|
cc ^= cc;
|
||||||
|
vv|= a;
|
||||||
|
x **= 2;
|
|
@ -0,0 +1,3 @@
|
||||||
|
2+2*2;
|
||||||
|
2 + 2 == 5;
|
||||||
|
1/0 !== infty;
|
|
@ -0,0 +1,3 @@
|
||||||
|
;
|
||||||
|
; ;
|
||||||
|
;
|
|
@ -0,0 +1,2 @@
|
||||||
|
++a; b++;
|
||||||
|
a--, --b;
|
|
@ -0,0 +1,103 @@
|
||||||
|
from typing import List, Optional
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
import difflib
|
||||||
|
from jasminesnake.js_stream import JSStringStream
|
||||||
|
import jasminesnake.ast as js_ast
|
||||||
|
|
||||||
|
|
||||||
|
class JSTest:
|
||||||
|
_test_name: str
|
||||||
|
_test_file: str
|
||||||
|
_result_file: Optional[str]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
return self._test_name
|
||||||
|
|
||||||
|
def __init__(self, name: str, test_file: str, result_file: Optional[str]):
|
||||||
|
self._test_name = name
|
||||||
|
self._test_file = test_file
|
||||||
|
self._result_file = result_file
|
||||||
|
|
||||||
|
def run(self, must_fail: bool = False):
|
||||||
|
payload = Path(self._test_file).read_text()
|
||||||
|
jst = JSStringStream(payload)
|
||||||
|
tree = jst.parse()
|
||||||
|
ast_tree = None
|
||||||
|
try:
|
||||||
|
ast_tree = js_ast.from_parse_tree(tree)
|
||||||
|
except NotImplementedError as e:
|
||||||
|
print("Seems like some nodes are not implemented :^)")
|
||||||
|
print("Error message: ")
|
||||||
|
if hasattr(e, "message"):
|
||||||
|
print(e.message)
|
||||||
|
else:
|
||||||
|
print(e)
|
||||||
|
|
||||||
|
return must_fail
|
||||||
|
|
||||||
|
expected = None
|
||||||
|
if self._result_file is not None:
|
||||||
|
expected = Path(self._result_file).read_text()
|
||||||
|
|
||||||
|
got = js_ast.to_ascii_tree(ast_tree, ast_format="short")
|
||||||
|
|
||||||
|
del jst
|
||||||
|
del tree
|
||||||
|
del ast_tree
|
||||||
|
|
||||||
|
if expected is not None:
|
||||||
|
if expected == got:
|
||||||
|
print("Test {} OK...".format(self._test_name))
|
||||||
|
else:
|
||||||
|
print(
|
||||||
|
"Error in test `{}':\nExpected:\n```{}```\nGot:\n```{}```".format(
|
||||||
|
self._test_name, expected, got
|
||||||
|
)
|
||||||
|
)
|
||||||
|
# for i, s in enumerate(difflib.ndiff(expected, got)):
|
||||||
|
# if s[0] != " ":
|
||||||
|
# print(s[0], ord(s[-1]), "at", i)
|
||||||
|
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
print("Test {} has no result file!\nGot:\n{}".format(self._test_name, got))
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class JSTestCollection:
|
||||||
|
tests: List[JSTest]
|
||||||
|
|
||||||
|
def __init__(self, module_path: str):
|
||||||
|
self.tests = []
|
||||||
|
basedir = os.path.abspath(module_path)
|
||||||
|
tests_dir = os.path.join(basedir, "t")
|
||||||
|
results_dir = os.path.join(basedir, "r")
|
||||||
|
|
||||||
|
# Collect tests
|
||||||
|
test_files = [
|
||||||
|
os.path.join(tests_dir, f)
|
||||||
|
for f in os.listdir(tests_dir)
|
||||||
|
if os.path.isfile(os.path.join(tests_dir, f))
|
||||||
|
]
|
||||||
|
test_names = [
|
||||||
|
os.path.splitext(os.path.basename(path))[0] for path in test_files
|
||||||
|
]
|
||||||
|
|
||||||
|
for (test_name, test_file) in zip(test_names, test_files):
|
||||||
|
result_file = os.path.join(results_dir, test_name) + ".ast"
|
||||||
|
print(test_name, test_file, result_file)
|
||||||
|
if not os.path.isfile(result_file):
|
||||||
|
result_file = None
|
||||||
|
|
||||||
|
test_case = JSTest(test_name, test_file, result_file)
|
||||||
|
self.tests.append(test_case)
|
||||||
|
|
||||||
|
def run_all(self, must_fail: bool = False):
|
||||||
|
for test in self.tests:
|
||||||
|
if not test.run(must_fail):
|
||||||
|
return False
|
||||||
|
return True
|
|
@ -0,0 +1,18 @@
|
||||||
|
Program at 1:0
|
||||||
|
+-- sourceType: script
|
||||||
|
+-- body:
|
||||||
|
| +-- 0: ExpressionStatement at 1:0
|
||||||
|
| | +-- expression: SequenceExpression at 1:0
|
||||||
|
| | | +-- expressions:
|
||||||
|
| | | | +-- 0: ArrayExpression at 1:0
|
||||||
|
| | | | | +-- elements:
|
||||||
|
| | | | | | +-- 0: Literal at 1:1
|
||||||
|
| | | | | | | +-- value: 4.0
|
||||||
|
| | | | | | +-- 1: Literal at 1:3
|
||||||
|
| | | | | | | +-- value: 4.0
|
||||||
|
| | | | | | +-- 2: Literal at 1:5
|
||||||
|
| | | | | | | +-- value: 4.0
|
||||||
|
| | | | | | +-- 3: Literal at 1:7
|
||||||
|
| | | | | | | +-- value: 4.0
|
||||||
|
| | | | | | +-- 4: Literal at 1:9
|
||||||
|
| | | | | | | +-- value: 4.0
|
|
@ -0,0 +1,13 @@
|
||||||
|
Program at 1:0
|
||||||
|
+-- sourceType: script
|
||||||
|
+-- body:
|
||||||
|
| +-- 0: ExpressionStatement at 1:0
|
||||||
|
| | +-- expression: SequenceExpression at 1:0
|
||||||
|
| | | +-- expressions:
|
||||||
|
| | | | +-- 0: ArrayExpression at 1:0
|
||||||
|
| | | | | +-- elements:
|
||||||
|
| | | | | | +-- 0: SpreadElement at 1:1
|
||||||
|
| | | | | | | +-- argument: Identifier at 1:4
|
||||||
|
| | | | | | | | +-- name: a
|
||||||
|
| | | | | | +-- 1: Identifier at 1:7
|
||||||
|
| | | | | | | +-- name: b
|
|
@ -0,0 +1,19 @@
|
||||||
|
Program at 1:0
|
||||||
|
+-- sourceType: script
|
||||||
|
+-- body:
|
||||||
|
| +-- 0: VariableDeclaration at 1:0
|
||||||
|
| | +-- kind: let
|
||||||
|
| | +-- declarations:
|
||||||
|
| | | +-- 0: VariableDeclarator at 1:4
|
||||||
|
| | | | +-- id: ArrayPattern at 1:4
|
||||||
|
| | | | | +-- elements:
|
||||||
|
| | | | | | +-- 0: Identifier at 1:5
|
||||||
|
| | | | | | | +-- name: a
|
||||||
|
| | | | | | +-- 1: Identifier at 1:8
|
||||||
|
| | | | | | | +-- name: b
|
||||||
|
| | | | +-- init: ArrayExpression at 1:13
|
||||||
|
| | | | | +-- elements:
|
||||||
|
| | | | | | +-- 0: Literal at 1:14
|
||||||
|
| | | | | | | +-- value: 4.0
|
||||||
|
| | | | | | +-- 1: Literal at 1:17
|
||||||
|
| | | | | | | +-- value: 4.0
|
|
@ -0,0 +1,33 @@
|
||||||
|
Program at 1:0
|
||||||
|
+-- sourceType: script
|
||||||
|
+-- body:
|
||||||
|
| +-- 0: ExpressionStatement at 1:0
|
||||||
|
| | +-- expression: SequenceExpression at 1:0
|
||||||
|
| | | +-- expressions:
|
||||||
|
| | | | +-- 0: Literal at 1:0
|
||||||
|
| | | | | +-- value: 4444.0
|
||||||
|
| +-- 1: ExpressionStatement at 2:0
|
||||||
|
| | +-- expression: SequenceExpression at 2:0
|
||||||
|
| | | +-- expressions:
|
||||||
|
| | | | +-- 0: Literal at 2:0
|
||||||
|
| | | | | +-- value: 444444444.4444444
|
||||||
|
| +-- 2: ExpressionStatement at 3:0
|
||||||
|
| | +-- expression: SequenceExpression at 3:0
|
||||||
|
| | | +-- expressions:
|
||||||
|
| | | | +-- 0: Literal at 3:0
|
||||||
|
| | | | | +-- value: 4.0
|
||||||
|
| +-- 3: ExpressionStatement at 4:0
|
||||||
|
| | +-- expression: SequenceExpression at 4:0
|
||||||
|
| | | +-- expressions:
|
||||||
|
| | | | +-- 0: true
|
||||||
|
| | | | | +-- value: True
|
||||||
|
| +-- 4: ExpressionStatement at 5:0
|
||||||
|
| | +-- expression: SequenceExpression at 5:0
|
||||||
|
| | | +-- expressions:
|
||||||
|
| | | | +-- 0: false
|
||||||
|
| | | | | +-- value: False
|
||||||
|
| +-- 5: ExpressionStatement at 6:0
|
||||||
|
| | +-- expression: SequenceExpression at 6:0
|
||||||
|
| | | +-- expressions:
|
||||||
|
| | | | +-- 0: "String literal"
|
||||||
|
| | | | | +-- value: String literal
|
|
@ -0,0 +1,8 @@
|
||||||
|
Program at 1:0
|
||||||
|
+-- sourceType: script
|
||||||
|
+-- body:
|
||||||
|
| +-- 0: ExpressionStatement at 1:0
|
||||||
|
| | +-- expression: SequenceExpression at 1:0
|
||||||
|
| | | +-- expressions:
|
||||||
|
| | | | +-- 0: "String literal, but single quoted"
|
||||||
|
| | | | | +-- value: String literal, but single quoted
|
|
@ -0,0 +1 @@
|
||||||
|
[4,4,4,4,4,];
|
|
@ -0,0 +1 @@
|
||||||
|
[...a, b];
|
|
@ -0,0 +1 @@
|
||||||
|
let [a, b] = [4, 4];
|
|
@ -0,0 +1,6 @@
|
||||||
|
4444;
|
||||||
|
444_444_444.444_444_444;
|
||||||
|
4;
|
||||||
|
true;
|
||||||
|
false;
|
||||||
|
"String literal";
|
|
@ -0,0 +1 @@
|
||||||
|
'String literal, but single quoted'
|
|
@ -0,0 +1,38 @@
|
||||||
|
Program at 1:0
|
||||||
|
+-- sourceType: script
|
||||||
|
+-- body:
|
||||||
|
| +-- 0: BlockStatement at 1:0
|
||||||
|
| | +-- body:
|
||||||
|
| | | +-- 0: VariableDeclaration at 1:1
|
||||||
|
| | | | +-- kind: let
|
||||||
|
| | | | +-- declarations:
|
||||||
|
| | | | | +-- 0: VariableDeclarator at 1:5
|
||||||
|
| | | | | | +-- id: Identifier at 1:5
|
||||||
|
| | | | | | | +-- name: a
|
||||||
|
| | | | | | +-- init: Literal at 1:9
|
||||||
|
| | | | | | | +-- value: 15.0
|
||||||
|
| | | | | +-- 1: VariableDeclarator at 1:13
|
||||||
|
| | | | | | +-- id: Identifier at 1:13
|
||||||
|
| | | | | | | +-- name: b
|
||||||
|
| | | | | | +-- init: None
|
||||||
|
| | | +-- 1: BlockStatement at 1:16
|
||||||
|
| | | | +-- body:
|
||||||
|
| | | | | +-- 0: ExpressionStatement at 1:17
|
||||||
|
| | | | | | +-- expression: SequenceExpression at 1:17
|
||||||
|
| | | | | | | +-- expressions:
|
||||||
|
| | | | | | | | +-- 0: Literal at 1:17
|
||||||
|
| | | | | | | | | +-- value: 1337.228
|
||||||
|
| | | | | | | | +-- 1: false
|
||||||
|
| | | | | | | | | +-- value: False
|
||||||
|
| | | | | | | | +-- 2: "String"
|
||||||
|
| | | | | | | | | +-- value: String
|
||||||
|
| | | +-- 2: EmptyStatement at 1:45
|
||||||
|
| | | +-- 3: BlockStatement at 1:47
|
||||||
|
| | | | +-- body:
|
||||||
|
| | | | | +-- 0: VariableDeclaration at 1:48
|
||||||
|
| | | | | | +-- kind: var
|
||||||
|
| | | | | | +-- declarations:
|
||||||
|
| | | | | | | +-- 0: VariableDeclarator at 1:52
|
||||||
|
| | | | | | | | +-- id: Identifier at 1:52
|
||||||
|
| | | | | | | | | +-- name: aaaaaaaaaaaaaa
|
||||||
|
| | | | | | | | +-- init: None
|
|
@ -0,0 +1,65 @@
|
||||||
|
Program at 1:0
|
||||||
|
+-- sourceType: script
|
||||||
|
+-- body:
|
||||||
|
| +-- 0: VariableDeclaration at 1:0
|
||||||
|
| | +-- kind: let
|
||||||
|
| | +-- declarations:
|
||||||
|
| | | +-- 0: VariableDeclarator at 1:4
|
||||||
|
| | | | +-- id: Identifier at 1:4
|
||||||
|
| | | | | +-- name: a
|
||||||
|
| | | | +-- init: None
|
||||||
|
| +-- 1: VariableDeclaration at 2:0
|
||||||
|
| | +-- kind: var
|
||||||
|
| | +-- declarations:
|
||||||
|
| | | +-- 0: VariableDeclarator at 2:4
|
||||||
|
| | | | +-- id: Identifier at 2:4
|
||||||
|
| | | | | +-- name: b
|
||||||
|
| | | | +-- init: None
|
||||||
|
| +-- 2: VariableDeclaration at 4:0
|
||||||
|
| | +-- kind: let
|
||||||
|
| | +-- declarations:
|
||||||
|
| | | +-- 0: VariableDeclarator at 4:4
|
||||||
|
| | | | +-- id: Identifier at 4:4
|
||||||
|
| | | | | +-- name: zzz
|
||||||
|
| | | | +-- init: Literal at 4:10
|
||||||
|
| | | | | +-- value: 0.0
|
||||||
|
| | | +-- 1: VariableDeclarator at 4:13
|
||||||
|
| | | | +-- id: Identifier at 4:13
|
||||||
|
| | | | | +-- name: k
|
||||||
|
| | | | +-- init: None
|
||||||
|
| +-- 3: VariableDeclaration at 5:0
|
||||||
|
| | +-- kind: let
|
||||||
|
| | +-- declarations:
|
||||||
|
| | | +-- 0: VariableDeclarator at 5:4
|
||||||
|
| | | | +-- id: Identifier at 5:4
|
||||||
|
| | | | | +-- name: cc
|
||||||
|
| | | | +-- init: None
|
||||||
|
| | | +-- 1: VariableDeclarator at 5:8
|
||||||
|
| | | | +-- id: Identifier at 5:8
|
||||||
|
| | | | | +-- name: asa
|
||||||
|
| | | | +-- init: None
|
||||||
|
| +-- 4: VariableDeclaration at 6:0
|
||||||
|
| | +-- kind: let
|
||||||
|
| | +-- declarations:
|
||||||
|
| | | +-- 0: VariableDeclarator at 6:4
|
||||||
|
| | | | +-- id: Identifier at 6:4
|
||||||
|
| | | | | +-- name: cccccc
|
||||||
|
| | | | +-- init: None
|
||||||
|
| | | +-- 1: VariableDeclarator at 6:12
|
||||||
|
| | | | +-- id: Identifier at 6:12
|
||||||
|
| | | | | +-- name: asasa
|
||||||
|
| | | | +-- init: Literal at 6:20
|
||||||
|
| | | | | +-- value: 0.0
|
||||||
|
| +-- 5: VariableDeclaration at 8:0
|
||||||
|
| | +-- kind: var
|
||||||
|
| | +-- declarations:
|
||||||
|
| | | +-- 0: VariableDeclarator at 8:4
|
||||||
|
| | | | +-- id: Identifier at 8:4
|
||||||
|
| | | | | +-- name: x
|
||||||
|
| | | | +-- init: Literal at 8:8
|
||||||
|
| | | | | +-- value: 0.0
|
||||||
|
| | | +-- 1: VariableDeclarator at 8:11
|
||||||
|
| | | | +-- id: Identifier at 8:11
|
||||||
|
| | | | | +-- name: y
|
||||||
|
| | | | +-- init: Literal at 8:15
|
||||||
|
| | | | | +-- value: 0.0
|
|
@ -0,0 +1 @@
|
||||||
|
{let a = 15, b; {1_337.2_28, false, "String"}; {var aaaaaaaaaaaaaa}}
|
|
@ -0,0 +1,8 @@
|
||||||
|
let a;
|
||||||
|
var b;
|
||||||
|
|
||||||
|
let zzz = 0, k;
|
||||||
|
let cc, asa;
|
||||||
|
let cccccc, asasa = 0;
|
||||||
|
|
||||||
|
var x = 0, y = 0
|
|
@ -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(){}
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
import os
|
||||||
|
import pytest
|
||||||
|
from js_test_suite import *
|
||||||
|
|
||||||
|
BASE_PATH = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
|
||||||
|
|
||||||
|
class TestAST:
|
||||||
|
def test_literals(self):
|
||||||
|
tcl = JSTestCollection(os.path.join(BASE_PATH, "literals"))
|
||||||
|
assert tcl.run_all()
|
||||||
|
|
||||||
|
def test_statements(self):
|
||||||
|
tcs = JSTestCollection(os.path.join(BASE_PATH, "statements"))
|
||||||
|
assert tcs.run_all()
|
||||||
|
|
||||||
|
# @pytest.mark.skip(reason="Not yet implemented")
|
||||||
|
def test_expressions(self):
|
||||||
|
tce = JSTestCollection(os.path.join(BASE_PATH, "expressions"))
|
||||||
|
assert tce.run_all()
|
||||||
|
|
||||||
|
# @pytest.mark.xfail(reason="Not yet implemented features.")
|
||||||
|
def test_todos(self):
|
||||||
|
tcb = JSTestCollection(os.path.join(BASE_PATH, "todos"))
|
||||||
|
assert tcb.run_all(must_fail=True)
|
||||||
|
|
||||||
|
@pytest.mark.xfail(reason="Bugs.")
|
||||||
|
def test_bugs(self):
|
||||||
|
tcb = JSTestCollection(os.path.join(BASE_PATH, "bugs"))
|
||||||
|
assert tcb.run_all(must_fail=True)
|
|
@ -0,0 +1 @@
|
||||||
|
if (1) 0;
|
|
@ -0,0 +1,4 @@
|
||||||
|
for (let a = 0; a < b; ++a) c++;
|
||||||
|
for (;b > c; --b) {a = b/c}
|
||||||
|
|
||||||
|
for (;;) {}
|
|
@ -0,0 +1,4 @@
|
||||||
|
// Object literals?
|
||||||
|
let a = {a: 4, b: 4};
|
||||||
|
let k = {"a444": 444, 'b555': 555};
|
||||||
|
|
9
tox.ini
9
tox.ini
|
@ -1,10 +1,11 @@
|
||||||
[pytest]
|
[tox]
|
||||||
envlist = py37,py38
|
skipsdist = true
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
changedir = tests
|
#changedir = tests
|
||||||
deps =
|
deps =
|
||||||
|
-rrequirements.txt
|
||||||
pytest
|
pytest
|
||||||
commands =
|
commands =
|
||||||
# Any commands go here
|
# Any commands go here
|
||||||
pytest --basetemp="{envtmpdir}" {posargs}
|
python -m pytest -s --basetemp="{envtmpdir}" {posargs}
|
Loading…
Reference in New Issue