@Override public Object call(ExecutionContext context, Object self, Object... args) { // 15.3.2.1 int numArgs = args.length; String body = ""; if (numArgs > 0) { body = Types.toString(context, args[numArgs - 1]); } StringBuffer formalParams = new StringBuffer(); boolean first = true; Set<String> seenParams = new HashSet<>(); boolean duplicateFormalParams = false; for (int i = 0; i < numArgs - 1; ++i) { if (!first) { formalParams.append(","); } String param = Types.toString(context, args[i]); if (seenParams.contains(param)) { duplicateFormalParams = true; } seenParams.add(param); formalParams.append(param); first = false; } StringBuffer code = new StringBuffer(); code.append("function(" + formalParams.toString() + "){\n"); code.append(body); code.append("}"); try { FunctionDescriptor descriptor = parseFunction(context, code.toString()); JSCompiler compiler = context.getGlobalObject().getCompiler(); JSFunction function = compiler.compileFunction( context, descriptor.getFormalParameters(), descriptor.getBlock(), false); if (function.isStrict() && duplicateFormalParams) { throw new ThrowException( context, context.createSyntaxError("duplicate formal parameters in function definition")); } function.setPrototype(getPrototype()); return function; } catch (RecognitionException e) { throw new ThrowException(context, context.createSyntaxError(e.getMessage())); } }
public FunctionDescriptor parseFunction(ExecutionContext context, String code) throws RecognitionException { final ANTLRStringStream stream = new ANTLRStringStream(code); ES3Lexer lexer = new ES3Lexer(stream); CommonTokenStream lexerStream = new CommonTokenStream(lexer); ES3Parser parser = new ES3Parser(lexerStream); ES3Parser.functionExpression_return function = parser.functionExpression(); List<String> errors = parser.getErrors(); if (!errors.isEmpty()) { throw new ThrowException(context, context.createSyntaxError(errors.get(0))); } CommonTree tree = (CommonTree) function.getTree(); CommonTreeNodeStream treeNodeStream = new CommonTreeNodeStream(tree); treeNodeStream.setTokenStream(lexerStream); ES3Walker walker = new ES3Walker(treeNodeStream); Executor executor = new Executor(); executor.setBlockManager(context.getBlockManager()); walker.setExecutor(executor); FunctionDescriptor descriptor = walker.functionDescriptor(); return descriptor; }
@Override public Object call(ExecutionContext context, Object self, Object... args) { // 15.3.2.1 int numArgs = args.length; String body = ""; StringBuilder formalParams = new StringBuilder(); boolean first = true; Set<String> seenParams = new HashSet<>(); boolean duplicateFormalParams = false; for (int i = 0; i < numArgs - 1; ++i) { String paramStr = Types.toString(context, args[i]); StringTokenizer paramTokens = new StringTokenizer(paramStr, ","); while (paramTokens.hasMoreTokens()) { if (!first) { formalParams.append(","); } String param = paramTokens.nextToken().trim(); if (seenParams.contains(param)) { duplicateFormalParams = true; } seenParams.add(param); formalParams.append(param); first = false; } } if (numArgs > 0) { body = Types.toString(context, args[numArgs - 1]); } StringBuilder code = new StringBuilder(); code.append("function(" + formalParams.toString() + "){\n"); code.append(body); code.append("}"); try { FunctionDescriptor descriptor = parseFunction(context, code.toString()); JSCompiler compiler = context.getGlobalObject().getCompiler(); JSFunction function = compiler.compileFunction( context, descriptor.getIdentifier(), descriptor.getFormalParameterNames(), descriptor.getBlock(), descriptor.isStrict()); if (function.isStrict()) { if (duplicateFormalParams) { throw new ThrowException( context, context.createSyntaxError("duplicate formal parameters in function definition")); } if (seenParams.contains("eval")) { throw new ThrowException( context, context.createSyntaxError( "formal parameter 'eval' not allowed in function definition in strict-mode")); } } function.setPrototype(getPrototype()); return function; } catch (ParserException e) { throw new ThrowException(context, context.createSyntaxError(e.getMessage())); } catch (IOException e) { throw new ThrowException(context, context.createSyntaxError(e.getMessage())); } }