OLD | NEW |
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 import 'dart:async'; | 5 import 'dart:async'; |
6 import 'package:expect/expect.dart'; | 6 import 'package:expect/expect.dart'; |
7 import 'package:async_helper/async_helper.dart'; | 7 import 'package:async_helper/async_helper.dart'; |
8 import 'mock_compiler.dart'; | 8 import 'mock_compiler.dart'; |
9 import 'package:compiler/src/js/js.dart' as jsAst; | 9 import 'package:compiler/src/js/js.dart' as jsAst; |
10 import 'package:compiler/src/js/js.dart' show js; | 10 import 'package:compiler/src/js/js.dart' show js; |
11 | 11 |
12 Future testExpression(String expression, [String expect = ""]) { | 12 Future testExpression(String expression, [String expect = ""]) { |
13 jsAst.Node node = js(expression); | 13 jsAst.Node node = js(expression); |
14 return MockCompiler.create((MockCompiler compiler) { | 14 return MockCompiler.create((MockCompiler compiler) { |
15 String jsText = | 15 String jsText = |
16 jsAst.prettyPrint(node, | 16 jsAst.prettyPrint(node, compiler, allowVariableMinification: false); |
17 compiler, | |
18 allowVariableMinification: false); | |
19 if (expect == "") { | 17 if (expect == "") { |
20 Expect.stringEquals(expression, jsText); | 18 Expect.stringEquals(expression, jsText); |
21 } else { | 19 } else { |
22 Expect.stringEquals(expect, jsText); | 20 Expect.stringEquals(expect, jsText); |
23 } | 21 } |
24 }); | 22 }); |
25 } | 23 } |
26 | 24 |
27 Future testError(String expression, [String expect = ""]) { | 25 Future testError(String expression, [String expect = ""]) { |
28 return new Future.sync(() { | 26 return new Future.sync(() { |
29 bool doCheck(exception) { | 27 bool doCheck(exception) { |
30 Expect.isTrue(exception.toString().contains(expect)); | 28 Expect.isTrue(exception.toString().contains(expect)); |
31 return true; | 29 return true; |
32 } | 30 } |
| 31 |
33 Expect.throws(() => js(expression), doCheck); | 32 Expect.throws(() => js(expression), doCheck); |
34 }); | 33 }); |
35 } | 34 } |
36 | 35 |
37 void main() { | 36 void main() { |
38 asyncTest(() => Future.wait([ | 37 asyncTest(() => Future.wait([ |
39 // Asterisk indicates deviations from real JS. | 38 // Asterisk indicates deviations from real JS. |
40 // Simple var test. | 39 // Simple var test. |
41 testExpression('var a = ""'), | 40 testExpression('var a = ""'), |
42 // Parse and print will normalize whitespace. | 41 // Parse and print will normalize whitespace. |
43 testExpression(' var a = "" ', 'var a = ""'), | 42 testExpression(' var a = "" ', 'var a = ""'), |
44 // Operator precedence. | 43 // Operator precedence. |
45 testExpression('x = a + b * c'), | 44 testExpression('x = a + b * c'), |
46 testExpression('x = a * b + c'), | 45 testExpression('x = a * b + c'), |
47 testExpression('x = a + b * c + d'), | 46 testExpression('x = a + b * c + d'), |
48 testExpression('x = a * b + c * d'), | 47 testExpression('x = a * b + c * d'), |
49 testExpression('remaining = (remaining / 88) | 0', | 48 testExpression('remaining = (remaining / 88) | 0', |
50 'remaining = remaining / 88 | 0'), | 49 'remaining = remaining / 88 | 0'), |
51 // Binary operators have left associativity. | 50 // Binary operators have left associativity. |
52 testExpression('x = a + b + c'), | 51 testExpression('x = a + b + c'), |
53 // We can cope with relational operators and non-relational. | 52 // We can cope with relational operators and non-relational. |
54 testExpression('a + b == c + d'), | 53 testExpression('a + b == c + d'), |
55 // The prettyprinter will insert braces where needed. | 54 // The prettyprinter will insert braces where needed. |
56 testExpression('a + (b == c) + d'), | 55 testExpression('a + (b == c) + d'), |
57 // We can handle () for calls. | 56 // We can handle () for calls. |
58 testExpression('foo(bar)'), | 57 testExpression('foo(bar)'), |
59 testExpression('foo(bar, baz)'), | 58 testExpression('foo(bar, baz)'), |
60 // Chained calls without parentheses. | 59 // Chained calls without parentheses. |
61 testExpression('foo(bar)(baz)'), | 60 testExpression('foo(bar)(baz)'), |
62 // Chaned calls with and without new. | 61 // Chaned calls with and without new. |
63 testExpression('new foo(bar)(baz)'), | 62 testExpression('new foo(bar)(baz)'), |
64 testExpression('new foo.bar(bar)(baz)'), | 63 testExpression('new foo.bar(bar)(baz)'), |
65 testExpression('foo.bar(bar)(baz)'), | 64 testExpression('foo.bar(bar)(baz)'), |
66 testExpression('constructor = new Function(str)()'), | 65 testExpression('constructor = new Function(str)()'), |
67 // The prettyprinter understands chained calls without extra parentheses. | 66 // The prettyprinter understands chained calls without extra parentheses
. |
68 testExpression('(foo(bar))(baz)', 'foo(bar)(baz)'), | 67 testExpression('(foo(bar))(baz)', 'foo(bar)(baz)'), |
69 // Chains of dotting and calls. | 68 // Chains of dotting and calls. |
70 testExpression('foo.bar(baz)'), | 69 testExpression('foo.bar(baz)'), |
71 // String literal. | 70 // String literal. |
72 testExpression('var x = "fisk"'), | 71 testExpression('var x = "fisk"'), |
73 // String literal with \n. | 72 // String literal with \n. |
74 testExpression(r'var x = "\n"'), | 73 testExpression(r'var x = "\n"'), |
75 // String literal with escaped quote. | 74 // String literal with escaped quote. |
76 testExpression(r'var x = "\""'), | 75 testExpression(r'var x = "\""'), |
77 // *No clever escapes. | 76 // *No clever escapes. |
78 testError(r'var x = "\x42"', 'escapes are not allowed in literals'), | 77 testError(r'var x = "\x42"', 'escapes are not allowed in literals'), |
79 // Operator new. | 78 // Operator new. |
80 testExpression('new Foo()'), | 79 testExpression('new Foo()'), |
81 // New with dotted access. | 80 // New with dotted access. |
82 testExpression('new Frobinator.frobinate()'), | 81 testExpression('new Frobinator.frobinate()'), |
83 testExpression('new Frobinator().frobinate()'), | 82 testExpression('new Frobinator().frobinate()'), |
84 // The prettyprinter strips some superfluous parentheses. | 83 // The prettyprinter strips some superfluous parentheses. |
85 testExpression('(new Frobinator()).frobinate()', | 84 testExpression( |
86 'new Frobinator().frobinate()'), | 85 '(new Frobinator()).frobinate()', 'new Frobinator().frobinate()'), |
87 // *We want a bracket on 'new'. | 86 // *We want a bracket on 'new'. |
88 testError('new Foo', 'Parentheses are required'), | 87 testError('new Foo', 'Parentheses are required'), |
89 testError('(new Foo)', 'Parentheses are required'), | 88 testError('(new Foo)', 'Parentheses are required'), |
90 // Bogus operators. | 89 // Bogus operators. |
91 testError('a +++ b', 'Unknown operator'), | 90 testError('a +++ b', 'Unknown operator'), |
92 // This isn't perl. There are rules. | 91 // This isn't perl. There are rules. |
93 testError('a <=> b', 'Unknown operator'), | 92 testError('a <=> b', 'Unknown operator'), |
94 // Typeof. | 93 // Typeof. |
95 testExpression('typeof foo == "number"'), | 94 testExpression('typeof foo == "number"'), |
96 // Strange relation. | 95 // Strange relation. |
97 testExpression('a < b < c'), | 96 testExpression('a < b < c'), |
98 // Chained var. | 97 // Chained var. |
99 testExpression('var x = 0, y = 1.2, z = 42'), | 98 testExpression('var x = 0, y = 1.2, z = 42'), |
100 // Empty object literal. | 99 // Empty object literal. |
101 testExpression('foo({}, {})'), | 100 testExpression('foo({}, {})'), |
102 // *Can't handle non-empty object literals | 101 // *Can't handle non-empty object literals |
103 testExpression('foo({meaning: 42})'), | 102 testExpression('foo({meaning: 42})'), |
104 // Literals. | 103 // Literals. |
105 testExpression('x(false, true, null)'), | 104 testExpression('x(false, true, null)'), |
106 // *We should really throw here. | 105 // *We should really throw here. |
107 testExpression('var false = 42'), | 106 testExpression('var false = 42'), |
108 testExpression('var new = 42'), | 107 testExpression('var new = 42'), |
109 // Bad keyword. | 108 // Bad keyword. |
110 testError('var typeof = 42', "Expected ALPHA"), | 109 testError('var typeof = 42', "Expected ALPHA"), |
111 // Malformed decimal/hex. | 110 // Malformed decimal/hex. |
112 testError('var x = 1.1.1', "Unparseable number"), | 111 testError('var x = 1.1.1', "Unparseable number"), |
113 testError('var x = 0xabcdefga', "Unparseable number"), | 112 testError('var x = 0xabcdefga', "Unparseable number"), |
114 testError('var x = 0xabcdef\$a', "Unparseable number"), | 113 testError('var x = 0xabcdef\$a', "Unparseable number"), |
115 testError('var x = 0x ', "Unparseable number"), | 114 testError('var x = 0x ', "Unparseable number"), |
116 // Good hex constants. | 115 // Good hex constants. |
117 testExpression('var x = 0xff'), | 116 testExpression('var x = 0xff'), |
118 testExpression('var x = 0xff + 0xff'), | 117 testExpression('var x = 0xff + 0xff'), |
119 testExpression('var x = 0xaF + 0x0123456789abcdefABCDEF'), | 118 testExpression('var x = 0xaF + 0x0123456789abcdefABCDEF'), |
120 // All sorts of keywords are allowed as property names in ES5. | 119 // All sorts of keywords are allowed as property names in ES5. |
121 testExpression('x.new = 0'), | 120 testExpression('x.new = 0'), |
122 testExpression('x.delete = 0'), | 121 testExpression('x.delete = 0'), |
123 testExpression('x.for = 0'), | 122 testExpression('x.for = 0'), |
124 testExpression('x.instanceof = 0'), | 123 testExpression('x.instanceof = 0'), |
125 testExpression('x.in = 0'), | 124 testExpression('x.in = 0'), |
126 testExpression('x.void = 0'), | 125 testExpression('x.void = 0'), |
127 testExpression('x.continue = 0'), | 126 testExpression('x.continue = 0'), |
128 // More unary. | 127 // More unary. |
129 testExpression('x = !x'), | 128 testExpression('x = !x'), |
130 testExpression('!x == false'), | 129 testExpression('!x == false'), |
131 testExpression('var foo = void 0'), | 130 testExpression('var foo = void 0'), |
132 testExpression('delete foo.bar'), | 131 testExpression('delete foo.bar'), |
133 testExpression('delete foo'), | 132 testExpression('delete foo'), |
134 testExpression('x in y'), | 133 testExpression('x in y'), |
135 testExpression('x instanceof y'), | 134 testExpression('x instanceof y'), |
136 testExpression('a * b in c * d'), | 135 testExpression('a * b in c * d'), |
137 testExpression('a * b instanceof c * d'), | 136 testExpression('a * b instanceof c * d'), |
138 testError('x typeof y', 'Unparsed junk'), | 137 testError('x typeof y', 'Unparsed junk'), |
139 testExpression('x &= ~mask'), | 138 testExpression('x &= ~mask'), |
140 // Await is parsed as an unary prefix operator. | 139 // Await is parsed as an unary prefix operator. |
141 testExpression('var foo = await 0'), | 140 testExpression('var foo = await 0'), |
142 testExpression('await x++'), | 141 testExpression('await x++'), |
143 testExpression('void (await (x++))', 'void await x++'), | 142 testExpression('void (await (x++))', 'void await x++'), |
144 testExpression('void (await x)++'), | 143 testExpression('void (await x)++'), |
145 testExpression('++(await x)++'), | 144 testExpression('++(await x)++'), |
146 // Adjacent tokens. | 145 // Adjacent tokens. |
147 testExpression('foo[x[bar]]'), | 146 testExpression('foo[x[bar]]'), |
148 testExpression('foo[[bar]]'), | 147 testExpression('foo[[bar]]'), |
149 // Prefix ++ etc. | 148 // Prefix ++ etc. |
150 testExpression("++x"), | 149 testExpression("++x"), |
151 testExpression("++foo.bar"), | 150 testExpression("++foo.bar"), |
152 testExpression("+x"), | 151 testExpression("+x"), |
153 testExpression("+foo.bar"), | 152 testExpression("+foo.bar"), |
154 testExpression("-x"), | 153 testExpression("-x"), |
155 testExpression("-foo.bar"), | 154 testExpression("-foo.bar"), |
156 testExpression("--x"), | 155 testExpression("--x"), |
157 testExpression("--foo.bar"), | 156 testExpression("--foo.bar"), |
158 // Postfix ++ etc. | 157 // Postfix ++ etc. |
159 testExpression("x++"), | 158 testExpression("x++"), |
160 testExpression("foo.bar++"), | 159 testExpression("foo.bar++"), |
161 testExpression("x--"), | 160 testExpression("x--"), |
162 testExpression("foo.bar--"), | 161 testExpression("foo.bar--"), |
163 // Both! | 162 // Both! |
164 testExpression("++x++"), | 163 testExpression("++x++"), |
165 testExpression("++foo.bar++"), | 164 testExpression("++foo.bar++"), |
166 testExpression("--x--"), | 165 testExpression("--x--"), |
167 testExpression("--foo.bar--"), | 166 testExpression("--foo.bar--"), |
168 // *We can't handle stacked unary operators (apart from !). | 167 // *We can't handle stacked unary operators (apart from !). |
169 testError("x++ ++"), | 168 testError("x++ ++"), |
170 testError("++ typeof x"), | 169 testError("++ typeof x"), |
171 testExpression(r"var $supportsProtoName = !!{}.__proto__"), | 170 testExpression(r"var $supportsProtoName = !!{}.__proto__"), |
172 // ++ used as a binary operator. | 171 // ++ used as a binary operator. |
173 testError("x++ ++ 42"), | 172 testError("x++ ++ 42"), |
174 // Shift operators. | 173 // Shift operators. |
175 testExpression("x << 5"), | 174 testExpression("x << 5"), |
176 testExpression("x << y + 1"), | 175 testExpression("x << y + 1"), |
177 testExpression("x <<= y + 1"), | 176 testExpression("x <<= y + 1"), |
178 // Array initializers. | 177 // Array initializers. |
179 testExpression("x = ['foo', 'bar', x[4]]"), | 178 testExpression("x = ['foo', 'bar', x[4]]"), |
180 testExpression("[]"), | 179 testExpression("[]"), |
181 testError("[42 42]"), | 180 testError("[42 42]"), |
182 testExpression('beebop([1, 2, 3])'), | 181 testExpression('beebop([1, 2, 3])'), |
183 // Array literals with holes in them. | 182 // Array literals with holes in them. |
184 testExpression("[1,, 2]"), | 183 testExpression("[1,, 2]"), |
185 testExpression("[1,]", "[1]"), | 184 testExpression("[1,]", "[1]"), |
186 testExpression("[1,,]", "[1,,]"), | 185 testExpression("[1,,]", "[1,,]"), |
187 testExpression("[,]"), | 186 testExpression("[,]"), |
188 testExpression("[,,]"), | 187 testExpression("[,,]"), |
189 testExpression("[, 42]"), | 188 testExpression("[, 42]"), |
190 // Ternary operator. | 189 // Ternary operator. |
191 testExpression("x = a ? b : c"), | 190 testExpression("x = a ? b : c"), |
192 testExpression("y = a == null ? b : a"), | 191 testExpression("y = a == null ? b : a"), |
193 testExpression("y = a == null ? b + c : a + c"), | 192 testExpression("y = a == null ? b + c : a + c"), |
194 testExpression("foo = a ? b : c ? d : e"), | 193 testExpression("foo = a ? b : c ? d : e"), |
195 testExpression("foo = a ? b ? c : d : e"), | 194 testExpression("foo = a ? b ? c : d : e"), |
196 testExpression("foo = (a = v) ? b = w : c = x ? d = y : e = z"), | 195 testExpression("foo = (a = v) ? b = w : c = x ? d = y : e = z"), |
197 testExpression("foo = (a = v) ? b = w ? c = x : d = y : e = z"), | 196 testExpression("foo = (a = v) ? b = w ? c = x : d = y : e = z"), |
198 // Stacked assignment. | 197 // Stacked assignment. |
199 testExpression("a = b = c"), | 198 testExpression("a = b = c"), |
200 testExpression("var a = b = c"), | 199 testExpression("var a = b = c"), |
201 ])); | 200 ])); |
202 } | 201 } |
OLD | NEW |