/* * Automatic semicolon insertion (E5 Section 7.9). * * Note: depending on implementation a few tests will cover behavior, * or insertion must be tested in all possible syntactic constructs. */ /*FIXME*/ /*=== 10 14 ===*/ function f_basic1() { var x // parsed as "x = 1 + 2 + 3 + 4;" x = 1 + 2 + 3 + 4 print(x) // parsed as "x = 2 + 3 + 4 + 5;", because must parse longest // possible valid expression x = 2 + 3 + 4 + 5 print(x) } f_basic1(); /*=== 123 ===*/ // semicolon inserted at end of block, offending token is '}' // rule 1 of E5 Section 7.9.1 function f_basic2() { return 123 } print(f_basic2()); /*=== 234 ===*/ // semicolon inserted at end of input // rule 2 of E5 Section 7.9.1 function f_basic3() { return eval("234"); } print(f_basic3()); /*=== 10 20 -> 10 21 -> 11 21 10 20 -> 10 19 -> 9 19 return from inner return from inner undefined SyntaxError ===*/ // semicolon inserted in the middle of a restricted // production (even if continuing was possible syntactically) // rule 3 of E5 Section 7.9.1 var x = 10; var y = 20; function f_postinc() { print(x, y); // interpreted as "x; ++y;" x ++y print('->', x, y); // interpreted as "x++; y;" x++ y print('->', x, y); } function f_postdec() { print(x, y); // interpreted as "x; --y;" x --y print('->', x, y); // interpreted as "x--; y;" x-- y print('->', x, y); } function f_continue() { var done = false; outer: for (;;) { if (done) { print('return from outer'); return; } for (;;) { if (done) { print('return from inner'); return; } done = true; // interpreted as 'continue; outer;' // continues inner loop -> exits from inner // ('continue outer' would exit from outer) continue outer } } } function f_break() { outer: for (;;) { for (;;) { // interpreted as 'break: outer' break outer } print('return from inner'); return; } print('return from outer'); } function f_return() { /* interpreted as "return; 123;" */ return 123; } /* Note: there is no empty variant for 'throw' (unlike for return, break, * and continue), so a line break between throw and its value is a * SyntaxError. */ var src_throw = "function() {\n" + " try {\n" + " // interpreted as 'throw; 123' instead of 'throw 123'\n" + " throw\n" + " 123\n" + " } catch(e) {\n" + " print(e);\n" + " }\n" + "}"; try { x = 10; y = 20; f_postinc(); } catch (e) { print(e.name); } try { x = 10; y = 20; f_postdec(); } catch (e) { print(e.name); } try { f_continue(); } catch (e) { print(e.name); } try { f_break(); } catch (e) { print(e.name); } try { print(f_return()); } catch (e) { print(e.name); } try { var f_throw = eval(src_throw); f_throw(); } catch (e) { print(e.name); } /*=== SyntaxError SyntaxError ===*/ /* A specific post-increment/decrement case; e.g. "a+b\n++" must be * interpreted as "a+b;++;" which is a SyntaxError. */ try { eval("a+b\n++"); } catch (e) { print(e.name); } try { eval("a+b\n--"); } catch (e) { print(e.name); }