20faaa5d94
Change-Id: Ib18f554c1076f27a3f7c0df5a36410da41a1f467 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/148784 Reviewed-by: Paul Berry <paulberry@google.com> Reviewed-by: Sigmund Cherem <sigmund@google.com>
194 lines
6.7 KiB
Dart
194 lines
6.7 KiB
Dart
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
// @dart = 2.7
|
|
|
|
import 'package:expect/expect.dart';
|
|
import 'package:compiler/src/js/js.dart' as jsAst;
|
|
import 'package:compiler/src/js/js.dart' show js;
|
|
|
|
testExpression(String expression, [String expect = ""]) {
|
|
jsAst.Node node = js(expression);
|
|
String jsText = jsAst.prettyPrint(node, allowVariableMinification: false);
|
|
if (expect == "") {
|
|
Expect.stringEquals(expression, jsText);
|
|
} else {
|
|
Expect.stringEquals(expect, jsText);
|
|
}
|
|
}
|
|
|
|
testError(String expression, [String expect = ""]) {
|
|
bool doCheck(exception) {
|
|
Expect.isTrue(exception.toString().contains(expect));
|
|
return true;
|
|
}
|
|
|
|
Expect.throws(() => js(expression), doCheck);
|
|
}
|
|
|
|
void main() {
|
|
// Asterisk indicates deviations from real JS.
|
|
// Simple var test.
|
|
testExpression('var a = ""');
|
|
// Parse and print will normalize whitespace.
|
|
testExpression(' var a = "" ', 'var a = ""');
|
|
// Operator precedence.
|
|
testExpression('x = a + b * c');
|
|
testExpression('x = a * b + c');
|
|
testExpression('x = a + b * c + d');
|
|
testExpression('x = a * b + c * d');
|
|
testExpression(
|
|
'remaining = (remaining / 88) | 0', 'remaining = remaining / 88 | 0');
|
|
// Binary operators have left associativity.
|
|
testExpression('x = a + b + c');
|
|
// We can cope with relational operators and non-relational.
|
|
testExpression('a + b == c + d');
|
|
// The prettyprinter will insert braces where needed.
|
|
testExpression('a + (b == c) + d');
|
|
// We can handle () for calls.
|
|
testExpression('foo(bar)');
|
|
testExpression('foo(bar, baz)');
|
|
// Chained calls without parentheses.
|
|
testExpression('foo(bar)(baz)');
|
|
// Chained calls with and without new.
|
|
testExpression('new foo(bar)(baz)');
|
|
testExpression('new foo.bar(bar)(baz)');
|
|
testExpression('foo.bar(bar)(baz)');
|
|
testExpression('constructor = new Function(str)()');
|
|
// The prettyprinter understands chained calls without extra parentheses.
|
|
testExpression('(foo(bar))(baz)', 'foo(bar)(baz)');
|
|
// Chains of dotting and calls.
|
|
testExpression('foo.bar(baz)');
|
|
// String literal.
|
|
testExpression('var x = "fisk"');
|
|
// String literal with \n.
|
|
testExpression(r'var x = "\n"');
|
|
// String literal with escaped quote.
|
|
testExpression(r'var x = "\""');
|
|
// *No clever escapes.
|
|
testError(r'var x = "\x42"', 'escapes are not allowed in literals');
|
|
// Operator new.
|
|
testExpression('new Foo()');
|
|
// New with dotted access.
|
|
testExpression('new Frobinator.frobinate()');
|
|
testExpression('new Frobinator().frobinate()');
|
|
// The prettyprinter strips some superfluous parentheses.
|
|
testExpression(
|
|
'(new Frobinator()).frobinate()', 'new Frobinator().frobinate()');
|
|
// *We want a bracket on 'new'.
|
|
testError('new Foo', 'Parentheses are required');
|
|
testError('(new Foo)', 'Parentheses are required');
|
|
// Bogus operators.
|
|
testError('a +++ b', 'Unknown operator');
|
|
// This isn't perl. There are rules.
|
|
testError('a <=> b', 'Unknown operator');
|
|
// Typeof.
|
|
testExpression('typeof foo == "number"');
|
|
// Strange relation.
|
|
testExpression('a < b < c');
|
|
// Chained var.
|
|
testExpression('var x = 0, y = 1.2, z = 42');
|
|
// Empty object literal.
|
|
testExpression('foo({}, {})');
|
|
// *Can't handle non-empty object literals
|
|
testExpression('foo({meaning: 42})');
|
|
// Literals.
|
|
testExpression('x(false, true, null)');
|
|
// *We should really throw here.
|
|
testExpression('var false = 42');
|
|
testExpression('var new = 42');
|
|
// Bad keyword.
|
|
testError('var typeof = 42', "Expected ALPHA");
|
|
// Malformed decimal/hex.
|
|
testError('var x = 1.1.1', "Unparseable number");
|
|
testError('var x = 0xabcdefga', "Unparseable number");
|
|
testError('var x = 0xabcdef\$a', "Unparseable number");
|
|
testError('var x = 0x ', "Unparseable number");
|
|
// Good hex constants.
|
|
testExpression('var x = 0xff');
|
|
testExpression('var x = 0xff + 0xff');
|
|
testExpression('var x = 0xaF + 0x0123456789abcdefA');
|
|
// All sorts of keywords are allowed as property names in ES5.
|
|
testExpression('x.new = 0');
|
|
testExpression('x.delete = 0');
|
|
testExpression('x.for = 0');
|
|
testExpression('x.instanceof = 0');
|
|
testExpression('x.in = 0');
|
|
testExpression('x.void = 0');
|
|
testExpression('x.continue = 0');
|
|
// More unary.
|
|
testExpression('x = !x');
|
|
testExpression('!x == false');
|
|
testExpression('var foo = void 0');
|
|
testExpression('delete foo.bar');
|
|
testExpression('delete foo');
|
|
testExpression('x in y');
|
|
testExpression('x instanceof y');
|
|
testExpression('a * b in c * d');
|
|
testExpression('a * b instanceof c * d');
|
|
testError('x typeof y', 'Unparsed junk');
|
|
testExpression('x &= ~mask');
|
|
// Await is parsed as an unary prefix operator.
|
|
testExpression('var foo = await 0');
|
|
testExpression('await x++');
|
|
testExpression('void (await (x++))', 'void await x++');
|
|
testExpression('void (await x)++');
|
|
testExpression('++(await x)++');
|
|
// Adjacent tokens.
|
|
testExpression('foo[x[bar]]');
|
|
testExpression('foo[[bar]]');
|
|
// Prefix ++ etc.
|
|
testExpression("++x");
|
|
testExpression("++foo.bar");
|
|
testExpression("+x");
|
|
testExpression("+foo.bar");
|
|
testExpression("-x");
|
|
testExpression("-foo.bar");
|
|
testExpression("--x");
|
|
testExpression("--foo.bar");
|
|
// Postfix ++ etc.
|
|
testExpression("x++");
|
|
testExpression("foo.bar++");
|
|
testExpression("x--");
|
|
testExpression("foo.bar--");
|
|
// Both!
|
|
testExpression("++x++");
|
|
testExpression("++foo.bar++");
|
|
testExpression("--x--");
|
|
testExpression("--foo.bar--");
|
|
// *We can't handle stacked unary operators (apart from !).
|
|
testError("x++ ++");
|
|
testError("++ typeof x");
|
|
testExpression(r"var $supportsProtoName = !!{}.__proto__");
|
|
// ++ used as a binary operator.
|
|
testError("x++ ++ 42");
|
|
// Shift operators.
|
|
testExpression("x << 5");
|
|
testExpression("x << y + 1");
|
|
testExpression("x <<= y + 1");
|
|
// Array initializers.
|
|
testExpression("x = ['foo', 'bar', x[4]]");
|
|
testExpression("[]");
|
|
testError("[42 42]");
|
|
testExpression('beebop([1, 2, 3])');
|
|
// Array literals with holes in them.
|
|
testExpression("[1,, 2]");
|
|
testExpression("[1,]", "[1]");
|
|
testExpression("[1,,]", "[1,,]");
|
|
testExpression("[,]");
|
|
testExpression("[,,]");
|
|
testExpression("[, 42]");
|
|
// Ternary operator.
|
|
testExpression("x = a ? b : c");
|
|
testExpression("y = a == null ? b : a");
|
|
testExpression("y = a == null ? b + c : a + c");
|
|
testExpression("foo = a ? b : c ? d : e");
|
|
testExpression("foo = a ? b ? c : d : e");
|
|
testExpression("foo = (a = v) ? b = w : c = x ? d = y : e = z");
|
|
testExpression("foo = (a = v) ? b = w ? c = x : d = y : e = z");
|
|
// Stacked assignment.
|
|
testExpression("a = b = c");
|
|
testExpression("var a = b = c");
|
|
}
|