c878108cc8
All non-pubspec changes generated by `dart format pkg/compiler`. Change-Id: Iadaa70974816d96ccb47813fe72d5a2bb83d6bda Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/400181 Reviewed-by: Nate Biggs <natebiggs@google.com> Commit-Queue: Mayank Patke <fishythefish@google.com>
248 lines
8.6 KiB
Dart
248 lines
8.6 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.
|
|
|
|
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) {
|
|
final exceptionText = '$exception';
|
|
Expect.isTrue(
|
|
exceptionText.contains(expect),
|
|
'Missing "$expect" in "$exceptionText"',
|
|
);
|
|
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 = "\""''', r"""var x = '"'""");
|
|
// *No clever escapes.
|
|
testError(r'var x = "\x42"', 'Hex escapes not supported');
|
|
// 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 _Category.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");
|
|
|
|
// Arrow functions.
|
|
testExpression("(x) => x", "x => x");
|
|
testExpression("(x) => {\n return x;\n}", "x => {\n return x;\n}");
|
|
testExpression("(x, y) => {\n return x + y;\n}");
|
|
testExpression("(x, y) => x + y");
|
|
testExpression("() => 42");
|
|
testExpression('() => ({foo: "bar"})');
|
|
testExpression("() => {}", """
|
|
() => {
|
|
}""");
|
|
// Arrow function invocation.
|
|
testExpression("(() => 1)()");
|
|
testExpression("((x) => x)(y)", "(x => x)(y)");
|
|
testExpression("(() => {x = 1;})()", """
|
|
(() => {
|
|
x = 1;
|
|
})()""");
|
|
// Arrow functions with operators.
|
|
testExpression("a = (b) => c", "a = b => c");
|
|
testExpression("a = ((b) => b)(c)", "a = (b => b)(c)");
|
|
testExpression("(x) => (y) => z + y", "x => y => z + y");
|
|
testExpression("!((x) => (y) => x + y)", "!(x => y => x + y)");
|
|
testExpression("(x) => !((y) => x + y)", "x => !(y => x + y)");
|
|
testExpression("(x) => (y) => !(x + y)", "x => y => !(x + y)");
|
|
testExpression("((x) => (y) => x + y) && z", "(x => y => x + y) && z");
|
|
testExpression("(x) => (((y) => x + y) && z)", "x => (y => x + y) && z");
|
|
testExpression("(x) => (y) => ((x + y) && z)", "x => y => x + y && z");
|
|
testExpression("z && ((x) => (y) => x + y)", "z && (x => y => x + y)");
|
|
testExpression("(x) => (z && ((y) => x + y))", "x => z && (y => x + y)");
|
|
testExpression("(x) => (y) => (z && x + y)", "x => y => z && x + y");
|
|
testExpression("(x) => (y) => ((z && x) + y)", "x => y => (z && x) + y");
|
|
// Methods.
|
|
testExpression("{ foo() {}, bar() {}, }", """
|
|
{
|
|
foo() {
|
|
},
|
|
bar() {
|
|
}
|
|
}""");
|
|
|
|
// Exponentiation operator.
|
|
testExpression("a ** b");
|
|
//* Parsed with incorrect association:
|
|
testExpression("a ** b ** c", "(a ** b) ** c");
|
|
testExpression("(a ** b) ** c", "(a ** b) ** c");
|
|
testExpression("a ** (b ** c)", "a ** b ** c");
|
|
testExpression("a **= b");
|
|
}
|