summaryrefslogtreecommitdiffstats
path: root/third_party/rust/jsparagus/tests/test_js.py
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/jsparagus/tests/test_js.py')
-rw-r--r--third_party/rust/jsparagus/tests/test_js.py207
1 files changed, 207 insertions, 0 deletions
diff --git a/third_party/rust/jsparagus/tests/test_js.py b/third_party/rust/jsparagus/tests/test_js.py
new file mode 100644
index 0000000000..571232f77a
--- /dev/null
+++ b/third_party/rust/jsparagus/tests/test_js.py
@@ -0,0 +1,207 @@
+""" Tests for the JS parser. """
+
+import unittest
+import jsparagus.lexer
+from js_parser.parser import parse_Script, JSParser
+from js_parser.lexer import JSLexer
+
+
+class ESTestCase(unittest.TestCase):
+ def parse(self, s):
+ if isinstance(s, list):
+ f = JSLexer(JSParser())
+ for chunk in s:
+ f.write(chunk)
+ return f.close()
+ else:
+ return parse_Script(s)
+
+ def assert_parses(self, s):
+ self.parse(s)
+
+ def assert_incomplete(self, s):
+ """Assert that s fails to parse with UnexpectedEndError.
+
+ (This should be the case if `s` is a prefix of a valid Script.)
+ """
+ self.assertRaises(jsparagus.lexer.UnexpectedEndError,
+ lambda: parse_Script(s))
+
+ def assert_syntax_error(self, s):
+ """Assert that s fails to parse."""
+ with self.assertRaises(jsparagus.lexer.SyntaxError):
+ parse_Script(s)
+
+ def assert_can_close_after(self, s):
+ parser = JSParser()
+ lexer = JSLexer(parser)
+ if isinstance(s, list):
+ for chunk in s:
+ lexer.write(chunk)
+ else:
+ lexer.write(s)
+ self.assertTrue(lexer.can_close())
+
+ # === Tests!
+
+ def test_asi_at_end(self):
+ self.assert_parses("3 + 4")
+ self.assert_syntax_error("3 4")
+ self.assert_incomplete("3 +")
+ self.assert_incomplete("{")
+ self.assert_incomplete("{;")
+
+ def test_asi_at_block_end(self):
+ self.assert_parses("{ doCrimes() }")
+ self.assert_parses("function f() { ok }")
+
+ def test_asi_after_line_terminator(self):
+ self.assert_parses('''\
+ switch (value) {
+ case 1: break
+ case 2: console.log('2');
+ }
+ ''')
+ self.assert_syntax_error(
+ "switch (value) { case 1: break case 2: console.log('2'); }")
+
+ def test_asi_after_no_line_terminator_here(self):
+ self.assert_parses('''\
+ function f() {
+ return
+ x;
+ }
+ ''')
+
+ def test_asi_suppressed(self):
+ # The specification says ASI does not happen in the production
+ # EmptyStatement : `;`.
+ self.assert_syntax_error("if (true)")
+ self.assert_syntax_error("{ for (;;) }")
+
+ # ASI does not happen in for(;;) loops.
+ self.assert_syntax_error("for ( \n ; ) {}")
+ self.assert_syntax_error("for ( ; \n ) {}")
+ self.assert_syntax_error("for ( \n \n ) {}")
+ self.assert_syntax_error("for (var i = 0 \n i < 9; i++) {}")
+ self.assert_syntax_error("for (var i = 0; i < 9 \n i++) {}")
+ self.assert_syntax_error("for (i = 0 \n i < 9; i++) {}")
+ self.assert_syntax_error("for (i = 0; i < 9 \n i++) {}")
+ self.assert_syntax_error("for (let i = 0 \n i < 9; i++) {}")
+
+ # ASI is suppressed in the production ClassElement[Yield, Await] : `;`
+ # to prevent an infinite loop of ASI. lol
+ self.assert_syntax_error("class Fail { \n +1; }")
+
+ def test_if_else(self):
+ self.assert_parses("if (x) f();")
+ self.assert_incomplete("if (x)")
+ self.assert_parses("if (x) f(); else g();")
+ self.assert_incomplete("if (x) f(); else")
+ self.assert_parses("if (x) if (y) g(); else h();")
+ self.assert_parses("if (x) if (y) g(); else h(); else j();")
+
+ def test_lexer_decimal(self):
+ self.assert_parses("0.")
+ self.assert_parses(".5")
+ self.assert_syntax_error(".")
+
+ def test_arrow(self):
+ self.assert_parses("x => x")
+ self.assert_parses("f = x => x;")
+ self.assert_parses("(x, y) => [y, x]")
+ self.assert_parses("f = (x, y) => {}")
+ self.assert_syntax_error("(x, y) => {x: x, y: y}")
+
+ def test_invalid_character(self):
+ self.assert_syntax_error("\0")
+ self.assert_syntax_error("—x;")
+ self.assert_syntax_error("const ONE_THIRD = 1 ÷ 3;")
+
+ def test_regexp(self):
+ self.assert_parses(r"/\w/")
+ self.assert_parses("/[A-Z]/")
+ self.assert_parses("/[//]/")
+ self.assert_parses("/a*a/")
+ self.assert_parses("/**//x*/")
+ self.assert_parses("{} /x/")
+ self.assert_parses("of / 2")
+
+ def test_incomplete_comments(self):
+ self.assert_syntax_error("/*")
+ self.assert_syntax_error("/* hello world")
+ self.assert_syntax_error("/* hello world *")
+ self.assert_parses(["/* hello\n", " world */"])
+ self.assert_parses(["// oawfeoiawj", "ioawefoawjie"])
+ self.assert_parses(["// oawfeoiawj", "ioawefoawjie\n ok();"])
+ self.assert_parses(["// oawfeoiawj", "ioawefoawjie", "jiowaeawojefiw"])
+ self.assert_parses(["// oawfeoiawj", "ioawefoawjie", "jiowaeawojefiw\n ok();"])
+
+ def test_awkward_chunks(self):
+ self.assert_parses(["let", "ter.head = 1;"])
+ self.assert_parses(["let", " x = 1;"])
+
+ # `list()` here explodes the string into a list of one-character strings.
+ self.assert_parses(list("function f() { ok(); }"))
+
+ self.assertEqual(
+ self.parse(["/xyzzy/", "g;"]),
+ ('script',
+ ('script_body',
+ ('statement_list_single',
+ ('expression_statement',
+ ('regexp_literal', '/xyzzy/g'))))))
+
+ self.assertEqual(
+ self.parse(['x/', '=2;']),
+ ('script',
+ ('script_body',
+ ('statement_list_single',
+ ('expression_statement',
+ ('compound_assignment_expr',
+ ('identifier_expr', ('identifier_reference', 'x')),
+ ('box_assign_op', ('div_assign_op', '/=')),
+ ('numeric_literal', '2')))))))
+
+ def test_can_close(self):
+ self.assert_can_close_after([])
+ self.assert_can_close_after("")
+ self.assert_can_close_after("2 + 2;\n")
+ self.assert_can_close_after("// seems ok\n")
+
+ def test_can_close_with_asi(self):
+ self.assert_can_close_after("2 + 2\n")
+
+ def test_conditional_keywords(self):
+ # property names
+ self.assert_parses("let obj = {if: 3, function: 4};")
+ self.assert_parses("assert(obj.if == 3);")
+
+ # method names
+ self.assert_parses("""
+ class C {
+ if() {}
+ function() {}
+ }
+ """)
+
+ self.assert_parses("var let = [new Date];") # let as identifier
+ self.assert_parses("let v = let;") # let as keyword, then identifier
+ # Next line would fail because the multitoken `let [` lookahead isn't implemented yet.
+ # self.assert_parses("let.length;") # `let .` -> ExpressionStatement
+ self.assert_syntax_error("let[0].getYear();") # `let [` -> LexicalDeclaration
+
+ self.assert_parses("""
+ var of = [1, 2, 3];
+ for (of of of) console.log(of); // logs 1, 2, 3
+ """)
+ self.assert_parses("var of, let, private, target;")
+ self.assert_parses("class X { get y() {} }")
+ self.assert_parses("async: { break async; }")
+ self.assert_parses("var get = { get get() {}, set get(v) {}, set: 3 };")
+ self.assert_parses("for (async of => {};;) {}")
+ # self.assert_parses("for (async of []) {}") # would fail
+
+
+if __name__ == '__main__':
+ unittest.main()