09d7da9250
BUG= http://dartbug.com/5654 R=lrn@google.com, srdjan@google.com Committed: https://code.google.com/p/dart/source/detail?r=23062 Reverted: https://code.google.com/p/dart/source/detail?r=23065 Committed: https://code.google.com/p/dart/source/detail?r=23066 Reverted: https://code.google.com/p/dart/source/detail?r=23068 Review URL: https://codereview.chromium.org//15333006 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@23071 260f80e4-7a28-3924-810f-c04153c831b5
190 lines
6.6 KiB
Dart
190 lines
6.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 'mock_compiler.dart';
|
|
import '../../../sdk/lib/_internal/compiler/implementation/js/js.dart' as jsAst;
|
|
import '../../../sdk/lib/_internal/compiler/implementation/js/js.dart' show js;
|
|
|
|
void testExpression(String expression, [String expect = ""]) {
|
|
jsAst.Node node = js(expression);
|
|
MockCompiler compiler = new MockCompiler();
|
|
String jsText =
|
|
jsAst.prettyPrint(node,
|
|
compiler,
|
|
allowVariableMinification: false).getText();
|
|
if (expect == "") {
|
|
Expect.stringEquals(expression, jsText);
|
|
} else {
|
|
Expect.stringEquals(expect, jsText);
|
|
}
|
|
}
|
|
|
|
void 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)');
|
|
// Chaned 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
|
|
testError('foo({meaning: 42})', 'Expected RBRACE');
|
|
// 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 + 0x0123456789abcdefABCDEF');
|
|
// 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');
|
|
// 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])');
|
|
// *We can't parse array literals with holes in them.
|
|
testError("[1,, 2]");
|
|
testError("[1,]");
|
|
testError("[,]");
|
|
testError("[, 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");
|
|
}
|