/* * E5 Section 15.3.2: function constructor argument list is not * necessarily just identifier names, a call argument may contain * multiple argument declarations. * * The arguments joined with "," should parse as a FormalParameterList_opt. * Apparently this means that the source can contain newlines and comments * too! */ /*=== 6 6 6 6 6 6 ===*/ var f1, f2, f3, f4, f5, f6; try { print(eval('f1 = new Function("a", "b", "c", "return a+b+c"); f1(1,2,3);')); } catch (e) { print(e.name); } try { print(eval('f2 = new Function("a, b, c", "return a+b+c"); f2(1,2,3);')); } catch (e) { print(e.name); } try { print(eval('f3 = new Function("a, b", "c", "return a+b+c"); f3(1,2,3);')); } catch (e) { print(e.name); } try { print(eval('f4 = new Function("a /*first*/", "b /*second*/, c /*third*/", "return a+b+c"); f4(1,2,3);')); } catch (e) { print(e.name); } try { /* It's unclear in the specification whether this should be a SyntaxError or not. * If one naively constructs a parse string as: * * function (a, b, c //last) { return a+b+c } * * Then this would be a syntax error. On the other hand, the specification does not * say that this should be done; rather, the argument list, joined by commas, should * be parsed as a FormalParameterList_opt and the body should be parsed as a * FunctionBody, separately. So we interpret this to mean that this should actually * work correctly, as comments are allowed anywhere in source code. The formal * argument list to be parsed is: * * a,b, c // last * * This fails in V8 and Rhino, though. For example, Rhino will complain: * * SyntaxError: missing ) after formal parameters * * V8 (Node) will complain: * * [SyntaxError: Unexpected token return] * */ print(eval('f5 = new Function("a", "b, c // last", "return a+b+c"); f5(1,2,3);')); } catch (e) { print(e.name); } try { /* Here the format argument list to be parsed would be: * * a * ,b * ,c // last [newline] * * Again, this should parse as a FormalParameterList_opt but fails to do so in * Rhino and V8. Rhino will complain: * * SyntaxError: unterminated string literal * * whereas V8 will complain: * * [SyntaxError: Unexpected token ILLEGAL] */ eval('f6 = new Function("a\n", "b\n,c // last\n", "return a+b+c"); f6(1,2,3);'); } catch (e) { print(e.name); } /*=== function () {if (1) {print('foo')}} foo SyntaxError ===*/ /* It would be tempting to implement the Function constuctor as follows: * * 1. Coerce the argument names and join with commas -> formals * 2. Coerce the function body -> body * 3. Let T = 'function(' + formals + ') { + body + '}' * * However, this would not be correct. E5 Section 15.3.2.1 step 7 * requires that 'formals' must parse as a FormalParameterList_opt * by itself. * * The test case below ensures that this is indeed the case. The * following function: * * function () {if (1) {print('foo')}} * ==========--------===-------------= * * is split into parts in a sneaky way. */ var fake_arg = ") {if (1"; var fake_body = "print('foo')}"; var fake_val; try { // this should work (parens used to ensure function expression parses) fake_val = 'function (' + fake_arg + ') {' + fake_body + '}'; print(fake_val); eval('(' + fake_val + ') ()'); } catch (e) { print(e.name); } try { // this should not (but does, e.g. on Rhino) new Function(fake_arg, fake_body)(); } catch (e) { print(e.name); } /*=== OBJ1 OBJ2 OBJ3 7 ===*/ /* The coercion order of arguments is specified to match function argument * order, i.e. ToString() coerce first the formal arguments and finally * the body. */ var obj1 = { toString: function() { print('OBJ1'); return 'x'; } }; var obj2 = { toString: function() { print('OBJ2'); return 'y'; } }; var obj3 = { toString: function() { print('OBJ3'); return 'print(x+y)'; } }; try { new Function(obj1, obj2, obj3)(3,4); } catch (e) { print(e.name); } /*=== undefined foo foo 1 foo 1 2 ===*/ /* Misc additional tests for implementation-dependent reasons. */ try { // no arguments or body -> body evaluates to an empty string, so // should behave like "function() {}", i.e. return undefined print(new Function()()); } catch (e) { print(e.name); } try { // empty args new Function("print('foo')")(); } catch (e) { print(e.name); } try { // 1 arg new Function("x", "print('foo', x)")(1); } catch (e) { print(e.name); } try { // 2 args new Function("x", "y", "print('foo', x, y)")(1, 2); } catch (e) { print(e.name); }