1 from unittest
import TestCase
3 from io
import StringIO
4 from unittest
.mock
import patch
5 from math
import inf
, ldexp
, copysign
6 from itertools
import product
, combinations
, chain
9 def test_identifier_escaped(self
):
11 (r
'ab\u0063de', 'abcde'),
12 (r
'\u005Cu123\u0034', '\\u1234'),
14 with self
.subTest(code
):
15 self
.assert_statement(code
, ('identifier', name
))
16 for code
in ('ab\\y0033z', 'ab\\', '\\u123\\u0034'):
17 with self
.subTest(code
):
18 parser
= javascript
.parse(StringIO(code
))
19 self
.assertRaises(Exception, next
, parser
, None)
21 def test_token_buffering(self
):
22 with patch
.object(javascript
.Parser
, 'BUFSIZE', 10):
23 self
.assert_statement('abcdefg >>>= x',
24 ('>>>=', ('identifier', 'abcdefg'), ('identifier', 'x')),
27 def test_precedence_non_assign(self
):
28 pairs
= combinations(self
.DECREASING_PREC_NON_ASSIGN
, 2)
29 for [higher
, lower
] in pairs
:
30 for [higher
, lower
] in product(higher
, lower
):
31 with self
.subTest(f
'{higher} vs {lower}'):
32 self
.assert_statement(f
'A {lower} B {higher} C',
33 (lower
, self
.A
, (higher
, self
.B
, self
.C
)))
34 self
.assert_statement(f
'A {higher} B {lower} C',
35 (lower
, (higher
, self
.A
, self
.B
), self
.C
))
37 def test_assign_precedence(self
):
38 for assign
in self
.ASSIGNMENTS
:
39 for op
in chain
.from_iterable(self
.ASSIGN_RHS_ONLY
):
40 with self
.subTest(f
'{assign} {op}'):
41 self
.assert_statement(f
'A {assign} B {op} C',
42 (assign
, self
.A
, (op
, self
.B
, self
.C
)))
43 self
.assert_statement(f
'A . B {assign} C',
44 (assign
, ('property', self
.A
, 'B'), self
.C
))
45 self
.assert_statement(f
'A, B {assign} C',
46 (',', self
.A
, (assign
, self
.B
, self
.C
)))
47 self
.assert_statement(f
'A {assign} B, C',
48 (',', (assign
, self
.A
, self
.B
), self
.C
))
50 def test_left_associativity(self
):
51 for set in self
.DECREASING_PREC_NON_ASSIGN
:
52 for [lhs
, rhs
] in product(set, repeat
=2):
53 with self
.subTest(f
'{lhs} {rhs}'):
54 self
.assert_statement(f
'A {lhs} B {rhs} C',
55 (rhs
, (lhs
, self
.A
, self
.B
), self
.C
))
57 def test_right_associativity(self
):
58 for [lhs
, rhs
] in product(self
.ASSIGNMENTS
, repeat
=2):
59 with self
.subTest(f
'{lhs} {rhs}'):
60 self
.assert_statement(f
'A {lhs} B {rhs} C',
61 (lhs
, self
.A
, (rhs
, self
.B
, self
.C
)))
63 def test_conditional_precedence(self
):
64 for higher
in self
.ASSIGN_RHS_ONLY
:
66 with self
.subTest(higher
):
67 self
.assert_statement(f
'1 {higher} 2 ? 3 : 4',
68 ('?', (higher
, 1, 2), 3, 4))
69 self
.assert_statement(f
'1 ? 2 {higher} 3 : 4',
70 ('?', 1, (higher
, 2, 3), 4))
71 self
.assert_statement(f
'1 ? 2 : 3 {higher} 4',
72 ('?', 1, 2, (higher
, 3, 4)))
74 self
.assert_statement('1, 2 ? 3 : 4', (',', 1, ('?', 2, 3, 4)))
75 self
.assert_statement('1 ? 2 : 3, 4', (',', ('?', 1, 2, 3), 4))
77 for assign
in self
.ASSIGNMENTS
:
78 with self
.subTest(assign
):
79 self
.assert_statement(f
'A {assign} 1 ? 2 : 3',
80 (assign
, self
.A
, ('?', 1, 2, 3)))
81 self
.assert_statement(f
'1 ? A {assign} 2 : 3',
82 ('?', 1, (assign
, self
.A
, 2), 3))
83 self
.assert_statement(f
'1 ? 2 : A {assign} 3',
84 ('?', 1, 2, (assign
, self
.A
, 3)))
86 self
.assert_statement('1 ? 2 : 3 ? 4 : 5',
87 ('?', 1, 2, ('?', 3, 4, 5)))
88 self
.assert_statement('1 ? 2 ? 3 : 4 : 5',
89 ('?', 1, ('?', 2, 3, 4), 5))
92 ('*', '/', '%'), ('+', '-'),
94 ('<', '>', '<=', '>=', 'instanceof', 'in'),
95 ('==', '!=', '===', '!=='),
96 ('&',), ('^',), ('|',), ('&&',), ('||',),
98 DECREASING_PREC_NON_ASSIGN
= ASSIGN_RHS_ONLY
+ ((',',),)
101 = ('', '*', '/', '%', '+', '-', '<<', '>>', '>>>', '&', '^', '|')
102 ASSIGNMENTS
= tuple(f
'{op}=' for op
in ASSIGNMENTS
)
104 A
= ('identifier', 'A')
105 B
= ('identifier', 'B')
106 C
= ('identifier', 'C')
108 def test_comment_greed(self
):
109 self
.assert_statement('/* Comment */ 83 /* Comment */', 83)
111 def test_rounding(self
):
112 for [code
, rounded
] in (
113 ('0.24703''28229''20623''27208e-323', 0),
114 ('0.24703''28229''20623''27209e-323', ldexp(2**-52, -1022)),
115 ('24703''28229''20623''27208e-343', 0),
116 ('24703''28229''20623''27209e-343', ldexp(2**-52, -1022)),
117 ('0.17976''93134''86231''58079e+309', ldexp(1 - 2**-53, +1024)),
118 ('0.17976''93134''86231''58080e+309', inf
),
119 ('17976''93134''86231''58079e+289', ldexp(1 - 2**-53, +1024)),
120 ('17976''93134''86231''58080e+289', inf
),
121 (f
'{2**52 + 0}.5', 2**52),
122 (f
'{2**52 + 1}.5', 2**52 + 2),
123 (hex( 2**1024 - 2**(1024 - 53) + (0b10 << (1024 - 55)) ), inf
),
124 (hex( 2**1024 - 2**(1024 - 53) + (0b01 << (1024 - 55)) ),
125 ldexp(1 - 2**-53, +1024)),
126 (hex(2**53 + 0b01), 2**53),
127 (hex(2**53 + 0b11), 2**53 + 0b100),
129 with self
.subTest(code
):
130 [[labels
, code
]] = javascript
.parse(StringIO(code
))
131 self
.assertEqual(code
, rounded
)
132 self
.assertEqual(copysign(1, code
), copysign(1, rounded
))
134 def test_div_vs_regex(self
):
135 regex
= ('regex', 'a', 'g')
137 return ('/', ('/', x
, ('identifier', 'a')), ('identifier', 'g'))
141 ('x /a/g', div( ('identifier', 'x') )),
142 ('{ /a/g }', ('block', (
143 (frozenset(), regex
),
145 ('return /a/g', ('return', regex
)),
146 ('[] /a/g', div([])),
147 ('++ /a/g', ('prefix ++', regex
)),
148 ('\n ++ /a/g', ('prefix ++', regex
)),
149 ('x ++ /a/g', div( ('postfix ++', ('identifier', 'x')) )),
150 ('++ ++ /a/g', ('prefix ++', ('prefix ++', regex
))),
152 ('( { } /a/g )', div(('object', []))),
153 ('( x ) /a/g', div( ('identifier', 'x') )),
155 ('if', ('identifier', 'x'), (frozenset(), regex
),
156 (frozenset(), ('block', ())))),
157 ('try {} catch (x) {} /a/g', regex
),
158 ('try {} finally {} /a/g', regex
),
160 with self
.subTest(code
):
161 for stmt
in javascript
.parse(StringIO(code
)):
163 self
.assertEqual(stmt
, (frozenset(), ast
))
165 def test_array_literal(self
):
166 ELISION
= ('undefined',)
167 self
.assert_statement('[]', [])
168 self
.assert_statement('[, ]', [ELISION
])
169 self
.assert_statement('[, , ]', [ELISION
, ELISION
])
170 self
.assert_statement('[81]', [81])
171 self
.assert_statement('[81, ]', [81])
172 self
.assert_statement('[81, , ]', [81, ELISION
])
173 self
.assert_statement('[81, , , ]', [81, ELISION
, ELISION
])
174 self
.assert_statement('[81, 82]', [81, 82])
175 self
.assert_statement('[81, , 82]', [81, ELISION
, 82])
176 self
.assert_statement('[81, , , 82]', [81, ELISION
, ELISION
, 82])
178 def test_object_literal(self
):
179 self
.assert_statement('({})', ('object', []))
180 self
.assert_statement('({A: 81})', ('object', [('A', 81)]))
181 self
.assert_statement('({A: 81, B: 82})',
182 ('object', [('A', 81), ('B', 82)]))
183 self
.assert_statement('({"A": 81})', ('object', [('A', 81)]))
184 self
.assert_statement('({81: 82})', ('object', [(81, 82)]))
186 def assert_statement(self
, code
, expected
):
187 [code
] = javascript
.parse(StringIO(code
))
188 self
.assertEqual(code
, (frozenset(), expected
))