/*
 *  If a non-strict context contains a strict function, where do 'strict'
 *  semantics actually begin?
 *
 *  Clearly, all the statements inside the function obey strict semantics.
 *  What about the argument list of the function?  For instance, consider:
 *
 *    (function (a,a) { 'use strict'; return a; })(1,2);
 *
 *  Strict code cannot contain a function expression with two arguments
 *  of the same name.  However, in this case the function expression itself
 *  exists in non-strict code.
 *
 *  E5 Section 11.2.5 refers to Section 13 for the semantics of evaluating
 *  a FunctionExpression.  The specification text for a FunctionExpression
 *  is as follows:
 *
 *    The production
 *
 *    FunctionExpression : function ( FormalParameterList_opt ) { FunctionBody }
 *
 *    is evaluated as follows:
 *
 *    1. Return the result of creating a new Function object as specified in
 *       13.2 with parameters specified by FormalParameterList_opt and body
 *       specified by FunctionBody. Pass in the LexicalEnvironment of the
 *       running execution context as the Scope. Pass in true as the Strict
 *       flag if the FunctionExpression is contained in strict code or if
 *       its FunctionBody is strict code.
 *
 *  This refers to Section 13.2 for creating a function object.  The 'Strict'
 *  flag for that "call" is set to true here, because FunctionBody is strict
 *  code.  However, the algorithm of Section 13.2 does no strict-mode related
 *  checks for duplicate argument names.
 *
 *  E5 Section 13.1 describes strict mode restrictions, which include:
 *
 *    It is a SyntaxError if any Identifier value occurs more than once within
 *    a FormalParameterList of a strict mode FunctionDeclaration or
 *    FunctionExpression.
 *
 *  Does this apply?  The FunctionExpression itself is *not* in strict mode.
 *  FormalParameterList is presumably evaluated in non-strict mode.
 *
 *  When building functions with the Function constructor, the specification
 *  clearly states that strict mode restrictions are checked and applied
 *  after function parsing: E5 Section 15.3.2.1, step 10.  Thus it would
 *  seem reasonable to have the same semantics for other function parsing
 *  cases, too.
 *
 *  In any case, V8 will throw SyntaxError in this case, and we follows that
 *  behavior.  Test cases below check for this expected behavior.
 *
 *  Note that the strict mode restrictions of E5 Section 13.1 are a bit
 *  awkward to check from an implementation perspective: while we're parsing
 *  a function expression (in particular, a possible name and the argument
 *  list) we don't yet know that the function may turn out to be strict.
 *  The optional function name and the argument list need to be checked
 *  at some point, when we know we're dealing with a strict function.
 */

/*===
2
SyntaxError
===*/

/* Duplicate argument names */

try {
    // non-strict function -> acceptable syntax, latter parameter
    // is bound to 'a'
    eval("(function (a,a) { print(a); })(1,2);");
} catch (e) {
    print(e.name);
}

try {
    // SyntaxError
    eval("(function (a,a) { 'use strict'; print(a); })(1,2);");
} catch (e) {
    print(e.name);
}

/*===
1
SyntaxError
1
SyntaxError
===*/

/* Argument named 'eval' or 'arguments' */

try {
    eval("(function (eval) { print(eval); })(1);");
} catch (e) {
    print(e.name);
}

try {
    eval("(function (eval) { 'use strict'; print(eval); })(1);");
} catch (e) {
    print(e.name);
}

try {
    eval("(function (arguments) { print(arguments); })(1);");
} catch (e) {
    print(e.name);
}

try {
    eval("(function (arguments) { 'use strict'; print(arguments); })(1);");
} catch (e) {
    print(e.name);
}

/*===
1
SyntaxError
1
SyntaxError
===*/

/* Function name 'eval' or 'arguments' */

try {
    eval("(function eval(a) { print(a); })(1);");
} catch (e) {
    print(e.name);
}

try {
    eval("(function eval(a) { 'use strict'; print(a); })(1);");
} catch (e) {
    print(e.name);
}

try {
    eval("(function arguments(a) { print(a); })(1);");
} catch (e) {
    print(e.name);
}

try {
    eval("(function arguments(a) { 'use strict'; print(a); })(1);");
} catch (e) {
    print(e.name);
}

