diff --git a/src/jdk/nashorn/internal/parser/AbstractParser.java b/src/jdk/nashorn/internal/parser/AbstractParser.java index 676ca7f506ac01889a51acd1e4e9edf6370ce64c..8f65e0f702e5ac0845efedffe17777eb504332d3 100644 --- a/src/jdk/nashorn/internal/parser/AbstractParser.java +++ b/src/jdk/nashorn/internal/parser/AbstractParser.java @@ -37,8 +37,8 @@ import jdk.nashorn.internal.runtime.ECMAErrors; import jdk.nashorn.internal.runtime.ErrorManager; import jdk.nashorn.internal.runtime.JSErrorType; import jdk.nashorn.internal.runtime.ParserException; -import jdk.nashorn.internal.runtime.regexp.RegExpFactory; import jdk.nashorn.internal.runtime.Source; +import jdk.nashorn.internal.runtime.regexp.RegExpFactory; /** * Base class for parsers. @@ -244,6 +244,16 @@ public abstract class AbstractParser { return new ParserException(errorType, formatted, source, line, column, token); } + /** + * Report a warning to the error manager. + * + * @param errorType The error type of the warning + * @param message Warning message. + */ + protected final void warning(final JSErrorType errorType, final String message, final long errorToken) { + errors.warning(error(errorType, message, errorToken)); + } + /** * Generate 'expected' message. * diff --git a/src/jdk/nashorn/internal/parser/Parser.java b/src/jdk/nashorn/internal/parser/Parser.java index 70066853b37f1cb3c37aa02b5737e6e07b230dbd..ab70859b5ec16db914b00a1c13aefdbc413f9333 100644 --- a/src/jdk/nashorn/internal/parser/Parser.java +++ b/src/jdk/nashorn/internal/parser/Parser.java @@ -675,9 +675,6 @@ loop: if (type == FUNCTION) { // As per spec (ECMA section 12), function declarations as arbitrary statement // is not "portable". Implementation can issue a warning or disallow the same. - if (isStrictMode && !topLevel) { - throw error(AbstractParser.message("strict.no.func.here"), token); - } functionExpression(true, topLevel); return; } @@ -2332,6 +2329,12 @@ loop: if (isStatement) { if (topLevel) { functionNode = functionNode.setFlag(lc, FunctionNode.IS_DECLARED); + } else if (isStrictMode) { + throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("strict.no.func.decl.here"), functionToken); + } else if (env._function_statement == ScriptEnvironment.FunctionStatementBehavior.ERROR) { + throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("no.func.decl.here"), functionToken); + } else if (env._function_statement == ScriptEnvironment.FunctionStatementBehavior.WARNING) { + warning(JSErrorType.SYNTAX_ERROR, AbstractParser.message("no.func.decl.here.warn"), functionToken); } if (ARGUMENTS.symbolName().equals(name.getName())) { lc.setFlag(lc.getCurrentFunction(), FunctionNode.DEFINES_ARGUMENTS); diff --git a/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java b/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java index 9a6e5954d00b266325e011a039cbbf8668a37028..74fab0cebe3e3aa7529491b0979100160f764c9a 100644 --- a/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java +++ b/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java @@ -85,6 +85,33 @@ public final class ScriptEnvironment { /** Launch using as fx application */ public final boolean _fx; + /** + * Behavior when encountering a function declaration in a lexical context where only statements are acceptable + * (function declarations are source elements, but not statements). + */ + public enum FunctionStatementBehavior { + /** + * Accept the function declaration silently and treat it as if it were a function expression assigned to a local + * variable. + */ + ACCEPT, + /** + * Log a parser warning, but accept the function declaration and treat it as if it were a function expression + * assigned to a local variable. + */ + WARNING, + /** + * Raise a {@code SyntaxError}. + */ + ERROR + } + + /** + * Behavior when encountering a function declaration in a lexical context where only statements are acceptable + * (function declarations are source elements, but not statements). + */ + public final FunctionStatementBehavior _function_statement; + /** Should lazy compilation take place */ public final boolean _lazy_compilation; @@ -161,6 +188,13 @@ public final class ScriptEnvironment { _early_lvalue_error = options.getBoolean("early.lvalue.error"); _empty_statements = options.getBoolean("empty.statements"); _fullversion = options.getBoolean("fullversion"); + if(options.getBoolean("function.statement.error")) { + _function_statement = FunctionStatementBehavior.ERROR; + } else if(options.getBoolean("function.statement.warning")) { + _function_statement = FunctionStatementBehavior.WARNING; + } else { + _function_statement = FunctionStatementBehavior.ACCEPT; + } _fx = options.getBoolean("fx"); _lazy_compilation = options.getBoolean("lazy.compilation"); _loader_per_compile = options.getBoolean("loader.per.compile"); diff --git a/src/jdk/nashorn/internal/runtime/options/Options.java b/src/jdk/nashorn/internal/runtime/options/Options.java index 3e09fa57c08036cbfab7db37e30d63e425eeff22..16f3bc0f5ef0f091972e7ae8ac9e5ee23ae1b0d1 100644 --- a/src/jdk/nashorn/internal/runtime/options/Options.java +++ b/src/jdk/nashorn/internal/runtime/options/Options.java @@ -243,7 +243,13 @@ public final class Options { */ public String getString(final String key) { final Option option = get(key); - return option != null ? (String)option.getValue() : null; + if(option != null) { + final String value = (String)option.getValue(); + if(value != null) { + return value.intern(); + } + } + return null; } /** diff --git a/src/jdk/nashorn/internal/runtime/resources/Options.properties b/src/jdk/nashorn/internal/runtime/resources/Options.properties index 820f7788e573d3f788d5b76bff1714f23b45a84f..2b52e8b95b02a958fedbabd6db0d99f085732da8 100644 --- a/src/jdk/nashorn/internal/runtime/resources/Options.properties +++ b/src/jdk/nashorn/internal/runtime/resources/Options.properties @@ -144,6 +144,20 @@ nashorn.option.fullversion = { \ desc="Print full version info of Nashorn." \ } +nashorn.option.function.statement.error= { \ + name="--function-statement-error", \ + desc="Report an error when function declaration is used as a statement.", \ + is_undocumented=true, \ + default=false \ +} + +nashorn.option.function.statement.warning = { \ + name="--function-statement-warning", \ + desc="Warn when function declaration is used as a statement.", \ + is_undocumented=true, \ + default=false \ +} + nashorn.option.fx = { \ name="-fx", \ desc="Launch script as an fx application.", \ diff --git a/test/script/basic/JDK-8008814-3.js b/test/script/basic/JDK-8008814-3.js new file mode 100644 index 0000000000000000000000000000000000000000..87a9ebf4f536b286054f148219853490a13689e1 --- /dev/null +++ b/test/script/basic/JDK-8008814-3.js @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * NASHORN-8008814: it's not a compile time error to have a nested strict function declaration when the outer one is not strict + * + * @test + * @run + */ + +function f() { + if(true) { + function g() { + "use strict"; + print("g invoked!") + } + } + g() +} +f() diff --git a/test/script/basic/JDK-8008814-3.js.EXPECTED b/test/script/basic/JDK-8008814-3.js.EXPECTED new file mode 100644 index 0000000000000000000000000000000000000000..dab29578348f6cfe1cef4c4486965ae592afe420 --- /dev/null +++ b/test/script/basic/JDK-8008814-3.js.EXPECTED @@ -0,0 +1 @@ +g invoked! diff --git a/test/script/basic/JDK-8008814-4.js b/test/script/basic/JDK-8008814-4.js new file mode 100644 index 0000000000000000000000000000000000000000..baca0221730d3c3dd60383407088d801a610a924 --- /dev/null +++ b/test/script/basic/JDK-8008814-4.js @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * NASHORN-8008814: it's not a compile time error to have a nested function declaration when warnings are reported + * + * @option --function-statement-warning + * @test + * @run/ignore-std-error + */ + +function f() { + if(true) { + function g() { + print("g invoked!") + } + } + g() +} +f() diff --git a/test/script/basic/JDK-8008814-4.js.EXPECTED b/test/script/basic/JDK-8008814-4.js.EXPECTED new file mode 100644 index 0000000000000000000000000000000000000000..dab29578348f6cfe1cef4c4486965ae592afe420 --- /dev/null +++ b/test/script/basic/JDK-8008814-4.js.EXPECTED @@ -0,0 +1 @@ +g invoked! diff --git a/test/script/error/JDK-8008814-1.js b/test/script/error/JDK-8008814-1.js new file mode 100644 index 0000000000000000000000000000000000000000..324d090c13fc2f9fb3928b0cf117dad0e6e4e734 --- /dev/null +++ b/test/script/error/JDK-8008814-1.js @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * NASHORN-8008814: it's a compile time error to have a nested function declaration when there's an option to treat it as an error + * + * @option --function-statement-error + * @test/compile-error + */ + +if(true) { + function g() { + } +} diff --git a/test/script/error/JDK-8008814-1.js.EXPECTED b/test/script/error/JDK-8008814-1.js.EXPECTED new file mode 100644 index 0000000000000000000000000000000000000000..36fbedfe4e30194bf7d3afff7cbf8e04ff2a3a4f --- /dev/null +++ b/test/script/error/JDK-8008814-1.js.EXPECTED @@ -0,0 +1,3 @@ +test/script/error/NASHORN-8008814-1.js:32:2 Function declarations can only occur at program or function body level. You should use a function expression here instead. + function g() { + ^ diff --git a/test/script/error/JDK-8008814-2.js b/test/script/error/JDK-8008814-2.js new file mode 100644 index 0000000000000000000000000000000000000000..079b253f42d0c147c61289eb5ccab5cea4382773 --- /dev/null +++ b/test/script/error/JDK-8008814-2.js @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * NASHORN-8008814: it's a compile time error to have a nested function declaration in strict mode + * + * @test/compile-error + */ + +"use strict"; +if(true) { + function g() { + } +} diff --git a/test/script/error/JDK-8008814-2.js.EXPECTED b/test/script/error/JDK-8008814-2.js.EXPECTED new file mode 100644 index 0000000000000000000000000000000000000000..8b4335873d7ea4eb3ce01ff90e7925ba8a529c4b --- /dev/null +++ b/test/script/error/JDK-8008814-2.js.EXPECTED @@ -0,0 +1,3 @@ +test/script/error/NASHORN-8008814-2.js:32:2 In strict mode, function declarations can only occur at program or function body level. You should use a function expression here instead. + function g() { + ^