summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwolfbeast <mcwerewolf@wolfbeast.com>2019-04-06 12:12:20 +0200
committerwolfbeast <mcwerewolf@wolfbeast.com>2019-04-06 12:14:14 +0200
commita9682a32af09f2fb8ae39c66fdc19ecdee24e591 (patch)
tree738033a7ad68a052403875d43ade1bf26ee2edf7
parentcc07da9cb4d6e7a53f8d953427ffc2bca2e0c2df (diff)
parenta5d22aa6106fbd3c8cec12333b14d4c65cd98647 (diff)
downloadUXP-a9682a32af09f2fb8ae39c66fdc19ecdee24e591.tar
UXP-a9682a32af09f2fb8ae39c66fdc19ecdee24e591.tar.gz
UXP-a9682a32af09f2fb8ae39c66fdc19ecdee24e591.tar.lz
UXP-a9682a32af09f2fb8ae39c66fdc19ecdee24e591.tar.xz
UXP-a9682a32af09f2fb8ae39c66fdc19ecdee24e591.zip
Merge branch '816'
This merges both the JS Front-end parser changes to better structure the parser code, and the TC39 `toString()` revision proposal with the exception of ES6 classes.
-rw-r--r--devtools/client/webconsole/test/browser_webconsole_output_02.js4
-rw-r--r--devtools/server/tests/unit/test_listsources-04.js4
-rw-r--r--js/src/builtin/Object.cpp280
-rw-r--r--js/src/frontend/BytecodeCompiler.cpp12
-rw-r--r--js/src/frontend/BytecodeCompiler.h2
-rw-r--r--js/src/frontend/BytecodeEmitter.cpp17
-rw-r--r--js/src/frontend/BytecodeEmitter.h2
-rw-r--r--js/src/frontend/FullParseHandler.h17
-rw-r--r--js/src/frontend/ParseNode.h8
-rw-r--r--js/src/frontend/Parser.cpp1296
-rw-r--r--js/src/frontend/Parser.h101
-rw-r--r--js/src/frontend/SharedContext.h5
-rw-r--r--js/src/frontend/SyntaxParseHandler.h7
-rw-r--r--js/src/frontend/TokenStream.cpp8
-rw-r--r--js/src/frontend/TokenStream.h11
-rw-r--r--js/src/jit-test/tests/asm.js/testSource.js48
-rw-r--r--js/src/jit-test/tests/basic/function-tosource-bug779694.js2
-rw-r--r--js/src/jit-test/tests/basic/function-tosource-constructor.js16
-rw-r--r--js/src/jit-test/tests/basic/function-tosource-getset.js10
-rw-r--r--js/src/jit-test/tests/basic/testLet.js2
-rw-r--r--js/src/jit-test/tests/debug/Script-gc-02.js2
-rw-r--r--js/src/jit-test/tests/debug/Script-gc-03.js2
-rw-r--r--js/src/jit-test/tests/debug/Script-sourceStart-04.js4
-rw-r--r--js/src/jit-test/tests/debug/Source-text-02.js1
-rw-r--r--js/src/jit-test/tests/latin1/assorted.js6
-rw-r--r--js/src/jit-test/tests/latin1/function.js4
-rw-r--r--js/src/js.msg9
-rw-r--r--js/src/jsapi.cpp46
-rw-r--r--js/src/jsfun.cpp92
-rw-r--r--js/src/jsscript.cpp47
-rw-r--r--js/src/jsscript.h49
-rw-r--r--js/src/tests/ecma_2017/Function/Object-toSource.js370
-rw-r--r--js/src/tests/ecma_2017/Function/browser.js0
-rw-r--r--js/src/tests/ecma_2017/Function/shell.js0
-rw-r--r--js/src/tests/ecma_6/Generators/runtime.js2
-rw-r--r--js/src/tests/js1_5/Scope/regress-185485.js2
-rw-r--r--js/src/tests/js1_7/extensions/regress-354945-01.js2
-rw-r--r--js/src/tests/js1_7/extensions/regress-354945-02.js2
-rw-r--r--js/src/tests/js1_7/geniter/regress-352197.js2
-rw-r--r--js/src/tests/js1_8/genexps/regress-683738.js8
-rw-r--r--js/src/tests/js1_8_5/regress/regress-584355.js2
-rw-r--r--js/src/wasm/AsmJS.cpp24
-rw-r--r--testing/web-platform/tests/webstorage/storage_string_conversion.html6
-rwxr-xr-xtesting/xpcshell/selftest.py2
-rw-r--r--toolkit/modules/tests/xpcshell/test_Log.js6
45 files changed, 1551 insertions, 991 deletions
diff --git a/devtools/client/webconsole/test/browser_webconsole_output_02.js b/devtools/client/webconsole/test/browser_webconsole_output_02.js
index 4c61cf041..837ec673c 100644
--- a/devtools/client/webconsole/test/browser_webconsole_output_02.js
+++ b/devtools/client/webconsole/test/browser_webconsole_output_02.js
@@ -24,7 +24,7 @@ var inputTests = [
{
input: "(function() { return 42; })",
output: "function ()",
- printOutput: "function () { return 42; }",
+ printOutput: "function() { return 42; }",
suppressClick: true
},
@@ -40,7 +40,7 @@ var inputTests = [
{
input: "testobj1.testfn2",
output: "function testfn2()",
- printOutput: "function () { return 42; }",
+ printOutput: "function() { return 42; }",
suppressClick: true
},
diff --git a/devtools/server/tests/unit/test_listsources-04.js b/devtools/server/tests/unit/test_listsources-04.js
index 6da99a6ce..8e1a57bf0 100644
--- a/devtools/server/tests/unit/test_listsources-04.js
+++ b/devtools/server/tests/unit/test_listsources-04.js
@@ -29,12 +29,12 @@ function run_test_with_server(server, cb) {
addSources(debuggee);
threadClient.getSources(Task.async(function* (res) {
- do_check_true(res.sources.length === 3, "3 sources exist");
+ do_check_eq(res.sources.length, 3, "3 sources exist");
yield threadClient.reconfigure({ useSourceMaps: false });
threadClient.getSources(function(res) {
- do_check_true(res.sources.length === 1, "1 source exist");
+ do_check_eq(res.sources.length, 1, "1 source exist");
client.close().then(cb);
});
}));
diff --git a/js/src/builtin/Object.cpp b/js/src/builtin/Object.cpp
index cd4ac122c..389bb57db 100644
--- a/js/src/builtin/Object.cpp
+++ b/js/src/builtin/Object.cpp
@@ -9,11 +9,13 @@
#include "mozilla/ArrayUtils.h"
#include "jscntxt.h"
+#include "jsstr.h"
#include "builtin/Eval.h"
#include "frontend/BytecodeCompiler.h"
#include "jit/InlinableNatives.h"
#include "js/UniquePtr.h"
+#include "vm/AsyncFunction.h"
#include "vm/StringBuffer.h"
#include "jsobjinlines.h"
@@ -124,6 +126,27 @@ obj_toSource(JSContext* cx, unsigned argc, Value* vp)
return true;
}
+template <typename CharT>
+static bool
+Consume(const CharT*& s, const CharT* e, const char *chars)
+{
+ size_t len = strlen(chars);
+ if (s + len >= e)
+ return false;
+ if (!EqualChars(s, chars, len))
+ return false;
+ s += len;
+ return true;
+}
+
+template <typename CharT>
+static void
+ConsumeSpaces(const CharT*& s, const CharT* e)
+{
+ while (*s == ' ' && s < e)
+ s++;
+}
+
/*
* Given a function source string, return the offset and length of the part
* between '(function $name' and ')'.
@@ -133,37 +156,53 @@ static bool
ArgsAndBodySubstring(mozilla::Range<const CharT> chars, size_t* outOffset, size_t* outLen)
{
const CharT* const start = chars.begin().get();
- const CharT* const end = chars.end().get();
const CharT* s = start;
+ const CharT* e = chars.end().get();
- uint8_t parenChomp = 0;
- if (s[0] == '(') {
- s++;
- parenChomp = 1;
- }
-
- /* Try to jump "function" keyword. */
- s = js_strchr_limit(s, ' ', end);
- if (!s)
+ if (s == e)
return false;
- /*
- * Jump over the function's name: it can't be encoded as part
- * of an ECMA getter or setter.
- */
- s = js_strchr_limit(s, '(', end);
- if (!s)
- return false;
+ // Remove enclosing parentheses.
+ if (*s == '(' && *(e - 1) == ')') {
+ s++;
+ e--;
+ }
- if (*s == ' ')
+ (void) Consume(s, e, "async");
+ ConsumeSpaces(s, e);
+ (void) (Consume(s, e, "function") || Consume(s, e, "get") || Consume(s, e, "set"));
+ ConsumeSpaces(s, e);
+ (void) Consume(s, e, "*");
+ ConsumeSpaces(s, e);
+
+ // Jump over the function's name.
+ if (Consume(s, e, "[")) {
+ s = js_strchr_limit(s, ']', e);
+ if (!s)
+ return false;
s++;
+ ConsumeSpaces(s, e);
+ if (*s != '(')
+ return false;
+ } else {
+ s = js_strchr_limit(s, '(', e);
+ if (!s)
+ return false;
+ }
*outOffset = s - start;
- *outLen = end - s - parenChomp;
+ *outLen = e - s;
MOZ_ASSERT(*outOffset + *outLen <= chars.length());
return true;
}
+enum class PropertyKind {
+ Getter,
+ Setter,
+ Method,
+ Normal
+};
+
JSString*
js::ObjectToSource(JSContext* cx, HandleObject obj)
{
@@ -182,59 +221,28 @@ js::ObjectToSource(JSContext* cx, HandleObject obj)
if (!buf.append('{'))
return nullptr;
- RootedValue v0(cx), v1(cx);
- MutableHandleValue val[2] = {&v0, &v1};
-
- RootedString str0(cx), str1(cx);
- MutableHandleString gsop[2] = {&str0, &str1};
-
AutoIdVector idv(cx);
if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY | JSITER_SYMBOLS, &idv))
return nullptr;
bool comma = false;
- for (size_t i = 0; i < idv.length(); ++i) {
- RootedId id(cx, idv[i]);
- Rooted<PropertyDescriptor> desc(cx);
- if (!GetOwnPropertyDescriptor(cx, obj, id, &desc))
- return nullptr;
-
- int valcnt = 0;
- if (desc.object()) {
- if (desc.isAccessorDescriptor()) {
- if (desc.hasGetterObject() && desc.getterObject()) {
- val[valcnt].setObject(*desc.getterObject());
- gsop[valcnt].set(cx->names().get);
- valcnt++;
- }
- if (desc.hasSetterObject() && desc.setterObject()) {
- val[valcnt].setObject(*desc.setterObject());
- gsop[valcnt].set(cx->names().set);
- valcnt++;
- }
- } else {
- valcnt = 1;
- val[0].set(desc.value());
- gsop[0].set(nullptr);
- }
- }
-
+ auto AddProperty = [cx, &comma, &buf](HandleId id, HandleValue val, PropertyKind kind) -> bool {
/* Convert id to a string. */
RootedString idstr(cx);
if (JSID_IS_SYMBOL(id)) {
RootedValue v(cx, SymbolValue(JSID_TO_SYMBOL(id)));
idstr = ValueToSource(cx, v);
if (!idstr)
- return nullptr;
+ return false;
} else {
RootedValue idv(cx, IdToValue(id));
idstr = ToString<CanGC>(cx, idv);
if (!idstr)
- return nullptr;
+ return false;
/*
- * If id is a string that's not an identifier, or if it's a negative
- * integer, then it must be quoted.
+ * If id is a string that's not an identifier, or if it's a
+ * negative integer, then it must be quoted.
*/
if (JSID_IS_ATOM(id)
? !IsIdentifier(JSID_TO_ATOM(id))
@@ -242,28 +250,65 @@ js::ObjectToSource(JSContext* cx, HandleObject obj)
{
idstr = QuoteString(cx, idstr, char16_t('\''));
if (!idstr)
- return nullptr;
+ return false;
}
}
- for (int j = 0; j < valcnt; j++) {
- /* Convert val[j] to its canonical source form. */
- JSString* valsource = ValueToSource(cx, val[j]);
- if (!valsource)
- return nullptr;
+ RootedString valsource(cx, ValueToSource(cx, val));
+ if (!valsource)
+ return false;
- RootedLinearString valstr(cx, valsource->ensureLinear(cx));
- if (!valstr)
- return nullptr;
+ RootedLinearString valstr(cx, valsource->ensureLinear(cx));
+ if (!valstr)
+ return false;
+
+ if (comma && !buf.append(", "))
+ return false;
+ comma = true;
+
+ size_t voffset, vlength;
+
+ // Methods and accessors can return exact syntax of source, that fits
+ // into property without adding property name or "get"/"set" prefix.
+ // Use the exact syntax when the following conditions are met:
+ //
+ // * It's a function object
+ // (exclude proxies)
+ // * Function's kind and property's kind are same
+ // (this can be false for dynamically defined properties)
+ // * Function has explicit name
+ // (this can be false for computed property and dynamically defined
+ // properties)
+ // * Function's name and property's name are same
+ // (this can be false for dynamically defined properties)
+ if (kind == PropertyKind::Getter || kind == PropertyKind::Setter ||
+ kind == PropertyKind::Method)
+ {
+ RootedFunction fun(cx);
+ if (val.toObject().is<JSFunction>()) {
+ fun = &val.toObject().as<JSFunction>();
+ // Method's case should be checked on caller.
+ if (((fun->isGetter() && kind == PropertyKind::Getter) ||
+ (fun->isSetter() && kind == PropertyKind::Setter) ||
+ kind == PropertyKind::Method) &&
+ fun->explicitName())
+ {
+ bool result;
+ if (!EqualStrings(cx, fun->explicitName(), idstr, &result))
+ return false;
- size_t voffset = 0;
- size_t vlength = valstr->length();
+ if (result) {
+ if (!buf.append(valstr))
+ return false;
+ return true;
+ }
+ }
+ }
- /*
- * Remove '(function ' from the beginning of valstr and ')' from the
- * end so that we can put "get" in front of the function definition.
- */
- if (gsop[j] && IsFunctionObject(val[j])) {
+ {
+ // When falling back try to generate a better string
+ // representation by skipping the prelude, and also removing
+ // the enclosing parentheses.
bool success;
JS::AutoCheckCannotGC nogc;
if (valstr->hasLatin1Chars())
@@ -271,29 +316,90 @@ js::ObjectToSource(JSContext* cx, HandleObject obj)
else
success = ArgsAndBodySubstring(valstr->twoByteRange(nogc), &voffset, &vlength);
if (!success)
- gsop[j].set(nullptr);
+ kind = PropertyKind::Normal;
}
- if (comma && !buf.append(", "))
- return nullptr;
- comma = true;
+ if (kind == PropertyKind::Getter) {
+ if (!buf.append("get "))
+ return false;
+ } else if (kind == PropertyKind::Setter) {
+ if (!buf.append("set "))
+ return false;
+ } else if (kind == PropertyKind::Method && fun) {
+ if (IsWrappedAsyncFunction(fun)) {
+ if (!buf.append("async "))
+ return false;
+ }
- if (gsop[j]) {
- if (!buf.append(gsop[j]) || !buf.append(' '))
- return nullptr;
+ if (fun->isStarGenerator()) {
+ if (!buf.append('*'))
+ return false;
+ }
}
- if (JSID_IS_SYMBOL(id) && !buf.append('['))
- return nullptr;
- if (!buf.append(idstr))
- return nullptr;
- if (JSID_IS_SYMBOL(id) && !buf.append(']'))
- return nullptr;
- if (!buf.append(gsop[j] ? ' ' : ':'))
- return nullptr;
+ }
+ bool needsBracket = JSID_IS_SYMBOL(id);
+ if (needsBracket && !buf.append('['))
+ return false;
+ if (!buf.append(idstr))
+ return false;
+ if (needsBracket && !buf.append(']'))
+ return false;
+
+ if (kind == PropertyKind::Getter || kind == PropertyKind::Setter ||
+ kind == PropertyKind::Method)
+ {
if (!buf.appendSubstring(valstr, voffset, vlength))
- return nullptr;
+ return false;
+ } else {
+ if (!buf.append(':'))
+ return false;
+ if (!buf.append(valstr))
+ return false;
+ }
+ return true;
+ };
+
+ RootedId id(cx);
+ Rooted<PropertyDescriptor> desc(cx);
+ RootedValue val(cx);
+ RootedFunction fun(cx);
+ for (size_t i = 0; i < idv.length(); ++i) {
+ id = idv[i];
+ if (!GetOwnPropertyDescriptor(cx, obj, id, &desc))
+ return nullptr;
+
+ if (!desc.object())
+ continue;
+
+ if (desc.isAccessorDescriptor()) {
+ if (desc.hasGetterObject() && desc.getterObject()) {
+ val.setObject(*desc.getterObject());
+ if (!AddProperty(id, val, PropertyKind::Getter))
+ return nullptr;
+ }
+ if (desc.hasSetterObject() && desc.setterObject()) {
+ val.setObject(*desc.setterObject());
+ if (!AddProperty(id, val, PropertyKind::Setter))
+ return nullptr;
+ }
+ continue;
}
+
+ val.set(desc.value());
+ if (IsFunctionObject(val, fun.address())) {
+ if (IsWrappedAsyncFunction(fun))
+ fun = GetUnwrappedAsyncFunction(fun);
+
+ if (fun->isMethod()) {
+ if (!AddProperty(id, val, PropertyKind::Method))
+ return nullptr;
+ continue;
+ }
+ }
+
+ if (!AddProperty(id, val, PropertyKind::Normal))
+ return nullptr;
}
if (!buf.append('}'))
diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp
index 76afe80b1..b5be5f5ac 100644
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -77,7 +77,7 @@ class MOZ_STACK_CLASS BytecodeCompiler
bool canLazilyParse();
bool createParser();
bool createSourceAndParser(Maybe<uint32_t> parameterListEnd = Nothing());
- bool createScript();
+ bool createScript(uint32_t preludeStart = 0);
bool emplaceEmitter(Maybe<BytecodeEmitter>& emitter, SharedContext* sharedContext);
bool handleParseFailure(const Directives& newDirectives);
bool deoptimizeArgumentsInEnclosingScripts(JSContext* cx, HandleObject environment);
@@ -242,10 +242,11 @@ BytecodeCompiler::createSourceAndParser(Maybe<uint32_t> parameterListEnd /* = No
}
bool
-BytecodeCompiler::createScript()
+BytecodeCompiler::createScript(uint32_t preludeStart /* = 0 */)
{
script = JSScript::Create(cx, options,
- sourceObject, /* sourceStart = */ 0, sourceBuffer.length());
+ sourceObject, /* sourceStart = */ 0, sourceBuffer.length(),
+ preludeStart);
return script != nullptr;
}
@@ -456,7 +457,7 @@ BytecodeCompiler::compileStandaloneFunction(MutableHandleFunction fun,
if (fn->pn_funbox->function()->isInterpreted()) {
MOZ_ASSERT(fun == fn->pn_funbox->function());
- if (!createScript())
+ if (!createScript(fn->pn_funbox->preludeStart))
return false;
Maybe<BytecodeEmitter> emitter;
@@ -650,7 +651,8 @@ frontend::CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const cha
MOZ_ASSERT(sourceObject);
Rooted<JSScript*> script(cx, JSScript::Create(cx, options, sourceObject,
- lazy->begin(), lazy->end()));
+ lazy->begin(), lazy->end(),
+ lazy->preludeStart()));
if (!script)
return false;
diff --git a/js/src/frontend/BytecodeCompiler.h b/js/src/frontend/BytecodeCompiler.h
index 72e967639..0bc1ab2ab 100644
--- a/js/src/frontend/BytecodeCompiler.h
+++ b/js/src/frontend/BytecodeCompiler.h
@@ -109,6 +109,8 @@ IsIdentifier(JSLinearString* str);
* As above, but taking chars + length.
*/
bool
+IsIdentifier(const char* chars, size_t length);
+bool
IsIdentifier(const char16_t* chars, size_t length);
/* True if str is a keyword. Defined in TokenStream.cpp. */
diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp
index 4eb7bf880..b3dd6d777 100644
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -3559,9 +3559,11 @@ BytecodeEmitter::maybeSetSourceMap()
if (parser->options().sourceMapURL()) {
// Warn about the replacement, but use the new one.
if (parser->ss->hasSourceMapURL()) {
- if(!parser->report(ParseWarning, false, nullptr, JSMSG_ALREADY_HAS_PRAGMA,
- parser->ss->filename(), "//# sourceMappingURL"))
+ if (!parser->reportNoOffset(ParseWarning, false, JSMSG_ALREADY_HAS_PRAGMA,
+ parser->ss->filename(), "//# sourceMappingURL"))
+ {
return false;
+ }
}
if (!parser->ss->setSourceMapURL(cx, parser->options().sourceMapURL()))
@@ -3606,13 +3608,13 @@ BytecodeEmitter::reportError(ParseNode* pn, unsigned errorNumber, ...)
}
bool
-BytecodeEmitter::reportStrictWarning(ParseNode* pn, unsigned errorNumber, ...)
+BytecodeEmitter::reportExtraWarning(ParseNode* pn, unsigned errorNumber, ...)
{
TokenPos pos = pn ? pn->pn_pos : tokenStream()->currentToken().pos;
va_list args;
va_start(args, errorNumber);
- bool result = tokenStream()->reportStrictWarningErrorNumberVA(pos.begin, errorNumber, args);
+ bool result = tokenStream()->reportExtraWarningErrorNumberVA(pos.begin, errorNumber, args);
va_end(args);
return result;
}
@@ -7834,7 +7836,8 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto)
Rooted<JSObject*> sourceObject(cx, script->sourceObject());
Rooted<JSScript*> script(cx, JSScript::Create(cx, options, sourceObject,
- funbox->bufStart, funbox->bufEnd));
+ funbox->bufStart, funbox->bufEnd,
+ funbox->preludeStart));
if (!script)
return false;
@@ -8704,13 +8707,13 @@ BytecodeEmitter::emitStatement(ParseNode* pn)
}
if (directive) {
- if (!reportStrictWarning(pn2, JSMSG_CONTRARY_NONDIRECTIVE, directive))
+ if (!reportExtraWarning(pn2, JSMSG_CONTRARY_NONDIRECTIVE, directive))
return false;
}
} else {
current->currentLine = parser->tokenStream.srcCoords.lineNum(pn2->pn_pos.begin);
current->lastColumn = 0;
- if (!reportStrictWarning(pn2, JSMSG_USELESS_EXPR))
+ if (!reportExtraWarning(pn2, JSMSG_USELESS_EXPR))
return false;
}
}
diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h
index 04307c8c1..32668a34c 100644
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -388,7 +388,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
}
bool reportError(ParseNode* pn, unsigned errorNumber, ...);
- bool reportStrictWarning(ParseNode* pn, unsigned errorNumber, ...);
+ bool reportExtraWarning(ParseNode* pn, unsigned errorNumber, ...);
bool reportStrictModeError(ParseNode* pn, unsigned errorNumber, ...);
// If pn contains a useful expression, return true with *answer set to true.
diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h
index 0fd137796..b619cf24c 100644
--- a/js/src/frontend/FullParseHandler.h
+++ b/js/src/frontend/FullParseHandler.h
@@ -670,9 +670,18 @@ class FullParseHandler
pn->setDirectRHSAnonFunction(true);
}
- ParseNode* newFunctionDefinition() {
- return new_<CodeNode>(PNK_FUNCTION, pos());
+ ParseNode* newFunctionStatement() {
+ return new_<CodeNode>(PNK_FUNCTION, JSOP_NOP, pos());
}
+
+ ParseNode* newFunctionExpression() {
+ return new_<CodeNode>(PNK_FUNCTION, JSOP_LAMBDA, pos());
+ }
+
+ ParseNode* newArrowFunction() {
+ return new_<CodeNode>(PNK_FUNCTION, JSOP_LAMBDA_ARROW, pos());
+ }
+
bool setComprehensionLambdaBody(ParseNode* pn, ParseNode* body) {
MOZ_ASSERT(body->isKind(PNK_STATEMENTLIST));
ParseNode* paramsBody = newList(PNK_PARAMSBODY, body);
@@ -699,7 +708,7 @@ class FullParseHandler
}
ParseNode* newModule() {
- return new_<CodeNode>(PNK_MODULE, pos());
+ return new_<CodeNode>(PNK_MODULE, JSOP_NOP, pos());
}
ParseNode* newLexicalScope(LexicalScope::Data* bindings, ParseNode* body) {
@@ -845,7 +854,7 @@ class FullParseHandler
MOZ_MUST_USE ParseNode* setLikelyIIFE(ParseNode* pn) {
return parenthesize(pn);
}
- void setPrologue(ParseNode* pn) {
+ void setInDirectivePrologue(ParseNode* pn) {
pn->pn_prologue = true;
}
diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h
index c58dab431..c3523afe4 100644
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -926,10 +926,14 @@ struct ListNode : public ParseNode
struct CodeNode : public ParseNode
{
- CodeNode(ParseNodeKind kind, const TokenPos& pos)
- : ParseNode(kind, JSOP_NOP, PN_CODE, pos)
+ CodeNode(ParseNodeKind kind, JSOp op, const TokenPos& pos)
+ : ParseNode(kind, op, PN_CODE, pos)
{
MOZ_ASSERT(kind == PNK_FUNCTION || kind == PNK_MODULE);
+ MOZ_ASSERT_IF(kind == PNK_MODULE, op == JSOP_NOP);
+ MOZ_ASSERT(op == JSOP_NOP || // statement, module
+ op == JSOP_LAMBDA_ARROW || // arrow function
+ op == JSOP_LAMBDA); // expression, method, comprehension, accessor, &c.
MOZ_ASSERT(!pn_body);
MOZ_ASSERT(!pn_objbox);
}
diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
index 209265a58..daacbb50b 100644
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -63,13 +63,13 @@ using BindingIter = ParseContext::Scope::BindingIter;
using UsedNamePtr = UsedNameTracker::UsedNameMap::Ptr;
/* Read a token. Report an error and return null() if that token isn't of type tt. */
-#define MUST_MATCH_TOKEN_MOD(tt, modifier, errno) \
+#define MUST_MATCH_TOKEN_MOD(tt, modifier, errorNumber) \
JS_BEGIN_MACRO \
TokenKind token; \
if (!tokenStream.getToken(&token, modifier)) \
return null(); \
if (token != tt) { \
- report(ParseError, false, null(), errno); \
+ error(errorNumber); \
return null(); \
} \
JS_END_MACRO
@@ -441,7 +441,8 @@ UsedNameTracker::rewind(RewindToken token)
}
FunctionBox::FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* traceListHead,
- JSFunction* fun, Directives directives, bool extraWarnings,
+ JSFunction* fun, uint32_t preludeStart,
+ Directives directives, bool extraWarnings,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind)
: ObjectBox(fun, traceListHead),
SharedContext(cx, Kind::ObjectBox, directives, extraWarnings),
@@ -454,6 +455,7 @@ FunctionBox::FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* trac
bufEnd(0),
startLine(1),
startColumn(0),
+ preludeStart(preludeStart),
length(0),
generatorKindBits_(GeneratorKindAsBits(generatorKind)),
asyncKindBits_(AsyncKindAsBits(asyncKind)),
@@ -569,61 +571,116 @@ FunctionBox::initWithEnclosingScope(Scope* enclosingScope)
}
template <typename ParseHandler>
+void
+Parser<ParseHandler>::error(unsigned errorNumber, ...)
+{
+ va_list args;
+ va_start(args, errorNumber);
+#ifdef DEBUG
+ bool result =
+#endif
+ tokenStream.reportCompileErrorNumberVA(pos().begin, JSREPORT_ERROR, errorNumber, args);
+ MOZ_ASSERT(!result, "reporting an error returned true?");
+ va_end(args);
+}
+
+template <typename ParseHandler>
+void
+Parser<ParseHandler>::errorAt(uint32_t offset, unsigned errorNumber, ...)
+{
+ va_list args;
+ va_start(args, errorNumber);
+#ifdef DEBUG
+ bool result =
+#endif
+ tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_ERROR, errorNumber, args);
+ MOZ_ASSERT(!result, "reporting an error returned true?");
+ va_end(args);
+}
+
+template <typename ParseHandler>
bool
-Parser<ParseHandler>::reportHelper(ParseReportKind kind, bool strict, uint32_t offset,
- unsigned errorNumber, va_list args)
+Parser<ParseHandler>::warning(unsigned errorNumber, ...)
{
- bool result = false;
- switch (kind) {
- case ParseError:
- result = tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_ERROR, errorNumber, args);
- break;
- case ParseWarning:
- result =
- tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_WARNING, errorNumber, args);
- break;
- case ParseExtraWarning:
- result = tokenStream.reportStrictWarningErrorNumberVA(offset, errorNumber, args);
- break;
- case ParseStrictError:
- result = tokenStream.reportStrictModeErrorNumberVA(offset, strict, errorNumber, args);
- break;
- }
+ va_list args;
+ va_start(args, errorNumber);
+ bool result =
+ tokenStream.reportCompileErrorNumberVA(pos().begin, JSREPORT_WARNING, errorNumber, args);
+ va_end(args);
return result;
}
template <typename ParseHandler>
bool
-Parser<ParseHandler>::report(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...)
+Parser<ParseHandler>::warningAt(uint32_t offset, unsigned errorNumber, ...)
{
- uint32_t offset = (pn ? handler.getPosition(pn) : pos()).begin;
-
va_list args;
va_start(args, errorNumber);
- bool result = reportHelper(kind, strict, offset, errorNumber, args);
+ bool result =
+ tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_WARNING, errorNumber, args);
va_end(args);
return result;
}
template <typename ParseHandler>
bool
-Parser<ParseHandler>::reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...)
+Parser<ParseHandler>::extraWarning(unsigned errorNumber, ...)
{
va_list args;
va_start(args, errorNumber);
- bool result = reportHelper(kind, strict, TokenStream::NoOffset, errorNumber, args);
+ bool result = tokenStream.reportExtraWarningErrorNumberVA(pos().begin, errorNumber, args);
va_end(args);
return result;
}
template <typename ParseHandler>
bool
-Parser<ParseHandler>::reportWithOffset(ParseReportKind kind, bool strict, uint32_t offset,
- unsigned errorNumber, ...)
+Parser<ParseHandler>::strictModeError(unsigned errorNumber, ...)
+{
+ va_list args;
+ va_start(args, errorNumber);
+ bool res =
+ tokenStream.reportStrictModeErrorNumberVA(pos().begin, pc->sc()->strict(),
+ errorNumber, args);
+ va_end(args);
+ return res;
+}
+
+template <typename ParseHandler>
+bool
+Parser<ParseHandler>::strictModeErrorAt(uint32_t offset, unsigned errorNumber, ...)
{
va_list args;
va_start(args, errorNumber);
- bool result = reportHelper(kind, strict, offset, errorNumber, args);
+ bool res =
+ tokenStream.reportStrictModeErrorNumberVA(offset, pc->sc()->strict(), errorNumber, args);
+ va_end(args);
+ return res;
+}
+
+template <typename ParseHandler>
+bool
+Parser<ParseHandler>::reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...)
+{
+ va_list args;
+ va_start(args, errorNumber);
+ bool result = false;
+ uint32_t offset = TokenStream::NoOffset;
+ switch (kind) {
+ case ParseError:
+ result = tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_ERROR, errorNumber, args);
+ break;
+ case ParseWarning:
+ result =
+ tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_WARNING, errorNumber, args);
+ break;
+ case ParseExtraWarning:
+ result = tokenStream.reportExtraWarningErrorNumberVA(offset, errorNumber, args);
+ break;
+ case ParseStrictError:
+ result = tokenStream.reportStrictModeErrorNumberVA(offset, strict, errorNumber, args);
+ break;
+ }
va_end(args);
return result;
}
@@ -738,7 +795,8 @@ Parser<ParseHandler>::newObjectBox(JSObject* obj)
template <typename ParseHandler>
FunctionBox*
-Parser<ParseHandler>::newFunctionBox(Node fn, JSFunction* fun, Directives inheritedDirectives,
+Parser<ParseHandler>::newFunctionBox(Node fn, JSFunction* fun, uint32_t preludeStart,
+ Directives inheritedDirectives,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
bool tryAnnexB)
{
@@ -753,8 +811,9 @@ Parser<ParseHandler>::newFunctionBox(Node fn, JSFunction* fun, Directives inheri
* function.
*/
FunctionBox* funbox =
- alloc.new_<FunctionBox>(context, alloc, traceListHead, fun, inheritedDirectives,
- options().extraWarningsOption, generatorKind, asyncKind);
+ alloc.new_<FunctionBox>(context, alloc, traceListHead, fun, preludeStart,
+ inheritedDirectives, options().extraWarningsOption,
+ generatorKind, asyncKind);
if (!funbox) {
ReportOutOfMemory(context);
return nullptr;
@@ -822,8 +881,7 @@ Parser<ParseHandler>::parse()
if (!tokenStream.getToken(&tt, TokenStream::Operand))
return null();
if (tt != TOK_EOF) {
- report(ParseError, false, null(), JSMSG_GARBAGE_AFTER_INPUT,
- "script", TokenKindToDesc(tt));
+ error(JSMSG_GARBAGE_AFTER_INPUT, "script", TokenKindToDesc(tt));
return null();
}
if (foldConstants) {
@@ -834,21 +892,6 @@ Parser<ParseHandler>::parse()
return pn;
}
-template <typename ParseHandler>
-bool
-Parser<ParseHandler>::reportBadReturn(Node pn, ParseReportKind kind,
- unsigned errnum, unsigned anonerrnum)
-{
- JSAutoByteString name;
- if (JSAtom* atom = pc->functionBox()->function()->explicitName()) {
- if (!AtomToPrintableString(context, atom, &name))
- return false;
- } else {
- errnum = anonerrnum;
- }
- return report(kind, pc->sc()->strict(), pn, errnum, name.ptr());
-}
-
/*
* Strict mode forbids introducing new definitions for 'eval', 'arguments', or
* for any strict mode reserved keyword.
@@ -879,8 +922,7 @@ Parser<ParseHandler>::checkStrictBinding(PropertyName* name, TokenPos pos)
JSAutoByteString bytes;
if (!AtomToPrintableString(context, name, &bytes))
return false;
- return reportWithOffset(ParseStrictError, pc->sc()->strict(), pos.begin,
- JSMSG_BAD_BINDING, bytes.ptr());
+ return strictModeErrorAt(pos.begin, JSMSG_BAD_BINDING, bytes.ptr());
}
return true;
@@ -916,8 +958,7 @@ Parser<ParseHandler>::reportRedeclaration(HandlePropertyName name, DeclarationKi
JSAutoByteString bytes;
if (!AtomToPrintableString(context, name, &bytes))
return;
- reportWithOffset(ParseError, false, pos.begin, JSMSG_REDECLARED_VAR,
- DeclarationKindString(kind), bytes.ptr());
+ errorAt(pos.begin, JSMSG_REDECLARED_VAR, DeclarationKindString(kind), bytes.ptr());
}
// notePositionalFormalParameter is called for both the arguments of a regular
@@ -937,7 +978,7 @@ Parser<ParseHandler>::notePositionalFormalParameter(Node fn, HandlePropertyName
{
if (AddDeclaredNamePtr p = pc->functionScope().lookupDeclaredNameForAdd(name)) {
if (disallowDuplicateParams) {
- report(ParseError, false, null(), JSMSG_BAD_DUP_ARGS);
+ error(JSMSG_BAD_DUP_ARGS);
return false;
}
@@ -949,11 +990,8 @@ Parser<ParseHandler>::notePositionalFormalParameter(Node fn, HandlePropertyName
JSAutoByteString bytes;
if (!AtomToPrintableString(context, name, &bytes))
return false;
- if (!report(ParseStrictError, pc->sc()->strict(), null(),
- JSMSG_DUPLICATE_FORMAL, bytes.ptr()))
- {
+ if (!strictModeError(JSMSG_DUPLICATE_FORMAL, bytes.ptr()))
return false;
- }
}
*duplicatedParam = true;
@@ -1189,11 +1227,11 @@ Parser<ParseHandler>::checkLexicalDeclarationDirectlyWithinBlock(ParseContext::S
if (!StatementKindIsBraced(stmt.kind()) &&
stmt.kind() != StatementKind::ForLoopLexicalHead)
{
- reportWithOffset(ParseError, false, pos.begin,
- stmt.kind() == StatementKind::Label
- ? JSMSG_LEXICAL_DECL_LABEL
- : JSMSG_LEXICAL_DECL_NOT_IN_BLOCK,
- DeclarationKindString(kind));
+ errorAt(pos.begin,
+ stmt.kind() == StatementKind::Label
+ ? JSMSG_LEXICAL_DECL_LABEL
+ : JSMSG_LEXICAL_DECL_NOT_IN_BLOCK,
+ DeclarationKindString(kind));
return false;
}
@@ -1235,7 +1273,7 @@ Parser<ParseHandler>::noteDeclaredName(HandlePropertyName name, DeclarationKind
AddDeclaredNamePtr p = pc->functionScope().lookupDeclaredNameForAdd(name);
if (p) {
- report(ParseError, false, null(), JSMSG_BAD_DUP_ARGS);
+ error(JSMSG_BAD_DUP_ARGS);
return false;
}
@@ -1249,7 +1287,7 @@ Parser<ParseHandler>::noteDeclaredName(HandlePropertyName name, DeclarationKind
// Functions in block have complex allowances in sloppy mode for being
// labelled that other lexical declarations do not have. Those checks
// are more complex than calling checkLexicalDeclarationDirectlyWithin-
- // Block and are done in checkFunctionDefinition.
+ // Block and are done inline in callers.
ParseContext::Scope* scope = pc->innermostScope();
if (AddDeclaredNamePtr p = scope->lookupDeclaredNameForAdd(name)) {
@@ -1283,7 +1321,7 @@ Parser<ParseHandler>::noteDeclaredName(HandlePropertyName name, DeclarationKind
// contain 'let'. (CatchParameter is the only lexical binding form
// without this restriction.)
if (name == context->names().let) {
- reportWithOffset(ParseError, false, pos.begin, JSMSG_LEXICAL_DECL_DEFINES_LET);
+ errorAt(pos.begin, JSMSG_LEXICAL_DECL_DEFINES_LET);
return false;
}
@@ -1442,8 +1480,7 @@ Parser<FullParseHandler>::checkStatementsEOF()
if (!tokenStream.peekToken(&tt, TokenStream::Operand))
return false;
if (tt != TOK_EOF) {
- report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN,
- "expression", TokenKindToDesc(tt));
+ error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt));
return false;
}
return true;
@@ -1908,7 +1945,7 @@ Parser<FullParseHandler>::evalBody(EvalSharedContext* evalsc)
// script.
if (hasUsedName(context->names().arguments)) {
if (IsArgumentsUsedInLegacyGenerator(context, pc->sc()->compilationEnclosingScope())) {
- report(ParseError, false, nullptr, JSMSG_BAD_GENEXP_BODY, js_arguments_str);
+ error(JSMSG_BAD_GENEXP_BODY, js_arguments_str);
return nullptr;
}
}
@@ -2006,7 +2043,7 @@ Parser<FullParseHandler>::moduleBody(ModuleSharedContext* modulesc)
if (!tokenStream.getToken(&tt, TokenStream::Operand))
return null();
if (tt != TOK_EOF) {
- report(ParseError, false, null(), JSMSG_GARBAGE_AFTER_INPUT, "module", TokenKindToDesc(tt));
+ error(JSMSG_GARBAGE_AFTER_INPUT, "module", TokenKindToDesc(tt));
return null();
}
@@ -2214,6 +2251,7 @@ Parser<SyntaxParseHandler>::finishFunction()
LazyScript* lazy = LazyScript::Create(context, fun, pc->closedOverBindingsForLazy(),
pc->innerFunctionsForLazy, versionNumber(),
funbox->bufStart, funbox->bufEnd,
+ funbox->preludeStart,
funbox->startLine, funbox->startColumn);
if (!lazy)
return false;
@@ -2267,7 +2305,34 @@ Parser<FullParseHandler>::standaloneFunction(HandleFunction fun,
{
MOZ_ASSERT(checkOptionsCalled);
- Node fn = handler.newFunctionDefinition();
+ // Skip prelude.
+ TokenKind tt;
+ if (!tokenStream.getToken(&tt))
+ return null();
+ if (asyncKind == AsyncFunction) {
+ MOZ_ASSERT(tt == TOK_ASYNC);
+ if (!tokenStream.getToken(&tt))
+ return null();
+ }
+ MOZ_ASSERT(tt == TOK_FUNCTION);
+
+ if (!tokenStream.getToken(&tt))
+ return null();
+ if (generatorKind == StarGenerator && asyncKind == SyncFunction) {
+ MOZ_ASSERT(tt == TOK_MUL);
+ if (!tokenStream.getToken(&tt))
+ return null();
+ }
+
+ // Skip function name, if present.
+ if (tt == TOK_NAME || tt == TOK_YIELD) {
+ MOZ_ASSERT(tokenStream.currentName() == fun->explicitName());
+ } else {
+ MOZ_ASSERT(fun->explicitName() == nullptr);
+ tokenStream.ungetToken();
+ }
+
+ Node fn = handler.newFunctionStatement();
if (!fn)
return null();
@@ -2276,8 +2341,8 @@ Parser<FullParseHandler>::standaloneFunction(HandleFunction fun,
return null();
fn->pn_body = argsbody;
- FunctionBox* funbox = newFunctionBox(fn, fun, inheritedDirectives, generatorKind,
- asyncKind, /* tryAnnexB = */ false);
+ FunctionBox* funbox = newFunctionBox(fn, fun, /* preludeStart = */ 0, inheritedDirectives,
+ generatorKind, asyncKind, /* tryAnnexB = */ false);
if (!funbox)
return null();
funbox->initStandaloneFunction(enclosingScope);
@@ -2295,12 +2360,10 @@ Parser<FullParseHandler>::standaloneFunction(HandleFunction fun,
return null();
}
- TokenKind tt;
if (!tokenStream.getToken(&tt, TokenStream::Operand))
return null();
if (tt != TOK_EOF) {
- report(ParseError, false, null(), JSMSG_GARBAGE_AFTER_INPUT,
- "function body", TokenKindToDesc(tt));
+ error(JSMSG_GARBAGE_AFTER_INPUT, "function body", TokenKindToDesc(tt));
return null();
}
@@ -2705,8 +2768,7 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn
if (!tokenStream.getToken(&tt, firstTokenModifier))
return false;
if (tt != TOK_LP) {
- report(ParseError, false, null(),
- kind == Arrow ? JSMSG_BAD_ARROW_ARGS : JSMSG_PAREN_BEFORE_FORMAL);
+ error(kind == Arrow ? JSMSG_BAD_ARROW_ARGS : JSMSG_PAREN_BEFORE_FORMAL);
return false;
}
@@ -2738,13 +2800,13 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn
AtomVector& positionalFormals = pc->positionalFormalParameterNames();
if (IsGetterKind(kind)) {
- report(ParseError, false, null(), JSMSG_ACCESSOR_WRONG_ARGS, "getter", "no", "s");
+ error(JSMSG_ACCESSOR_WRONG_ARGS, "getter", "no", "s");
return false;
}
while (true) {
if (hasRest) {
- report(ParseError, false, null(), JSMSG_PARAMETER_AFTER_REST);
+ error(JSMSG_PARAMETER_AFTER_REST);
return false;
}
@@ -2756,15 +2818,14 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn
if (tt == TOK_TRIPLEDOT) {
if (IsSetterKind(kind)) {
- report(ParseError, false, null(),
- JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", "");
+ error(JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", "");
return false;
}
disallowDuplicateParams = true;
if (duplicatedParam) {
// Has duplicated args before the rest parameter.
- report(ParseError, false, null(), JSMSG_BAD_DUP_ARGS);
+ error(JSMSG_BAD_DUP_ARGS);
return false;
}
@@ -2775,7 +2836,7 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn
return false;
if (tt != TOK_NAME && tt != TOK_YIELD && tt != TOK_LB && tt != TOK_LC) {
- report(ParseError, false, null(), JSMSG_NO_REST_NAME);
+ error(JSMSG_NO_REST_NAME);
return false;
}
}
@@ -2786,7 +2847,7 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn
disallowDuplicateParams = true;
if (duplicatedParam) {
// Has duplicated args before the destructuring parameter.
- report(ParseError, false, null(), JSMSG_BAD_DUP_ARGS);
+ error(JSMSG_BAD_DUP_ARGS);
return false;
}
@@ -2814,7 +2875,7 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn
// case:
//
// async await => 1
- report(ParseError, false, null(), JSMSG_RESERVED_ID, "await");
+ error(JSMSG_RESERVED_ID, "await");
return false;
}
@@ -2834,12 +2895,12 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn
}
default:
- report(ParseError, false, null(), JSMSG_MISSING_FORMAL);
+ error(JSMSG_MISSING_FORMAL);
return false;
}
if (positionalFormals.length() >= ARGNO_LIMIT) {
- report(ParseError, false, null(), JSMSG_TOO_MANY_FUN_ARGS);
+ error(JSMSG_TOO_MANY_FUN_ARGS);
return false;
}
@@ -2854,12 +2915,12 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn
MOZ_ASSERT(!parenFreeArrow);
if (hasRest) {
- report(ParseError, false, null(), JSMSG_REST_WITH_DEFAULT);
+ error(JSMSG_REST_WITH_DEFAULT);
return false;
}
disallowDuplicateParams = true;
if (duplicatedParam) {
- report(ParseError, false, null(), JSMSG_BAD_DUP_ARGS);
+ error(JSMSG_BAD_DUP_ARGS);
return false;
}
@@ -2903,12 +2964,11 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn
return false;
if (tt != TOK_RP) {
if (IsSetterKind(kind)) {
- report(ParseError, false, null(),
- JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", "");
+ error(JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", "");
return false;
}
- report(ParseError, false, null(), JSMSG_PAREN_AFTER_FORMAL);
+ error(JSMSG_PAREN_AFTER_FORMAL);
return false;
}
}
@@ -2921,78 +2981,17 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn
funbox->function()->setArgCount(positionalFormals.length());
} else if (IsSetterKind(kind)) {
- report(ParseError, false, null(), JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", "");
+ error(JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", "");
return false;
}
return true;
}
-template <typename ParseHandler>
-bool
-Parser<ParseHandler>::checkFunctionDefinition(HandleAtom funAtom, Node pn, FunctionSyntaxKind kind,
- GeneratorKind generatorKind, bool* tryAnnexB)
-{
- if (kind == Statement) {
- TokenPos pos = handler.getPosition(pn);
- RootedPropertyName funName(context, funAtom->asPropertyName());
-
- // In sloppy mode, Annex B.3.2 allows labelled function
- // declarations. Otherwise it is a parse error.
- ParseContext::Statement* declaredInStmt = pc->innermostStatement();
- if (declaredInStmt && declaredInStmt->kind() == StatementKind::Label) {
- MOZ_ASSERT(!pc->sc()->strict(),
- "labeled functions shouldn't be parsed in strict mode");
-
- // Find the innermost non-label statement. Report an error if it's
- // unbraced: functions can't appear in it. Otherwise the statement
- // (or its absence) determines the scope the function's bound in.
- while (declaredInStmt && declaredInStmt->kind() == StatementKind::Label)
- declaredInStmt = declaredInStmt->enclosing();
-
- if (declaredInStmt && !StatementKindIsBraced(declaredInStmt->kind())) {
- reportWithOffset(ParseError, false, pos.begin, JSMSG_SLOPPY_FUNCTION_LABEL);
- return false;
- }
- }
-
- if (declaredInStmt) {
- MOZ_ASSERT(declaredInStmt->kind() != StatementKind::Label);
- MOZ_ASSERT(StatementKindIsBraced(declaredInStmt->kind()));
-
- if (!pc->sc()->strict() && generatorKind == NotGenerator) {
- // Under sloppy mode, try Annex B.3.3 semantics. If making an
- // additional 'var' binding of the same name does not throw an
- // early error, do so. This 'var' binding would be assigned
- // the function object when its declaration is reached, not at
- // the start of the block.
-
- if (!tryDeclareVarForAnnexBLexicalFunction(funName, tryAnnexB))
- return false;
- }
-
- if (!noteDeclaredName(funName, DeclarationKind::LexicalFunction, pos))
- return false;
- } else {
- if (!noteDeclaredName(funName, DeclarationKind::BodyLevelFunction, pos))
- return false;
-
- // Body-level functions in modules are always closed over.
- if (pc->atModuleLevel())
- pc->varScope().lookupDeclaredName(funName)->value()->setClosedOver();
- }
- } else {
- // A function expression does not introduce any binding.
- handler.setOp(pn, kind == Arrow ? JSOP_LAMBDA_ARROW : JSOP_LAMBDA);
- }
-
- return true;
-}
-
template <>
bool
-Parser<FullParseHandler>::skipLazyInnerFunction(ParseNode* pn, FunctionSyntaxKind kind,
- bool tryAnnexB)
+Parser<FullParseHandler>::skipLazyInnerFunction(ParseNode* pn, uint32_t preludeStart,
+ FunctionSyntaxKind kind, bool tryAnnexB)
{
// When a lazily-parsed function is called, we only fully parse (and emit)
// that function, not any of its nested children. The initial syntax-only
@@ -3001,7 +3000,7 @@ Parser<FullParseHandler>::skipLazyInnerFunction(ParseNode* pn, FunctionSyntaxKin
RootedFunction fun(context, handler.nextLazyInnerFunction());
MOZ_ASSERT(!fun->isLegacyGenerator());
- FunctionBox* funbox = newFunctionBox(pn, fun, Directives(/* strict = */ false),
+ FunctionBox* funbox = newFunctionBox(pn, fun, preludeStart, Directives(/* strict = */ false),
fun->generatorKind(), fun->asyncKind(), tryAnnexB);
if (!funbox)
return false;
@@ -3031,8 +3030,8 @@ Parser<FullParseHandler>::skipLazyInnerFunction(ParseNode* pn, FunctionSyntaxKin
template <>
bool
-Parser<SyntaxParseHandler>::skipLazyInnerFunction(Node pn, FunctionSyntaxKind kind,
- bool tryAnnexB)
+Parser<SyntaxParseHandler>::skipLazyInnerFunction(Node pn, uint32_t preludeStart,
+ FunctionSyntaxKind kind, bool tryAnnexB)
{
MOZ_CRASH("Cannot skip lazy inner functions when syntax parsing");
}
@@ -3051,7 +3050,7 @@ Parser<ParseHandler>::addExprAndGetNextTemplStrToken(YieldHandling yieldHandling
if (!tokenStream.getToken(&tt))
return false;
if (tt != TOK_RC) {
- report(ParseError, false, null(), JSMSG_TEMPLSTR_UNTERM_EXPR);
+ error(JSMSG_TEMPLSTR_UNTERM_EXPR);
return false;
}
@@ -3108,31 +3107,20 @@ Parser<ParseHandler>::templateLiteral(YieldHandling yieldHandling)
template <typename ParseHandler>
typename ParseHandler::Node
-Parser<ParseHandler>::functionDefinition(InHandling inHandling, YieldHandling yieldHandling,
+Parser<ParseHandler>::functionDefinition(uint32_t preludeStart, Node pn, InHandling inHandling,
+ YieldHandling yieldHandling,
HandleAtom funName, FunctionSyntaxKind kind,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
- InvokedPrediction invoked)
+ bool tryAnnexB /* = false */)
{
MOZ_ASSERT_IF(kind == Statement, funName);
MOZ_ASSERT_IF(asyncKind == AsyncFunction, generatorKind == StarGenerator);
- Node pn = handler.newFunctionDefinition();
- if (!pn)
- return null();
-
- if (invoked)
- pn = handler.setLikelyIIFE(pn);
-
- // Note the declared name and check for early errors.
- bool tryAnnexB = false;
- if (!checkFunctionDefinition(funName, pn, kind, generatorKind, &tryAnnexB))
- return null();
-
// When fully parsing a LazyScript, we do not fully reparse its inner
// functions, which are also lazy. Instead, their free variables and
// source extents are recorded and may be skipped.
if (handler.canSkipLazyInnerFunctions()) {
- if (!skipLazyInnerFunction(pn, kind, tryAnnexB))
+ if (!skipLazyInnerFunction(pn, preludeStart, kind, tryAnnexB))
return null();
return pn;
}
@@ -3165,8 +3153,9 @@ Parser<ParseHandler>::functionDefinition(InHandling inHandling, YieldHandling yi
// reparse a function due to failed syntax parsing and encountering new
// "use foo" directives.
while (true) {
- if (trySyntaxParseInnerFunction(pn, fun, inHandling, yieldHandling, kind, generatorKind,
- asyncKind, tryAnnexB, directives, &newDirectives))
+ if (trySyntaxParseInnerFunction(pn, fun, preludeStart, inHandling, yieldHandling, kind,
+ generatorKind, asyncKind, tryAnnexB, directives,
+ &newDirectives))
{
break;
}
@@ -3193,6 +3182,7 @@ Parser<ParseHandler>::functionDefinition(InHandling inHandling, YieldHandling yi
template <>
bool
Parser<FullParseHandler>::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunction fun,
+ uint32_t preludeStart,
InHandling inHandling,
YieldHandling yieldHandling,
FunctionSyntaxKind kind,
@@ -3226,14 +3216,15 @@ Parser<FullParseHandler>::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunct
// Make a FunctionBox before we enter the syntax parser, because |pn|
// still expects a FunctionBox to be attached to it during BCE, and
// the syntax parser cannot attach one to it.
- FunctionBox* funbox = newFunctionBox(pn, fun, inheritedDirectives, generatorKind,
- asyncKind, tryAnnexB);
+ FunctionBox* funbox = newFunctionBox(pn, fun, preludeStart, inheritedDirectives,
+ generatorKind, asyncKind, tryAnnexB);
if (!funbox)
return false;
funbox->initWithEnclosingParseContext(pc, kind);
- if (!parser->innerFunction(SyntaxParseHandler::NodeGeneric, pc, funbox, inHandling,
- yieldHandling, kind, inheritedDirectives, newDirectives))
+ if (!parser->innerFunction(SyntaxParseHandler::NodeGeneric, pc, funbox, preludeStart,
+ inHandling, yieldHandling, kind,
+ inheritedDirectives, newDirectives))
{
if (parser->hadAbortedSyntaxParse()) {
// Try again with a full parse. UsedNameTracker needs to be
@@ -3259,13 +3250,14 @@ Parser<FullParseHandler>::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunct
} while (false);
// We failed to do a syntax parse above, so do the full parse.
- return innerFunction(pn, pc, fun, inHandling, yieldHandling, kind, generatorKind, asyncKind,
- tryAnnexB, inheritedDirectives, newDirectives);
+ return innerFunction(pn, pc, fun, preludeStart, inHandling, yieldHandling, kind,
+ generatorKind, asyncKind, tryAnnexB, inheritedDirectives, newDirectives);
}
template <>
bool
Parser<SyntaxParseHandler>::trySyntaxParseInnerFunction(Node pn, HandleFunction fun,
+ uint32_t preludeStart,
InHandling inHandling,
YieldHandling yieldHandling,
FunctionSyntaxKind kind,
@@ -3276,13 +3268,14 @@ Parser<SyntaxParseHandler>::trySyntaxParseInnerFunction(Node pn, HandleFunction
Directives* newDirectives)
{
// This is already a syntax parser, so just parse the inner function.
- return innerFunction(pn, pc, fun, inHandling, yieldHandling, kind, generatorKind, asyncKind,
- tryAnnexB, inheritedDirectives, newDirectives);
+ return innerFunction(pn, pc, fun, preludeStart, inHandling, yieldHandling, kind,
+ generatorKind, asyncKind, tryAnnexB, inheritedDirectives, newDirectives);
}
template <typename ParseHandler>
bool
Parser<ParseHandler>::innerFunction(Node pn, ParseContext* outerpc, FunctionBox* funbox,
+ uint32_t preludeStart,
InHandling inHandling, YieldHandling yieldHandling,
FunctionSyntaxKind kind, Directives inheritedDirectives,
Directives* newDirectives)
@@ -3306,6 +3299,7 @@ Parser<ParseHandler>::innerFunction(Node pn, ParseContext* outerpc, FunctionBox*
template <typename ParseHandler>
bool
Parser<ParseHandler>::innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun,
+ uint32_t preludeStart,
InHandling inHandling, YieldHandling yieldHandling,
FunctionSyntaxKind kind,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
@@ -3317,14 +3311,14 @@ Parser<ParseHandler>::innerFunction(Node pn, ParseContext* outerpc, HandleFuncti
// parser. In that case, outerpc is a ParseContext from the full parser
// instead of the current top of the stack of the syntax parser.
- FunctionBox* funbox = newFunctionBox(pn, fun, inheritedDirectives, generatorKind,
- asyncKind, tryAnnexB);
+ FunctionBox* funbox = newFunctionBox(pn, fun, preludeStart, inheritedDirectives,
+ generatorKind, asyncKind, tryAnnexB);
if (!funbox)
return false;
funbox->initWithEnclosingParseContext(outerpc, kind);
- return innerFunction(pn, outerpc, funbox, inHandling, yieldHandling, kind, inheritedDirectives,
- newDirectives);
+ return innerFunction(pn, outerpc, funbox, preludeStart, inHandling, yieldHandling, kind,
+ inheritedDirectives, newDirectives);
}
template <typename ParseHandler>
@@ -3354,13 +3348,13 @@ Parser<FullParseHandler>::standaloneLazyFunction(HandleFunction fun, bool strict
{
MOZ_ASSERT(checkOptionsCalled);
- Node pn = handler.newFunctionDefinition();
+ Node pn = handler.newFunctionStatement();
if (!pn)
return null();
Directives directives(strict);
- FunctionBox* funbox = newFunctionBox(pn, fun, directives, generatorKind, asyncKind,
- /* tryAnnexB = */ false);
+ FunctionBox* funbox = newFunctionBox(pn, fun, /* preludeStart = */ 0, directives,
+ generatorKind, asyncKind, /* tryAnnexB = */ false);
if (!funbox)
return null();
funbox->initFromLazyFunction();
@@ -3436,7 +3430,7 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
if (!tokenStream.matchToken(&matched, TOK_ARROW))
return false;
if (!matched) {
- report(ParseError, false, null(), JSMSG_BAD_ARROW_ARGS);
+ error(JSMSG_BAD_ARROW_ARGS);
return false;
}
}
@@ -3444,7 +3438,7 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
// When parsing something for new Function() we have to make sure to
// only treat a certain part of the source as a parameter list.
if (parameterListEnd.isSome() && parameterListEnd.value() != pos().begin) {
- report(ParseError, false, null(), JSMSG_UNEXPECTED_PARAMLIST_END);
+ error(JSMSG_UNEXPECTED_PARAMLIST_END);
return false;
}
@@ -3457,7 +3451,7 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
if ((funbox->isStarGenerator() && !funbox->isAsync()) || kind == Method ||
kind == GetterNoExpressionClosure || kind == SetterNoExpressionClosure ||
IsConstructorKind(kind)) {
- report(ParseError, false, null(), JSMSG_CURLY_BEFORE_BODY);
+ error(JSMSG_CURLY_BEFORE_BODY);
return false;
}
@@ -3466,7 +3460,7 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
if (!warnOnceAboutExprClosure())
return false;
#else
- report(ParseError, false, null(), JSMSG_CURLY_BEFORE_BODY);
+ error(JSMSG_CURLY_BEFORE_BODY);
return false;
#endif
}
@@ -3499,7 +3493,7 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
if (!tokenStream.matchToken(&matched, TOK_RC, TokenStream::Operand))
return false;
if (!matched) {
- report(ParseError, false, null(), JSMSG_CURLY_AFTER_BODY);
+ error(JSMSG_CURLY_AFTER_BODY);
return false;
}
funbox->bufEnd = pos().end;
@@ -3529,8 +3523,8 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
template <typename ParseHandler>
typename ParseHandler::Node
-Parser<ParseHandler>::functionStmt(YieldHandling yieldHandling, DefaultHandling defaultHandling,
- FunctionAsyncKind asyncKind)
+Parser<ParseHandler>::functionStmt(uint32_t preludeStart, YieldHandling yieldHandling,
+ DefaultHandling defaultHandling, FunctionAsyncKind asyncKind)
{
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION));
@@ -3549,15 +3543,33 @@ Parser<ParseHandler>::functionStmt(YieldHandling yieldHandling, DefaultHandling
}
}
- RootedPropertyName name(context);
- GeneratorKind generatorKind = asyncKind == AsyncFunction ? StarGenerator : NotGenerator;
+ // In sloppy mode, Annex B.3.2 allows labelled function declarations.
+ // Otherwise it's a parse error.
+ ParseContext::Statement* declaredInStmt = pc->innermostStatement();
+ if (declaredInStmt && declaredInStmt->kind() == StatementKind::Label) {
+ MOZ_ASSERT(!pc->sc()->strict(),
+ "labeled functions shouldn't be parsed in strict mode");
+
+ // Find the innermost non-label statement. Report an error if it's
+ // unbraced: functions can't appear in it. Otherwise the statement
+ // (or its absence) determines the scope the function's bound in.
+ while (declaredInStmt && declaredInStmt->kind() == StatementKind::Label)
+ declaredInStmt = declaredInStmt->enclosing();
+
+ if (declaredInStmt && !StatementKindIsBraced(declaredInStmt->kind())) {
+ error(JSMSG_SLOPPY_FUNCTION_LABEL);
+ return null();
+ }
+ }
+
TokenKind tt;
if (!tokenStream.getToken(&tt))
return null();
+ GeneratorKind generatorKind = asyncKind == AsyncFunction ? StarGenerator : NotGenerator;
if (tt == TOK_MUL) {
if (asyncKind != SyncFunction) {
- report(ParseError, false, null(), JSMSG_ASYNC_GENERATOR);
+ error(JSMSG_ASYNC_GENERATOR);
return null();
}
generatorKind = StarGenerator;
@@ -3565,6 +3577,7 @@ Parser<ParseHandler>::functionStmt(YieldHandling yieldHandling, DefaultHandling
return null();
}
+ RootedPropertyName name(context);
if (tt == TOK_NAME || tt == TOK_YIELD) {
name = bindingIdentifier(yieldHandling);
if (!name)
@@ -3574,13 +3587,44 @@ Parser<ParseHandler>::functionStmt(YieldHandling yieldHandling, DefaultHandling
tokenStream.ungetToken();
} else {
/* Unnamed function expressions are forbidden in statement context. */
- report(ParseError, false, null(), JSMSG_UNNAMED_FUNCTION_STMT);
+ error(JSMSG_UNNAMED_FUNCTION_STMT);
return null();
}
+ // Note the declared name and check for early errors.
+ bool tryAnnexB = false;
+ if (declaredInStmt) {
+ MOZ_ASSERT(declaredInStmt->kind() != StatementKind::Label);
+ MOZ_ASSERT(StatementKindIsBraced(declaredInStmt->kind()));
+
+ if (!pc->sc()->strict() && generatorKind == NotGenerator) {
+ // In sloppy mode, try Annex B.3.3 semantics. If making an
+ // additional 'var' binding of the same name does not throw an
+ // early error, do so. This 'var' binding would be assigned
+ // the function object when its declaration is reached, not at
+ // the start of the block.
+ if (!tryDeclareVarForAnnexBLexicalFunction(name, &tryAnnexB))
+ return null();
+ }
+
+ if (!noteDeclaredName(name, DeclarationKind::LexicalFunction, pos()))
+ return null();
+ } else {
+ if (!noteDeclaredName(name, DeclarationKind::BodyLevelFunction, pos()))
+ return null();
+
+ // Body-level functions in modules are always closed over.
+ if (pc->atModuleLevel())
+ pc->varScope().lookupDeclaredName(name)->value()->setClosedOver();
+ }
+
+ Node pn = handler.newFunctionStatement();
+ if (!pn)
+ return null();
+
YieldHandling newYieldHandling = GetYieldHandling(generatorKind, asyncKind);
- Node fun = functionDefinition(InAllowed, newYieldHandling, name, Statement, generatorKind,
- asyncKind, PredictUninvoked);
+ Node fun = functionDefinition(preludeStart, pn, InAllowed, newYieldHandling,
+ name, Statement, generatorKind, asyncKind, tryAnnexB);
if (!fun)
return null();
@@ -3597,7 +3641,8 @@ Parser<ParseHandler>::functionStmt(YieldHandling yieldHandling, DefaultHandling
template <typename ParseHandler>
typename ParseHandler::Node
-Parser<ParseHandler>::functionExpr(InvokedPrediction invoked, FunctionAsyncKind asyncKind)
+Parser<ParseHandler>::functionExpr(uint32_t preludeStart, InvokedPrediction invoked,
+ FunctionAsyncKind asyncKind)
{
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION));
@@ -3609,7 +3654,7 @@ Parser<ParseHandler>::functionExpr(InvokedPrediction invoked, FunctionAsyncKind
if (tt == TOK_MUL) {
if (asyncKind != SyncFunction) {
- report(ParseError, false, null(), JSMSG_ASYNC_GENERATOR);
+ error(JSMSG_ASYNC_GENERATOR);
return null();
}
generatorKind = StarGenerator;
@@ -3628,8 +3673,15 @@ Parser<ParseHandler>::functionExpr(InvokedPrediction invoked, FunctionAsyncKind
tokenStream.ungetToken();
}
- return functionDefinition(InAllowed, yieldHandling, name, Expression, generatorKind,
- asyncKind, invoked);
+ Node pn = handler.newFunctionExpression();
+ if (!pn)
+ return null();
+
+ if (invoked)
+ pn = handler.setLikelyIIFE(pn);
+
+ return functionDefinition(preludeStart, pn, InAllowed, yieldHandling, name, Expression,
+ generatorKind, asyncKind);
}
/*
@@ -3654,10 +3706,11 @@ template <typename ParseHandler>
bool
Parser<ParseHandler>::checkUnescapedName()
{
- if (!tokenStream.currentToken().nameContainsEscape())
+ const Token& token = tokenStream.currentToken();
+ if (!token.nameContainsEscape())
return true;
- report(ParseError, false, null(), JSMSG_ESCAPED_KEYWORD);
+ errorAt(token.pos.begin, JSMSG_ESCAPED_KEYWORD);
return false;
}
@@ -3733,10 +3786,10 @@ Parser<FullParseHandler>::asmJS(Node list)
*/
template <typename ParseHandler>
bool
-Parser<ParseHandler>::maybeParseDirective(Node list, Node pn, bool* cont)
+Parser<ParseHandler>::maybeParseDirective(Node list, Node possibleDirective, bool* cont)
{
TokenPos directivePos;
- JSAtom* directive = handler.isStringExprStatement(pn, &directivePos);
+ JSAtom* directive = handler.isStringExprStatement(possibleDirective, &directivePos);
*cont = !!directive;
if (!*cont)
@@ -3753,7 +3806,7 @@ Parser<ParseHandler>::maybeParseDirective(Node list, Node pn, bool* cont)
// directive in the future. We don't want to interfere with people
// taking advantage of directive-prologue-enabled features that appear
// in other browsers first.
- handler.setPrologue(pn);
+ handler.setInDirectivePrologue(possibleDirective);
if (directive == context->names().useStrict) {
// Functions with non-simple parameter lists (destructuring,
@@ -3767,8 +3820,7 @@ Parser<ParseHandler>::maybeParseDirective(Node list, Node pn, bool* cont)
: funbox->hasParameterExprs
? "default"
: "rest";
- reportWithOffset(ParseError, false, directivePos.begin,
- JSMSG_STRICT_NON_SIMPLE_PARAMS, parameterKind);
+ errorAt(directivePos.begin, JSMSG_STRICT_NON_SIMPLE_PARAMS, parameterKind);
return false;
}
}
@@ -3781,7 +3833,7 @@ Parser<ParseHandler>::maybeParseDirective(Node list, Node pn, bool* cont)
// occur in the directive prologue -- octal escapes -- and
// complain now.
if (tokenStream.sawOctalEscape()) {
- report(ParseError, false, null(), JSMSG_DEPRECATED_OCTAL);
+ error(JSMSG_DEPRECATED_OCTAL);
return false;
}
pc->sc()->strictScript = true;
@@ -3789,7 +3841,7 @@ Parser<ParseHandler>::maybeParseDirective(Node list, Node pn, bool* cont)
} else if (directive == context->names().useAsm) {
if (pc->isFunctionBox())
return asmJS(list);
- return report(ParseWarning, false, pn, JSMSG_USE_ASM_DIRECTIVE_FAIL);
+ return warningAt(directivePos.begin, JSMSG_USE_ASM_DIRECTIVE_FAIL);
}
}
return true;
@@ -3821,10 +3873,8 @@ Parser<ParseHandler>::statementList(YieldHandling yieldHandling)
if (tt == TOK_EOF || tt == TOK_RC)
break;
if (afterReturn) {
- TokenPos pos(0, 0);
- if (!tokenStream.peekTokenPos(&pos, TokenStream::Operand))
+ if (!tokenStream.peekOffset(&statementBegin, TokenStream::Operand))
return null();
- statementBegin = pos.begin;
}
Node next = statementListItem(yieldHandling, canHaveDirectives);
if (!next) {
@@ -3835,11 +3885,9 @@ Parser<ParseHandler>::statementList(YieldHandling yieldHandling)
if (!warnedAboutStatementsAfterReturn) {
if (afterReturn) {
if (!handler.isStatementPermittedAfterReturnStatement(next)) {
- if (!reportWithOffset(ParseWarning, false, statementBegin,
- JSMSG_STMT_AFTER_RETURN))
- {
+ if (!warningAt(statementBegin, JSMSG_STMT_AFTER_RETURN))
return null();
- }
+
warnedAboutStatementsAfterReturn = true;
}
} else if (handler.isReturnStatement(next)) {
@@ -3870,7 +3918,7 @@ Parser<ParseHandler>::condition(InHandling inHandling, YieldHandling yieldHandli
/* Check for (a = b) and warn about possible (a == b) mistype. */
if (handler.isUnparenthesizedAssignment(pn)) {
- if (!report(ParseExtraWarning, false, null(), JSMSG_EQUAL_AS_ASSIGN))
+ if (!extraWarning(JSMSG_EQUAL_AS_ASSIGN))
return null();
}
return pn;
@@ -3927,7 +3975,8 @@ Parser<ParseHandler>::PossibleError::hasError(ErrorKind kind)
template <typename ParseHandler>
void
-Parser<ParseHandler>::PossibleError::setPending(ErrorKind kind, Node pn, unsigned errorNumber)
+Parser<ParseHandler>::PossibleError::setPending(ErrorKind kind, const TokenPos& pos,
+ unsigned errorNumber)
{
// Don't overwrite a previously recorded error.
if (hasError(kind))
@@ -3936,23 +3985,25 @@ Parser<ParseHandler>::PossibleError::setPending(ErrorKind kind, Node pn, unsigne
// If we report an error later, we'll do it from the position where we set
// the state to pending.
Error& err = error(kind);
- err.offset_ = (pn ? parser_.handler.getPosition(pn) : parser_.pos()).begin;
+ err.offset_ = pos.begin;
err.errorNumber_ = errorNumber;
err.state_ = ErrorState::Pending;
}
template <typename ParseHandler>
void
-Parser<ParseHandler>::PossibleError::setPendingDestructuringError(Node pn, unsigned errorNumber)
+Parser<ParseHandler>::PossibleError::setPendingDestructuringErrorAt(const TokenPos& pos,
+ unsigned errorNumber)
{
- setPending(ErrorKind::Destructuring, pn, errorNumber);
+ setPending(ErrorKind::Destructuring, pos, errorNumber);
}
template <typename ParseHandler>
void
-Parser<ParseHandler>::PossibleError::setPendingExpressionError(Node pn, unsigned errorNumber)
+Parser<ParseHandler>::PossibleError::setPendingExpressionErrorAt(const TokenPos& pos,
+ unsigned errorNumber)
{
- setPending(ErrorKind::Expression, pn, errorNumber);
+ setPending(ErrorKind::Expression, pos, errorNumber);
}
template <typename ParseHandler>
@@ -3963,7 +4014,7 @@ Parser<ParseHandler>::PossibleError::checkForError(ErrorKind kind)
return true;
Error& err = error(kind);
- parser_.reportWithOffset(ParseError, false, err.offset_, err.errorNumber_);
+ parser_.errorAt(err.offset_, err.errorNumber_);
return false;
}
@@ -4017,19 +4068,6 @@ Parser<ParseHandler>::PossibleError::transferErrorsTo(PossibleError* other)
transferErrorTo(ErrorKind::Expression, other);
}
-template <typename ParseHandler>
-bool
-Parser<ParseHandler>::checkAssignmentToCall(Node target, unsigned msg)
-{
- MOZ_ASSERT(handler.isFunctionCall(target));
-
- // Assignment to function calls is forbidden in ES6. We're still somewhat
- // concerned about sites using this in dead code, so forbid it only in
- // strict mode code (or if the werror option has been set), and otherwise
- // warn.
- return report(ParseStrictError, pc->sc()->strict(), target, msg);
-}
-
template <>
bool
Parser<FullParseHandler>::checkDestructuringName(ParseNode* expr, Maybe<DeclarationKind> maybeDecl)
@@ -4040,7 +4078,7 @@ Parser<FullParseHandler>::checkDestructuringName(ParseNode* expr, Maybe<Declarat
// around names). Use our nicer error message for parenthesized, nested
// patterns.
if (handler.isParenthesizedDestructuringPattern(expr)) {
- report(ParseError, false, expr, JSMSG_BAD_DESTRUCT_PARENS);
+ errorAt(expr->pn_pos.begin, JSMSG_BAD_DESTRUCT_PARENS);
return false;
}
@@ -4050,31 +4088,29 @@ Parser<FullParseHandler>::checkDestructuringName(ParseNode* expr, Maybe<Declarat
// Destructuring patterns in declarations must only contain
// unparenthesized names.
if (!handler.isUnparenthesizedName(expr)) {
- report(ParseError, false, expr, JSMSG_NO_VARIABLE_NAME);
+ errorAt(expr->pn_pos.begin, JSMSG_NO_VARIABLE_NAME);
return false;
}
RootedPropertyName name(context, expr->name());
- return noteDeclaredName(name, *maybeDecl, handler.getPosition(expr));
+ return noteDeclaredName(name, *maybeDecl, expr->pn_pos);
}
// Otherwise this is an expression in destructuring outside a declaration.
- if (!reportIfNotValidSimpleAssignmentTarget(expr, KeyedDestructuringAssignment))
- return false;
-
- MOZ_ASSERT(!handler.isFunctionCall(expr),
- "function calls shouldn't be considered valid targets in "
- "destructuring patterns");
-
if (handler.isNameAnyParentheses(expr)) {
- // The arguments/eval identifiers are simple in non-strict mode code.
- // Warn to discourage their use nonetheless.
- return reportIfArgumentsEvalTarget(expr);
+ if (const char* chars = handler.nameIsArgumentsEvalAnyParentheses(expr, context)) {
+ if (!strictModeErrorAt(expr->pn_pos.begin, JSMSG_BAD_STRICT_ASSIGN, chars))
+ return false;
+ }
+
+ return true;
}
- // Nothing further to do for property accesses.
- MOZ_ASSERT(handler.isPropertyAccess(expr));
- return true;
+ if (handler.isPropertyAccess(expr))
+ return true;
+
+ errorAt(expr->pn_pos.begin, JSMSG_BAD_DESTRUCT_TARGET);
+ return false;
}
template <>
@@ -4132,7 +4168,7 @@ Parser<FullParseHandler>::checkDestructuringArray(ParseNode* arrayPattern,
ParseNode* target;
if (element->isKind(PNK_SPREAD)) {
if (element->pn_next) {
- report(ParseError, false, element->pn_next, JSMSG_PARAMETER_AFTER_REST);
+ errorAt(element->pn_next->pn_pos.begin, JSMSG_PARAMETER_AFTER_REST);
return false;
}
target = element->pn_kid;
@@ -4195,7 +4231,7 @@ Parser<FullParseHandler>::checkDestructuringPattern(ParseNode* pattern,
PossibleError* possibleError /* = nullptr */)
{
if (pattern->isKind(PNK_ARRAYCOMP)) {
- report(ParseError, false, pattern, JSMSG_ARRAY_COMP_LEFTSIDE);
+ errorAt(pattern->pn_pos.begin, JSMSG_ARRAY_COMP_LEFTSIDE);
return false;
}
@@ -4252,11 +4288,11 @@ Parser<ParseHandler>::destructuringDeclarationWithoutYieldOrAwait(DeclarationKin
Node res = destructuringDeclaration(kind, yieldHandling, tt);
if (res) {
if (pc->lastYieldOffset != startYieldOffset) {
- reportWithOffset(ParseError, false, pc->lastYieldOffset, JSMSG_YIELD_IN_DEFAULT);
+ errorAt(pc->lastYieldOffset, JSMSG_YIELD_IN_DEFAULT);
return null();
}
if (pc->lastAwaitOffset != startAwaitOffset) {
- reportWithOffset(ParseError, false, pc->lastAwaitOffset, JSMSG_AWAIT_IN_DEFAULT);
+ errorAt(pc->lastAwaitOffset, JSMSG_AWAIT_IN_DEFAULT);
return null();
}
}
@@ -4334,14 +4370,7 @@ Parser<ParseHandler>::declarationPattern(Node decl, DeclarationKind declKind, To
}
}
- TokenKind token;
- if (!tokenStream.getToken(&token, TokenStream::None))
- return null();
-
- if (token != TOK_ASSIGN) {
- report(ParseError, false, null(), JSMSG_BAD_DESTRUCT_DECL);
- return null();
- }
+ MUST_MATCH_TOKEN(TOK_ASSIGN, JSMSG_BAD_DESTRUCT_DECL);
Node init = assignExpr(forHeadKind ? InProhibited : InAllowed,
yieldHandling, TripledotProhibited);
@@ -4374,6 +4403,10 @@ Parser<ParseHandler>::initializerInNameDeclaration(Node decl, Node binding,
{
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_ASSIGN));
+ uint32_t initializerOffset;
+ if (!tokenStream.peekOffset(&initializerOffset, TokenStream::Operand))
+ return false;
+
Node initializer = assignExpr(forHeadKind ? InProhibited : InAllowed,
yieldHandling, TripledotProhibited);
if (!initializer)
@@ -4391,7 +4424,7 @@ Parser<ParseHandler>::initializerInNameDeclaration(Node decl, Node binding,
//
// for (var/let/const x = ... of ...); // BAD
if (isForOf) {
- report(ParseError, false, binding, JSMSG_BAD_FOR_LEFTSIDE);
+ errorAt(initializerOffset, JSMSG_OF_AFTER_FOR_LOOP_DECL);
return false;
}
@@ -4400,18 +4433,15 @@ Parser<ParseHandler>::initializerInNameDeclaration(Node decl, Node binding,
//
// for (let/const x = ... in ...); // BAD
if (DeclarationKindIsLexical(declKind)) {
- report(ParseError, false, binding, JSMSG_BAD_FOR_LEFTSIDE);
+ errorAt(initializerOffset, JSMSG_IN_AFTER_LEXICAL_FOR_DECL);
return false;
}
// This leaves only initialized for-in |var| declarations. ES6
// forbids these; later ES un-forbids in non-strict mode code.
*forHeadKind = PNK_FORIN;
- if (!report(ParseStrictError, pc->sc()->strict(), initializer,
- JSMSG_INVALID_FOR_IN_DECL_WITH_INIT))
- {
+ if (!strictModeErrorAt(initializerOffset, JSMSG_INVALID_FOR_IN_DECL_WITH_INIT))
return false;
- }
*forInOrOfExpression = expressionAfterForInOrOf(PNK_FORIN, yieldHandling);
if (!*forInOrOfExpression)
@@ -4456,7 +4486,7 @@ Parser<ParseHandler>::declarationName(Node decl, DeclarationKind declKind, Token
{
// Anything other than TOK_YIELD or TOK_NAME is an error.
if (tt != TOK_NAME && tt != TOK_YIELD) {
- report(ParseError, false, null(), JSMSG_NO_VARIABLE_NAME);
+ error(JSMSG_NO_VARIABLE_NAME);
return null();
}
@@ -4516,7 +4546,7 @@ Parser<ParseHandler>::declarationName(Node decl, DeclarationKind declKind, Token
// Normal const declarations, and const declarations in for(;;)
// heads, must be initialized.
if (declKind == DeclarationKind::Const) {
- report(ParseError, false, binding, JSMSG_BAD_CONST_DECL);
+ errorAt(namePos.begin, JSMSG_BAD_CONST_DECL);
return null();
}
}
@@ -4656,7 +4686,7 @@ Parser<FullParseHandler>::namedImportsOrNamespaceImport(TokenKind tt, Node impor
return false;
if (afterAs != TOK_NAME && afterAs != TOK_YIELD) {
- report(ParseError, false, null(), JSMSG_NO_BINDING_NAME);
+ error(JSMSG_NO_BINDING_NAME);
return false;
}
} else {
@@ -4668,7 +4698,7 @@ Parser<FullParseHandler>::namedImportsOrNamespaceImport(TokenKind tt, Node impor
JSAutoByteString bytes;
if (!AtomToPrintableString(context, importName, &bytes))
return false;
- report(ParseError, false, null(), JSMSG_AS_AFTER_RESERVED_WORD, bytes.ptr());
+ error(JSMSG_AS_AFTER_RESERVED_WORD, bytes.ptr());
return false;
}
}
@@ -4710,7 +4740,7 @@ Parser<FullParseHandler>::namedImportsOrNamespaceImport(TokenKind tt, Node impor
return false;
if (tt != TOK_NAME || tokenStream.currentName() != context->names().as) {
- report(ParseError, false, null(), JSMSG_AS_AFTER_IMPORT_STAR);
+ error(JSMSG_AS_AFTER_IMPORT_STAR);
return false;
}
@@ -4765,7 +4795,7 @@ Parser<FullParseHandler>::importDeclaration()
MOZ_ASSERT(tokenStream.currentToken().type == TOK_IMPORT);
if (!pc->atModuleLevel()) {
- report(ParseError, false, null(), JSMSG_IMPORT_DECL_AT_TOP_LEVEL);
+ error(JSMSG_IMPORT_DECL_AT_TOP_LEVEL);
return null();
}
@@ -4814,7 +4844,7 @@ Parser<FullParseHandler>::importDeclaration()
return null();
if (tt != TOK_LC && tt != TOK_MUL) {
- report(ParseError, false, null(), JSMSG_NAMED_IMPORTS_OR_NAMESPACE_IMPORT);
+ error(JSMSG_NAMED_IMPORTS_OR_NAMESPACE_IMPORT);
return null();
}
@@ -4830,7 +4860,7 @@ Parser<FullParseHandler>::importDeclaration()
return null();
if (tt != TOK_NAME || tokenStream.currentName() != context->names().from) {
- report(ParseError, false, null(), JSMSG_FROM_AFTER_IMPORT_CLAUSE);
+ error(JSMSG_FROM_AFTER_IMPORT_CLAUSE);
return null();
}
@@ -4843,7 +4873,7 @@ Parser<FullParseHandler>::importDeclaration()
// equivalent to |import {} from 'a'|.
importSpecSet->pn_pos.end = importSpecSet->pn_pos.begin;
} else {
- report(ParseError, false, null(), JSMSG_DECLARATION_AFTER_IMPORT);
+ error(JSMSG_DECLARATION_AFTER_IMPORT);
return null();
}
@@ -4881,7 +4911,7 @@ Parser<FullParseHandler>::checkExportedName(JSAtom* exportName)
if (!AtomToPrintableString(context, exportName, &str))
return false;
- report(ParseError, false, null(), JSMSG_DUPLICATE_EXPORT_NAME, str.ptr());
+ error(JSMSG_DUPLICATE_EXPORT_NAME, str.ptr());
return false;
}
@@ -4924,7 +4954,7 @@ Parser<FullParseHandler>::exportDeclaration()
MOZ_ASSERT(tokenStream.currentToken().type == TOK_EXPORT);
if (!pc->atModuleLevel()) {
- report(ParseError, false, null(), JSMSG_EXPORT_DECL_AT_TOP_LEVEL);
+ error(JSMSG_EXPORT_DECL_AT_TOP_LEVEL);
return null();
}
@@ -4957,14 +4987,8 @@ Parser<FullParseHandler>::exportDeclaration()
bool foundAs;
if (!tokenStream.matchContextualKeyword(&foundAs, context->names().as))
return null();
- if (foundAs) {
- if (!tokenStream.getToken(&tt, TokenStream::KeywordIsName))
- return null();
- if (tt != TOK_NAME) {
- report(ParseError, false, null(), JSMSG_NO_EXPORT_NAME);
- return null();
- }
- }
+ if (foundAs)
+ MUST_MATCH_TOKEN_MOD(TOK_NAME, TokenStream::KeywordIsName, JSMSG_NO_EXPORT_NAME);
Node exportName = newName(tokenStream.currentName());
if (!exportName)
@@ -5049,7 +5073,7 @@ Parser<FullParseHandler>::exportDeclaration()
if (!tokenStream.getToken(&tt))
return null();
if (tt != TOK_NAME || tokenStream.currentName() != context->names().from) {
- report(ParseError, false, null(), JSMSG_FROM_AFTER_EXPORT_STAR);
+ error(JSMSG_FROM_AFTER_EXPORT_STAR);
return null();
}
@@ -5074,7 +5098,7 @@ Parser<FullParseHandler>::exportDeclaration()
}
case TOK_FUNCTION:
- kid = functionStmt(YieldIsKeyword, NameRequired);
+ kid = functionStmt(pos().begin, YieldIsKeyword, NameRequired);
if (!kid)
return null();
@@ -5114,7 +5138,7 @@ Parser<FullParseHandler>::exportDeclaration()
ParseNode* nameNode = nullptr;
switch (tt) {
case TOK_FUNCTION:
- kid = functionStmt(YieldIsKeyword, AllowDefaultName);
+ kid = functionStmt(pos().begin, YieldIsKeyword, AllowDefaultName);
if (!kid)
return null();
break;
@@ -5131,7 +5155,7 @@ Parser<FullParseHandler>::exportDeclaration()
if (nextSameLine == TOK_FUNCTION) {
tokenStream.consumeKnownToken(nextSameLine);
- kid = functionStmt(YieldIsName, AllowDefaultName, AsyncFunction);
+ kid = functionStmt(pos().begin, YieldIsName, AllowDefaultName, AsyncFunction);
if (!kid)
return null();
break;
@@ -5185,7 +5209,7 @@ Parser<FullParseHandler>::exportDeclaration()
MOZ_FALLTHROUGH;
default:
- report(ParseError, false, null(), JSMSG_DECLARATION_AFTER_EXPORT);
+ error(JSMSG_DECLARATION_AFTER_EXPORT);
return null();
}
@@ -5232,7 +5256,7 @@ Parser<ParseHandler>::consequentOrAlternative(YieldHandling yieldHandling)
// will report the strict mode error.
if (!pc->sc()->strict()) {
tokenStream.consumeKnownToken(next, TokenStream::Operand);
- return functionStmt(yieldHandling, NameRequired);
+ return functionStmt(pos().begin, yieldHandling, NameRequired);
}
}
@@ -5261,7 +5285,7 @@ Parser<ParseHandler>::ifStatement(YieldHandling yieldHandling)
if (!tokenStream.peekToken(&tt, TokenStream::Operand))
return null();
if (tt == TOK_SEMI) {
- if (!report(ParseExtraWarning, false, null(), JSMSG_EMPTY_CONSEQUENT))
+ if (!extraWarning(JSMSG_EMPTY_CONSEQUENT))
return null();
}
@@ -5362,37 +5386,6 @@ Parser<ParseHandler>::matchInOrOf(bool* isForInp, bool* isForOfp)
template <class ParseHandler>
bool
-Parser<ParseHandler>::validateForInOrOfLHSExpression(Node target, PossibleError* possibleError)
-{
- if (handler.isUnparenthesizedDestructuringPattern(target))
- return checkDestructuringPattern(target, Nothing(), possibleError);
-
- // All other permitted targets are simple.
- if (!reportIfNotValidSimpleAssignmentTarget(target, ForInOrOfTarget))
- return false;
-
- if (handler.isPropertyAccess(target))
- return true;
-
- if (handler.isNameAnyParentheses(target)) {
- // The arguments/eval identifiers are simple in non-strict mode code,
- // but warn to discourage use nonetheless.
- if (!reportIfArgumentsEvalTarget(target))
- return false;
-
- handler.adjustGetToSet(target);
- return true;
- }
-
- if (handler.isFunctionCall(target))
- return checkAssignmentToCall(target, JSMSG_BAD_FOR_LEFTSIDE);
-
- report(ParseError, false, target, JSMSG_BAD_FOR_LEFTSIDE);
- return false;
-}
-
-template <class ParseHandler>
-bool
Parser<ParseHandler>::forHeadStart(YieldHandling yieldHandling,
ParseNodeKind* forHeadKind,
Node* forInitialPart,
@@ -5471,6 +5464,10 @@ Parser<ParseHandler>::forHeadStart(YieldHandling yieldHandling,
return *forInitialPart != null();
}
+ uint32_t exprOffset;
+ if (!tokenStream.peekOffset(&exprOffset, TokenStream::Operand))
+ return false;
+
// Finally, handle for-loops that start with expressions. Pass
// |InProhibited| so that |in| isn't parsed in a RelationalExpression as a
// binary operator. |in| makes it a for-in loop, *not* an |in| expression.
@@ -5508,14 +5505,35 @@ Parser<ParseHandler>::forHeadStart(YieldHandling yieldHandling,
//
// See ES6 13.7.
if (isForOf && letIsIdentifier) {
- report(ParseError, false, *forInitialPart, JSMSG_LET_STARTING_FOROF_LHS);
+ errorAt(exprOffset, JSMSG_LET_STARTING_FOROF_LHS);
return false;
}
*forHeadKind = isForIn ? PNK_FORIN : PNK_FOROF;
- if (!validateForInOrOfLHSExpression(*forInitialPart, &possibleError))
+ // Verify the left-hand side expression doesn't have a forbidden form.
+ if (handler.isUnparenthesizedDestructuringPattern(*forInitialPart)) {
+ if (!checkDestructuringPattern(*forInitialPart, Nothing(), &possibleError))
+ return false;
+ } else if (handler.isNameAnyParentheses(*forInitialPart)) {
+ const char* chars = handler.nameIsArgumentsEvalAnyParentheses(*forInitialPart, context);
+ if (chars) {
+ // |chars| is "arguments" or "eval" here.
+ if (!strictModeErrorAt(exprOffset, JSMSG_BAD_STRICT_ASSIGN, chars))
+ return false;
+ }
+
+ handler.adjustGetToSet(*forInitialPart);
+ } else if (handler.isPropertyAccess(*forInitialPart)) {
+ // Permitted: no additional testing/fixup needed.
+ } else if (handler.isFunctionCall(*forInitialPart)) {
+ if (!strictModeErrorAt(exprOffset, JSMSG_BAD_FOR_LEFTSIDE))
+ return false;
+ } else {
+ errorAt(exprOffset, JSMSG_BAD_FOR_LEFTSIDE);
return false;
+ }
+
if (!possibleError.checkForExpressionError())
return false;
@@ -5599,7 +5617,7 @@ Parser<ParseHandler>::forStatement(YieldHandling yieldHandling)
Node init = startNode;
if (isForEach) {
- reportWithOffset(ParseError, false, begin, JSMSG_BAD_FOR_EACH_LOOP);
+ errorAt(begin, JSMSG_BAD_FOR_EACH_LOOP);
return null();
}
@@ -5659,19 +5677,13 @@ Parser<ParseHandler>::forStatement(YieldHandling yieldHandling)
iflags |= JSITER_ENUMERATE;
} else {
if (isForEach) {
- report(ParseError, false, startNode, JSMSG_BAD_FOR_EACH_LOOP);
+ errorAt(begin, JSMSG_BAD_FOR_EACH_LOOP);
return null();
}
stmt.refineForKind(StatementKind::ForOfLoop);
}
- if (!handler.isDeclarationList(target)) {
- MOZ_ASSERT(!forLoopLexicalScope);
- if (!checkAndMarkAsAssignmentLhs(target, PlainAssignment))
- return null();
- }
-
// Parser::declaration consumed everything up to the closing ')'. That
// token follows an {Assignment,}Expression, so the next token must be
// consumed as if an operator continued the expression, i.e. as None.
@@ -5735,7 +5747,7 @@ Parser<ParseHandler>::switchStatement(YieldHandling yieldHandling)
switch (tt) {
case TOK_DEFAULT:
if (seenDefault) {
- report(ParseError, false, null(), JSMSG_TOO_MANY_DEFAULTS);
+ error(JSMSG_TOO_MANY_DEFAULTS);
return null();
}
seenDefault = true;
@@ -5749,7 +5761,7 @@ Parser<ParseHandler>::switchStatement(YieldHandling yieldHandling)
break;
default:
- report(ParseError, false, null(), JSMSG_BAD_SWITCH);
+ error(JSMSG_BAD_SWITCH);
return null();
}
@@ -5768,10 +5780,8 @@ Parser<ParseHandler>::switchStatement(YieldHandling yieldHandling)
if (tt == TOK_RC || tt == TOK_CASE || tt == TOK_DEFAULT)
break;
if (afterReturn) {
- TokenPos pos(0, 0);
- if (!tokenStream.peekTokenPos(&pos, TokenStream::Operand))
+ if (!tokenStream.peekOffset(&statementBegin, TokenStream::Operand))
return null();
- statementBegin = pos.begin;
}
Node stmt = statementListItem(yieldHandling);
if (!stmt)
@@ -5779,11 +5789,9 @@ Parser<ParseHandler>::switchStatement(YieldHandling yieldHandling)
if (!warnedAboutStatementsAfterReturn) {
if (afterReturn) {
if (!handler.isStatementPermittedAfterReturnStatement(stmt)) {
- if (!reportWithOffset(ParseWarning, false, statementBegin,
- JSMSG_STMT_AFTER_RETURN))
- {
+ if (!warningAt(statementBegin, JSMSG_STMT_AFTER_RETURN))
return null();
- }
+
warnedAboutStatementsAfterReturn = true;
}
} else if (handler.isReturnStatement(stmt)) {
@@ -5833,8 +5841,10 @@ Parser<ParseHandler>::continueStatement(YieldHandling yieldHandling)
for (;;) {
stmt = ParseContext::Statement::findNearest(stmt, isLoop);
if (!stmt) {
- report(ParseError, false, null(),
- foundLoop ? JSMSG_LABEL_NOT_FOUND : JSMSG_BAD_CONTINUE);
+ if (foundLoop)
+ error(JSMSG_LABEL_NOT_FOUND);
+ else
+ errorAt(begin, JSMSG_BAD_CONTINUE);
return null();
}
@@ -5854,7 +5864,7 @@ Parser<ParseHandler>::continueStatement(YieldHandling yieldHandling)
break;
}
} else if (!pc->findInnermostStatement(isLoop)) {
- report(ParseError, false, null(), JSMSG_BAD_CONTINUE);
+ error(JSMSG_BAD_CONTINUE);
return null();
}
@@ -5884,7 +5894,7 @@ Parser<ParseHandler>::breakStatement(YieldHandling yieldHandling)
};
if (!pc->findInnermostStatement<ParseContext::LabelStatement>(hasSameLabel)) {
- report(ParseError, false, null(), JSMSG_LABEL_NOT_FOUND);
+ error(JSMSG_LABEL_NOT_FOUND);
return null();
}
} else {
@@ -5893,7 +5903,7 @@ Parser<ParseHandler>::breakStatement(YieldHandling yieldHandling)
};
if (!pc->findInnermostStatement(isBreakTarget)) {
- report(ParseError, false, null(), JSMSG_TOUGH_BREAK);
+ errorAt(begin, JSMSG_TOUGH_BREAK);
return null();
}
}
@@ -5949,10 +5959,9 @@ Parser<ParseHandler>::returnStatement(YieldHandling yieldHandling)
if (!pn)
return null();
+ /* Disallow "return v;" in legacy generators. */
if (pc->isLegacyGenerator() && exprNode) {
- /* Disallow "return v;" in legacy generators. */
- reportBadReturn(pn, ParseError, JSMSG_BAD_GENERATOR_RETURN,
- JSMSG_BAD_ANON_GENERATOR_RETURN);
+ errorAt(begin, JSMSG_BAD_GENERATOR_RETURN);
return null();
}
@@ -6043,13 +6052,12 @@ Parser<ParseHandler>::yieldExpression(InHandling inHandling)
return null();
if (!pc->isFunctionBox()) {
- report(ParseError, false, null(), JSMSG_BAD_RETURN_OR_YIELD, js_yield_str);
+ error(JSMSG_BAD_RETURN_OR_YIELD, js_yield_str);
return null();
}
if (pc->functionBox()->isArrow()) {
- reportWithOffset(ParseError, false, begin,
- JSMSG_YIELD_IN_ARROW, js_yield_str);
+ errorAt(begin, JSMSG_YIELD_IN_ARROW, js_yield_str);
return null();
}
@@ -6057,8 +6065,7 @@ Parser<ParseHandler>::yieldExpression(InHandling inHandling)
pc->functionBox()->function()->isGetter() ||
pc->functionBox()->function()->isSetter())
{
- reportWithOffset(ParseError, false, begin,
- JSMSG_YIELD_IN_METHOD, js_yield_str);
+ errorAt(begin, JSMSG_YIELD_IN_METHOD, js_yield_str);
return null();
}
@@ -6069,8 +6076,7 @@ Parser<ParseHandler>::yieldExpression(InHandling inHandling)
)
{
/* As in Python (see PEP-255), disallow return v; in generators. */
- reportBadReturn(null(), ParseError, JSMSG_BAD_GENERATOR_RETURN,
- JSMSG_BAD_ANON_GENERATOR_RETURN);
+ errorAt(begin, JSMSG_BAD_GENERATOR_RETURN);
return null();
}
@@ -6124,14 +6130,13 @@ Parser<ParseHandler>::withStatement(YieldHandling yieldHandling)
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_WITH));
uint32_t begin = pos().begin;
- // In most cases, we want the constructs forbidden in strict mode code to be
- // a subset of those that JSOPTION_EXTRA_WARNINGS warns about, and we should
- // use reportStrictModeError. However, 'with' is the sole instance of a
- // construct that is forbidden in strict mode code, but doesn't even merit a
- // warning under JSOPTION_EXTRA_WARNINGS. See
+ // Usually we want the constructs forbidden in strict mode code to be a
+ // subset of those that ContextOptions::extraWarnings() warns about, and we
+ // use strictModeError directly. But while 'with' is forbidden in strict
+ // mode code, it doesn't even merit a warning in non-strict code. See
// https://bugzilla.mozilla.org/show_bug.cgi?id=514576#c1.
if (pc->sc()->strict()) {
- if (!report(ParseStrictError, true, null(), JSMSG_STRICT_CODE_WITH))
+ if (!strictModeError(JSMSG_STRICT_CODE_WITH))
return null();
}
@@ -6170,7 +6175,7 @@ Parser<ParseHandler>::labeledItem(YieldHandling yieldHandling)
// GeneratorDeclaration is only matched by HoistableDeclaration in
// StatementListItem, so generators can't be inside labels.
if (next == TOK_MUL) {
- report(ParseError, false, null(), JSMSG_GENERATOR_LABEL);
+ error(JSMSG_GENERATOR_LABEL);
return null();
}
@@ -6178,11 +6183,11 @@ Parser<ParseHandler>::labeledItem(YieldHandling yieldHandling)
// is ever matched. Per Annex B.3.2 that modifies this text, this
// applies only to strict mode code.
if (pc->sc()->strict()) {
- report(ParseError, false, null(), JSMSG_FUNCTION_LABEL);
+ error(JSMSG_FUNCTION_LABEL);
return null();
}
- return functionStmt(yieldHandling, NameRequired);
+ return functionStmt(pos().begin, yieldHandling, NameRequired);
}
tokenStream.ungetToken();
@@ -6201,13 +6206,13 @@ Parser<ParseHandler>::labeledStatement(YieldHandling yieldHandling)
return stmt->label() == label;
};
+ uint32_t begin = pos().begin;
+
if (pc->findInnermostStatement<ParseContext::LabelStatement>(hasSameLabel)) {
- report(ParseError, false, null(), JSMSG_DUPLICATE_LABEL);
+ errorAt(begin, JSMSG_DUPLICATE_LABEL);
return null();
}
- uint32_t begin = pos().begin;
-
tokenStream.consumeKnownToken(TOK_COLON);
/* Push a label struct and parse the statement. */
@@ -6231,11 +6236,11 @@ Parser<ParseHandler>::throwStatement(YieldHandling yieldHandling)
if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand))
return null();
if (tt == TOK_EOF || tt == TOK_SEMI || tt == TOK_RC) {
- report(ParseError, false, null(), JSMSG_MISSING_EXPR_AFTER_THROW);
+ error(JSMSG_MISSING_EXPR_AFTER_THROW);
return null();
}
if (tt == TOK_EOL) {
- report(ParseError, false, null(), JSMSG_LINE_BREAK_AFTER_THROW);
+ error(JSMSG_LINE_BREAK_AFTER_THROW);
return null();
}
@@ -6309,7 +6314,7 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
/* Check for another catch after unconditional catch. */
if (hasUnconditionalCatch) {
- report(ParseError, false, null(), JSMSG_CATCH_AFTER_GENERAL);
+ error(JSMSG_CATCH_AFTER_GENERAL);
return null();
}
@@ -6357,7 +6362,7 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
}
default:
- report(ParseError, false, null(), JSMSG_CATCH_IDENTIFIER);
+ error(JSMSG_CATCH_IDENTIFIER);
return null();
}
@@ -6425,7 +6430,7 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
tokenStream.ungetToken();
}
if (!catchList && !finallyBlock) {
- report(ParseError, false, null(), JSMSG_CATCH_OR_FINALLY);
+ error(JSMSG_CATCH_OR_FINALLY);
return null();
}
@@ -6502,49 +6507,6 @@ JSOpFromPropertyType(PropertyType propType)
}
}
-static FunctionSyntaxKind
-FunctionSyntaxKindFromPropertyType(PropertyType propType)
-{
- switch (propType) {
- case PropertyType::Getter:
- return Getter;
- case PropertyType::GetterNoExpressionClosure:
- return GetterNoExpressionClosure;
- case PropertyType::Setter:
- return Setter;
- case PropertyType::SetterNoExpressionClosure:
- return SetterNoExpressionClosure;
- case PropertyType::Method:
- case PropertyType::GeneratorMethod:
- case PropertyType::AsyncMethod:
- return Method;
- case PropertyType::Constructor:
- return ClassConstructor;
- case PropertyType::DerivedConstructor:
- return DerivedClassConstructor;
- default:
- MOZ_CRASH("unexpected property type");
- }
-}
-
-static GeneratorKind
-GeneratorKindFromPropertyType(PropertyType propType)
-{
- if (propType == PropertyType::GeneratorMethod)
- return StarGenerator;
- if (propType == PropertyType::AsyncMethod)
- return StarGenerator;
- return NotGenerator;
-}
-
-static FunctionAsyncKind
-AsyncKindFromPropertyType(PropertyType propType)
-{
- if (propType == PropertyType::AsyncMethod)
- return AsyncFunction;
- return SyncFunction;
-}
-
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
@@ -6570,7 +6532,7 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
tokenStream.ungetToken();
} else {
// Class statements must have a bound name
- report(ParseError, false, null(), JSMSG_UNNAMED_CLASS_STMT);
+ error(JSMSG_UNNAMED_CLASS_STMT);
return null();
}
} else {
@@ -6631,8 +6593,7 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
return null();
if (tt == TOK_RC) {
tokenStream.consumeKnownToken(tt, TokenStream::KeywordIsName);
- report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN,
- "property name", TokenKindToDesc(tt));
+ error(JSMSG_UNEXPECTED_TOKEN, "property name", TokenKindToDesc(tt));
return null();
}
@@ -6649,6 +6610,10 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
tokenStream.ungetToken();
}
+ uint32_t nameOffset;
+ if (!tokenStream.peekOffset(&nameOffset))
+ return null();
+
PropertyType propType;
Node propName = propertyName(yieldHandling, classMethods, &propType, &propAtom);
if (!propName)
@@ -6659,7 +6624,7 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
propType != PropertyType::AsyncMethod &&
propType != PropertyType::Constructor && propType != PropertyType::DerivedConstructor)
{
- report(ParseError, false, null(), JSMSG_BAD_METHOD_DEF);
+ errorAt(nameOffset, JSMSG_BAD_METHOD_DEF);
return null();
}
@@ -6669,17 +6634,17 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
propType = PropertyType::SetterNoExpressionClosure;
if (!isStatic && propAtom == context->names().constructor) {
if (propType != PropertyType::Method) {
- report(ParseError, false, propName, JSMSG_BAD_METHOD_DEF);
+ errorAt(nameOffset, JSMSG_BAD_METHOD_DEF);
return null();
}
if (seenConstructor) {
- report(ParseError, false, propName, JSMSG_DUPLICATE_PROPERTY, "constructor");
+ errorAt(nameOffset, JSMSG_DUPLICATE_PROPERTY, "constructor");
return null();
}
seenConstructor = true;
propType = hasHeritage ? PropertyType::DerivedConstructor : PropertyType::Constructor;
} else if (isStatic && propAtom == context->names().prototype) {
- report(ParseError, false, propName, JSMSG_BAD_METHOD_DEF);
+ errorAt(nameOffset, JSMSG_BAD_METHOD_DEF);
return null();
}
@@ -6701,7 +6666,7 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
if (!tokenStream.isCurrentTokenType(TOK_RB))
funName = propAtom;
}
- Node fn = methodDefinition(propType, funName);
+ Node fn = methodDefinition(nameOffset, propType, funName);
if (!fn)
return null();
@@ -6906,8 +6871,7 @@ Parser<ParseHandler>::statement(YieldHandling yieldHandling)
}
if (forbiddenLetDeclaration) {
- report(ParseError, false, null(), JSMSG_FORBIDDEN_AS_STATEMENT,
- "lexical declarations");
+ error(JSMSG_FORBIDDEN_AS_STATEMENT, "lexical declarations");
return null();
}
}
@@ -6961,7 +6925,7 @@ Parser<ParseHandler>::statement(YieldHandling yieldHandling)
// detected this way, so don't bother passing around an extra parameter
// everywhere.
if (!pc->isFunctionBox()) {
- report(ParseError, false, null(), JSMSG_BAD_RETURN_OR_YIELD, js_return_str);
+ error(JSMSG_BAD_RETURN_OR_YIELD, js_return_str);
return null();
}
return returnStatement(yieldHandling);
@@ -6989,12 +6953,12 @@ Parser<ParseHandler>::statement(YieldHandling yieldHandling)
// statement of |if| or |else|, but Parser::consequentOrAlternative
// handles that).
case TOK_FUNCTION:
- report(ParseError, false, null(), JSMSG_FORBIDDEN_AS_STATEMENT, "function declarations");
+ error(JSMSG_FORBIDDEN_AS_STATEMENT, "function declarations");
return null();
// |class| is also forbidden by lookahead restriction.
case TOK_CLASS:
- report(ParseError, false, null(), JSMSG_FORBIDDEN_AS_STATEMENT, "classes");
+ error(JSMSG_FORBIDDEN_AS_STATEMENT, "classes");
return null();
// ImportDeclaration (only inside modules)
@@ -7008,11 +6972,11 @@ Parser<ParseHandler>::statement(YieldHandling yieldHandling)
// Miscellaneous error cases arguably better caught here than elsewhere.
case TOK_CATCH:
- report(ParseError, false, null(), JSMSG_CATCH_WITHOUT_TRY);
+ error(JSMSG_CATCH_WITHOUT_TRY);
return null();
case TOK_FINALLY:
- report(ParseError, false, null(), JSMSG_FINALLY_WITHOUT_TRY);
+ error(JSMSG_FINALLY_WITHOUT_TRY);
return null();
// NOTE: default case handled in the ExpressionStatement section.
@@ -7053,7 +7017,7 @@ Parser<ParseHandler>::statementListItem(YieldHandling yieldHandling,
if (!canHaveDirectives && tokenStream.currentToken().atom() == context->names().useAsm) {
if (!abortIfSyntaxParser())
return null();
- if (!report(ParseWarning, false, null(), JSMSG_USE_ASM_DIRECTIVE_FAIL))
+ if (!warning(JSMSG_USE_ASM_DIRECTIVE_FAIL))
return null();
}
return expressionStatement(yieldHandling);
@@ -7094,8 +7058,9 @@ Parser<ParseHandler>::statementListItem(YieldHandling yieldHandling,
if (!tokenStream.peekTokenSameLine(&nextSameLine))
return null();
if (nextSameLine == TOK_FUNCTION) {
+ uint32_t preludeStart = pos().begin;
tokenStream.consumeKnownToken(TOK_FUNCTION);
- return functionStmt(yieldHandling, NameRequired, AsyncFunction);
+ return functionStmt(preludeStart, yieldHandling, NameRequired, AsyncFunction);
}
}
@@ -7146,7 +7111,7 @@ Parser<ParseHandler>::statementListItem(YieldHandling yieldHandling,
// detected this way, so don't bother passing around an extra parameter
// everywhere.
if (!pc->isFunctionBox()) {
- report(ParseError, false, null(), JSMSG_BAD_RETURN_OR_YIELD, js_return_str);
+ error(JSMSG_BAD_RETURN_OR_YIELD, js_return_str);
return null();
}
return returnStatement(yieldHandling);
@@ -7174,7 +7139,7 @@ Parser<ParseHandler>::statementListItem(YieldHandling yieldHandling,
// HoistableDeclaration[?Yield, ~Default]
case TOK_FUNCTION:
- return functionStmt(yieldHandling, NameRequired);
+ return functionStmt(pos().begin, yieldHandling, NameRequired);
// ClassDeclaration[?Yield, ~Default]
case TOK_CLASS:
@@ -7198,11 +7163,11 @@ Parser<ParseHandler>::statementListItem(YieldHandling yieldHandling,
// Miscellaneous error cases arguably better caught here than elsewhere.
case TOK_CATCH:
- report(ParseError, false, null(), JSMSG_CATCH_WITHOUT_TRY);
+ error(JSMSG_CATCH_WITHOUT_TRY);
return null();
case TOK_FINALLY:
- report(ParseError, false, null(), JSMSG_FINALLY_WITHOUT_TRY);
+ error(JSMSG_FINALLY_WITHOUT_TRY);
return null();
// NOTE: default case handled in the ExpressionStatement section.
@@ -7247,8 +7212,7 @@ Parser<ParseHandler>::expr(InHandling inHandling, YieldHandling yieldHandling,
if (!tokenStream.peekToken(&tt))
return null();
if (tt != TOK_ARROW) {
- report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN,
- "expression", TokenKindToDesc(TOK_RP));
+ error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(TOK_RP));
return null();
}
@@ -7405,7 +7369,7 @@ Parser<ParseHandler>::orExpr1(InHandling inHandling, YieldHandling yieldHandling
return null();
// Report an error for unary expressions on the LHS of **.
if (tok == TOK_POW && handler.isUnparenthesizedUnaryExpression(pn)) {
- report(ParseError, false, null(), JSMSG_BAD_POW_LEFTSIDE);
+ error(JSMSG_BAD_POW_LEFTSIDE);
return null();
}
pnk = BinaryOpTokenKindToParseNodeKind(tok);
@@ -7475,45 +7439,6 @@ Parser<ParseHandler>::condExpr1(InHandling inHandling, YieldHandling yieldHandli
return handler.newConditional(condition, thenExpr, elseExpr);
}
-template <typename ParseHandler>
-bool
-Parser<ParseHandler>::checkAndMarkAsAssignmentLhs(Node target, AssignmentFlavor flavor,
- PossibleError* possibleError)
-{
- MOZ_ASSERT(flavor != KeyedDestructuringAssignment,
- "destructuring must use special checking/marking code, not "
- "this method");
-
- if (handler.isUnparenthesizedDestructuringPattern(target)) {
- if (flavor == CompoundAssignment) {
- report(ParseError, false, null(), JSMSG_BAD_DESTRUCT_ASS);
- return false;
- }
-
- return checkDestructuringPattern(target, Nothing(), possibleError);
- }
-
- // All other permitted targets are simple.
- if (!reportIfNotValidSimpleAssignmentTarget(target, flavor))
- return false;
-
- if (handler.isPropertyAccess(target))
- return true;
-
- if (handler.isNameAnyParentheses(target)) {
- // The arguments/eval identifiers are simple in non-strict mode code,
- // but warn to discourage use nonetheless.
- if (!reportIfArgumentsEvalTarget(target))
- return false;
-
- handler.adjustGetToSet(target);
- return true;
- }
-
- MOZ_ASSERT(handler.isFunctionCall(target));
- return checkAssignmentToCall(target, JSMSG_BAD_LEFTSIDE_OF_ASS);
-}
-
class AutoClearInDestructuringDecl
{
ParseContext* pc_;
@@ -7558,6 +7483,8 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
if (!tokenStream.getToken(&tt, TokenStream::Operand))
return null();
+ uint32_t exprOffset = pos().begin;
+
bool endsExpr;
if (tt == TOK_NAME) {
@@ -7625,8 +7552,7 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
if (!tokenStream.getToken(&tt))
return null();
if (tt != TOK_ARROW) {
- report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN,
- "'=>' after argument list", TokenKindToDesc(tt));
+ error(JSMSG_UNEXPECTED_TOKEN, "'=>' after argument list", TokenKindToDesc(tt));
return null();
}
@@ -7664,7 +7590,7 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
MOZ_ASSERT(next == TOK_ARROW || next == TOK_EOL);
if (next != TOK_ARROW) {
- report(ParseError, false, null(), JSMSG_LINE_BREAK_BEFORE_ARROW);
+ error(JSMSG_LINE_BREAK_BEFORE_ARROW);
return null();
}
tokenStream.consumeKnownToken(TOK_ARROW);
@@ -7677,8 +7603,10 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
tokenStream.seek(start);
- if (!tokenStream.peekToken(&next, TokenStream::Operand))
+ if (!tokenStream.getToken(&next, TokenStream::Operand))
return null();
+ uint32_t preludeStart = pos().begin;
+ tokenStream.ungetToken();
GeneratorKind generatorKind = NotGenerator;
FunctionAsyncKind asyncKind = SyncFunction;
@@ -7702,7 +7630,11 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
}
}
- Node arrowFunc = functionDefinition(inHandling, yieldHandling, nullptr,
+ Node pn = handler.newArrowFunction();
+ if (!pn)
+ return null();
+
+ Node arrowFunc = functionDefinition(preludeStart, pn, inHandling, yieldHandling, nullptr,
Arrow, generatorKind, asyncKind);
if (!arrowFunc)
return null();
@@ -7752,9 +7684,33 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
return lhs;
}
- AssignmentFlavor flavor = kind == PNK_ASSIGN ? PlainAssignment : CompoundAssignment;
- if (!checkAndMarkAsAssignmentLhs(lhs, flavor, &possibleErrorInner))
+ // Verify the left-hand side expression doesn't have a forbidden form.
+ if (handler.isUnparenthesizedDestructuringPattern(lhs)) {
+ if (kind != PNK_ASSIGN) {
+ error(JSMSG_BAD_DESTRUCT_ASS);
+ return null();
+ }
+
+ if (!checkDestructuringPattern(lhs, Nothing(), &possibleErrorInner))
+ return null();
+ } else if (handler.isNameAnyParentheses(lhs)) {
+ if (const char* chars = handler.nameIsArgumentsEvalAnyParentheses(lhs, context)) {
+ // |chars| is "arguments" or "eval" here.
+ if (!strictModeErrorAt(exprOffset, JSMSG_BAD_STRICT_ASSIGN, chars))
+ return null();
+ }
+
+ handler.adjustGetToSet(lhs);
+ } else if (handler.isPropertyAccess(lhs)) {
+ // Permitted: no additional testing/fixup needed.
+ } else if (handler.isFunctionCall(lhs)) {
+ if (!strictModeErrorAt(exprOffset, JSMSG_BAD_LEFTSIDE_OF_ASS))
+ return null();
+ } else {
+ errorAt(exprOffset, JSMSG_BAD_LEFTSIDE_OF_ASS);
return null();
+ }
+
if (!possibleErrorInner.checkForExpressionError())
return null();
@@ -7801,91 +7757,29 @@ Parser<ParseHandler>::isValidSimpleAssignmentTarget(Node node,
template <typename ParseHandler>
bool
-Parser<ParseHandler>::reportIfArgumentsEvalTarget(Node nameNode)
-{
- const char* chars = handler.nameIsArgumentsEvalAnyParentheses(nameNode, context);
- if (!chars)
- return true;
-
- if (!report(ParseStrictError, pc->sc()->strict(), nameNode, JSMSG_BAD_STRICT_ASSIGN, chars))
- return false;
-
- MOZ_ASSERT(!pc->sc()->strict(),
- "an error should have been reported if this was strict mode "
- "code");
- return true;
-}
-
-template <typename ParseHandler>
-bool
-Parser<ParseHandler>::reportIfNotValidSimpleAssignmentTarget(Node target, AssignmentFlavor flavor)
+Parser<ParseHandler>::checkIncDecOperand(Node operand, uint32_t operandOffset)
{
- FunctionCallBehavior behavior = flavor == KeyedDestructuringAssignment
- ? ForbidAssignmentToFunctionCalls
- : PermitAssignmentToFunctionCalls;
- if (isValidSimpleAssignmentTarget(target, behavior))
- return true;
-
- if (handler.isNameAnyParentheses(target)) {
- // Use a special error if the target is arguments/eval. This ensures
- // targeting these names is consistently a SyntaxError (which error numbers
- // below don't guarantee) while giving us a nicer error message.
- if (!reportIfArgumentsEvalTarget(target))
+ if (handler.isNameAnyParentheses(operand)) {
+ if (const char* chars = handler.nameIsArgumentsEvalAnyParentheses(operand, context)) {
+ if (!strictModeErrorAt(operandOffset, JSMSG_BAD_STRICT_ASSIGN, chars))
+ return false;
+ }
+ } else if (handler.isPropertyAccess(operand)) {
+ // Permitted: no additional testing/fixup needed.
+ } else if (handler.isFunctionCall(operand)) {
+ // Assignment to function calls is forbidden in ES6. We're still
+ // somewhat concerned about sites using this in dead code, so forbid it
+ // only in strict mode code (or if the werror option has been set), and
+ // otherwise warn.
+ if (!strictModeErrorAt(operandOffset, JSMSG_BAD_INCOP_OPERAND))
return false;
- }
-
- unsigned errnum = 0;
- const char* extra = nullptr;
-
- switch (flavor) {
- case IncrementAssignment:
- errnum = JSMSG_BAD_OPERAND;
- extra = "increment";
- break;
-
- case DecrementAssignment:
- errnum = JSMSG_BAD_OPERAND;
- extra = "decrement";
- break;
-
- case KeyedDestructuringAssignment:
- errnum = JSMSG_BAD_DESTRUCT_TARGET;
- break;
-
- case PlainAssignment:
- case CompoundAssignment:
- errnum = JSMSG_BAD_LEFTSIDE_OF_ASS;
- break;
-
- case ForInOrOfTarget:
- errnum = JSMSG_BAD_FOR_LEFTSIDE;
- break;
- }
-
- report(ParseError, pc->sc()->strict(), target, errnum, extra);
- return false;
-}
-
-template <typename ParseHandler>
-bool
-Parser<ParseHandler>::checkAndMarkAsIncOperand(Node target, AssignmentFlavor flavor)
-{
- MOZ_ASSERT(flavor == IncrementAssignment || flavor == DecrementAssignment);
-
- // Check.
- if (!reportIfNotValidSimpleAssignmentTarget(target, flavor))
+ } else {
+ errorAt(operandOffset, JSMSG_BAD_INCOP_OPERAND);
return false;
-
- // Mark.
- if (handler.isNameAnyParentheses(target)) {
- // Assignment to arguments/eval is allowed outside strict mode code,
- // but it's dodgy. Report a strict warning (error, if werror was set).
- if (!reportIfArgumentsEvalTarget(target))
- return false;
- } else if (handler.isFunctionCall(target)) {
- if (!checkAssignmentToCall(target, JSMSG_BAD_INCOP_OPERAND))
- return false;
}
+
+ MOZ_ASSERT(isValidSimpleAssignmentTarget(operand, PermitAssignmentToFunctionCalls),
+ "inconsistent increment/decrement operand validation");
return true;
}
@@ -7949,18 +7843,21 @@ Parser<ParseHandler>::unaryExpr(YieldHandling yieldHandling, TripledotHandling t
TokenKind tt2;
if (!tokenStream.getToken(&tt2, TokenStream::Operand))
return null();
- Node pn2 = memberExpr(yieldHandling, TripledotProhibited, tt2);
- if (!pn2)
- return null();
- AssignmentFlavor flavor = (tt == TOK_INC) ? IncrementAssignment : DecrementAssignment;
- if (!checkAndMarkAsIncOperand(pn2, flavor))
+
+ uint32_t operandOffset = pos().begin;
+ Node operand = memberExpr(yieldHandling, TripledotProhibited, tt2);
+ if (!operand || !checkIncDecOperand(operand, operandOffset))
return null();
+
return handler.newUpdate((tt == TOK_INC) ? PNK_PREINCREMENT : PNK_PREDECREMENT,
- begin,
- pn2);
+ begin, operand);
}
case TOK_DELETE: {
+ uint32_t exprOffset;
+ if (!tokenStream.peekOffset(&exprOffset, TokenStream::Operand))
+ return null();
+
Node expr = unaryExpr(yieldHandling, TripledotProhibited);
if (!expr)
return null();
@@ -7968,8 +7865,9 @@ Parser<ParseHandler>::unaryExpr(YieldHandling yieldHandling, TripledotHandling t
// Per spec, deleting any unary expression is valid -- it simply
// returns true -- except for one case that is illegal in strict mode.
if (handler.isNameAnyParentheses(expr)) {
- if (!report(ParseStrictError, pc->sc()->strict(), expr, JSMSG_DEPRECATED_DELETE_OPERAND))
+ if (!strictModeErrorAt(exprOffset, JSMSG_DEPRECATED_DELETE_OPERAND))
return null();
+
pc->sc()->setBindingsAccessedDynamically();
}
@@ -7980,7 +7878,7 @@ Parser<ParseHandler>::unaryExpr(YieldHandling yieldHandling, TripledotHandling t
if (!pc->isAsync()) {
// TOK_AWAIT can be returned in module, even if it's not inside
// async function.
- report(ParseError, false, null(), JSMSG_RESERVED_ID, "await");
+ error(JSMSG_RESERVED_ID, "await");
return null();
}
@@ -7992,24 +7890,23 @@ Parser<ParseHandler>::unaryExpr(YieldHandling yieldHandling, TripledotHandling t
}
default: {
- Node pn = memberExpr(yieldHandling, tripledotHandling, tt, /* allowCallSyntax = */ true,
+ Node expr = memberExpr(yieldHandling, tripledotHandling, tt, /* allowCallSyntax = */ true,
possibleError, invoked);
- if (!pn)
+ if (!expr)
return null();
/* Don't look across a newline boundary for a postfix incop. */
if (!tokenStream.peekTokenSameLine(&tt))
return null();
- if (tt == TOK_INC || tt == TOK_DEC) {
- tokenStream.consumeKnownToken(tt);
- AssignmentFlavor flavor = (tt == TOK_INC) ? IncrementAssignment : DecrementAssignment;
- if (!checkAndMarkAsIncOperand(pn, flavor))
- return null();
- return handler.newUpdate((tt == TOK_INC) ? PNK_POSTINCREMENT : PNK_POSTDECREMENT,
- begin,
- pn);
- }
- return pn;
+
+ if (tt != TOK_INC && tt != TOK_DEC)
+ return expr;
+
+ tokenStream.consumeKnownToken(tt);
+ if (!checkIncDecOperand(expr, begin))
+ return null();
+ return handler.newUpdate((tt == TOK_INC) ? PNK_POSTINCREMENT : PNK_POSTDECREMENT,
+ begin, expr);
}
}
}
@@ -8031,10 +7928,9 @@ template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::generatorComprehensionLambda(unsigned begin)
{
- Node genfn = handler.newFunctionDefinition();
+ Node genfn = handler.newFunctionExpression();
if (!genfn)
return null();
- handler.setOp(genfn, JSOP_LAMBDA);
ParseContext* outerpc = pc;
@@ -8054,8 +7950,8 @@ Parser<ParseHandler>::generatorComprehensionLambda(unsigned begin)
// Create box for fun->object early to root it.
Directives directives(/* strict = */ outerpc->sc()->strict());
- FunctionBox* genFunbox = newFunctionBox(genfn, fun, directives, StarGenerator, SyncFunction,
- /* tryAnnexB = */ false);
+ FunctionBox* genFunbox = newFunctionBox(genfn, fun, /* preludeStart = */ 0, directives,
+ StarGenerator, SyncFunction, /* tryAnnexB = */ false);
if (!genFunbox)
return null();
genFunbox->isGenexpLambda = true;
@@ -8087,12 +7983,14 @@ Parser<ParseHandler>::generatorComprehensionLambda(unsigned begin)
MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_IN_PAREN);
+ uint32_t end = pos().end;
handler.setBeginPosition(comp, begin);
- handler.setEndPosition(comp, pos().end);
+ handler.setEndPosition(comp, end);
+ genFunbox->bufEnd = end;
handler.addStatementToList(body, comp);
- handler.setEndPosition(body, pos().end);
+ handler.setEndPosition(body, end);
handler.setBeginPosition(genfn, begin);
- handler.setEndPosition(genfn, pos().end);
+ handler.setEndPosition(genfn, end);
Node generator = newDotGeneratorName();
if (!generator)
@@ -8131,7 +8029,7 @@ Parser<ParseHandler>::comprehensionFor(GeneratorKind comprehensionKind)
MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_VARIABLE_NAME);
RootedPropertyName name(context, tokenStream.currentName());
if (name == context->names().let) {
- report(ParseError, false, null(), JSMSG_LET_COMP_BINDING);
+ error(JSMSG_LET_COMP_BINDING);
return null();
}
TokenPos namePos = pos();
@@ -8142,7 +8040,7 @@ Parser<ParseHandler>::comprehensionFor(GeneratorKind comprehensionKind)
if (!tokenStream.matchContextualKeyword(&matched, context->names().of))
return null();
if (!matched) {
- report(ParseError, false, null(), JSMSG_OF_AFTER_FOR_NAME);
+ error(JSMSG_OF_AFTER_FOR_NAME);
return null();
}
@@ -8203,7 +8101,7 @@ Parser<ParseHandler>::comprehensionIf(GeneratorKind comprehensionKind)
/* Check for (a = b) and warn about possible (a == b) mistype. */
if (handler.isUnparenthesizedAssignment(cond)) {
- if (!report(ParseExtraWarning, false, null(), JSMSG_EQUAL_AS_ASSIGN))
+ if (!extraWarning(JSMSG_EQUAL_AS_ASSIGN))
return null();
}
@@ -8264,8 +8162,7 @@ Parser<ParseHandler>::comprehension(GeneratorKind comprehensionKind)
return null();
if (comprehensionKind != NotGenerator && pc->lastYieldOffset != startYieldOffset) {
- reportWithOffset(ParseError, false, pc->lastYieldOffset,
- JSMSG_BAD_GENEXP_BODY, js_yield_str);
+ errorAt(pc->lastYieldOffset, JSMSG_BAD_GENEXP_BODY, js_yield_str);
return null();
}
@@ -8327,11 +8224,11 @@ Parser<ParseHandler>::assignExprWithoutYieldOrAwait(YieldHandling yieldHandling)
Node res = assignExpr(InAllowed, yieldHandling, TripledotProhibited);
if (res) {
if (pc->lastYieldOffset != startYieldOffset) {
- reportWithOffset(ParseError, false, pc->lastYieldOffset, JSMSG_YIELD_IN_DEFAULT);
+ errorAt(pc->lastYieldOffset, JSMSG_YIELD_IN_DEFAULT);
return null();
}
if (pc->lastAwaitOffset != startAwaitOffset) {
- reportWithOffset(ParseError, false, pc->lastAwaitOffset, JSMSG_AWAIT_IN_DEFAULT);
+ errorAt(pc->lastAwaitOffset, JSMSG_AWAIT_IN_DEFAULT);
return null();
}
}
@@ -8388,13 +8285,8 @@ Parser<ParseHandler>::argumentList(YieldHandling yieldHandling, Node listNode, b
}
}
- TokenKind tt;
- if (!tokenStream.getToken(&tt))
- return false;
- if (tt != TOK_RP) {
- report(ParseError, false, null(), JSMSG_PAREN_AFTER_ARGS);
- return false;
- }
+ MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_ARGS);
+
handler.setEndPosition(listNode, pos().end);
return true;
}
@@ -8485,14 +8377,14 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TripledotHandling
if (tt == TOK_NAME) {
PropertyName* field = tokenStream.currentName();
if (handler.isSuperBase(lhs) && !checkAndMarkSuperScope()) {
- report(ParseError, false, null(), JSMSG_BAD_SUPERPROP, "property");
+ error(JSMSG_BAD_SUPERPROP, "property");
return null();
}
nextMember = handler.newPropertyAccess(lhs, field, pos().end);
if (!nextMember)
return null();
} else {
- report(ParseError, false, null(), JSMSG_NAME_AFTER_DOT);
+ error(JSMSG_NAME_AFTER_DOT);
return null();
}
} else if (tt == TOK_LB) {
@@ -8503,7 +8395,7 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TripledotHandling
MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_IN_INDEX);
if (handler.isSuperBase(lhs) && !checkAndMarkSuperScope()) {
- report(ParseError, false, null(), JSMSG_BAD_SUPERPROP, "member");
+ error(JSMSG_BAD_SUPERPROP, "member");
return null();
}
nextMember = handler.newPropertyByValue(lhs, propExpr, pos().end);
@@ -8515,12 +8407,12 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TripledotHandling
{
if (handler.isSuperBase(lhs)) {
if (!pc->sc()->allowSuperCall()) {
- report(ParseError, false, null(), JSMSG_BAD_SUPERCALL);
+ error(JSMSG_BAD_SUPERCALL);
return null();
}
if (tt != TOK_LP) {
- report(ParseError, false, null(), JSMSG_BAD_SUPER);
+ error(JSMSG_BAD_SUPER);
return null();
}
@@ -8547,7 +8439,7 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TripledotHandling
return null();
} else {
if (options().selfHostingMode && handler.isPropertyAccess(lhs)) {
- report(ParseError, false, null(), JSMSG_SELFHOSTED_METHOD_CALL);
+ error(JSMSG_SELFHOSTED_METHOD_CALL);
return null();
}
@@ -8629,7 +8521,7 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TripledotHandling
}
if (handler.isSuperBase(lhs)) {
- report(ParseError, false, null(), JSMSG_BAD_SUPER);
+ error(JSMSG_BAD_SUPER);
return null();
}
@@ -8682,7 +8574,7 @@ Parser<ParseHandler>::labelOrIdentifierReference(YieldHandling yieldHandling,
? "static"
: nullptr;
if (badName) {
- report(ParseError, false, null(), JSMSG_RESERVED_ID, badName);
+ error(JSMSG_RESERVED_ID, badName);
return nullptr;
}
}
@@ -8691,7 +8583,7 @@ Parser<ParseHandler>::labelOrIdentifierReference(YieldHandling yieldHandling,
pc->sc()->strict() ||
versionNumber() >= JSVERSION_1_7)
{
- report(ParseError, false, null(), JSMSG_RESERVED_ID, "yield");
+ error(JSMSG_RESERVED_ID, "yield");
return nullptr;
}
}
@@ -8727,7 +8619,7 @@ Parser<ParseHandler>::bindingIdentifier(YieldHandling yieldHandling)
? "eval"
: nullptr;
if (badName) {
- report(ParseError, false, null(), JSMSG_BAD_STRICT_ASSIGN, badName);
+ error(JSMSG_BAD_STRICT_ASSIGN, badName);
return nullptr;
}
@@ -8737,7 +8629,7 @@ Parser<ParseHandler>::bindingIdentifier(YieldHandling yieldHandling)
? "static"
: nullptr;
if (badName) {
- report(ParseError, false, null(), JSMSG_RESERVED_ID, badName);
+ error(JSMSG_RESERVED_ID, badName);
return nullptr;
}
}
@@ -8746,7 +8638,7 @@ Parser<ParseHandler>::bindingIdentifier(YieldHandling yieldHandling)
pc->sc()->strict() ||
versionNumber() >= JSVERSION_1_7)
{
- report(ParseError, false, null(), JSMSG_RESERVED_ID, "yield");
+ error(JSMSG_RESERVED_ID, "yield");
return nullptr;
}
}
@@ -8845,7 +8737,7 @@ Parser<ParseHandler>::arrayInitializer(YieldHandling yieldHandling, PossibleErro
TokenStream::Modifier modifier = TokenStream::Operand;
for (; ; index++) {
if (index >= NativeObject::MAX_DENSE_ELEMENTS_COUNT) {
- report(ParseError, false, null(), JSMSG_ARRAY_INIT_TOO_BIG);
+ error(JSMSG_ARRAY_INIT_TOO_BIG);
return null();
}
@@ -8888,7 +8780,7 @@ Parser<ParseHandler>::arrayInitializer(YieldHandling yieldHandling, PossibleErro
break;
}
if (tt == TOK_TRIPLEDOT && possibleError)
- possibleError->setPendingDestructuringError(null(), JSMSG_REST_WITH_COMMA);
+ possibleError->setPendingDestructuringErrorAt(pos(), JSMSG_REST_WITH_COMMA);
}
}
@@ -8955,7 +8847,7 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList,
}
if (isAsync && isGenerator) {
- report(ParseError, false, null(), JSMSG_ASYNC_GENERATOR);
+ error(JSMSG_ASYNC_GENERATOR);
return null();
}
@@ -9068,7 +8960,7 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList,
}
default:
- report(ParseError, false, null(), JSMSG_BAD_PROP_ID);
+ error(JSMSG_BAD_PROP_ID);
return null();
}
@@ -9078,7 +8970,7 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList,
if (tt == TOK_COLON) {
if (isGenerator) {
- report(ParseError, false, null(), JSMSG_BAD_PROP_ID);
+ error(JSMSG_BAD_PROP_ID);
return null();
}
*propType = PropertyType::Normal;
@@ -9087,7 +8979,7 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList,
if (ltok == TOK_NAME && (tt == TOK_COMMA || tt == TOK_RC || tt == TOK_ASSIGN)) {
if (isGenerator) {
- report(ParseError, false, null(), JSMSG_BAD_PROP_ID);
+ error(JSMSG_BAD_PROP_ID);
return null();
}
tokenStream.ungetToken();
@@ -9108,7 +9000,7 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList,
return propName;
}
- report(ParseError, false, null(), JSMSG_COLON_AFTER_ID);
+ error(JSMSG_COLON_AFTER_ID);
return null();
}
@@ -9158,6 +9050,8 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling, PossibleError*
if (tt == TOK_RC)
break;
+ TokenPos namePos = pos();
+
tokenStream.ungetToken();
PropertyType propType;
@@ -9181,14 +9075,14 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling, PossibleError*
// Directly report the error when we're not in a
// destructuring context.
if (!possibleError) {
- report(ParseError, false, propName, JSMSG_DUPLICATE_PROTO_PROPERTY);
+ errorAt(namePos.begin, JSMSG_DUPLICATE_PROTO_PROPERTY);
return null();
}
// Otherwise delay error reporting until we've determined
// whether or not we're destructuring.
- possibleError->setPendingExpressionError(propName,
- JSMSG_DUPLICATE_PROTO_PROPERTY);
+ possibleError->setPendingExpressionErrorAt(namePos,
+ JSMSG_DUPLICATE_PROTO_PROPERTY);
}
seenPrototypeMutation = true;
@@ -9196,8 +9090,7 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling, PossibleError*
// __proto__: v mutates [[Prototype]]. Getters, setters,
// method/generator definitions, computed property name
// versions of all of these, and shorthands do not.
- uint32_t begin = handler.getPosition(propName).begin;
- if (!handler.addPrototypeMutation(literal, begin, propExpr))
+ if (!handler.addPrototypeMutation(literal, namePos.begin, propExpr))
return null();
} else {
if (!handler.isConstant(propExpr))
@@ -9217,7 +9110,7 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling, PossibleError*
return null();
if (propToken != TOK_NAME && propToken != TOK_YIELD) {
- report(ParseError, false, null(), JSMSG_RESERVED_ID, TokenKindToDesc(propToken));
+ error(JSMSG_RESERVED_ID, TokenKindToDesc(propToken));
return null();
}
@@ -9242,7 +9135,7 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling, PossibleError*
return null();
if (propToken != TOK_NAME && propToken != TOK_YIELD) {
- report(ParseError, false, null(), JSMSG_RESERVED_ID, TokenKindToDesc(propToken));
+ error(JSMSG_RESERVED_ID, TokenKindToDesc(propToken));
return null();
}
@@ -9266,14 +9159,14 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling, PossibleError*
// Destructuring defaults are definitely not allowed in this object literal,
// because of something the caller knows about the preceding code.
// For example, maybe the preceding token is an operator: `x + {y=z}`.
- report(ParseError, false, null(), JSMSG_COLON_AFTER_ID);
+ error(JSMSG_COLON_AFTER_ID);
return null();
}
// Here we set a pending error so that later in the parse, once we've
// determined whether or not we're destructuring, the error can be
// reported or ignored appropriately.
- possibleError->setPendingExpressionError(null(), JSMSG_COLON_AFTER_ID);
+ possibleError->setPendingExpressionErrorAt(pos(), JSMSG_COLON_AFTER_ID);
}
Node rhs;
@@ -9309,7 +9202,7 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling, PossibleError*
}
}
- Node fn = methodDefinition(propType, funName);
+ Node fn = methodDefinition(namePos.begin, propType, funName);
if (!fn)
return null();
@@ -9325,7 +9218,7 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling, PossibleError*
if (tt == TOK_RC)
break;
if (tt != TOK_COMMA) {
- report(ParseError, false, null(), JSMSG_CURLY_AFTER_LIST);
+ error(JSMSG_CURLY_AFTER_LIST);
return null();
}
}
@@ -9336,13 +9229,62 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling, PossibleError*
template <typename ParseHandler>
typename ParseHandler::Node
-Parser<ParseHandler>::methodDefinition(PropertyType propType, HandleAtom funName)
+Parser<ParseHandler>::methodDefinition(uint32_t preludeStart, PropertyType propType,
+ HandleAtom funName)
{
- FunctionSyntaxKind kind = FunctionSyntaxKindFromPropertyType(propType);
- GeneratorKind generatorKind = GeneratorKindFromPropertyType(propType);
- FunctionAsyncKind asyncKind = AsyncKindFromPropertyType(propType);
+ FunctionSyntaxKind kind;
+ switch (propType) {
+ case PropertyType::Getter:
+ kind = Getter;
+ break;
+
+ case PropertyType::GetterNoExpressionClosure:
+ kind = GetterNoExpressionClosure;
+ break;
+
+ case PropertyType::Setter:
+ kind = Setter;
+ break;
+
+ case PropertyType::SetterNoExpressionClosure:
+ kind = SetterNoExpressionClosure;
+ break;
+
+ case PropertyType::Method:
+ case PropertyType::GeneratorMethod:
+ case PropertyType::AsyncMethod:
+ kind = Method;
+ break;
+
+ case PropertyType::Constructor:
+ kind = ClassConstructor;
+ break;
+
+ case PropertyType::DerivedConstructor:
+ kind = DerivedClassConstructor;
+ break;
+
+ default:
+ MOZ_CRASH("Parser: methodDefinition: unexpected property type");
+ }
+
+ GeneratorKind generatorKind = (propType == PropertyType::GeneratorMethod ||
+ propType == PropertyType::AsyncMethod)
+ ? StarGenerator
+ : NotGenerator;
+
+ FunctionAsyncKind asyncKind = (propType == PropertyType::AsyncMethod)
+ ? AsyncFunction
+ : SyncFunction;
+
YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind);
- return functionDefinition(InAllowed, yieldHandling, funName, kind, generatorKind, asyncKind);
+
+ Node pn = handler.newFunctionExpression();
+ if (!pn)
+ return null();
+
+ return functionDefinition(preludeStart, pn, InAllowed, yieldHandling, funName,
+ kind, generatorKind, asyncKind);
}
template <typename ParseHandler>
@@ -9372,8 +9314,7 @@ Parser<ParseHandler>::tryNewTarget(Node &newTarget)
if (!tokenStream.getToken(&next))
return false;
if (next != TOK_NAME || tokenStream.currentName() != context->names().target) {
- report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN,
- "target", TokenKindToDesc(next));
+ error(JSMSG_UNEXPECTED_TOKEN, "target", TokenKindToDesc(next));
return false;
}
@@ -9381,7 +9322,7 @@ Parser<ParseHandler>::tryNewTarget(Node &newTarget)
return false;
if (!pc->sc()->allowNewTarget()) {
- reportWithOffset(ParseError, false, begin, JSMSG_BAD_NEWTARGET);
+ errorAt(begin, JSMSG_BAD_NEWTARGET);
return false;
}
@@ -9404,7 +9345,7 @@ Parser<ParseHandler>::primaryExpr(YieldHandling yieldHandling, TripledotHandling
switch (tt) {
case TOK_FUNCTION:
- return functionExpr(invoked);
+ return functionExpr(pos().begin, invoked);
case TOK_CLASS:
return classDefinition(yieldHandling, ClassExpression, NameRequired);
@@ -9428,8 +9369,7 @@ Parser<ParseHandler>::primaryExpr(YieldHandling yieldHandling, TripledotHandling
if (!tokenStream.peekToken(&next))
return null();
if (next != TOK_ARROW) {
- report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN,
- "expression", TokenKindToDesc(TOK_RP));
+ error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(TOK_RP));
return null();
}
@@ -9471,8 +9411,9 @@ Parser<ParseHandler>::primaryExpr(YieldHandling yieldHandling, TripledotHandling
return null();
if (nextSameLine == TOK_FUNCTION) {
+ uint32_t preludeStart = pos().begin;
tokenStream.consumeKnownToken(TOK_FUNCTION);
- return functionExpr(PredictUninvoked, AsyncFunction);
+ return functionExpr(preludeStart, PredictUninvoked, AsyncFunction);
}
}
@@ -9515,8 +9456,7 @@ Parser<ParseHandler>::primaryExpr(YieldHandling yieldHandling, TripledotHandling
// name, closing parenthesis, and arrow, and allow it only if all are
// present.
if (tripledotHandling != TripledotAllowed) {
- report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN,
- "expression", TokenKindToDesc(tt));
+ error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt));
return null();
}
@@ -9538,8 +9478,7 @@ Parser<ParseHandler>::primaryExpr(YieldHandling yieldHandling, TripledotHandling
// or "arguments" should be prohibited. Argument-parsing code
// handles that.
if (next != TOK_NAME && next != TOK_YIELD) {
- report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN,
- "rest argument name", TokenKindToDesc(next));
+ error(JSMSG_UNEXPECTED_TOKEN, "rest argument name", TokenKindToDesc(next));
return null();
}
}
@@ -9547,8 +9486,7 @@ Parser<ParseHandler>::primaryExpr(YieldHandling yieldHandling, TripledotHandling
if (!tokenStream.getToken(&next))
return null();
if (next != TOK_RP) {
- report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN,
- "closing parenthesis", TokenKindToDesc(next));
+ error(JSMSG_UNEXPECTED_TOKEN, "closing parenthesis", TokenKindToDesc(next));
return null();
}
@@ -9557,8 +9495,7 @@ Parser<ParseHandler>::primaryExpr(YieldHandling yieldHandling, TripledotHandling
if (next != TOK_ARROW) {
// Advance the scanner for proper error location reporting.
tokenStream.consumeKnownToken(next);
- report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN,
- "'=>' after argument list", TokenKindToDesc(next));
+ error(JSMSG_UNEXPECTED_TOKEN, "'=>' after argument list", TokenKindToDesc(next));
return null();
}
@@ -9569,8 +9506,7 @@ Parser<ParseHandler>::primaryExpr(YieldHandling yieldHandling, TripledotHandling
}
default:
- report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN,
- "expression", TokenKindToDesc(tt));
+ error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt));
return null();
}
}
@@ -9595,7 +9531,7 @@ Parser<ParseHandler>::warnOnceAboutExprClosure()
return true;
if (!cx->compartment()->warnedAboutExprClosure) {
- if (!report(ParseWarning, false, null(), JSMSG_DEPRECATED_EXPR_CLOSURE))
+ if (!warning(JSMSG_DEPRECATED_EXPR_CLOSURE))
return false;
cx->compartment()->warnedAboutExprClosure = true;
}
@@ -9613,7 +9549,7 @@ Parser<ParseHandler>::warnOnceAboutForEach()
if (!cx->compartment()->warnedAboutForEach) {
// Disabled warning spew.
- // if (!report(ParseWarning, false, null(), JSMSG_DEPRECATED_FOR_EACH))
+ // if (!warning(JSMSG_DEPRECATED_FOR_EACH))
// return false;
cx->compartment()->warnedAboutForEach = true;
}
diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h
index 12642fad8..156a1c1b0 100644
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -769,13 +769,13 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
*
* Ex:
* PossibleError possibleError(*this);
- * possibleError.setPendingExpressionError(pn, JSMSG_BAD_PROP_ID);
+ * possibleError.setPendingExpressionErrorAt(pos, JSMSG_BAD_PROP_ID);
* // A JSMSG_BAD_PROP_ID ParseError is reported, returns false.
* if (!possibleError.checkForExpressionError())
* return false; // we reach this point with a pending exception
*
* PossibleError possibleError(*this);
- * possibleError.setPendingExpressionError(pn, JSMSG_BAD_PROP_ID);
+ * possibleError.setPendingExpressionErrorAt(pos, JSMSG_BAD_PROP_ID);
* // Returns true, no error is reported.
* if (!possibleError.checkForDestructuringError())
* return false; // not reached, no pending exception
@@ -815,7 +815,7 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
// Set a pending error. Only a single error may be set per instance and
// error kind.
- void setPending(ErrorKind kind, Node pn, unsigned errorNumber);
+ void setPending(ErrorKind kind, const TokenPos& pos, unsigned errorNumber);
// If there is a pending error, report it and return false, otherwise
// return true.
@@ -830,12 +830,12 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
// Set a pending destructuring error. Only a single error may be set
// per instance, i.e. subsequent calls to this method are ignored and
// won't overwrite the existing pending error.
- void setPendingDestructuringError(Node pn, unsigned errorNumber);
+ void setPendingDestructuringErrorAt(const TokenPos& pos, unsigned errorNumber);
// Set a pending expression error. Only a single error may be set per
// instance, i.e. subsequent calls to this method are ignored and won't
// overwrite the existing pending error.
- void setPendingExpressionError(Node pn, unsigned errorNumber);
+ void setPendingExpressionErrorAt(const TokenPos& pos, unsigned errorNumber);
// If there is a pending destructuring error, report it and return
// false, otherwise return true. Clears any pending expression error.
@@ -903,14 +903,40 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
void prepareNodeForMutation(Node node) { handler.prepareNodeForMutation(node); }
void freeTree(Node node) { handler.freeTree(node); }
- private:
- bool reportHelper(ParseReportKind kind, bool strict, uint32_t offset,
- unsigned errorNumber, va_list args);
public:
- bool report(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...);
bool reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...);
- bool reportWithOffset(ParseReportKind kind, bool strict, uint32_t offset, unsigned errorNumber,
- ...);
+
+ /* Report the given error at the current offset. */
+ void error(unsigned errorNumber, ...);
+
+ /* Report the given error at the given offset. */
+ void errorAt(uint32_t offset, unsigned errorNumber, ...);
+
+ /*
+ * Handle a strict mode error at the current offset. Report an error if in
+ * strict mode code, or warn if not, using the given error number and
+ * arguments.
+ */
+ MOZ_MUST_USE bool strictModeError(unsigned errorNumber, ...);
+
+ /*
+ * Handle a strict mode error at the given offset. Report an error if in
+ * strict mode code, or warn if not, using the given error number and
+ * arguments.
+ */
+ MOZ_MUST_USE bool strictModeErrorAt(uint32_t offset, unsigned errorNumber, ...);
+
+ /* Report the given warning at the current offset. */
+ MOZ_MUST_USE bool warning(unsigned errorNumber, ...);
+
+ /* Report the given warning at the given offset. */
+ MOZ_MUST_USE bool warningAt(uint32_t offset, unsigned errorNumber, ...);
+
+ /*
+ * If extra warnings are enabled, report the given warning at the current
+ * offset.
+ */
+ MOZ_MUST_USE bool extraWarning(unsigned errorNumber, ...);
Parser(ExclusiveContext* cx, LifoAlloc& alloc, const ReadOnlyCompileOptions& options,
const char16_t* chars, size_t length, bool foldConstants, UsedNameTracker& usedNames,
@@ -954,7 +980,8 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
* cx->tempLifoAlloc.
*/
ObjectBox* newObjectBox(JSObject* obj);
- FunctionBox* newFunctionBox(Node fn, JSFunction* fun, Directives directives,
+ FunctionBox* newFunctionBox(Node fn, JSFunction* fun, uint32_t preludeStart,
+ Directives directives,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
bool tryAnnexB);
@@ -1034,8 +1061,9 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
// Parse an inner function given an enclosing ParseContext and a
// FunctionBox for the inner function.
- bool innerFunction(Node pn, ParseContext* outerpc, FunctionBox* funbox, InHandling inHandling,
- YieldHandling yieldHandling, FunctionSyntaxKind kind,
+ bool innerFunction(Node pn, ParseContext* outerpc, FunctionBox* funbox, uint32_t preludeStart,
+ InHandling inHandling, YieldHandling yieldHandling,
+ FunctionSyntaxKind kind,
Directives inheritedDirectives, Directives* newDirectives);
// Parse a function's formal parameters and its body assuming its function
@@ -1088,9 +1116,10 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
* Some parsers have two versions: an always-inlined version (with an 'i'
* suffix) and a never-inlined version (with an 'n' suffix).
*/
- Node functionStmt(YieldHandling yieldHandling, DefaultHandling defaultHandling,
+ Node functionStmt(uint32_t preludeStart,
+ YieldHandling yieldHandling, DefaultHandling defaultHandling,
FunctionAsyncKind asyncKind = SyncFunction);
- Node functionExpr(InvokedPrediction invoked = PredictUninvoked,
+ Node functionExpr(uint32_t preludeStart, InvokedPrediction invoked = PredictUninvoked,
FunctionAsyncKind asyncKind = SyncFunction);
Node statementList(YieldHandling yieldHandling);
@@ -1106,7 +1135,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
Node* forInitialPart,
mozilla::Maybe<ParseContext::Scope>& forLetImpliedScope,
Node* forInOrOfExpression);
- bool validateForInOrOfLHSExpression(Node target, PossibleError* possibleError);
Node expressionAfterForInOrOf(ParseNodeKind forHeadKind, YieldHandling yieldHandling);
Node switchStatement(YieldHandling yieldHandling);
@@ -1222,7 +1250,7 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
bool tryNewTarget(Node& newTarget);
bool checkAndMarkSuperScope();
- Node methodDefinition(PropertyType propType, HandleAtom funName);
+ Node methodDefinition(uint32_t preludeStart, PropertyType propType, HandleAtom funName);
/*
* Additional JS parsers.
@@ -1230,10 +1258,11 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
bool functionArguments(YieldHandling yieldHandling, FunctionSyntaxKind kind,
Node funcpn);
- Node functionDefinition(InHandling inHandling, YieldHandling yieldHandling, HandleAtom name,
+ Node functionDefinition(uint32_t preludeStart, Node pn,
+ InHandling inHandling, YieldHandling yieldHandling, HandleAtom name,
FunctionSyntaxKind kind,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
- InvokedPrediction invoked = PredictUninvoked);
+ bool tryAnnexB = false);
// Parse a function body. Pass StatementListBody if the body is a list of
// statements; pass ExpressionBody if the body is a single expression.
@@ -1298,17 +1327,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
#endif
}
- enum AssignmentFlavor {
- PlainAssignment,
- CompoundAssignment,
- KeyedDestructuringAssignment,
- IncrementAssignment,
- DecrementAssignment,
- ForInOrOfTarget
- };
-
- bool checkAndMarkAsAssignmentLhs(Node pn, AssignmentFlavor flavor,
- PossibleError* possibleError=nullptr);
bool matchInOrOf(bool* isForInp, bool* isForOfp);
bool hasUsedFunctionSpecialName(HandlePropertyName name);
@@ -1319,16 +1337,16 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
Node newDotGeneratorName();
bool declareDotGeneratorName();
- bool checkFunctionDefinition(HandleAtom funAtom, Node pn, FunctionSyntaxKind kind,
- GeneratorKind generatorKind, bool* tryAnnexB);
- bool skipLazyInnerFunction(Node pn, FunctionSyntaxKind kind, bool tryAnnexB);
- bool innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun,
+ bool skipLazyInnerFunction(Node pn, uint32_t preludeStart, FunctionSyntaxKind kind,
+ bool tryAnnexB);
+ bool innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun, uint32_t preludeStart,
InHandling inHandling, YieldHandling yieldHandling,
FunctionSyntaxKind kind,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind, bool tryAnnexB,
Directives inheritedDirectives, Directives* newDirectives);
- bool trySyntaxParseInnerFunction(Node pn, HandleFunction fun, InHandling inHandling,
- YieldHandling yieldHandling, FunctionSyntaxKind kind,
+ bool trySyntaxParseInnerFunction(Node pn, HandleFunction fun, uint32_t preludeStart,
+ InHandling inHandling, YieldHandling yieldHandling,
+ FunctionSyntaxKind kind,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
bool tryAnnexB,
Directives inheritedDirectives, Directives* newDirectives);
@@ -1346,10 +1364,7 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
FunctionCallBehavior behavior = ForbidAssignmentToFunctionCalls);
private:
- bool reportIfArgumentsEvalTarget(Node nameNode);
- bool reportIfNotValidSimpleAssignmentTarget(Node target, AssignmentFlavor flavor);
-
- bool checkAndMarkAsIncOperand(Node kid, AssignmentFlavor flavor);
+ bool checkIncDecOperand(Node operand, uint32_t operandOffset);
bool checkStrictAssignment(Node lhs);
bool checkStrictBinding(PropertyName* name, TokenPos pos);
@@ -1404,16 +1419,12 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
bool checkDestructuringObject(Node objectPattern, mozilla::Maybe<DeclarationKind> maybeDecl);
bool checkDestructuringName(Node expr, mozilla::Maybe<DeclarationKind> maybeDecl);
- bool checkAssignmentToCall(Node node, unsigned errnum);
-
Node newNumber(const Token& tok) {
return handler.newNumber(tok.number(), tok.decimalPoint(), tok.pos);
}
static Node null() { return ParseHandler::null(); }
- bool reportBadReturn(Node pn, ParseReportKind kind, unsigned errnum, unsigned anonerrnum);
-
JSAtom* prefixAccessorName(PropertyType propType, HandleAtom propAtom);
TokenPos pos() const { return tokenStream.currentToken().pos; }
diff --git a/js/src/frontend/SharedContext.h b/js/src/frontend/SharedContext.h
index a6ac542f6..b20417d5d 100644
--- a/js/src/frontend/SharedContext.h
+++ b/js/src/frontend/SharedContext.h
@@ -450,6 +450,7 @@ class FunctionBox : public ObjectBox, public SharedContext
uint32_t bufEnd;
uint32_t startLine;
uint32_t startColumn;
+ uint32_t preludeStart;
uint16_t length;
uint8_t generatorKindBits_; /* The GeneratorKind of this function. */
@@ -476,8 +477,8 @@ class FunctionBox : public ObjectBox, public SharedContext
FunctionContextFlags funCxFlags;
FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* traceListHead, JSFunction* fun,
- Directives directives, bool extraWarnings, GeneratorKind generatorKind,
- FunctionAsyncKind asyncKind);
+ uint32_t preludeStart, Directives directives, bool extraWarnings,
+ GeneratorKind generatorKind, FunctionAsyncKind asyncKind);
MutableHandle<LexicalScope::Data*> namedLambdaBindings() {
MOZ_ASSERT(context->compartment()->runtimeFromAnyThread()->keepAtoms());
diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h
index b7f00605b..00ea9d35d 100644
--- a/js/src/frontend/SyntaxParseHandler.h
+++ b/js/src/frontend/SyntaxParseHandler.h
@@ -342,7 +342,10 @@ class SyntaxParseHandler
void checkAndSetIsDirectRHSAnonFunction(Node pn) {}
- Node newFunctionDefinition() { return NodeFunctionDefinition; }
+ Node newFunctionStatement() { return NodeFunctionDefinition; }
+ Node newFunctionExpression() { return NodeFunctionDefinition; }
+ Node newArrowFunction() { return NodeFunctionDefinition; }
+
bool setComprehensionLambdaBody(Node pn, Node body) { return true; }
void setFunctionFormalParametersAndBody(Node pn, Node kid) {}
void setFunctionBody(Node pn, Node kid) {}
@@ -519,7 +522,7 @@ class SyntaxParseHandler
MOZ_MUST_USE Node setLikelyIIFE(Node pn) {
return pn; // Remain in syntax-parse mode.
}
- void setPrologue(Node pn) {}
+ void setInDirectivePrologue(Node pn) {}
bool isConstant(Node pn) { return false; }
diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
index 179a7c244..8438ff7c5 100644
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -172,6 +172,12 @@ frontend::IsIdentifier(JSLinearString* str)
}
bool
+frontend::IsIdentifier(const char* chars, size_t length)
+{
+ return ::IsIdentifier(chars, length);
+}
+
+bool
frontend::IsIdentifier(const char16_t* chars, size_t length)
{
return ::IsIdentifier(chars, length);
@@ -780,7 +786,7 @@ TokenStream::reportWarning(unsigned errorNumber, ...)
}
bool
-TokenStream::reportStrictWarningErrorNumberVA(uint32_t offset, unsigned errorNumber, va_list args)
+TokenStream::reportExtraWarningErrorNumberVA(uint32_t offset, unsigned errorNumber, va_list args)
{
if (!options().extraWarningsOption)
return true;
diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h
index 5d6b4b795..6ba9fba5a 100644
--- a/js/src/frontend/TokenStream.h
+++ b/js/src/frontend/TokenStream.h
@@ -375,8 +375,7 @@ class MOZ_STACK_CLASS TokenStream
va_list args);
bool reportStrictModeErrorNumberVA(uint32_t offset, bool strictMode, unsigned errorNumber,
va_list args);
- bool reportStrictWarningErrorNumberVA(uint32_t offset, unsigned errorNumber,
- va_list args);
+ bool reportExtraWarningErrorNumberVA(uint32_t offset, unsigned errorNumber, va_list args);
// asm.js reporter
void reportAsmJSError(uint32_t offset, unsigned errorNumber, ...);
@@ -570,6 +569,14 @@ class MOZ_STACK_CLASS TokenStream
return true;
}
+ MOZ_MUST_USE bool peekOffset(uint32_t* offset, Modifier modifier = None) {
+ TokenPos pos;
+ if (!peekTokenPos(&pos, modifier))
+ return false;
+ *offset = pos.begin;
+ return true;
+ }
+
// This is like peekToken(), with one exception: if there is an EOL
// between the end of the current token and the start of the next token, it
// return true and store TOK_EOL in |*ttp|. In that case, no token with
diff --git a/js/src/jit-test/tests/asm.js/testSource.js b/js/src/jit-test/tests/asm.js/testSource.js
index b44c52a6b..d7ad42864 100644
--- a/js/src/jit-test/tests/asm.js/testSource.js
+++ b/js/src/jit-test/tests/asm.js/testSource.js
@@ -32,7 +32,7 @@ var f0 = function() {
}
-funcBody1 = funcBody.replace('function f0','function ');
+funcBody1 = funcBody.replace('function f0','function');
assertEq(f0.toString(), funcBody1);
assertEq(f0.toSource(), '(' + funcBody1 + ')');
@@ -48,14 +48,14 @@ assertEq(g.toString(), funcBody2);
assertEq(g.toSource(), '(' + funcBody2 + ')');
f0 = new Function(bodyOnly);
-assertEq(f0.toString(), "function anonymous() {\n" + bodyOnly + "\n}");
-assertEq(f0.toSource(), "(function anonymous() {\n" + bodyOnly + "\n})");
+assertEq(f0.toString(), "function anonymous(\n) {\n" + bodyOnly + "\n}");
+assertEq(f0.toSource(), "(function anonymous(\n) {\n" + bodyOnly + "\n})");
if (isAsmJSCompilationAvailable() && isCachingEnabled()) {
var m = new Function(bodyOnly);
assertEq(isAsmJSModuleLoadedFromCache(m), true);
- assertEq(m.toString(), "function anonymous() {\n" + bodyOnly + "\n}");
- assertEq(m.toSource(), "(function anonymous() {\n" + bodyOnly + "\n})");
+ assertEq(m.toString(), "function anonymous(\n) {\n" + bodyOnly + "\n}");
+ assertEq(m.toSource(), "(function anonymous(\n) {\n" + bodyOnly + "\n})");
}
})();
@@ -91,7 +91,7 @@ f1 = function(glob) {
}
-funcBody1 = funcBody.replace('function f1', 'function ');
+funcBody1 = funcBody.replace('function f1', 'function');
assertEq(f1.toString(), funcBody1);
assertEq(f1.toSource(), '(' + funcBody1 + ')');
@@ -107,14 +107,14 @@ assertEq(g.toString(), funcBody2);
assertEq(g.toSource(), '(' + funcBody2 + ')');
f1 = new Function('glob', bodyOnly);
-assertEq(f1.toString(), "function anonymous(glob) {\n" + bodyOnly + "\n}");
-assertEq(f1.toSource(), "(function anonymous(glob) {\n" + bodyOnly + "\n})");
+assertEq(f1.toString(), "function anonymous(glob\n) {\n" + bodyOnly + "\n}");
+assertEq(f1.toSource(), "(function anonymous(glob\n) {\n" + bodyOnly + "\n})");
if (isAsmJSCompilationAvailable() && isCachingEnabled()) {
var m = new Function('glob', bodyOnly);
assertEq(isAsmJSModuleLoadedFromCache(m), true);
- assertEq(m.toString(), "function anonymous(glob) {\n" + bodyOnly + "\n}");
- assertEq(m.toSource(), "(function anonymous(glob) {\n" + bodyOnly + "\n})");
+ assertEq(m.toString(), "function anonymous(glob\n) {\n" + bodyOnly + "\n}");
+ assertEq(m.toSource(), "(function anonymous(glob\n) {\n" + bodyOnly + "\n})");
}
})();
@@ -144,14 +144,14 @@ var funcBody = 'function f2(glob, ffi) {\n\
assertEq(f2.toString(), funcBody);
assertEq(f2.toSource(), funcBody);
-f2 = function (glob, ffi) {
+f2 = function(glob, ffi) {
"use asm";
function g() {}
return g;
}
-funcBody1 = funcBody.replace('function f2', 'function ');
+funcBody1 = funcBody.replace('function f2', 'function');
assertEq(f2.toString(), funcBody1);
assertEq(f2.toSource(), '(' + funcBody1 + ')');
@@ -167,14 +167,14 @@ assertEq(g.toString(), funcBody2);
assertEq(g.toSource(), '(' + funcBody2 + ')');
f2 = new Function('glob', 'ffi', bodyOnly);
-assertEq(f2.toString(), "function anonymous(glob, ffi) {\n" + bodyOnly + "\n}");
-assertEq(f2.toSource(), "(function anonymous(glob, ffi) {\n" + bodyOnly + "\n})");
+assertEq(f2.toString(), "function anonymous(glob,ffi\n) {\n" + bodyOnly + "\n}");
+assertEq(f2.toSource(), "(function anonymous(glob,ffi\n) {\n" + bodyOnly + "\n})");
if (isAsmJSCompilationAvailable() && isCachingEnabled()) {
var m = new Function('glob', 'ffi', bodyOnly);
assertEq(isAsmJSModuleLoadedFromCache(m), true);
- assertEq(m.toString(), "function anonymous(glob, ffi) {\n" + bodyOnly + "\n}");
- assertEq(m.toSource(), "(function anonymous(glob, ffi) {\n" + bodyOnly + "\n})");
+ assertEq(m.toString(), "function anonymous(glob,ffi\n) {\n" + bodyOnly + "\n}");
+ assertEq(m.toSource(), "(function anonymous(glob,ffi\n) {\n" + bodyOnly + "\n})");
}
})();
@@ -204,14 +204,14 @@ var funcBody = 'function f3(glob, ffi, heap) {\n\
assertEq(f3.toString(), funcBody);
assertEq(f3.toSource(), funcBody);
-f3 = function (glob, ffi, heap) {
+f3 = function(glob, ffi, heap) {
"use asm";
function g() {}
return g;
}
-funcBody1 = funcBody.replace('function f3', 'function ');
+funcBody1 = funcBody.replace('function f3', 'function');
assertEq(f3.toString(), funcBody1);
assertEq(f3.toSource(), '(' + funcBody1 + ')');
@@ -227,14 +227,14 @@ assertEq(g.toString(), funcBody2);
assertEq(g.toSource(), '(' + funcBody2 + ')');
f3 = new Function('glob', 'ffi', 'heap', bodyOnly);
-assertEq(f3.toString(), "function anonymous(glob, ffi, heap) {\n" + bodyOnly + "\n}");
-assertEq(f3.toSource(), "(function anonymous(glob, ffi, heap) {\n" + bodyOnly + "\n})");
+assertEq(f3.toString(), "function anonymous(glob,ffi,heap\n) {\n" + bodyOnly + "\n}");
+assertEq(f3.toSource(), "(function anonymous(glob,ffi,heap\n) {\n" + bodyOnly + "\n})");
if (isAsmJSCompilationAvailable() && isCachingEnabled()) {
var m = new Function('glob', 'ffi', 'heap', bodyOnly);
assertEq(isAsmJSModuleLoadedFromCache(m), true);
- assertEq(m.toString(), "function anonymous(glob, ffi, heap) {\n" + bodyOnly + "\n}");
- assertEq(m.toSource(), "(function anonymous(glob, ffi, heap) {\n" + bodyOnly + "\n})");
+ assertEq(m.toString(), "function anonymous(glob,ffi,heap\n) {\n" + bodyOnly + "\n}");
+ assertEq(m.toSource(), "(function anonymous(glob,ffi,heap\n) {\n" + bodyOnly + "\n})");
}
})();
@@ -243,7 +243,7 @@ if (isAsmJSCompilationAvailable() && isCachingEnabled()) {
(function() {
var funcSource =
- `function (glob, ffi, heap) {
+ `function(glob, ffi, heap) {
"use asm";
function g() {}
return g;
@@ -252,7 +252,7 @@ var funcSource =
var f4 = eval("\"use strict\";\n(" + funcSource + ")");
var expectedToString = funcSource;
-var expectedToSource = '(' + expectedToString + ')'
+var expectedToSource = '(' + expectedToString + ')';
assertEq(f4.toString(), expectedToString);
assertEq(f4.toSource(), expectedToSource);
diff --git a/js/src/jit-test/tests/basic/function-tosource-bug779694.js b/js/src/jit-test/tests/basic/function-tosource-bug779694.js
index 3893d3ff2..782b2594b 100644
--- a/js/src/jit-test/tests/basic/function-tosource-bug779694.js
+++ b/js/src/jit-test/tests/basic/function-tosource-bug779694.js
@@ -5,4 +5,4 @@ for (var i=0; i<400; ++i) {
x += String.fromCharCode(i * 289);
}
var s = "'" + x + "'";
-assertEq(Function("evt", s).toString(), "function anonymous(evt) {\n" + s + "\n}");
+assertEq(Function("evt", s).toString(), "function anonymous(evt\n) {\n" + s + "\n}");
diff --git a/js/src/jit-test/tests/basic/function-tosource-constructor.js b/js/src/jit-test/tests/basic/function-tosource-constructor.js
index e1d144364..9a8961fe2 100644
--- a/js/src/jit-test/tests/basic/function-tosource-constructor.js
+++ b/js/src/jit-test/tests/basic/function-tosource-constructor.js
@@ -1,14 +1,14 @@
var f = Function("a", "b", "return a + b;");
-assertEq(f.toString(), "function anonymous(a, b) {\nreturn a + b;\n}");
-assertEq(f.toSource(), "(function anonymous(a, b) {\nreturn a + b;\n})");
+assertEq(f.toString(), "function anonymous(a,b\n) {\nreturn a + b;\n}");
+assertEq(f.toSource(), "(function anonymous(a,b\n) {\nreturn a + b;\n})");
assertEq(decompileFunction(f), f.toString());
f = Function("a", "...rest", "return rest[42] + b;");
-assertEq(f.toString(), "function anonymous(a, ...rest) {\nreturn rest[42] + b;\n}");
-assertEq(f.toSource(), "(function anonymous(a, ...rest) {\nreturn rest[42] + b;\n})")
+assertEq(f.toString(), "function anonymous(a,...rest\n) {\nreturn rest[42] + b;\n}");
+assertEq(f.toSource(), "(function anonymous(a,...rest\n) {\nreturn rest[42] + b;\n})")
assertEq(decompileFunction(f), f.toString());
f = Function("");
-assertEq(f.toString(), "function anonymous() {\n\n}");
+assertEq(f.toString(), "function anonymous(\n) {\n\n}");
f = Function("", "(abc)");
-assertEq(f.toString(), "function anonymous() {\n(abc)\n}");
-f = Function("", "return function (a, b) a + b;")();
-assertEq(f.toString(), "function (a, b) a + b");
+assertEq(f.toString(), "function anonymous(\n) {\n(abc)\n}");
+f = Function("", "return function (a,b) a + b;")();
+assertEq(f.toString(), "function (a,b) a + b");
diff --git a/js/src/jit-test/tests/basic/function-tosource-getset.js b/js/src/jit-test/tests/basic/function-tosource-getset.js
index 36c6d010e..1804d38f2 100644
--- a/js/src/jit-test/tests/basic/function-tosource-getset.js
+++ b/js/src/jit-test/tests/basic/function-tosource-getset.js
@@ -1,7 +1,7 @@
var o = {get prop() a + b, set prop(x) a + b};
var prop = Object.getOwnPropertyDescriptor(o, "prop");
-assertEq(prop.get.toString(), "function get prop() a + b");
-assertEq(prop.get.toSource(), "(function get prop() a + b)");
-assertEq(prop.set.toString(), "function set prop(x) a + b");
-assertEq(prop.set.toSource(), "(function set prop(x) a + b)");
-assertEq(o.toSource(), "({get prop () a + b, set prop (x) a + b})");
+assertEq(prop.get.toString(), "get prop() { a + b; }");
+assertEq(prop.get.toSource(), "get prop() { a + b; }");
+assertEq(prop.set.toString(), "set prop(x) { a + b; }");
+assertEq(prop.set.toSource(), "set prop(x) { a + b; }");
+assertEq(o.toSource(), "({get prop() { a + b; }, set prop(x) { a + b; }})");
diff --git a/js/src/jit-test/tests/basic/testLet.js b/js/src/jit-test/tests/basic/testLet.js
index 263c3eb8a..9a2f39197 100644
--- a/js/src/jit-test/tests/basic/testLet.js
+++ b/js/src/jit-test/tests/basic/testLet.js
@@ -9,7 +9,7 @@ function test(str, arg, result)
var fun = new Function('x', str);
var got = fun.toSource();
- var expect = '(function anonymous(x) {\n' + str + '\n})';
+ var expect = '(function anonymous(x\n) {\n' + str + '\n})';
if (got !== expect) {
print("GOT: " + got);
print("EXPECT: " + expect);
diff --git a/js/src/jit-test/tests/debug/Script-gc-02.js b/js/src/jit-test/tests/debug/Script-gc-02.js
index 04dd4b220..9689a6ebe 100644
--- a/js/src/jit-test/tests/debug/Script-gc-02.js
+++ b/js/src/jit-test/tests/debug/Script-gc-02.js
@@ -10,5 +10,5 @@ assertEq(arr.length, 10);
gc();
for (var i = 0; i < arr.length; i++)
- assertEq(arr[i].lineCount, 3);
+ assertEq(arr[i].lineCount, 4);
diff --git a/js/src/jit-test/tests/debug/Script-gc-03.js b/js/src/jit-test/tests/debug/Script-gc-03.js
index 30c3e8dbc..5ecb4556f 100644
--- a/js/src/jit-test/tests/debug/Script-gc-03.js
+++ b/js/src/jit-test/tests/debug/Script-gc-03.js
@@ -10,6 +10,6 @@ assertEq(arr.length, 100);
gc(g);
for (var i = 0; i < arr.length; i++)
- assertEq(arr[i].lineCount, 3);
+ assertEq(arr[i].lineCount, 4);
gc();
diff --git a/js/src/jit-test/tests/debug/Script-sourceStart-04.js b/js/src/jit-test/tests/debug/Script-sourceStart-04.js
index 2aa382b7b..4546818e4 100644
--- a/js/src/jit-test/tests/debug/Script-sourceStart-04.js
+++ b/js/src/jit-test/tests/debug/Script-sourceStart-04.js
@@ -20,6 +20,6 @@ function test(string, range) {
}
test("eval('2 * 3')", [0, 5]);
-test("new Function('2 * 3')", [0, 12]);
-test("new Function('x', 'x * x')", [0, 13]);
+test("new Function('2 * 3')", [0, 31]);
+test("new Function('x', 'x * x')", [0, 32]);
assertEq(count, 6);
diff --git a/js/src/jit-test/tests/debug/Source-text-02.js b/js/src/jit-test/tests/debug/Source-text-02.js
index 64cfce92a..46e76015e 100644
--- a/js/src/jit-test/tests/debug/Source-text-02.js
+++ b/js/src/jit-test/tests/debug/Source-text-02.js
@@ -3,6 +3,7 @@
let g = newGlobal();
let dbg = new Debugger(g);
+var text;
var count = 0;
dbg.onNewScript = function (script) {
++count;
diff --git a/js/src/jit-test/tests/latin1/assorted.js b/js/src/jit-test/tests/latin1/assorted.js
index cef79cb96..1389a1ada 100644
--- a/js/src/jit-test/tests/latin1/assorted.js
+++ b/js/src/jit-test/tests/latin1/assorted.js
@@ -12,18 +12,18 @@ var o = {};
Object.defineProperty(o, "prop", {get: function() { return 1; },
set: function() { return 2; },
enumerable: true, configurable: true});
-assertEq(o.toSource(), "({get prop () { return 1; }, set prop () { return 2; }})");
+assertEq(o.toSource(), "({get prop() { return 1; }, set prop() { return 2; }})");
// obj.toSource TwoByte
Object.defineProperty(o, "prop", {get: function() { return "\u1200"; },
set: function() { return "\u1200"; },
enumerable: true});
-assertEq(o.toSource(), '({get prop () { return "\\u1200"; }, set prop () { return "\\u1200"; }})');
+assertEq(o.toSource(), '({get prop() { return "\\u1200"; }, set prop() { return "\\u1200"; }})');
var ff = function() { return 10; };
ff.toSource = function() { return "((11))"; }
Object.defineProperty(o, "prop", {get: ff, set: ff, enumerable: true});
-assertEq(o.toSource(), "({prop:((11)), prop:((11))})");
+assertEq(o.toSource(), "({get prop(11), set prop(11)})");
// XDR
load(libdir + 'bytecode-cache.js');
diff --git a/js/src/jit-test/tests/latin1/function.js b/js/src/jit-test/tests/latin1/function.js
index a0dedf251..07a76733a 100644
--- a/js/src/jit-test/tests/latin1/function.js
+++ b/js/src/jit-test/tests/latin1/function.js
@@ -6,11 +6,11 @@ function test() {
var f = Function(arg1TwoByte, arg2Latin1, bodyLatin1);
assertEq(f(10, 20), 60);
- assertEq(f.toSource().includes("arg1\u1200, arg2"), true);
+ assertEq(f.toSource().includes("arg1\u1200,arg2"), true);
var bodyTwoByte = "return arg1\u1200 + arg2;";
f = Function(arg1TwoByte, arg2Latin1, bodyTwoByte);
assertEq(f(30, 40), 70);
- assertEq(f.toSource().includes("arg1\u1200, arg2"), true);
+ assertEq(f.toSource().includes("arg1\u1200,arg2"), true);
}
test();
diff --git a/js/src/js.msg b/js/src/js.msg
index a276dab94..4ded69a25 100644
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -186,7 +186,6 @@ MSG_DEF(JSMSG_AS_AFTER_IMPORT_STAR, 0, JSEXN_SYNTAXERR, "missing keyword 'as'
MSG_DEF(JSMSG_AS_AFTER_RESERVED_WORD, 1, JSEXN_SYNTAXERR, "missing keyword 'as' after reserved word '{0}'")
MSG_DEF(JSMSG_ASYNC_GENERATOR, 0, JSEXN_SYNTAXERR, "generator function or method can't be async")
MSG_DEF(JSMSG_AWAIT_IN_DEFAULT, 0, JSEXN_SYNTAXERR, "await can't be used in default expression")
-MSG_DEF(JSMSG_BAD_ANON_GENERATOR_RETURN, 0, JSEXN_TYPEERR, "anonymous generator function returns a value")
MSG_DEF(JSMSG_BAD_ARROW_ARGS, 0, JSEXN_SYNTAXERR, "invalid arrow-function arguments (parentheses around the arrow-function may help)")
MSG_DEF(JSMSG_BAD_BINDING, 1, JSEXN_SYNTAXERR, "redefining {0} is deprecated")
MSG_DEF(JSMSG_BAD_CONST_DECL, 0, JSEXN_SYNTAXERR, "missing = in const declaration")
@@ -200,12 +199,12 @@ MSG_DEF(JSMSG_BAD_FOR_EACH_LOOP, 0, JSEXN_SYNTAXERR, "invalid for each loo
MSG_DEF(JSMSG_BAD_FOR_LEFTSIDE, 0, JSEXN_SYNTAXERR, "invalid for-in/of left-hand side")
MSG_DEF(JSMSG_LEXICAL_DECL_DEFINES_LET,0, JSEXN_SYNTAXERR, "a lexical declaration can't define a 'let' binding")
MSG_DEF(JSMSG_LET_STARTING_FOROF_LHS, 0, JSEXN_SYNTAXERR, "an expression X in 'for (X of Y)' must not start with 'let'")
-MSG_DEF(JSMSG_BAD_GENERATOR_RETURN, 1, JSEXN_TYPEERR, "generator function {0} returns a value")
+MSG_DEF(JSMSG_BAD_FUNCTION_YIELD, 0, JSEXN_TYPEERR, "can't use 'yield' in a function that can return a value")
+MSG_DEF(JSMSG_BAD_GENERATOR_RETURN, 0, JSEXN_TYPEERR, "generator function can't return a value")
MSG_DEF(JSMSG_BAD_GENEXP_BODY, 1, JSEXN_SYNTAXERR, "illegal use of {0} in generator expression")
-MSG_DEF(JSMSG_BAD_INCOP_OPERAND, 0, JSEXN_REFERENCEERR, "invalid increment/decrement operand")
+MSG_DEF(JSMSG_BAD_INCOP_OPERAND, 0, JSEXN_SYNTAXERR, "invalid increment/decrement operand")
MSG_DEF(JSMSG_BAD_METHOD_DEF, 0, JSEXN_SYNTAXERR, "bad method definition")
MSG_DEF(JSMSG_BAD_OCTAL, 1, JSEXN_SYNTAXERR, "{0} is not a legal ECMA-262 octal constant")
-MSG_DEF(JSMSG_BAD_OPERAND, 1, JSEXN_SYNTAXERR, "invalid {0} operand")
MSG_DEF(JSMSG_BAD_POW_LEFTSIDE, 0, JSEXN_SYNTAXERR, "unparenthesized unary expression can't appear on the left-hand side of '**'")
MSG_DEF(JSMSG_BAD_PROP_ID, 0, JSEXN_SYNTAXERR, "invalid property id")
MSG_DEF(JSMSG_BAD_RETURN_OR_YIELD, 1, JSEXN_SYNTAXERR, "{0} not in function")
@@ -262,6 +261,8 @@ MSG_DEF(JSMSG_GARBAGE_AFTER_INPUT, 2, JSEXN_SYNTAXERR, "unexpected garbage a
MSG_DEF(JSMSG_IDSTART_AFTER_NUMBER, 0, JSEXN_SYNTAXERR, "identifier starts immediately after numeric literal")
MSG_DEF(JSMSG_ILLEGAL_CHARACTER, 0, JSEXN_SYNTAXERR, "illegal character")
MSG_DEF(JSMSG_IMPORT_DECL_AT_TOP_LEVEL, 0, JSEXN_SYNTAXERR, "import declarations may only appear at top level of a module")
+MSG_DEF(JSMSG_OF_AFTER_FOR_LOOP_DECL, 0, JSEXN_SYNTAXERR, "a declaration in the head of a for-of loop can't have an initializer")
+MSG_DEF(JSMSG_IN_AFTER_LEXICAL_FOR_DECL,0,JSEXN_SYNTAXERR, "a lexical declaration in the head of a for-in loop can't have an initializer")
MSG_DEF(JSMSG_INVALID_FOR_IN_DECL_WITH_INIT,0,JSEXN_SYNTAXERR,"for-in loop head declarations may not have initializers")
MSG_DEF(JSMSG_LABEL_NOT_FOUND, 0, JSEXN_SYNTAXERR, "label not found")
MSG_DEF(JSMSG_LET_COMP_BINDING, 0, JSEXN_SYNTAXERR, "'let' is not a valid name for a comprehension variable")
diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp
index 6114b8157..f78f94dc1 100644
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -4250,7 +4250,7 @@ JS_GetFunctionScript(JSContext* cx, HandleFunction fun)
*/
static bool
CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
- const char* name,
+ HandleAtom name, bool isInvalidName,
SourceBufferHolder& srcBuf, uint32_t parameterListEnd,
HandleObject enclosingEnv, HandleScope enclosingScope,
MutableHandleFunction fun)
@@ -4261,13 +4261,8 @@ CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
assertSameCompartment(cx, enclosingEnv);
RootedAtom funAtom(cx);
- if (name) {
- funAtom = Atomize(cx, name, strlen(name));
- if (!funAtom)
- return false;
- }
-
- fun.set(NewScriptedFunction(cx, 0, JSFunction::INTERPRETED_NORMAL, funAtom,
+ fun.set(NewScriptedFunction(cx, 0, JSFunction::INTERPRETED_NORMAL,
+ isInvalidName ? nullptr : name,
/* proto = */ nullptr,
gc::AllocKind::FUNCTION, TenuredObject,
enclosingEnv));
@@ -4285,11 +4280,17 @@ CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
return false;
}
+ // When function name is not a valid identifier, the generated function
+ // source in srcBuf doesn't have a function name. Set it here.
+ if (isInvalidName)
+ fun->setAtom(name);
+
return true;
}
static MOZ_MUST_USE bool
-BuildFunctionString(unsigned nargs, const char* const* argnames,
+BuildFunctionString(const char* name, size_t nameLen,
+ unsigned nargs, const char* const* argnames,
const SourceBufferHolder& srcBuf, StringBuffer* out,
uint32_t* parameterListEnd)
{
@@ -4298,6 +4299,12 @@ BuildFunctionString(unsigned nargs, const char* const* argnames,
if (!out->ensureTwoByteChars())
return false;
+ if (!out->append("function "))
+ return false;
+ if (name) {
+ if (!out->append(name, nameLen))
+ return false;
+ }
if (!out->append("("))
return false;
for (unsigned i = 0; i < nargs; i++) {
@@ -4334,15 +4341,32 @@ JS::CompileFunction(JSContext* cx, AutoObjectVector& envChain,
if (!CreateNonSyntacticEnvironmentChain(cx, envChain, &env, &scope))
return false;
+ size_t nameLen = 0;
+ bool isInvalidName = false;
+ RootedAtom nameAtom(cx);
+ if (name) {
+ nameLen = strlen(name);
+ nameAtom = Atomize(cx, name, nameLen);
+ if (!nameAtom)
+ return false;
+
+ // If name is not valid identifier
+ if (!js::frontend::IsIdentifier(name, nameLen))
+ isInvalidName = true;
+ }
+
uint32_t parameterListEnd;
StringBuffer funStr(cx);
- if (!BuildFunctionString(nargs, argnames, srcBuf, &funStr, &parameterListEnd))
+ if (!BuildFunctionString(isInvalidName ? nullptr : name, nameLen, nargs, argnames, srcBuf,
+ &funStr, &parameterListEnd)) {
return false;
+ }
size_t newLen = funStr.length();
SourceBufferHolder newSrcBuf(funStr.stealChars(), newLen, SourceBufferHolder::GiveOwnership);
- return CompileFunction(cx, options, name, newSrcBuf, parameterListEnd, env, scope, fun);
+ return CompileFunction(cx, options, nameAtom, isInvalidName, newSrcBuf, parameterListEnd, env,
+ scope, fun);
}
JS_PUBLIC_API(bool)
diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp
index 98311be2f..e624aa415 100644
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -781,8 +781,10 @@ CreateFunctionPrototype(JSContext* cx, JSProtoKey key)
RootedFunction functionProto(cx, &functionProto_->as<JSFunction>());
- const char* rawSource = "() {\n}";
+ const char* rawSource = "function () {\n}";
size_t sourceLen = strlen(rawSource);
+ size_t begin = 9;
+ MOZ_ASSERT(rawSource[begin] == '(');
mozilla::UniquePtr<char16_t[], JS::FreePolicy> source(InflateString(cx, rawSource, &sourceLen));
if (!source)
return nullptr;
@@ -804,8 +806,9 @@ CreateFunctionPrototype(JSContext* cx, JSProtoKey key)
RootedScript script(cx, JSScript::Create(cx,
options,
sourceObject,
- 0,
- ss->length()));
+ begin,
+ ss->length(),
+ 0));
if (!script || !JSScript::initFunctionPrototype(cx, script, functionProto))
return nullptr;
@@ -985,53 +988,62 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint)
}
}
- if (fun->isAsync()) {
- if (!out.append("async "))
- return nullptr;
- }
-
- bool funIsMethodOrNonArrowLambda = (fun->isLambda() && !fun->isArrow()) || fun->isMethod() ||
- fun->isGetter() || fun->isSetter();
+ bool funIsNonArrowLambda = fun->isLambda() && !fun->isArrow();
bool haveSource = fun->isInterpreted() && !fun->isSelfHostedBuiltin();
- // If we're not in pretty mode, put parentheses around lambda functions and methods.
- if (haveSource && !prettyPrint && funIsMethodOrNonArrowLambda) {
+ // If we're not in pretty mode, put parentheses around lambda functions
+ // so that eval returns lambda, not function statement.
+ if (haveSource && !prettyPrint && funIsNonArrowLambda) {
if (!out.append("("))
return nullptr;
}
- if (!fun->isArrow()) {
- bool ok;
- if (fun->isStarGenerator() && !fun->isAsync())
- ok = out.append("function* ");
- else
- ok = out.append("function ");
- if (!ok)
- return nullptr;
- }
- if (fun->explicitName()) {
- if (!out.append(fun->explicitName()))
- return nullptr;
- }
if (haveSource && !script->scriptSource()->hasSourceData() &&
!JSScript::loadSource(cx, script->scriptSource(), &haveSource))
{
return nullptr;
}
+
+ auto AppendPrelude = [&out, &fun]() {
+ if (fun->isAsync()) {
+ if (!out.append("async "))
+ return false;
+ }
+
+ if (!fun->isArrow()) {
+ if (!out.append("function"))
+ return false;
+
+ if (fun->isStarGenerator()) {
+ if (!out.append('*'))
+ return false;
+ }
+ }
+
+ if (fun->explicitName()) {
+ if (!out.append(' '))
+ return false;
+ if (!out.append(fun->explicitName()))
+ return false;
+ }
+ return true;
+ };
+
if (haveSource) {
- Rooted<JSFlatString*> src(cx, script->sourceData(cx));
+ Rooted<JSFlatString*> src(cx, script->sourceDataWithPrelude(cx));
if (!src)
return nullptr;
if (!out.append(src))
return nullptr;
- if (!prettyPrint && funIsMethodOrNonArrowLambda) {
+ if (!prettyPrint && funIsNonArrowLambda) {
if (!out.append(")"))
return nullptr;
}
} else if (fun->isInterpreted() && !fun->isSelfHostedBuiltin()) {
- if (!out.append("() {\n ") ||
+ if (!AppendPrelude() ||
+ !out.append("() {\n ") ||
!out.append("[sourceless code]") ||
!out.append("\n}"))
{
@@ -1042,13 +1054,15 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint)
bool derived = fun->infallibleIsDefaultClassConstructor(cx);
if (derived && fun->isDerivedClassConstructor()) {
- if (!out.append("(...args) {\n ") ||
+ if (!AppendPrelude() ||
+ !out.append("(...args) {\n ") ||
!out.append("super(...args);\n}"))
{
return nullptr;
}
} else {
- if (!out.append("() {\n "))
+ if (!AppendPrelude() ||
+ !out.append("() {\n "))
return nullptr;
if (!derived) {
@@ -1635,7 +1649,18 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator
StringBuffer sb(cx);
- if (!sb.append('('))
+ if (isAsync) {
+ if (!sb.append("async "))
+ return false;
+ }
+ if (!sb.append("function"))
+ return false;
+ if (isStarGenerator && !isAsync) {
+ if (!sb.append('*'))
+ return false;
+ }
+
+ if (!sb.append(" anonymous("))
return false;
if (args.length() > 1) {
@@ -1656,12 +1681,15 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator
if (i < args.length() - 2) {
// Step 9.d.iii.
- if (!sb.append(", "))
+ if (!sb.append(","))
return false;
}
}
}
+ if (!sb.append('\n'))
+ return false;
+
// Remember the position of ")".
Maybe<uint32_t> parameterListEnd = Some(uint32_t(sb.length()));
MOZ_ASSERT(FunctionConstructorMedialSigils[0] == ')');
diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp
index 9f914943e..33ae56d6f 100644
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -235,6 +235,7 @@ XDRRelazificationInfo(XDRState<mode>* xdr, HandleFunction fun, HandleScript scri
{
uint32_t begin = script->sourceStart();
uint32_t end = script->sourceEnd();
+ uint32_t preludeStart = script->preludeStart();
uint32_t lineno = script->lineno();
uint32_t column = script->column();
@@ -242,6 +243,7 @@ XDRRelazificationInfo(XDRState<mode>* xdr, HandleFunction fun, HandleScript scri
packedFields = lazy->packedFields();
MOZ_ASSERT(begin == lazy->begin());
MOZ_ASSERT(end == lazy->end());
+ MOZ_ASSERT(preludeStart == lazy->preludeStart());
MOZ_ASSERT(lineno == lazy->lineno());
MOZ_ASSERT(column == lazy->column());
// We can assert we have no inner functions because we don't
@@ -255,7 +257,7 @@ XDRRelazificationInfo(XDRState<mode>* xdr, HandleFunction fun, HandleScript scri
if (mode == XDR_DECODE) {
lazy.set(LazyScript::Create(cx, fun, script, enclosingScope, script,
- packedFields, begin, end, lineno, column));
+ packedFields, begin, end, preludeStart, lineno, column));
// As opposed to XDRLazyScript, we need to restore the runtime bits
// of the script, as we are trying to match the fact this function
@@ -517,7 +519,7 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope, HandleScrip
sourceObject = &enclosingScript->sourceObject()->as<ScriptSourceObject>();
}
- script = JSScript::Create(cx, options, sourceObject, 0, 0);
+ script = JSScript::Create(cx, options, sourceObject, 0, 0, 0);
if (!script)
return false;
@@ -600,6 +602,8 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope, HandleScrip
return false;
if (!xdr->codeUint32(&script->sourceEnd_))
return false;
+ if (!xdr->codeUint32(&script->preludeStart_))
+ return false;
if (!xdr->codeUint32(&lineno) ||
!xdr->codeUint32(&column) ||
@@ -930,6 +934,7 @@ js::XDRLazyScript(XDRState<mode>* xdr, HandleScope enclosingScope, HandleScript
{
uint32_t begin;
uint32_t end;
+ uint32_t preludeStart;
uint32_t lineno;
uint32_t column;
uint64_t packedFields;
@@ -943,12 +948,14 @@ js::XDRLazyScript(XDRState<mode>* xdr, HandleScope enclosingScope, HandleScript
begin = lazy->begin();
end = lazy->end();
+ preludeStart = lazy->preludeStart();
lineno = lazy->lineno();
column = lazy->column();
packedFields = lazy->packedFields();
}
if (!xdr->codeUint32(&begin) || !xdr->codeUint32(&end) ||
+ !xdr->codeUint32(&preludeStart) ||
!xdr->codeUint32(&lineno) || !xdr->codeUint32(&column) ||
!xdr->codeUint64(&packedFields))
{
@@ -957,7 +964,7 @@ js::XDRLazyScript(XDRState<mode>* xdr, HandleScope enclosingScope, HandleScript
if (mode == XDR_DECODE) {
lazy.set(LazyScript::Create(cx, fun, nullptr, enclosingScope, enclosingScript,
- packedFields, begin, end, lineno, column));
+ packedFields, begin, end, preludeStart, lineno, column));
if (!lazy)
return false;
fun->initLazyScript(lazy);
@@ -1430,6 +1437,13 @@ JSScript::sourceData(JSContext* cx)
return scriptSource()->substring(cx, sourceStart(), sourceEnd());
}
+JSFlatString*
+JSScript::sourceDataWithPrelude(JSContext* cx)
+{
+ MOZ_ASSERT(scriptSource()->hasSourceData());
+ return scriptSource()->substring(cx, preludeStart(), sourceEnd());
+}
+
UncompressedSourceCache::AutoHoldEntry::AutoHoldEntry()
: cache_(nullptr), sourceChunk_()
{
@@ -2428,7 +2442,8 @@ JSScript::initCompartment(ExclusiveContext* cx)
/* static */ JSScript*
JSScript::Create(ExclusiveContext* cx, const ReadOnlyCompileOptions& options,
- HandleObject sourceObject, uint32_t bufStart, uint32_t bufEnd)
+ HandleObject sourceObject, uint32_t bufStart, uint32_t bufEnd,
+ uint32_t preludeStart)
{
MOZ_ASSERT(bufStart <= bufEnd);
@@ -2450,6 +2465,7 @@ JSScript::Create(ExclusiveContext* cx, const ReadOnlyCompileOptions& options,
script->setSourceObject(sourceObject);
script->sourceStart_ = bufStart;
script->sourceEnd_ = bufEnd;
+ script->preludeStart_ = preludeStart;
return script;
}
@@ -3382,7 +3398,8 @@ CreateEmptyScriptForClone(JSContext* cx, HandleScript src)
.setNoScriptRval(src->noScriptRval())
.setVersion(src->getVersion());
- return JSScript::Create(cx, options, sourceObject, src->sourceStart(), src->sourceEnd());
+ return JSScript::Create(cx, options, sourceObject, src->sourceStart(), src->sourceEnd(),
+ src->preludeStart());
}
JSScript*
@@ -3932,7 +3949,8 @@ JSScript::formalLivesInArgumentsObject(unsigned argSlot)
}
LazyScript::LazyScript(JSFunction* fun, void* table, uint64_t packedFields,
- uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column)
+ uint32_t begin, uint32_t end,
+ uint32_t preludeStart, uint32_t lineno, uint32_t column)
: script_(nullptr),
function_(fun),
enclosingScope_(nullptr),
@@ -3941,6 +3959,7 @@ LazyScript::LazyScript(JSFunction* fun, void* table, uint64_t packedFields,
packedFields_(packedFields),
begin_(begin),
end_(end),
+ preludeStart_(preludeStart),
lineno_(lineno),
column_(column)
{
@@ -3990,7 +4009,7 @@ LazyScript::maybeForwardedScriptSource() const
/* static */ LazyScript*
LazyScript::CreateRaw(ExclusiveContext* cx, HandleFunction fun,
uint64_t packedFields, uint32_t begin, uint32_t end,
- uint32_t lineno, uint32_t column)
+ uint32_t preludeStart, uint32_t lineno, uint32_t column)
{
union {
PackedView p;
@@ -4018,7 +4037,8 @@ LazyScript::CreateRaw(ExclusiveContext* cx, HandleFunction fun,
cx->compartment()->scheduleDelazificationForDebugger();
- return new (res) LazyScript(fun, table.forget(), packed, begin, end, lineno, column);
+ return new (res) LazyScript(fun, table.forget(), packed, begin, end,
+ preludeStart, lineno, column);
}
/* static */ LazyScript*
@@ -4026,7 +4046,8 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun,
const frontend::AtomVector& closedOverBindings,
Handle<GCVector<JSFunction*, 8>> innerFunctions,
JSVersion version,
- uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column)
+ uint32_t begin, uint32_t end,
+ uint32_t preludeStart, uint32_t lineno, uint32_t column)
{
union {
PackedView p;
@@ -4049,7 +4070,8 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun,
p.isDerivedClassConstructor = false;
p.needsHomeObject = false;
- LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, lineno, column);
+ LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, preludeStart,
+ lineno, column);
if (!res)
return nullptr;
@@ -4070,7 +4092,7 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun,
HandleScript script, HandleScope enclosingScope,
HandleScript enclosingScript,
uint64_t packedFields, uint32_t begin, uint32_t end,
- uint32_t lineno, uint32_t column)
+ uint32_t preludeStart, uint32_t lineno, uint32_t column)
{
// Dummy atom which is not a valid property name.
RootedAtom dummyAtom(cx, cx->names().comma);
@@ -4079,7 +4101,8 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun,
// holding this lazy script.
HandleFunction dummyFun = fun;
- LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, lineno, column);
+ LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, preludeStart,
+ lineno, column);
if (!res)
return nullptr;
diff --git a/js/src/jsscript.h b/js/src/jsscript.h
index 87da79901..bb8635581 100644
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -575,10 +575,6 @@ class ScriptSource
introductionOffset_ = offset;
hasIntroductionOffset_ = true;
}
-
- uint32_t parameterListEnd() const {
- return parameterListEnd_;
- }
};
class ScriptSourceHolder
@@ -857,9 +853,19 @@ class JSScript : public js::gc::TenuredCell
uint32_t bodyScopeIndex_; /* index into the scopes array of the body scope */
- /* Range of characters in scriptSource which contains this script's source. */
+ // Range of characters in scriptSource which contains this script's source.
+ // each field points the following location.
+ //
+ // function * f(a, b) { return a + b; }
+ // ^ ^ ^
+ // | | |
+ // | sourceStart_ sourceEnd_
+ // |
+ // preludeStart_
+ //
uint32_t sourceStart_;
uint32_t sourceEnd_;
+ uint32_t preludeStart_;
// Number of times the script has been called or has had backedges taken.
// When running in ion, also increased for any inlined scripts. Reset if
@@ -1020,7 +1026,7 @@ class JSScript : public js::gc::TenuredCell
// instead of private to suppress -Wunused-private-field compiler warnings.
protected:
#if JS_BITS_PER_WORD == 32
- // Currently no padding is needed.
+ uint32_t padding;
#endif
//
@@ -1031,7 +1037,7 @@ class JSScript : public js::gc::TenuredCell
static JSScript* Create(js::ExclusiveContext* cx,
const JS::ReadOnlyCompileOptions& options,
js::HandleObject sourceObject, uint32_t sourceStart,
- uint32_t sourceEnd);
+ uint32_t sourceEnd, uint32_t preludeStart);
void initCompartment(js::ExclusiveContext* cx);
@@ -1178,6 +1184,10 @@ class JSScript : public js::gc::TenuredCell
return sourceEnd_;
}
+ size_t preludeStart() const {
+ return preludeStart_;
+ }
+
bool noScriptRval() const {
return noScriptRval_;
}
@@ -1501,7 +1511,8 @@ class JSScript : public js::gc::TenuredCell
bool mayReadFrameArgsDirectly();
JSFlatString* sourceData(JSContext* cx);
-
+ JSFlatString* sourceDataWithPrelude(JSContext* cx);
+
static bool loadSource(JSContext* cx, js::ScriptSource* ss, bool* worked);
void setSourceObject(JSObject* object);
@@ -1920,7 +1931,8 @@ class LazyScript : public gc::TenuredCell
// instead of private to suppress -Wunused-private-field compiler warnings.
protected:
#if JS_BITS_PER_WORD == 32
- uint32_t padding;
+ // uint32_t padding;
+ // Currently no padding is needed.
#endif
private:
@@ -1960,20 +1972,25 @@ class LazyScript : public gc::TenuredCell
};
// Source location for the script.
+ // See the comment in JSScript for the details.
uint32_t begin_;
uint32_t end_;
+ uint32_t preludeStart_;
+ // Line and column of |begin_| position, that is the position where we
+ // start parsing.
uint32_t lineno_;
uint32_t column_;
LazyScript(JSFunction* fun, void* table, uint64_t packedFields,
- uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column);
+ uint32_t begin, uint32_t end, uint32_t preludeStart,
+ uint32_t lineno, uint32_t column);
// Create a LazyScript without initializing the closedOverBindings and the
// innerFunctions. To be GC-safe, the caller must initialize both vectors
// with valid atoms and functions.
static LazyScript* CreateRaw(ExclusiveContext* cx, HandleFunction fun,
uint64_t packedData, uint32_t begin, uint32_t end,
- uint32_t lineno, uint32_t column);
+ uint32_t preludeStart, uint32_t lineno, uint32_t column);
public:
static const uint32_t NumClosedOverBindingsLimit = 1 << NumClosedOverBindingsBits;
@@ -1985,7 +2002,7 @@ class LazyScript : public gc::TenuredCell
const frontend::AtomVector& closedOverBindings,
Handle<GCVector<JSFunction*, 8>> innerFunctions,
JSVersion version, uint32_t begin, uint32_t end,
- uint32_t lineno, uint32_t column);
+ uint32_t preludeStart, uint32_t lineno, uint32_t column);
// Create a LazyScript and initialize the closedOverBindings and the
// innerFunctions with dummy values to be replaced in a later initialization
@@ -2000,7 +2017,7 @@ class LazyScript : public gc::TenuredCell
HandleScript script, HandleScope enclosingScope,
HandleScript enclosingScript,
uint64_t packedData, uint32_t begin, uint32_t end,
- uint32_t lineno, uint32_t column);
+ uint32_t preludeStart, uint32_t lineno, uint32_t column);
void initRuntimeFields(uint64_t packedFields);
@@ -2173,6 +2190,9 @@ class LazyScript : public gc::TenuredCell
uint32_t end() const {
return end_;
}
+ uint32_t preludeStart() const {
+ return preludeStart_;
+ }
uint32_t lineno() const {
return lineno_;
}
@@ -2199,7 +2219,8 @@ class LazyScript : public gc::TenuredCell
};
/* If this fails, add/remove padding within LazyScript. */
-JS_STATIC_ASSERT(sizeof(LazyScript) % js::gc::CellSize == 0);
+static_assert(sizeof(LazyScript) % js::gc::CellSize == 0,
+ "Size of LazyScript must be an integral multiple of js::gc::CellSize");
struct ScriptAndCounts
{
diff --git a/js/src/tests/ecma_2017/Function/Object-toSource.js b/js/src/tests/ecma_2017/Function/Object-toSource.js
new file mode 100644
index 000000000..33b9e588e
--- /dev/null
+++ b/js/src/tests/ecma_2017/Function/Object-toSource.js
@@ -0,0 +1,370 @@
+var BUGNUMBER = 1317400;
+var summary = "Function string representation in Object.prototype.toSource";
+
+print(BUGNUMBER + ": " + summary);
+
+// Methods.
+
+assertEq(({ foo(){} }).toSource(),
+ "({foo(){}})");
+assertEq(({ *foo(){} }).toSource(),
+ "({*foo(){}})");
+assertEq(({ async foo(){} }).toSource(),
+ "({async foo(){}})");
+
+assertEq(({ 1(){} }).toSource(),
+ "({1(){}})");
+
+// Methods with more spacing.
+// Spacing is kept.
+
+assertEq(({ foo (){} }).toSource(),
+ "({foo (){}})");
+assertEq(({ foo () {} }).toSource(),
+ "({foo () {}})");
+
+// Methods with computed name.
+// Method syntax is composed.
+
+let name = "foo";
+assertEq(({ [name](){} }).toSource(),
+ "({foo(){}})");
+assertEq(({ *[name](){} }).toSource(),
+ "({*foo(){}})");
+assertEq(({ async [name](){} }).toSource(),
+ "({async foo(){}})");
+
+assertEq(({ [ Symbol.iterator ](){} }).toSource(),
+ "({[Symbol.iterator](){}})");
+
+// Accessors.
+
+assertEq(({ get foo(){} }).toSource(),
+ "({get foo(){}})");
+assertEq(({ set foo(v){} }).toSource(),
+ "({set foo(v){}})");
+
+// Accessors with computed name.
+// Method syntax is composed.
+
+assertEq(({ get [name](){} }).toSource(),
+ "({get foo(){}})");
+assertEq(({ set [name](v){} }).toSource(),
+ "({set foo(v){}})");
+
+assertEq(({ get [ Symbol.iterator ](){} }).toSource(),
+ "({get [Symbol.iterator](){}})");
+assertEq(({ set [ Symbol.iterator ](v){} }).toSource(),
+ "({set [Symbol.iterator](v){}})");
+
+// Getter and setter with same name.
+// Getter always comes before setter.
+
+assertEq(({ get foo(){}, set foo(v){} }).toSource(),
+ "({get foo(){}, set foo(v){}})");
+assertEq(({ set foo(v){}, get foo(){} }).toSource(),
+ "({get foo(){}, set foo(v){}})");
+
+// Normal properties.
+
+assertEq(({ foo: function(){} }).toSource(),
+ "({foo:(function(){})})");
+assertEq(({ foo: function bar(){} }).toSource(),
+ "({foo:(function bar(){})})");
+assertEq(({ foo: function*(){} }).toSource(),
+ "({foo:(function*(){})})");
+assertEq(({ foo: async function(){} }).toSource(),
+ "({foo:(async function(){})})");
+
+// Normal properties with computed name.
+
+assertEq(({ [ Symbol.iterator ]: function(){} }).toSource(),
+ "({[Symbol.iterator]:(function(){})})");
+
+// Dynamically defined properties with function expression.
+// Never become a method syntax.
+
+let obj = {};
+obj.foo = function() {};
+assertEq(obj.toSource(),
+ "({foo:(function() {})})");
+
+obj = {};
+Object.defineProperty(obj, "foo", {value: function() {}});
+assertEq(obj.toSource(),
+ "({})");
+
+obj = {};
+Object.defineProperty(obj, "foo", {value: function() {}, enumerable: true});
+assertEq(obj.toSource(),
+ "({foo:(function() {})})");
+
+obj = {};
+Object.defineProperty(obj, "foo", {value: function bar() {}, enumerable: true});
+assertEq(obj.toSource(),
+ "({foo:(function bar() {})})");
+
+obj = {};
+Object.defineProperty(obj, Symbol.iterator, {value: function() {}, enumerable: true});
+assertEq(obj.toSource(),
+ "({[Symbol.iterator]:(function() {})})");
+
+// Dynamically defined property with other object's method.
+// Method syntax is composed.
+
+let method = ({foo() {}}).foo;
+
+obj = {};
+Object.defineProperty(obj, "foo", {value: method, enumerable: true});
+assertEq(obj.toSource(),
+ "({foo() {}})");
+
+obj = {};
+Object.defineProperty(obj, "bar", {value: method, enumerable: true});
+assertEq(obj.toSource(),
+ "({bar() {}})");
+
+method = ({*foo() {}}).foo;
+
+obj = {};
+Object.defineProperty(obj, "bar", {value: method, enumerable: true});
+assertEq(obj.toSource(),
+ "({*bar() {}})");
+
+method = ({async foo() {}}).foo;
+
+obj = {};
+Object.defineProperty(obj, "bar", {value: method, enumerable: true});
+assertEq(obj.toSource(),
+ "({async bar() {}})");
+
+// Dynamically defined accessors.
+// Accessor syntax is composed.
+
+obj = {};
+Object.defineProperty(obj, "foo", {get: function() {}, enumerable: true});
+assertEq(obj.toSource(),
+ "({get foo() {}})");
+
+obj = {};
+Object.defineProperty(obj, "foo", {set: function() {}, enumerable: true});
+assertEq(obj.toSource(),
+ "({set foo() {}})");
+
+obj = {};
+Object.defineProperty(obj, Symbol.iterator, {get: function() {}, enumerable: true});
+assertEq(obj.toSource(),
+ "({get [Symbol.iterator]() {}})");
+
+obj = {};
+Object.defineProperty(obj, Symbol.iterator, {set: function() {}, enumerable: true});
+assertEq(obj.toSource(),
+ "({set [Symbol.iterator]() {}})");
+
+// Dynamically defined accessors with other object's accessors.
+// Accessor syntax is composed.
+
+let accessor = Object.getOwnPropertyDescriptor({ get foo() {} }, "foo").get;
+obj = {};
+Object.defineProperty(obj, "foo", {get: accessor, enumerable: true});
+assertEq(obj.toSource(),
+ "({get foo() {}})");
+
+accessor = Object.getOwnPropertyDescriptor({ get bar() {} }, "bar").get;
+obj = {};
+Object.defineProperty(obj, "foo", {get: accessor, enumerable: true});
+assertEq(obj.toSource(),
+ "({get foo() {}})");
+
+accessor = Object.getOwnPropertyDescriptor({ set foo(v) {} }, "foo").set;
+obj = {};
+Object.defineProperty(obj, "foo", {get: accessor, enumerable: true});
+assertEq(obj.toSource(),
+ "({get foo(v) {}})");
+
+accessor = Object.getOwnPropertyDescriptor({ set bar(v) {} }, "bar").set;
+obj = {};
+Object.defineProperty(obj, "foo", {get: accessor, enumerable: true});
+assertEq(obj.toSource(),
+ "({get foo(v) {}})");
+
+accessor = Object.getOwnPropertyDescriptor({ get foo() {} }, "foo").get;
+obj = {};
+Object.defineProperty(obj, "foo", {set: accessor, enumerable: true});
+assertEq(obj.toSource(),
+ "({set foo() {}})");
+
+accessor = Object.getOwnPropertyDescriptor({ get bar() {} }, "bar").get;
+obj = {};
+Object.defineProperty(obj, "foo", {set: accessor, enumerable: true});
+assertEq(obj.toSource(),
+ "({set foo() {}})");
+
+accessor = Object.getOwnPropertyDescriptor({ set foo(v) {} }, "foo").set;
+obj = {};
+Object.defineProperty(obj, "foo", {set: accessor, enumerable: true});
+assertEq(obj.toSource(),
+ "({set foo(v) {}})");
+
+accessor = Object.getOwnPropertyDescriptor({ set bar(v) {} }, "bar").set;
+obj = {};
+Object.defineProperty(obj, "foo", {set: accessor, enumerable: true});
+assertEq(obj.toSource(),
+ "({set foo(v) {}})");
+
+// Methods with proxy.
+// Treated as normal property.
+
+method = ({foo() {}}).foo;
+let handler = {
+ get(that, name) {
+ if (name == "toSource") {
+ return function() {
+ return that.toSource();
+ };
+ }
+ return that[name];
+ }
+};
+let proxy = new Proxy(method, handler);
+
+obj = {};
+Object.defineProperty(obj, "foo", {value: proxy, enumerable: true});
+assertEq(obj.toSource(),
+ "({foo:foo() {}})");
+
+// Accessors with proxy.
+// Accessor syntax is composed.
+
+accessor = Object.getOwnPropertyDescriptor({ get foo() {} }, "foo").get;
+proxy = new Proxy(accessor, handler);
+
+obj = {};
+Object.defineProperty(obj, "foo", {get: proxy, enumerable: true});
+assertEq(obj.toSource(),
+ "({get foo() {}})");
+
+obj = {};
+Object.defineProperty(obj, "foo", {set: proxy, enumerable: true});
+assertEq(obj.toSource(),
+ "({set foo() {}})");
+
+// Methods from other global.
+// Treated as normal property.
+
+let g = newGlobal();
+
+method = g.eval("({ foo() {} }).foo");
+
+obj = {};
+Object.defineProperty(obj, "foo", {value: method, enumerable: true});
+assertEq(obj.toSource(),
+ "({foo:foo() {}})");
+
+// Accessors from other global.
+// Accessor syntax is composed.
+
+accessor = g.eval("Object.getOwnPropertyDescriptor({ get foo() {} }, 'foo').get");
+
+obj = {};
+Object.defineProperty(obj, "foo", {get: accessor, enumerable: true});
+assertEq(obj.toSource(),
+ "({get foo() {}})");
+
+accessor = g.eval("Object.getOwnPropertyDescriptor({ get bar() {} }, 'bar').get");
+
+obj = {};
+Object.defineProperty(obj, "foo", {get: accessor, enumerable: true});
+assertEq(obj.toSource(),
+ "({get foo() {}})");
+
+accessor = g.eval("Object.getOwnPropertyDescriptor({ set foo(v) {} }, 'foo').set");
+
+obj = {};
+Object.defineProperty(obj, "foo", {get: accessor, enumerable: true});
+assertEq(obj.toSource(),
+ "({get foo(v) {}})");
+
+accessor = g.eval("Object.getOwnPropertyDescriptor({ set bar(v) {} }, 'bar').set");
+
+obj = {};
+Object.defineProperty(obj, "foo", {get: accessor, enumerable: true});
+assertEq(obj.toSource(),
+ "({get foo(v) {}})");
+
+accessor = g.eval("Object.getOwnPropertyDescriptor({ get foo() {} }, 'foo').get");
+
+obj = {};
+Object.defineProperty(obj, "foo", {set: accessor, enumerable: true});
+assertEq(obj.toSource(),
+ "({set foo() {}})");
+
+accessor = g.eval("Object.getOwnPropertyDescriptor({ get bar() {} }, 'bar').get");
+
+obj = {};
+Object.defineProperty(obj, "foo", {set: accessor, enumerable: true});
+assertEq(obj.toSource(),
+ "({set foo() {}})");
+
+accessor = g.eval("Object.getOwnPropertyDescriptor({ set foo(v) {} }, 'foo').set");
+
+obj = {};
+Object.defineProperty(obj, "foo", {set: accessor, enumerable: true});
+assertEq(obj.toSource(),
+ "({set foo(v) {}})");
+
+accessor = g.eval("Object.getOwnPropertyDescriptor({ set bar(v) {} }, 'bar').set");
+
+obj = {};
+Object.defineProperty(obj, "foo", {set: accessor, enumerable: true});
+assertEq(obj.toSource(),
+ "({set foo(v) {}})");
+
+// **** Some weird cases ****
+
+// Accessors with generator or async.
+
+obj = {};
+Object.defineProperty(obj, "foo", {get: function*() {}, enumerable: true});
+assertEq(obj.toSource(),
+ "({get foo() {}})");
+
+obj = {};
+Object.defineProperty(obj, "foo", {set: async function() {}, enumerable: true});
+assertEq(obj.toSource(),
+ "({set foo() {}})");
+
+// Modified toSource.
+
+obj = { foo() {} };
+obj.foo.toSource = () => "hello";
+assertEq(obj.toSource(),
+ "({hello})");
+
+obj = { foo() {} };
+obj.foo.toSource = () => "bar() {}";
+assertEq(obj.toSource(),
+ "({bar() {}})");
+
+// Modified toSource with different method name.
+
+obj = {};
+Object.defineProperty(obj, "foo", {value: function bar() {}, enumerable: true});
+obj.foo.toSource = () => "hello";
+assertEq(obj.toSource(),
+ "({foo:hello})");
+
+obj = {};
+Object.defineProperty(obj, "foo", {value: function* bar() {}, enumerable: true});
+obj.foo.toSource = () => "hello";
+assertEq(obj.toSource(),
+ "({foo:hello})");
+
+obj = {};
+Object.defineProperty(obj, "foo", {value: async function bar() {}, enumerable: true});
+obj.foo.toSource = () => "hello";
+assertEq(obj.toSource(),
+ "({foo:hello})");
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
diff --git a/js/src/tests/ecma_2017/Function/browser.js b/js/src/tests/ecma_2017/Function/browser.js
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/js/src/tests/ecma_2017/Function/browser.js
diff --git a/js/src/tests/ecma_2017/Function/shell.js b/js/src/tests/ecma_2017/Function/shell.js
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/js/src/tests/ecma_2017/Function/shell.js
diff --git a/js/src/tests/ecma_6/Generators/runtime.js b/js/src/tests/ecma_6/Generators/runtime.js
index c4d3bb6a6..7146eef9f 100644
--- a/js/src/tests/ecma_6/Generators/runtime.js
+++ b/js/src/tests/ecma_6/Generators/runtime.js
@@ -109,7 +109,7 @@ function TestGeneratorFunction() {
// Doesn't matter particularly what string gets serialized, as long
// as it contains "function*" and "yield 10".
assertEq(GeneratorFunction('yield 10').toString(),
- "function* anonymous() {\nyield 10\n}");
+ "function* anonymous(\n) {\nyield 10\n}");
}
TestGeneratorFunction();
diff --git a/js/src/tests/js1_5/Scope/regress-185485.js b/js/src/tests/js1_5/Scope/regress-185485.js
index 19d190eea..a75bf885a 100644
--- a/js/src/tests/js1_5/Scope/regress-185485.js
+++ b/js/src/tests/js1_5/Scope/regress-185485.js
@@ -94,7 +94,7 @@ with (x)
}
status = inSection(5);
actual = x.g.toString();
-expect = (function () {}).toString();
+expect = (function() {}).toString();
addThis();
diff --git a/js/src/tests/js1_7/extensions/regress-354945-01.js b/js/src/tests/js1_7/extensions/regress-354945-01.js
index 76f1a3c82..1c57db0f7 100644
--- a/js/src/tests/js1_7/extensions/regress-354945-01.js
+++ b/js/src/tests/js1_7/extensions/regress-354945-01.js
@@ -6,7 +6,7 @@
//-----------------------------------------------------------------------------
var BUGNUMBER = 354945;
var summary = 'Do not crash with new Iterator';
-var expect = 'TypeError: trap __iterator__ for ({__iterator__:(function (){ })}) returned a primitive value';
+var expect = 'TypeError: trap __iterator__ for ({__iterator__:(function(){ })}) returned a primitive value';
var actual;
diff --git a/js/src/tests/js1_7/extensions/regress-354945-02.js b/js/src/tests/js1_7/extensions/regress-354945-02.js
index 261bf7de1..abef90f77 100644
--- a/js/src/tests/js1_7/extensions/regress-354945-02.js
+++ b/js/src/tests/js1_7/extensions/regress-354945-02.js
@@ -20,7 +20,7 @@ function test()
printBugNumber(BUGNUMBER);
printStatus (summary);
- expect = 'TypeError: trap __iterator__ for ({__iterator__:(function (){ })}) returned a primitive value';
+ expect = 'TypeError: trap __iterator__ for ({__iterator__:(function(){ })}) returned a primitive value';
var obj = {};
obj.__iterator__ = function(){ };
try
diff --git a/js/src/tests/js1_7/geniter/regress-352197.js b/js/src/tests/js1_7/geniter/regress-352197.js
index 7982e12ee..495717af7 100644
--- a/js/src/tests/js1_7/geniter/regress-352197.js
+++ b/js/src/tests/js1_7/geniter/regress-352197.js
@@ -20,7 +20,7 @@ function test()
printBugNumber(BUGNUMBER);
printStatus (summary);
- expect = /TypeError: anonymous generator function returns a value/;
+ expect = /TypeError: can't use 'yield' in a function that can return a value/;
try
{
var gen = eval('(function() { { return 5; } yield 3; })');
diff --git a/js/src/tests/js1_8/genexps/regress-683738.js b/js/src/tests/js1_8/genexps/regress-683738.js
index de563645d..b0309a90e 100644
--- a/js/src/tests/js1_8/genexps/regress-683738.js
+++ b/js/src/tests/js1_8/genexps/regress-683738.js
@@ -20,7 +20,7 @@ function test()
printBugNumber(BUGNUMBER);
printStatus (summary);
- expect = "generator function foo returns a value";
+ expect = "can't use 'yield' in a function that can return a value";
try
{
actual = 'No Error';
@@ -32,7 +32,7 @@ function test()
}
reportCompare(expect, actual, summary + ": 1");
- expect = "generator function foo returns a value";
+ expect = "generator function can't return a value";
try
{
actual = 'No Error';
@@ -44,7 +44,7 @@ function test()
}
reportCompare(expect, actual, summary + ": 2");
- expect = "generator function foo returns a value";
+ expect = "can't use 'yield' in a function that can return a value";
try
{
actual = 'No Error';
@@ -56,7 +56,7 @@ function test()
}
reportCompare(expect, actual, summary + ": 3");
- expect = "generator function foo returns a value";
+ expect = "generator function can't return a value";
try
{
actual = 'No Error';
diff --git a/js/src/tests/js1_8_5/regress/regress-584355.js b/js/src/tests/js1_8_5/regress/regress-584355.js
index 4ddfe65d3..7d1b81a2e 100644
--- a/js/src/tests/js1_8_5/regress/regress-584355.js
+++ b/js/src/tests/js1_8_5/regress/regress-584355.js
@@ -1,5 +1,5 @@
var actual;
-var expect = "function f() { ff (); }";
+var expect = "function f () { ff (); }";
function fun() {
(new Function ("function ff () { actual = '' + ff. caller; } function f () { ff (); } f ();")) ();
}
diff --git a/js/src/wasm/AsmJS.cpp b/js/src/wasm/AsmJS.cpp
index 2237d1d7f..a318d67a9 100644
--- a/js/src/wasm/AsmJS.cpp
+++ b/js/src/wasm/AsmJS.cpp
@@ -318,6 +318,7 @@ struct js::AsmJSMetadata : Metadata, AsmJSMetadataCacheablePod
// Function constructor, this will be the first character in the function
// source. Otherwise, it will be the opening parenthesis of the arguments
// list.
+ uint32_t preludeStart;
uint32_t srcStart;
uint32_t srcBodyStart;
bool strict;
@@ -1758,6 +1759,7 @@ class MOZ_STACK_CLASS ModuleValidator
if (!asmJSMetadata_)
return false;
+ asmJSMetadata_->preludeStart = moduleFunctionNode_->pn_funbox->preludeStart;
asmJSMetadata_->srcStart = moduleFunctionNode_->pn_body->pn_pos.begin;
asmJSMetadata_->srcBodyStart = parser_.tokenStream.currentToken().pos.end;
asmJSMetadata_->strict = parser_.pc->sc()->strict() &&
@@ -7049,6 +7051,7 @@ ParseFunction(ModuleValidator& m, ParseNode** fnOut, unsigned* line)
TokenStream& tokenStream = m.tokenStream();
tokenStream.consumeKnownToken(TOK_FUNCTION, TokenStream::Operand);
+ uint32_t preludeStart = tokenStream.currentToken().pos.begin;
*line = tokenStream.srcCoords.lineNum(tokenStream.currentToken().pos.end);
TokenKind tk;
@@ -7061,7 +7064,7 @@ ParseFunction(ModuleValidator& m, ParseNode** fnOut, unsigned* line)
if (!name)
return false;
- ParseNode* fn = m.parser().handler.newFunctionDefinition();
+ ParseNode* fn = m.parser().handler.newFunctionStatement();
if (!fn)
return false;
@@ -7071,7 +7074,7 @@ ParseFunction(ModuleValidator& m, ParseNode** fnOut, unsigned* line)
ParseContext* outerpc = m.parser().pc;
Directives directives(outerpc);
- FunctionBox* funbox = m.parser().newFunctionBox(fn, fun, directives, NotGenerator,
+ FunctionBox* funbox = m.parser().newFunctionBox(fn, fun, preludeStart, directives, NotGenerator,
SyncFunction, /* tryAnnexB = */ false);
if (!funbox)
return false;
@@ -8054,7 +8057,7 @@ HandleInstantiationFailure(JSContext* cx, CallArgs args, const AsmJSMetadata& me
return false;
}
- uint32_t begin = metadata.srcStart;
+ uint32_t begin = metadata.preludeStart;
uint32_t end = metadata.srcEndAfterCurly();
Rooted<JSFlatString*> src(cx, source->substringDontDeflate(cx, begin, end));
if (!src)
@@ -8085,7 +8088,7 @@ HandleInstantiationFailure(JSContext* cx, CallArgs args, const AsmJSMetadata& me
SourceBufferHolder::Ownership ownership = stableChars.maybeGiveOwnershipToCaller()
? SourceBufferHolder::GiveOwnership
: SourceBufferHolder::NoOwnership;
- SourceBufferHolder srcBuf(chars, stableChars.twoByteRange().length(), ownership);
+ SourceBufferHolder srcBuf(chars, end - begin, ownership);
if (!frontend::CompileStandaloneFunction(cx, &fun, options, srcBuf, Nothing()))
return false;
@@ -8537,6 +8540,7 @@ LookupAsmJSModuleInCache(ExclusiveContext* cx, AsmJSParser& parser, bool* loaded
return true;
// See AsmJSMetadata comment as well as ModuleValidator::init().
+ asmJSMetadata->preludeStart = parser.pc->functionBox()->preludeStart;
asmJSMetadata->srcStart = parser.pc->functionBox()->functionNode->pn_body->pn_pos.begin;
asmJSMetadata->srcBodyStart = parser.tokenStream.currentToken().pos.end;
asmJSMetadata->strict = parser.pc->sc()->strict() && !parser.pc->sc()->hasExplicitUseStrict();
@@ -8834,7 +8838,7 @@ js::AsmJSModuleToString(JSContext* cx, HandleFunction fun, bool addParenToLambda
MOZ_ASSERT(IsAsmJSModule(fun));
const AsmJSMetadata& metadata = AsmJSModuleFunctionToModule(fun).metadata().asAsmJS();
- uint32_t begin = metadata.srcStart;
+ uint32_t begin = metadata.preludeStart;
uint32_t end = metadata.srcEndAfterCurly();
ScriptSource* source = metadata.scriptSource.get();
@@ -8843,17 +8847,15 @@ js::AsmJSModuleToString(JSContext* cx, HandleFunction fun, bool addParenToLambda
if (addParenToLambda && fun->isLambda() && !out.append("("))
return nullptr;
- if (!out.append("function "))
- return nullptr;
-
- if (fun->explicitName() && !out.append(fun->explicitName()))
- return nullptr;
-
bool haveSource = source->hasSourceData();
if (!haveSource && !JSScript::loadSource(cx, source, &haveSource))
return nullptr;
if (!haveSource) {
+ if (!out.append("function "))
+ return nullptr;
+ if (fun->explicitName() && !out.append(fun->explicitName()))
+ return nullptr;
if (!out.append("() {\n [sourceless code]\n}"))
return nullptr;
} else {
diff --git a/testing/web-platform/tests/webstorage/storage_string_conversion.html b/testing/web-platform/tests/webstorage/storage_string_conversion.html
index 518b27521..c76eddfec 100644
--- a/testing/web-platform/tests/webstorage/storage_string_conversion.html
+++ b/testing/web-platform/tests/webstorage/storage_string_conversion.html
@@ -22,21 +22,21 @@
storage.b = 0;
assert_equals(storage.b, "0");
storage.c = function(){};
- assert_equals(storage.c, "function (){}");
+ assert_equals(storage.c, "function(){}");
storage.setItem('d', null);
assert_equals(storage.d, "null");
storage.setItem('e', 0);
assert_equals(storage.e, "0");
storage.setItem('f', function(){});
- assert_equals(storage.f, "function (){}");
+ assert_equals(storage.f, "function(){}");
storage['g'] = null;
assert_equals(storage.g, "null");
storage['h'] = 0;
assert_equals(storage.h, "0");
storage['i'] = function(){};
- assert_equals(storage.f, "function (){}");
+ assert_equals(storage.f, "function(){}");
}, name + " only stores strings");
});
diff --git a/testing/xpcshell/selftest.py b/testing/xpcshell/selftest.py
index 856f505fc..071ab5eda 100755
--- a/testing/xpcshell/selftest.py
+++ b/testing/xpcshell/selftest.py
@@ -1162,7 +1162,7 @@ add_test({
self.assertTestResult(False)
self.assertInLog(TEST_FAIL_STRING)
- self.assertInLog("TypeError: generator function run_test returns a value at")
+ self.assertInLog("TypeError: generator function can't return a value at")
self.assertInLog("test_error.js:4")
self.assertNotInLog(TEST_PASS_STRING)
diff --git a/toolkit/modules/tests/xpcshell/test_Log.js b/toolkit/modules/tests/xpcshell/test_Log.js
index 429bbcc50..6aee99c93 100644
--- a/toolkit/modules/tests/xpcshell/test_Log.js
+++ b/toolkit/modules/tests/xpcshell/test_Log.js
@@ -381,12 +381,12 @@ add_task(function* log_message_with_params() {
ob = function() {};
ob.toJSON = function() {throw "oh noes JSON"};
do_check_eq(formatMessage("Fail is ${sub}", {sub: ob}),
- 'Fail is (function () {})');
+ 'Fail is (function() {})');
// Fall back to .toString if both .toJSON and .toSource fail.
ob.toSource = function() {throw "oh noes SOURCE"};
do_check_eq(formatMessage("Fail is ${sub}", {sub: ob}),
- 'Fail is function () {}');
+ 'Fail is function() {}');
// Fall back to '[object]' if .toJSON, .toSource and .toString fail.
ob.toString = function() {throw "oh noes STRING"};
@@ -450,7 +450,7 @@ add_task(function* log_message_with_params() {
// doesn't cause the logger to fail.
let vOf = {a: 1, valueOf: function() {throw "oh noes valueOf"}};
do_check_eq(formatMessage("Broken valueOf ${}", vOf),
- 'Broken valueOf ({a:1, valueOf:(function () {throw "oh noes valueOf"})})');
+ 'Broken valueOf ({a:1, valueOf:(function() {throw "oh noes valueOf"})})');
// Test edge cases of bad data to formatter:
// If 'params' is not an object, format it as a basic type.