| 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 |