Chromium Code Reviews| Index: test/mjsunit/es8/syntactic-tail-call-parsing.js |
| diff --git a/test/mjsunit/es8/syntactic-tail-call-parsing.js b/test/mjsunit/es8/syntactic-tail-call-parsing.js |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..927ab2f87da4e771850e383a5ec2e029c8627b12 |
| --- /dev/null |
| +++ b/test/mjsunit/es8/syntactic-tail-call-parsing.js |
| @@ -0,0 +1,352 @@ |
| +// Copyright 2016 the V8 project authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +// Flags: --allow-natives-syntax --harmony-explicit-tailcalls |
| +// Flags: --harmony-do-expressions |
| + |
| +var SyntaxErrorTests = [ |
| + { msg: "Unexpected expression inside tail call", |
| + tests: [ |
| + { src: `()=>{ return continue foo ; }`, |
| + err: ` ^^^`, |
| + }, |
| + { src: `()=>{ return continue 42 ; }`, |
| + err: ` ^^`, |
| + }, |
| + { src: `()=>{ return continue new foo () ; }`, |
| + err: ` ^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ loop: return continue loop ; }`, |
| + err: ` ^^^^`, |
| + }, |
| + { src: `class A { foo() { return continue super.x ; } }`, |
| + err: ` ^^^^^^^`, |
| + }, |
| + { src: `()=>{ return continue this ; }`, |
| + err: ` ^^^^`, |
| + }, |
| + { src: `()=>{ return continue class A {} ; }`, |
| + err: ` ^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ return continue class A extends B {} ; }`, |
| + err: ` ^^^^^^^^^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ return continue function A() { } ; }`, |
| + err: ` ^^^^^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ return continue { a: b, c: d} ; }`, |
| + err: ` ^^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ return continue function* Gen() { yield 1; } ; }`, |
| + err: ` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^`, |
| + }, |
| + { src: `function A() { return continue new.target ; }`, |
| + err: ` ^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ return continue () ; }`, |
| + err: ` ^^`, |
| + }, |
| + { src: `()=>{ return continue ( 42 ) ; }`, |
| + err: ` ^^^^^^`, |
| + }, |
| + { src: "()=>{ return continue `123 ${foo} 34lk` ; }", |
| + err: ` ^^^^^^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ return continue do { x ? foo() : bar() ; } }`, |
| + err: ` ^^^^^^^^^^^^^^^^^^^^^^^^^^`, |
| + }, |
| + ], |
| + }, |
| + { msg: "Tail call expression is not allowed here", |
| + tests: [ |
| + { src: `()=>{ return continue continue continue b() ; }`, |
| + err: ` ^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ return continue ( continue b() ) ; }`, |
| + err: ` ^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ return continue f() - a ; }`, |
| + err: ` ^^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ return b + continue f() ; }`, |
| + err: ` ^^^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ return 1, 2, 3, continue f() , 4 ; }`, |
| + err: ` ^^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ var x = continue f ( ) ; }`, |
| + err: ` ^^^^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ return continue f () ? 1 : 2 ; }`, |
| + err: ` ^^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ return (1, 2, 3, continue f()), 4; }`, |
| + err: ` ^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ return [1, 2, continue f() ] ; }`, |
| + err: ` ^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ return [1, 2, ... continue f() ] ; }`, |
| + err: ` ^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ return [1, 2, continue f(), 3 ] ; }`, |
| + err: ` ^^^^^^^^^^^^`, |
| + }, |
| + { src: "()=>{ return `123 ${a} ${ continue foo ( ) } 34lk` ; }", |
| + err: ` ^^^^^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ return g( 1, 2, continue f() ); }`, |
| + err: ` ^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ return continue f() || a; }`, |
| + err: ` ^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ return continue foo() instanceof bar ; }`, |
| + err: ` ^^^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ return bar instanceof continue foo() ; }`, |
| + err: ` ^^^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ return continue foo() in bar ; }`, |
| + err: ` ^^^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ return bar in continue foo() ; }`, |
| + err: ` ^^^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ function* G() { yield continue foo(); } }`, |
| + err: ` ^^^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ (1, 2, 3, continue f() ) => {} }`, |
| + err: ` ^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ (... continue f()) => {} }`, |
| + err: ` ^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ (a, b, c, ... continue f() ) => {} }`, |
| + err: ` ^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ return a <= continue f(); }`, |
| + err: ` ^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ return b > continue f(); }`, |
| + err: ` ^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ return a << continue f(); }`, |
| + err: ` ^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ return b >> continue f(); }`, |
| + err: ` ^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ return c >>> continue f(); }`, |
| + err: ` ^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ return continue f() = a ; }`, |
| + err: ` ^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ return a = continue f() ; }`, |
| + err: ` ^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ return a += continue f(); }`, |
| + err: ` ^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ return a ** continue f() ; }`, |
| + err: ` ^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ return delete continue foo() ; }`, |
| + err: ` ^^^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ typeof continue foo() ; }`, |
| + err: ` ^^^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ return ~ continue foo() ; }`, |
| + err: ` ^^^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ return void continue foo() ; }`, |
| + err: ` ^^^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ return !continue foo() ; }`, |
| + err: ` ^^^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ return -continue foo() ; }`, |
| + err: ` ^^^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ return +continue foo() ; }`, |
| + err: ` ^^^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ return ++ continue f( ) ; }`, |
| + err: ` ^^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ return continue f() ++; }`, |
| + err: ` ^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ return continue f() --; }`, |
| + err: ` ^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ return (continue foo()) () ; }`, |
| + err: ` ^^^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ for (var i = continue foo(); i < 10; i++) bar(); }`, |
| + err: ` ^^^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ for (var i = 0; i < continue foo(); i++) bar(); }`, |
| + err: ` ^^^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ for (var i = 0; i < 10; continue foo()) bar(); }`, |
| + err: ` ^^^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ if (continue foo()) bar(); }`, |
| + err: ` ^^^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ while (continue foo()) bar(); }`, |
| + err: ` ^^^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ do { smth; } while (continue foo()) ; }`, |
| + err: ` ^^^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ throw continue foo() ; }`, |
| + err: ` ^^^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ switch (continue foo()) { case 1: break; } ; }`, |
| + err: ` ^^^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ with (continue foo()) { smth; } }`, |
| + err: ` ^^^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ let x = continue foo() }`, |
| + err: ` ^^^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ const c = continue foo() }`, |
| + err: ` ^^^^^^^^^^^^^^^`, |
| + }, |
| + { src: `class A {}; class B extends A { constructor() { return continue super () ; } }`, |
| + err: ` ^^^^^^^^^^^^^^^^^`, |
| + }, |
| + { src: `class A extends continue f () {}; }`, |
| + err: ` ^^^^^^^^^^^^^`, |
| + }, |
| + ], |
| + }, |
| + { msg: "Tail call expression in try block", |
| + tests: [ |
| + { src: `()=>{ try { return continue f ( ) ; } catch(e) {} }`, |
| + err: ` ^^^^^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ try { try { smth; } catch(e) { return continue f( ) ; } }`, |
| + err: ` ^^^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ try { try { smth; } catch(e) { return continue f( ) ; } } finally { bla; } }`, |
| + err: ` ^^^^^^^^^^^^^^`, |
| + }, |
| + ], |
| + }, |
| + { msg: "Tail call expression in catch block when finally block is also present", |
| + tests: [ |
| + { src: `()=>{ try { smth; } catch(e) { return continue f ( ) ; } finally { blah; } }`, |
| + err: ` ^^^^^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ try { smth; } catch(e) { try { smth; } catch (e) { return continue f ( ) ; } } finally { blah; } }`, |
| + err: ` ^^^^^^^^^^^^^^^^`, |
| + }, |
| + ], |
| + }, |
| + { msg: "Tail call expression in for-in/of body", |
| + tests: [ |
| + { src: `()=>{ for (var v in {a:0}) { return continue foo () ; } }`, |
| + err: ` ^^^^^^^^^^^^^^^^`, |
| + }, |
| + { src: `()=>{ for (var v of [1, 2, 3]) { return continue foo () ; } }`, |
| + err: ` ^^^^^^^^^^^^^^^^`, |
| + }, |
| + ], |
| + }, |
| + { msg: "Undefined label 'foo'", |
| + tests: [ |
| + { src: `()=>{ continue foo () ; }`, |
| + err: ` ^^^`, |
| + }, |
| + ], |
| + }, |
| +]; |
| + |
| + |
| +// Should parse successfully. |
| +var NoErrorTests = [ |
| + `()=>{ return continue a.b.c.foo () ; }`, |
| + `()=>{ return continue a().b.c().d.foo () ; }`, |
| + `()=>{ return continue foo (1)(2)(3, 4) ; }`, |
| + `()=>{ return ( continue b() ) ; }`, |
| + "()=>{ return continue bar`ab cd ef` ; }", |
| + "()=>{ return continue bar`ab ${cd} ef` ; }", |
| + `()=>{ return a || continue f() ; }`, |
| + `()=>{ return a && continue f() ; }`, |
| + `()=>{ return a , continue f() ; }`, |
| + `()=>{ function* G() { return continue foo(); } }`, |
| + `()=>{ class A { foo() { return continue super.f() ; } } }`, |
| + `()=>{ function B() { return continue new.target() ; } }`, |
| + `()=>{ return continue do { x ? foo() : bar() ; }() }`, |
|
rossberg
2016/05/04 10:45:30
Wait, why is this legal? A do expression shouldn't
Igor Sheludko
2016/05/04 11:50:14
Because it's actually a
return continue (do {...
|
| + `()=>{ return do { 1, continue foo() } }`, |
| + `()=>{ return do { x ? continue foo() : y } }`, |
| + `()=> continue (foo ()) ;`, |
| + `()=> a || continue foo () ;`, |
| + `()=> a && continue foo () ;`, |
| + `()=> a ? continue foo () : b;`, |
| +]; |
| + |
| + |
| +(function() { |
| + for (test_set of SyntaxErrorTests) { |
| + var expected_message = "SyntaxError: " + test_set.msg; |
| + for (test of test_set.tests) { |
| + var passed = true; |
| + var e = null; |
| + try { |
| + Realm.eval(0, test.src); |
| + } catch (ee) { |
| + e = ee; |
| + } |
| + print("======================================="); |
| + print("Expected | " + expected_message); |
| + print("Source | " + test.src); |
| + print(" | " + test.err); |
| + |
| + if (e === null) { |
| + print("FAILED"); |
| + throw new Error("SyntaxError was not thrown"); |
| + } |
| + |
| + var details = %GetMessageFromException(e); |
| + if (details.start_pos == undefined || |
| + details.end_pos == undefined) { |
| + throw new Error("Bad message object returned"); |
| + } |
| + var underline = " ".repeat(details.start_pos) + |
| + "^".repeat(details.end_pos - details.start_pos); |
| + var passed = expected_message === e.toString() && |
| + test.err === underline; |
| + |
| + if (passed) { |
| + print("PASSED"); |
| + print(); |
| + } else { |
| + print("---------------------------------------"); |
| + print("Actual | " + e); |
| + print("Source | " + test.src); |
| + print(" | " + underline); |
| + print("FAILED"); |
| + throw new Error("Test failed"); |
| + } |
| + } |
| + } |
| +})(); |
| + |
| + |
| +(function() { |
| + for (src of NoErrorTests) { |
| + print("======================================="); |
| + print("Source | " + src); |
| + Realm.eval(0, src); |
| + print("PASSED"); |
| + print(); |
| + } |
| +})(); |