1// Copyright 2016 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Flags: --allow-natives-syntax --harmony-explicit-tailcalls
6// Flags: --harmony-do-expressions --harmony-async-await
7"use strict";
8
9var SyntaxErrorTests = [
10  { msg: "Unexpected expression inside tail call",
11    tests: [
12      { src: `()=>{ return continue  foo ; }`,
13        err: `                       ^^^`,
14      },
15      { src: `()=>{ return  continue 42 ; }`,
16        err: `                       ^^`,
17      },
18      { src: `()=>{ return  continue   new foo ()  ; }`,
19        err: `                         ^^^^^^^^^^`,
20      },
21      { src: `()=>{ loop: return  continue  loop ; }`,
22        err: `                              ^^^^`,
23      },
24      { src: `class A { foo() { return  continue   super.x ; } }`,
25        err: `                                     ^^^^^^^`,
26      },
27      { src: `()=>{ return  continue  this  ; }`,
28        err: `                        ^^^^`,
29      },
30      { src: `()=>{ return  continue class A {} ; }`,
31        err: `                       ^^^^^^^^^^`,
32      },
33      { src: `()=>{ return  continue class A extends B {} ; }`,
34        err: `                       ^^^^^^^^^^^^^^^^^^^^`,
35      },
36      { src: `()=>{ return  continue function A() { } ; }`,
37        err: `                       ^^^^^^^^^^^^^^^^`,
38      },
39      { src: `()=>{ return  continue { a: b, c: d} ; }`,
40        err: `                       ^^^^^^^^^^^^^`,
41      },
42      { src: `()=>{ return  continue function* Gen() { yield 1; } ; }`,
43        err: `                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^`,
44      },
45      { src: `function A() { return  continue new.target ; }`,
46        err: `                                ^^^^^^^^^^`,
47      },
48      { src: `()=>{ return  continue () ; }`,
49        err: `                       ^^`,
50      },
51      { src: `()=>{ return  continue ( 42 ) ; }`,
52        err: `                       ^^^^^^`,
53      },
54      { src: "()=>{ return continue `123 ${foo} 34lk` ;  }",
55        err: `                      ^^^^^^^^^^^^^^^^^`,
56      },
57      { src: `()=>{ return continue do { x ? foo() : bar() ; } }`,
58        err: `                      ^^^^^^^^^^^^^^^^^^^^^^^^^^`,
59      },
60    ],
61  },
62  { msg: "Tail call expression is not allowed here",
63    tests: [
64      { src: `()=>{ return  continue continue continue b()  ; }`,
65        err: `                                ^^^^^^^^^^^^`,
66      },
67      { src: `()=>{ return  continue ( continue b() ) ; }`,
68        err: `                         ^^^^^^^^^^^^`,
69      },
70      { src: `()=>{ return   continue  f()   - a ; }`,
71        err: `               ^^^^^^^^^^^^^`,
72      },
73      { src: `()=>{ return b + continue   f()  ; }`,
74        err: `                 ^^^^^^^^^^^^^^`,
75      },
76      { src: `()=>{ return 1, 2, 3,   continue  f() , 4  ; }`,
77        err: `                        ^^^^^^^^^^^^^`,
78      },
79      { src: `()=>{ var x =  continue  f ( ) ; }`,
80        err: `               ^^^^^^^^^^^^^^^`,
81      },
82      { src: `()=>{ return   continue f () ? 1 : 2 ; }`,
83        err: `               ^^^^^^^^^^^^^`,
84      },
85      { src: `()=>{ return (1, 2, 3, continue f()), 4; }`,
86        err: `                       ^^^^^^^^^^^^`,
87      },
88      { src: `()=>{ return [1, 2, continue f() ] ;  }`,
89        err: `                    ^^^^^^^^^^^^`,
90      },
91      { src: `()=>{ return [1, 2, ... continue f() ] ;  }`,
92        err: `                        ^^^^^^^^^^^^`,
93      },
94      { src: `()=>{ return [1, 2, continue f(), 3 ] ;  }`,
95        err: `                    ^^^^^^^^^^^^`,
96      },
97      { src: "()=>{ return `123 ${a} ${ continue foo ( ) } 34lk` ;  }",
98        err: `                          ^^^^^^^^^^^^^^^^`,
99      },
100      { src: `()=>{ return g( 1, 2, continue f() ); }`,
101        err: `                      ^^^^^^^^^^^^`,
102      },
103      { src: `()=>{ return continue f() || a; }`,
104        err: `             ^^^^^^^^^^^^`,
105      },
106      { src: `()=>{ return a || b || c || continue f() || d; }`,
107        err: `                            ^^^^^^^^^^^^`,
108      },
109      { src: `()=>{ return a && b && c && continue f() && d; }`,
110        err: `                            ^^^^^^^^^^^^`,
111      },
112      { src: `()=>{ return a && b || c && continue f() ? d : e; }`,
113        err: `                            ^^^^^^^^^^^^`,
114      },
115      { src: `()=>{ return a ? b : c && continue f() && d || e; }`,
116        err: `                          ^^^^^^^^^^^^`,
117      },
118      { src: `()=>{ return continue foo() instanceof bar ; }`,
119        err: `             ^^^^^^^^^^^^^^`,
120      },
121      { src: `()=>{ return bar instanceof continue foo() ; }`,
122        err: `                            ^^^^^^^^^^^^^^`,
123      },
124      { src: `()=>{ return continue foo() in bar ; }`,
125        err: `             ^^^^^^^^^^^^^^`,
126      },
127      { src: `()=>{ return bar in continue foo() ; }`,
128        err: `                    ^^^^^^^^^^^^^^`,
129      },
130      { src: `()=>{ function* G() { yield continue foo(); } }`,
131        err: `                                     ^^^^^`,
132      },
133      { src: `()=>{ function* G() { return continue foo(); } }`,
134        err: `                                      ^^^^^`,
135      },
136      { src: `()=>{ (1, 2, 3, continue f() ) => {} }`,
137        err: `                ^^^^^^^^^^^^`,
138      },
139      { src: `()=>{ (... continue f()) => {}  }`,
140        err: `           ^^^^^^^^^^^^`,
141      },
142      { src: `()=>{ (a, b, c, ... continue f() ) => {}  }`,
143        err: `                    ^^^^^^^^^^^^`,
144      },
145      { src: `()=>{ return a <= continue f(); }`,
146        err: `                  ^^^^^^^^^^^^`,
147      },
148      { src: `()=>{ return b > continue f(); }`,
149        err: `                 ^^^^^^^^^^^^`,
150      },
151      { src: `()=>{ return a << continue f(); }`,
152        err: `                  ^^^^^^^^^^^^`,
153      },
154      { src: `()=>{ return b >> continue f(); }`,
155        err: `                  ^^^^^^^^^^^^`,
156      },
157      { src: `()=>{ return c >>> continue f(); }`,
158        err: `                   ^^^^^^^^^^^^`,
159      },
160      { src: `()=>{ return continue f() = a ; }`,
161        err: `             ^^^^^^^^^^^^`,
162      },
163      { src: `()=>{ return a = continue f() ; }`,
164        err: `                 ^^^^^^^^^^^^`,
165      },
166      { src: `()=>{ return a += continue f(); }`,
167        err: `                  ^^^^^^^^^^^^`,
168      },
169      { src: `()=>{ return a ** continue f() ; }`,
170        err: `                  ^^^^^^^^^^^^`,
171      },
172      { src: `()=>{ return delete continue foo() ; }`,
173        err: `                    ^^^^^^^^^^^^^^`,
174      },
175      { src: `()=>{ typeof continue foo()  ; }`,
176        err: `             ^^^^^^^^^^^^^^`,
177      },
178      { src: `()=>{ return ~ continue foo() ; }`,
179        err: `               ^^^^^^^^^^^^^^`,
180      },
181      { src: `()=>{ return void  continue foo() ; }`,
182        err: `                   ^^^^^^^^^^^^^^`,
183      },
184      { src: `()=>{ return !continue foo() ; }`,
185        err: `              ^^^^^^^^^^^^^^`,
186      },
187      { src: `()=>{ return -continue foo() ; }`,
188        err: `              ^^^^^^^^^^^^^^`,
189      },
190      { src: `()=>{ return +continue foo() ; }`,
191        err: `              ^^^^^^^^^^^^^^`,
192      },
193      { src: `()=>{ return ++ continue f( ) ; }`,
194        err: `                ^^^^^^^^^^^^^`,
195      },
196      { src: `()=>{ return continue f()  ++; }`,
197        err: `             ^^^^^^^^^^^^`,
198      },
199      { src: `()=>{ return continue f() --; }`,
200        err: `             ^^^^^^^^^^^^`,
201      },
202      { src: `()=>{ return (continue foo()) () ;  }`,
203        err: `              ^^^^^^^^^^^^^^`,
204      },
205      { src: `()=>{ for (var i = continue foo(); i < 10; i++) bar(); }`,
206        err: `                   ^^^^^^^^^^^^^^`,
207      },
208      { src: `()=>{ for (var i = 0; i < continue foo(); i++) bar(); }`,
209        err: `                          ^^^^^^^^^^^^^^`,
210      },
211      { src: `()=>{ for (var i = 0; i < 10; continue foo()) bar(); }`,
212        err: `                              ^^^^^^^^^^^^^^`,
213      },
214      { src: `()=>{ if (continue foo()) bar(); }`,
215        err: `          ^^^^^^^^^^^^^^`,
216      },
217      { src: `()=>{ while (continue foo()) bar(); }`,
218        err: `             ^^^^^^^^^^^^^^`,
219      },
220      { src: `()=>{ do { smth; } while (continue foo()) ; }`,
221        err: `                          ^^^^^^^^^^^^^^`,
222      },
223      { src: `()=>{ throw continue foo() ; }`,
224        err: `            ^^^^^^^^^^^^^^`,
225      },
226      { src: `()=>{ switch (continue foo()) { case 1: break; } ; }`,
227        err: `              ^^^^^^^^^^^^^^`,
228      },
229      { src: `()=>{ let x = continue foo() }`,
230        err: `              ^^^^^^^^^^^^^^`,
231      },
232      { src: `()=>{ const c = continue  foo() }`,
233        err: `                ^^^^^^^^^^^^^^^`,
234      },
235      { src: `class A {}; class B extends A { constructor() { return continue foo () ; } }`,
236        err: `                                                       ^^^^^^^^^^^^^^^`,
237      },
238      { src: `class A extends continue f () {}; }`,
239        err: `                ^^^^^^^^^^^^^`,
240      },
241      { src: `async() => continue foo()`,
242        err: `                    ^^^^^`,
243      },
244    ],
245  },
246  { msg: "Tail call expression in try block",
247    tests: [
248      { src: `()=>{ try { return  continue   f ( ) ; } catch(e) {} }`,
249        err: `                    ^^^^^^^^^^^^^^^^`,
250      },
251      { src: `()=>{ try { try { smth; } catch(e) { return  continue  f( ) ; } }`,
252        err: `                                             ^^^^^^^^^^^^^^`,
253      },
254      { src: `()=>{ try { try { smth; } catch(e) { return  continue  f( ) ; } } finally { bla; } }`,
255        err: `                                             ^^^^^^^^^^^^^^`,
256      },
257    ],
258  },
259  { msg: "Tail call expression in catch block when finally block is also present",
260    tests: [
261      { src: `()=>{ try { smth; } catch(e) { return  continue   f ( ) ; } finally { blah; } }`,
262        err: `                                       ^^^^^^^^^^^^^^^^`,
263      },
264      { src: `()=>{ try { smth; } catch(e) { try { smth; } catch (e) { return  continue   f ( ) ; } } finally { blah; } }`,
265        err: `                                                                 ^^^^^^^^^^^^^^^^`,
266      },
267    ],
268  },
269  { msg: "Tail call expression in for-in/of body",
270    tests: [
271      { src: `()=>{ for (var v in {a:0}) { return continue  foo () ; } }`,
272        err: `                                    ^^^^^^^^^^^^^^^^`,
273      },
274      { src: `()=>{ for (var v of [1, 2, 3]) { return continue  foo () ; } }`,
275        err: `                                        ^^^^^^^^^^^^^^^^`,
276      },
277    ],
278  },
279  { msg: "Tail call of a direct eval is not allowed",
280    tests: [
281      { src: `()=>{ return  continue  eval(" foo () " )  ; }`,
282        err: `                        ^^^^^^^^^^^^^^^^^`,
283      },
284      { src: `()=>{ return  a || continue  eval("", 1, 2)  ; }`,
285        err: `                             ^^^^^^^^^^^^^^`,
286      },
287      { src: `()=>{ return  a, continue  eval  ( )  ; }`,
288        err: `                           ^^^^^^^^^`,
289      },
290      { src: `()=> a, continue  eval  ( )  ; `,
291        err: `                  ^^^^^^^^^`,
292      },
293      { src: `()=> a || continue  eval  (' ' )  ; `,
294        err: `                    ^^^^^^^^^^^^`,
295      },
296    ],
297  },
298  { msg: "Undefined label 'foo'",
299    tests: [
300      { src: `()=>{ continue  foo () ; }`,
301        err: `                ^^^`,
302      },
303    ],
304  },
305];
306
307
308// Should parse successfully.
309var NoErrorTests = [
310  `()=>{ return continue  a.b.c.foo () ; }`,
311  `()=>{ return continue  a().b.c().d.foo () ; }`,
312  `()=>{ return continue  foo (1)(2)(3, 4) ; }`,
313  `()=>{ return continue (0, eval)(); }`,
314  `()=>{ return ( continue b() ) ; }`,
315  "()=>{ return continue bar`ab cd ef` ; }",
316  "()=>{ return continue bar`ab ${cd} ef` ; }",
317  `()=>{ return a || continue f() ; }`,
318  `()=>{ return a && continue f() ; }`,
319  `()=>{ return a , continue f() ; }`,
320  `()=>{ class A { foo() { return continue super.f() ; } } }`,
321  `()=>{ function B() { return continue new.target() ; } }`,
322  `()=>{ return continue do { x ? foo() : bar() ; }() }`,
323  `()=>{ return continue (do { x ? foo() : bar() ; })() }`,
324  `()=>{ return do { 1, continue foo() } }`,
325  `()=>{ return do { x ? continue foo() : y } }`,
326  `()=>{ return a || (b && continue c()); }`,
327  `()=>{ return a && (b || continue c()); }`,
328  `()=>{ return a || (b ? c : continue d()); }`,
329  `()=>{ return 1, 2, 3, a || (b ? c : continue d()); }`,
330  `()=> continue  (foo ()) ;`,
331  `()=> a || continue  foo () ;`,
332  `()=> a && continue  foo () ;`,
333  `()=> a ? continue  foo () : b;`,
334];
335
336
337(function() {
338  for (var test_set of SyntaxErrorTests) {
339    var expected_message = "SyntaxError: " + test_set.msg;
340    for (var test of test_set.tests) {
341      var passed = true;
342      var e = null;
343      try {
344        eval(test.src);
345      } catch (ee) {
346        e = ee;
347      }
348      print("=======================================");
349      print("Expected | " + expected_message);
350      print("Source   | " + test.src);
351      print("         | " + test.err);
352
353      if (e === null) {
354        print("FAILED");
355        throw new Error("SyntaxError was not thrown");
356      }
357
358      var details = %GetExceptionDetails(e);
359      if (details.start_pos == undefined ||
360          details.end_pos == undefined) {
361        throw new Error("Bad message object returned");
362      }
363      var underline = " ".repeat(details.start_pos) +
364                      "^".repeat(details.end_pos - details.start_pos);
365      var passed = expected_message === e.toString() &&
366                   test.err === underline;
367
368      if (passed) {
369        print("PASSED");
370        print();
371      } else {
372        print("---------------------------------------");
373        print("Actual   | " + e);
374        print("Source   | " + test.src);
375        print("         | " + underline);
376        print("FAILED");
377        throw new Error("Test failed");
378      }
379    }
380  }
381})();
382
383
384(function() {
385  for (var src of NoErrorTests) {
386    print("=======================================");
387    print("Source   | " + src);
388    src = `"use strict"; ` + src;
389    Realm.eval(0, src);
390    print("PASSED");
391    print();
392  }
393})();
394