|
|
|
Lines 91-106
GenerateBlockId(TokenStream &ts, ParseContext<FullParseHandler> *pc, uint32_t &b
|
Link Here
|
|---|
|
| 91 |
template <typename ParseHandler> |
91 |
template <typename ParseHandler> |
| 92 |
static void |
92 |
static void |
| 93 |
PushStatementPC(ParseContext<ParseHandler> *pc, StmtInfoPC *stmt, StmtType type) |
93 |
PushStatementPC(ParseContext<ParseHandler> *pc, StmtInfoPC *stmt, StmtType type) |
| 94 |
{ |
94 |
{ |
| 95 |
stmt->blockid = pc->blockid(); |
95 |
stmt->blockid = pc->blockid(); |
| 96 |
PushStatement(pc, stmt, type); |
96 |
PushStatement(pc, stmt, type); |
| 97 |
} |
97 |
} |
| 98 |
|
98 |
|
|
|
99 |
template <> |
| 100 |
bool |
| 101 |
ParseContext<FullParseHandler>::checkLocalsOverflow(TokenStream &ts) |
| 102 |
{ |
| 103 |
if (vars_.length() + bodyLevelLets_.length() >= LOCALNO_LIMIT) { |
| 104 |
ts.reportError(JSMSG_TOO_MANY_LOCALS); |
| 105 |
return false; |
| 106 |
} |
| 107 |
return true; |
| 108 |
} |
| 109 |
|
| 110 |
static void |
| 111 |
MarkUsesAsHoistedLet(ParseNode *pn) |
| 112 |
{ |
| 113 |
MOZ_ASSERT(pn->isDefn()); |
| 114 |
|
| 115 |
Definition *dn = (Definition *)pn; |
| 116 |
ParseNode **pnup = &dn->dn_uses; |
| 117 |
ParseNode *pnu; |
| 118 |
unsigned start = pn->pn_blockid; |
| 119 |
|
| 120 |
// In ES6, 'let' bindings cannot be accessed until initialized. |
| 121 |
// Distinguish hoisted uses as a different JSOp for easier compilation. |
| 122 |
while ((pnu = *pnup) != nullptr && pnu->pn_blockid >= start) { |
| 123 |
MOZ_ASSERT(pnu->isUsed()); |
| 124 |
pnu->pn_dflags |= PND_LET; |
| 125 |
pnup = &pnu->pn_link; |
| 126 |
} |
| 127 |
} |
| 128 |
|
| 99 |
// See comment on member function declaration. |
129 |
// See comment on member function declaration. |
| 100 |
template <> |
130 |
template <> |
| 101 |
bool |
131 |
bool |
| 102 |
ParseContext<FullParseHandler>::define(TokenStream &ts, |
132 |
ParseContext<FullParseHandler>::define(TokenStream &ts, |
| 103 |
HandlePropertyName name, ParseNode *pn, Definition::Kind kind) |
133 |
HandlePropertyName name, ParseNode *pn, Definition::Kind kind) |
| 104 |
{ |
134 |
{ |
| 105 |
JS_ASSERT(!pn->isUsed()); |
135 |
JS_ASSERT(!pn->isUsed()); |
| 106 |
JS_ASSERT_IF(pn->isDefn(), pn->isPlaceholder()); |
136 |
JS_ASSERT_IF(pn->isDefn(), pn->isPlaceholder()); |
|
Lines 145-160
ParseContext<FullParseHandler>::define(TokenStream &ts,
|
Link Here
|
|---|
|
| 145 |
if (kind == Definition::CONST) |
175 |
if (kind == Definition::CONST) |
| 146 |
pn->pn_dflags |= PND_CONST; |
176 |
pn->pn_dflags |= PND_CONST; |
| 147 |
|
177 |
|
| 148 |
Definition *dn = (Definition *)pn; |
178 |
Definition *dn = (Definition *)pn; |
| 149 |
switch (kind) { |
179 |
switch (kind) { |
| 150 |
case Definition::ARG: |
180 |
case Definition::ARG: |
| 151 |
JS_ASSERT(sc->isFunctionBox()); |
181 |
JS_ASSERT(sc->isFunctionBox()); |
| 152 |
dn->setOp((js_CodeSpec[dn->getOp()].format & JOF_SET) ? JSOP_SETARG : JSOP_GETARG); |
182 |
dn->setOp((js_CodeSpec[dn->getOp()].format & JOF_SET) ? JSOP_SETARG : JSOP_GETARG); |
|
|
183 |
dn->pn_blockid = bodyid; |
| 153 |
dn->pn_dflags |= PND_BOUND; |
184 |
dn->pn_dflags |= PND_BOUND; |
| 154 |
if (!dn->pn_cookie.set(ts, staticLevel, args_.length())) |
185 |
if (!dn->pn_cookie.set(ts, staticLevel, args_.length())) |
| 155 |
return false; |
186 |
return false; |
| 156 |
if (!args_.append(dn)) |
187 |
if (!args_.append(dn)) |
| 157 |
return false; |
188 |
return false; |
| 158 |
if (args_.length() >= ARGNO_LIMIT) { |
189 |
if (args_.length() >= ARGNO_LIMIT) { |
| 159 |
ts.reportError(JSMSG_TOO_MANY_FUN_ARGS); |
190 |
ts.reportError(JSMSG_TOO_MANY_FUN_ARGS); |
| 160 |
return false; |
191 |
return false; |
|
Lines 164-210
ParseContext<FullParseHandler>::define(TokenStream &ts,
|
Link Here
|
|---|
|
| 164 |
if (!decls_.addUnique(name, dn)) |
195 |
if (!decls_.addUnique(name, dn)) |
| 165 |
return false; |
196 |
return false; |
| 166 |
break; |
197 |
break; |
| 167 |
|
198 |
|
| 168 |
case Definition::CONST: |
199 |
case Definition::CONST: |
| 169 |
case Definition::VAR: |
200 |
case Definition::VAR: |
| 170 |
if (sc->isFunctionBox()) { |
201 |
if (sc->isFunctionBox()) { |
| 171 |
dn->setOp((js_CodeSpec[dn->getOp()].format & JOF_SET) ? JSOP_SETLOCAL : JSOP_GETLOCAL); |
202 |
dn->setOp((js_CodeSpec[dn->getOp()].format & JOF_SET) ? JSOP_SETLOCAL : JSOP_GETLOCAL); |
|
|
203 |
dn->pn_blockid = bodyid; |
| 172 |
dn->pn_dflags |= PND_BOUND; |
204 |
dn->pn_dflags |= PND_BOUND; |
| 173 |
if (!dn->pn_cookie.set(ts, staticLevel, vars_.length())) |
205 |
if (!dn->pn_cookie.set(ts, staticLevel, vars_.length())) |
| 174 |
return false; |
206 |
return false; |
| 175 |
if (!vars_.append(dn)) |
207 |
if (!vars_.append(dn)) |
| 176 |
return false; |
208 |
return false; |
| 177 |
if (vars_.length() >= LOCALNO_LIMIT) { |
209 |
if (!checkLocalsOverflow(ts)) |
| 178 |
ts.reportError(JSMSG_TOO_MANY_LOCALS); |
|
|
| 179 |
return false; |
210 |
return false; |
| 180 |
} |
|
|
| 181 |
} |
211 |
} |
| 182 |
if (!decls_.addUnique(name, dn)) |
212 |
if (!decls_.addUnique(name, dn)) |
| 183 |
return false; |
213 |
return false; |
| 184 |
break; |
214 |
break; |
| 185 |
|
215 |
|
| 186 |
case Definition::LET: |
216 |
case Definition::LET: |
| 187 |
dn->setOp((js_CodeSpec[dn->getOp()].format & JOF_SET) ? JSOP_SETLOCAL : JSOP_GETLOCAL); |
217 |
dn->setOp(JSOP_INITLET); |
| 188 |
dn->pn_dflags |= (PND_LET | PND_BOUND); |
218 |
dn->pn_dflags |= (PND_LET | PND_BOUND); |
| 189 |
JS_ASSERT(dn->pn_cookie.level() == staticLevel); /* see bindLet */ |
219 |
JS_ASSERT(dn->pn_cookie.level() == staticLevel); /* see bindLet */ |
|
|
220 |
if (atBodyLevel()) { |
| 221 |
if (!bodyLevelLets_.append(dn)) |
| 222 |
return false; |
| 223 |
if (!checkLocalsOverflow(ts)) |
| 224 |
return false; |
| 225 |
} |
| 226 |
|
| 227 |
// In ES6, lets cannot be accessed until initialized. If the |
| 228 |
// definition has existing uses, they need to be marked so that we |
| 229 |
// emit dead zone checks. |
| 230 |
MarkUsesAsHoistedLet(pn); |
| 231 |
|
| 190 |
if (!decls_.addShadow(name, dn)) |
232 |
if (!decls_.addShadow(name, dn)) |
| 191 |
return false; |
233 |
return false; |
| 192 |
break; |
234 |
break; |
| 193 |
|
235 |
|
| 194 |
default: |
236 |
default: |
| 195 |
MOZ_CRASH("unexpected kind"); |
237 |
MOZ_CRASH("unexpected kind"); |
| 196 |
} |
238 |
} |
| 197 |
|
239 |
|
| 198 |
return true; |
240 |
return true; |
| 199 |
} |
241 |
} |
| 200 |
|
242 |
|
| 201 |
template <> |
243 |
template <> |
| 202 |
bool |
244 |
bool |
|
|
245 |
ParseContext<SyntaxParseHandler>::checkLocalsOverflow(TokenStream &ts) |
| 246 |
{ |
| 247 |
return true; |
| 248 |
} |
| 249 |
|
| 250 |
template <> |
| 251 |
bool |
| 203 |
ParseContext<SyntaxParseHandler>::define(TokenStream &ts, HandlePropertyName name, Node pn, |
252 |
ParseContext<SyntaxParseHandler>::define(TokenStream &ts, HandlePropertyName name, Node pn, |
| 204 |
Definition::Kind kind) |
253 |
Definition::Kind kind) |
| 205 |
{ |
254 |
{ |
| 206 |
JS_ASSERT(!decls_.lookupFirst(name)); |
255 |
JS_ASSERT(!decls_.lookupFirst(name)); |
| 207 |
|
256 |
|
| 208 |
if (lexdeps.lookupDefn<SyntaxParseHandler>(name)) |
257 |
if (lexdeps.lookupDefn<SyntaxParseHandler>(name)) |
| 209 |
lexdeps->remove(name); |
258 |
lexdeps->remove(name); |
| 210 |
|
259 |
|
|
|
| 273 |
AppendPackedBindings(const ParseContext<ParseHandler> *pc, const DeclVector &vec, Binding *dst) |
322 |
AppendPackedBindings(const ParseContext<ParseHandler> *pc, const DeclVector &vec, Binding *dst) |
| 274 |
{ |
323 |
{ |
| 275 |
for (size_t i = 0; i < vec.length(); ++i, ++dst) { |
324 |
for (size_t i = 0; i < vec.length(); ++i, ++dst) { |
| 276 |
Definition *dn = vec[i]; |
325 |
Definition *dn = vec[i]; |
| 277 |
PropertyName *name = dn->name(); |
326 |
PropertyName *name = dn->name(); |
| 278 |
|
327 |
|
| 279 |
Binding::Kind kind; |
328 |
Binding::Kind kind; |
| 280 |
switch (dn->kind()) { |
329 |
switch (dn->kind()) { |
|
|
330 |
case Definition::LET: |
| 331 |
// Treat body-level let declarations as var bindings by falling |
| 332 |
// through. The fact that the binding is in fact a let declaration |
| 333 |
// is reflected in the slot. All body-level lets go after the |
| 334 |
// vars. |
| 281 |
case Definition::VAR: |
335 |
case Definition::VAR: |
| 282 |
kind = Binding::VARIABLE; |
336 |
kind = Binding::VARIABLE; |
| 283 |
break; |
337 |
break; |
| 284 |
case Definition::CONST: |
338 |
case Definition::CONST: |
| 285 |
kind = Binding::CONSTANT; |
339 |
kind = Binding::CONSTANT; |
| 286 |
break; |
340 |
break; |
| 287 |
case Definition::ARG: |
341 |
case Definition::ARG: |
| 288 |
kind = Binding::ARGUMENT; |
342 |
kind = Binding::ARGUMENT; |
|
Lines 308-344
AppendPackedBindings(const ParseContext<ParseHandler> *pc, const DeclVector &vec
|
Link Here
|
|---|
|
| 308 |
template <typename ParseHandler> |
362 |
template <typename ParseHandler> |
| 309 |
bool |
363 |
bool |
| 310 |
ParseContext<ParseHandler>::generateFunctionBindings(ExclusiveContext *cx, TokenStream &ts, |
364 |
ParseContext<ParseHandler>::generateFunctionBindings(ExclusiveContext *cx, TokenStream &ts, |
| 311 |
LifoAlloc &alloc, |
365 |
LifoAlloc &alloc, |
| 312 |
InternalHandle<Bindings*> bindings) const |
366 |
InternalHandle<Bindings*> bindings) const |
| 313 |
{ |
367 |
{ |
| 314 |
JS_ASSERT(sc->isFunctionBox()); |
368 |
JS_ASSERT(sc->isFunctionBox()); |
| 315 |
JS_ASSERT(args_.length() < ARGNO_LIMIT); |
369 |
JS_ASSERT(args_.length() < ARGNO_LIMIT); |
| 316 |
JS_ASSERT(vars_.length() < LOCALNO_LIMIT); |
370 |
JS_ASSERT(vars_.length() + bodyLevelLets_.length() < LOCALNO_LIMIT); |
| 317 |
|
371 |
|
| 318 |
/* |
372 |
/* |
| 319 |
* Avoid pathological edge cases by explicitly limiting the total number of |
373 |
* Avoid pathological edge cases by explicitly limiting the total number of |
| 320 |
* bindings to what will fit in a uint32_t. |
374 |
* bindings to what will fit in a uint32_t. |
| 321 |
*/ |
375 |
*/ |
| 322 |
if (UINT32_MAX - args_.length() <= vars_.length()) |
376 |
if (UINT32_MAX - args_.length() <= vars_.length() + bodyLevelLets_.length()) |
| 323 |
return ts.reportError(JSMSG_TOO_MANY_LOCALS); |
377 |
return ts.reportError(JSMSG_TOO_MANY_LOCALS); |
| 324 |
|
378 |
|
| 325 |
uint32_t count = args_.length() + vars_.length(); |
379 |
// Fix up the slots of body-level lets to come after the vars now that we |
|
|
380 |
// know how many vars there are. |
| 381 |
for (size_t i = 0; i < bodyLevelLets_.length(); i++) { |
| 382 |
Definition *dn = bodyLevelLets_[i]; |
| 383 |
if (!dn->pn_cookie.set(ts, dn->pn_cookie.level(), vars_.length() + i)) |
| 384 |
return false; |
| 385 |
} |
| 386 |
|
| 387 |
uint32_t count = args_.length() + vars_.length() + bodyLevelLets_.length(); |
| 326 |
Binding *packedBindings = alloc.newArrayUninitialized<Binding>(count); |
388 |
Binding *packedBindings = alloc.newArrayUninitialized<Binding>(count); |
| 327 |
if (!packedBindings) { |
389 |
if (!packedBindings) { |
| 328 |
js_ReportOutOfMemory(cx); |
390 |
js_ReportOutOfMemory(cx); |
| 329 |
return false; |
391 |
return false; |
| 330 |
} |
392 |
} |
| 331 |
|
393 |
|
| 332 |
AppendPackedBindings(this, args_, packedBindings); |
394 |
AppendPackedBindings(this, args_, packedBindings); |
| 333 |
AppendPackedBindings(this, vars_, packedBindings + args_.length()); |
395 |
AppendPackedBindings(this, vars_, packedBindings + args_.length()); |
|
|
396 |
AppendPackedBindings(this, bodyLevelLets_, packedBindings + args_.length() + vars_.length()); |
| 334 |
|
397 |
|
| 335 |
return Bindings::initWithTemporaryStorage(cx, bindings, args_.length(), vars_.length(), |
398 |
return Bindings::initWithTemporaryStorage(cx, bindings, args_.length(), vars_.length(), |
| 336 |
packedBindings, blockScopeDepth); |
399 |
bodyLevelLets_.length(), blockScopeDepth, |
|
|
400 |
packedBindings); |
| 337 |
} |
401 |
} |
| 338 |
|
402 |
|
| 339 |
template <typename ParseHandler> |
403 |
template <typename ParseHandler> |
| 340 |
bool |
404 |
bool |
| 341 |
Parser<ParseHandler>::reportHelper(ParseReportKind kind, bool strict, uint32_t offset, |
405 |
Parser<ParseHandler>::reportHelper(ParseReportKind kind, bool strict, uint32_t offset, |
| 342 |
unsigned errorNumber, va_list args) |
406 |
unsigned errorNumber, va_list args) |
| 343 |
{ |
407 |
{ |
| 344 |
bool result = false; |
408 |
bool result = false; |
|
Lines 973-990
Parser<ParseHandler>::functionBody(FunctionSyntaxKind kind, FunctionBodyType typ
|
Link Here
|
|---|
|
| 973 |
return null(); |
1037 |
return null(); |
| 974 |
|
1038 |
|
| 975 |
return pn; |
1039 |
return pn; |
| 976 |
} |
1040 |
} |
| 977 |
|
1041 |
|
| 978 |
/* See comment for use in Parser::functionDef. */ |
1042 |
/* See comment for use in Parser::functionDef. */ |
| 979 |
template <> |
1043 |
template <> |
| 980 |
bool |
1044 |
bool |
| 981 |
Parser<FullParseHandler>::makeDefIntoUse(Definition *dn, ParseNode *pn, JSAtom *atom) |
1045 |
Parser<FullParseHandler>::makeDefIntoUse(Definition *dn, ParseNode *pn, JSAtom *atom, |
|
|
1046 |
bool *pbodyLevelHoistedUse) |
| 982 |
{ |
1047 |
{ |
|
|
1048 |
// See comment in addFreeVariablesFromLazyFunction. |
| 1049 |
*pbodyLevelHoistedUse = !!dn->dn_uses; |
| 1050 |
|
| 983 |
/* Turn pn into a definition. */ |
1051 |
/* Turn pn into a definition. */ |
| 984 |
pc->updateDecl(atom, pn); |
1052 |
pc->updateDecl(atom, pn); |
| 985 |
|
1053 |
|
| 986 |
/* Change all uses of dn to be uses of pn. */ |
1054 |
/* Change all uses of dn to be uses of pn. */ |
| 987 |
for (ParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) { |
1055 |
for (ParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) { |
| 988 |
JS_ASSERT(pnu->isUsed()); |
1056 |
JS_ASSERT(pnu->isUsed()); |
| 989 |
JS_ASSERT(!pnu->isDefn()); |
1057 |
JS_ASSERT(!pnu->isDefn()); |
| 990 |
pnu->pn_lexdef = (Definition *) pn; |
1058 |
pnu->pn_lexdef = (Definition *) pn; |
|
|
| 1070 |
|
1138 |
|
| 1071 |
struct LetData { |
1139 |
struct LetData { |
| 1072 |
explicit LetData(ExclusiveContext *cx) : blockObj(cx) {} |
1140 |
explicit LetData(ExclusiveContext *cx) : blockObj(cx) {} |
| 1073 |
VarContext varContext; |
1141 |
VarContext varContext; |
| 1074 |
RootedStaticBlockObject blockObj; |
1142 |
RootedStaticBlockObject blockObj; |
| 1075 |
unsigned overflow; |
1143 |
unsigned overflow; |
| 1076 |
} let; |
1144 |
} let; |
| 1077 |
|
1145 |
|
| 1078 |
void initLet(VarContext varContext, StaticBlockObject &blockObj, unsigned overflow) { |
1146 |
void initLet(VarContext varContext, StaticBlockObject *blockObj, unsigned overflow) { |
| 1079 |
this->pn = ParseHandler::null(); |
1147 |
this->pn = ParseHandler::null(); |
| 1080 |
this->op = JSOP_NOP; |
1148 |
this->op = JSOP_INITLET; |
| 1081 |
this->binder = Parser<ParseHandler>::bindLet; |
1149 |
this->binder = Parser<ParseHandler>::bindLet; |
| 1082 |
this->let.varContext = varContext; |
1150 |
this->let.varContext = varContext; |
| 1083 |
this->let.blockObj = &blockObj; |
1151 |
this->let.blockObj = blockObj; |
| 1084 |
this->let.overflow = overflow; |
1152 |
this->let.overflow = overflow; |
| 1085 |
} |
1153 |
} |
| 1086 |
|
1154 |
|
| 1087 |
void initVarOrConst(JSOp op) { |
1155 |
void initVarOrConst(JSOp op) { |
| 1088 |
this->op = op; |
1156 |
this->op = op; |
| 1089 |
this->binder = Parser<ParseHandler>::bindVarOrConst; |
1157 |
this->binder = Parser<ParseHandler>::bindVarOrConst; |
| 1090 |
} |
1158 |
} |
| 1091 |
}; |
1159 |
}; |
|
Lines 1187-1203
ConvertDefinitionToNamedLambdaUse(TokenStream &ts, ParseContext<FullParseHandler
|
Link Here
|
|---|
|
| 1187 |
* Beware: this function is called for functions nested in other functions or |
1255 |
* Beware: this function is called for functions nested in other functions or |
| 1188 |
* global scripts but not for functions compiled through the Function |
1256 |
* global scripts but not for functions compiled through the Function |
| 1189 |
* constructor or JSAPI. To always execute code when a function has finished |
1257 |
* constructor or JSAPI. To always execute code when a function has finished |
| 1190 |
* parsing, use Parser::functionBody. |
1258 |
* parsing, use Parser::functionBody. |
| 1191 |
*/ |
1259 |
*/ |
| 1192 |
template <> |
1260 |
template <> |
| 1193 |
bool |
1261 |
bool |
| 1194 |
Parser<FullParseHandler>::leaveFunction(ParseNode *fn, ParseContext<FullParseHandler> *outerpc, |
1262 |
Parser<FullParseHandler>::leaveFunction(ParseNode *fn, ParseContext<FullParseHandler> *outerpc, |
| 1195 |
FunctionSyntaxKind kind) |
1263 |
bool bodyLevelHoistedUse, FunctionSyntaxKind kind) |
| 1196 |
{ |
1264 |
{ |
| 1197 |
outerpc->blockidGen = pc->blockidGen; |
1265 |
outerpc->blockidGen = pc->blockidGen; |
| 1198 |
|
1266 |
|
| 1199 |
FunctionBox *funbox = fn->pn_funbox; |
1267 |
FunctionBox *funbox = fn->pn_funbox; |
| 1200 |
JS_ASSERT(funbox == pc->sc->asFunctionBox()); |
1268 |
JS_ASSERT(funbox == pc->sc->asFunctionBox()); |
| 1201 |
|
1269 |
|
| 1202 |
/* Propagate unresolved lexical names up to outerpc->lexdeps. */ |
1270 |
/* Propagate unresolved lexical names up to outerpc->lexdeps. */ |
| 1203 |
if (pc->lexdeps->count()) { |
1271 |
if (pc->lexdeps->count()) { |
|
Lines 1259-1274
Parser<FullParseHandler>::leaveFunction(ParseNode *fn, ParseContext<FullParseHan
|
Link Here
|
|---|
|
| 1259 |
* when leaving the inner function. |
1327 |
* when leaving the inner function. |
| 1260 |
* |
1328 |
* |
| 1261 |
* The dn == outer_dn case arises with generator expressions |
1329 |
* The dn == outer_dn case arises with generator expressions |
| 1262 |
* (see LegacyCompExprTransplanter::transplant, the PN_CODE/PN_NAME |
1330 |
* (see LegacyCompExprTransplanter::transplant, the PN_CODE/PN_NAME |
| 1263 |
* case), and nowhere else, currently. |
1331 |
* case), and nowhere else, currently. |
| 1264 |
*/ |
1332 |
*/ |
| 1265 |
if (dn != outer_dn) { |
1333 |
if (dn != outer_dn) { |
| 1266 |
if (ParseNode *pnu = dn->dn_uses) { |
1334 |
if (ParseNode *pnu = dn->dn_uses) { |
|
|
1335 |
// In ES6, 'let' bindings cannot be accessed until |
| 1336 |
// initialized. If we are parsing a function with a |
| 1337 |
// hoisted body-level use, all free variables that get |
| 1338 |
// linked to an outer 'let' binding need to be marked as |
| 1339 |
// needing dead zone checks. e.g., |
| 1340 |
// |
| 1341 |
// function outer() { |
| 1342 |
// inner(); |
| 1343 |
// function inner() { use(x); } |
| 1344 |
// let x; |
| 1345 |
// } |
| 1346 |
// |
| 1347 |
// The use of 'x' inside 'inner' needs to be marked. |
| 1348 |
if (bodyLevelHoistedUse && outer_dn->isLet()) { |
| 1349 |
while (true) { |
| 1350 |
pnu->pn_dflags |= PND_LET; |
| 1351 |
if (!pnu->pn_link) |
| 1352 |
break; |
| 1353 |
pnu = pnu->pn_link; |
| 1354 |
} |
| 1355 |
pnu = dn->dn_uses; |
| 1356 |
} |
| 1357 |
|
| 1267 |
while (true) { |
1358 |
while (true) { |
| 1268 |
pnu->pn_lexdef = outer_dn; |
1359 |
pnu->pn_lexdef = outer_dn; |
| 1269 |
if (!pnu->pn_link) |
1360 |
if (!pnu->pn_link) |
| 1270 |
break; |
1361 |
break; |
| 1271 |
pnu = pnu->pn_link; |
1362 |
pnu = pnu->pn_link; |
| 1272 |
} |
1363 |
} |
| 1273 |
pnu->pn_link = outer_dn->dn_uses; |
1364 |
pnu->pn_link = outer_dn->dn_uses; |
| 1274 |
outer_dn->dn_uses = dn->dn_uses; |
1365 |
outer_dn->dn_uses = dn->dn_uses; |
|
Lines 1286-1307
Parser<FullParseHandler>::leaveFunction(ParseNode *fn, ParseContext<FullParseHan
|
Link Here
|
|---|
|
| 1286 |
InternalHandle<Bindings*> bindings = |
1377 |
InternalHandle<Bindings*> bindings = |
| 1287 |
InternalHandle<Bindings*>::fromMarkedLocation(&funbox->bindings); |
1378 |
InternalHandle<Bindings*>::fromMarkedLocation(&funbox->bindings); |
| 1288 |
return pc->generateFunctionBindings(context, tokenStream, alloc, bindings); |
1379 |
return pc->generateFunctionBindings(context, tokenStream, alloc, bindings); |
| 1289 |
} |
1380 |
} |
| 1290 |
|
1381 |
|
| 1291 |
template <> |
1382 |
template <> |
| 1292 |
bool |
1383 |
bool |
| 1293 |
Parser<SyntaxParseHandler>::leaveFunction(Node fn, ParseContext<SyntaxParseHandler> *outerpc, |
1384 |
Parser<SyntaxParseHandler>::leaveFunction(Node fn, ParseContext<SyntaxParseHandler> *outerpc, |
| 1294 |
FunctionSyntaxKind kind) |
1385 |
bool bodyLevelHoistedUse, FunctionSyntaxKind kind) |
| 1295 |
{ |
1386 |
{ |
| 1296 |
outerpc->blockidGen = pc->blockidGen; |
1387 |
outerpc->blockidGen = pc->blockidGen; |
| 1297 |
|
1388 |
|
| 1298 |
FunctionBox *funbox = pc->sc->asFunctionBox(); |
1389 |
FunctionBox *funbox = pc->sc->asFunctionBox(); |
| 1299 |
return addFreeVariablesFromLazyFunction(funbox->function(), outerpc); |
1390 |
return addFreeVariablesFromLazyFunction(funbox->function(), outerpc, bodyLevelHoistedUse); |
| 1300 |
} |
1391 |
} |
| 1301 |
|
1392 |
|
| 1302 |
/* |
1393 |
/* |
| 1303 |
* defineArg is called for both the arguments of a regular function definition |
1394 |
* defineArg is called for both the arguments of a regular function definition |
| 1304 |
* and the arguments specified by the Function constructor. |
1395 |
* and the arguments specified by the Function constructor. |
| 1305 |
* |
1396 |
* |
| 1306 |
* The 'disallowDuplicateArgs' bool indicates whether the use of another |
1397 |
* The 'disallowDuplicateArgs' bool indicates whether the use of another |
| 1307 |
* feature (destructuring or default arguments) disables duplicate arguments. |
1398 |
* feature (destructuring or default arguments) disables duplicate arguments. |
|
Lines 1562-1581
Parser<ParseHandler>::functionArguments(FunctionSyntaxKind kind, Node *listp, No
|
Link Here
|
|---|
|
| 1562 |
|
1653 |
|
| 1563 |
return true; |
1654 |
return true; |
| 1564 |
} |
1655 |
} |
| 1565 |
|
1656 |
|
| 1566 |
template <> |
1657 |
template <> |
| 1567 |
bool |
1658 |
bool |
| 1568 |
Parser<FullParseHandler>::checkFunctionDefinition(HandlePropertyName funName, |
1659 |
Parser<FullParseHandler>::checkFunctionDefinition(HandlePropertyName funName, |
| 1569 |
ParseNode **pn_, FunctionSyntaxKind kind, |
1660 |
ParseNode **pn_, FunctionSyntaxKind kind, |
| 1570 |
bool *pbodyProcessed) |
1661 |
bool *pbodyProcessed, |
|
|
1662 |
bool *pbodyLevelHoistedUse) |
| 1571 |
{ |
1663 |
{ |
| 1572 |
ParseNode *&pn = *pn_; |
1664 |
ParseNode *&pn = *pn_; |
| 1573 |
*pbodyProcessed = false; |
1665 |
*pbodyProcessed = false; |
|
|
1666 |
*pbodyLevelHoistedUse = false; |
| 1574 |
|
1667 |
|
| 1575 |
/* Function statements add a binding to the enclosing scope. */ |
1668 |
/* Function statements add a binding to the enclosing scope. */ |
| 1576 |
bool bodyLevel = pc->atBodyLevel(); |
1669 |
bool bodyLevel = pc->atBodyLevel(); |
| 1577 |
|
1670 |
|
| 1578 |
if (kind == Statement) { |
1671 |
if (kind == Statement) { |
| 1579 |
/* |
1672 |
/* |
| 1580 |
* Handle redeclaration and optimize cases where we can statically bind the |
1673 |
* Handle redeclaration and optimize cases where we can statically bind the |
| 1581 |
* function (thereby avoiding JSOP_DEFFUN and dynamic name lookup). |
1674 |
* function (thereby avoiding JSOP_DEFFUN and dynamic name lookup). |
|
Lines 1612-1628
Parser<FullParseHandler>::checkFunctionDefinition(HandlePropertyName funName,
|
Link Here
|
|---|
|
| 1612 |
// remains a definition. But change the function node pn so |
1705 |
// remains a definition. But change the function node pn so |
| 1613 |
// that it knows where the argument is located. |
1706 |
// that it knows where the argument is located. |
| 1614 |
pn->setOp(JSOP_GETARG); |
1707 |
pn->setOp(JSOP_GETARG); |
| 1615 |
pn->setDefn(true); |
1708 |
pn->setDefn(true); |
| 1616 |
pn->pn_cookie = dn->pn_cookie; |
1709 |
pn->pn_cookie = dn->pn_cookie; |
| 1617 |
pn->pn_dflags |= PND_BOUND; |
1710 |
pn->pn_dflags |= PND_BOUND; |
| 1618 |
dn->markAsAssigned(); |
1711 |
dn->markAsAssigned(); |
| 1619 |
} else { |
1712 |
} else { |
| 1620 |
if (!makeDefIntoUse(dn, pn, funName)) |
1713 |
if (!makeDefIntoUse(dn, pn, funName, pbodyLevelHoistedUse)) |
| 1621 |
return false; |
1714 |
return false; |
| 1622 |
} |
1715 |
} |
| 1623 |
} |
1716 |
} |
| 1624 |
} else if (bodyLevel) { |
1717 |
} else if (bodyLevel) { |
| 1625 |
/* |
1718 |
/* |
| 1626 |
* If this function was used before it was defined, claim the |
1719 |
* If this function was used before it was defined, claim the |
| 1627 |
* pre-created definition node for this function that primaryExpr |
1720 |
* pre-created definition node for this function that primaryExpr |
| 1628 |
* put in pc->lexdeps on first forward reference, and recycle pn. |
1721 |
* put in pc->lexdeps on first forward reference, and recycle pn. |
|
Lines 1635-1650
Parser<FullParseHandler>::checkFunctionDefinition(HandlePropertyName funName,
|
Link Here
|
|---|
|
| 1635 |
fn->pn_pos.end = pn->pn_pos.end; |
1728 |
fn->pn_pos.end = pn->pn_pos.end; |
| 1636 |
|
1729 |
|
| 1637 |
fn->pn_body = nullptr; |
1730 |
fn->pn_body = nullptr; |
| 1638 |
fn->pn_cookie.makeFree(); |
1731 |
fn->pn_cookie.makeFree(); |
| 1639 |
|
1732 |
|
| 1640 |
pc->lexdeps->remove(funName); |
1733 |
pc->lexdeps->remove(funName); |
| 1641 |
handler.freeTree(pn); |
1734 |
handler.freeTree(pn); |
| 1642 |
pn = fn; |
1735 |
pn = fn; |
|
|
1736 |
|
| 1737 |
*pbodyLevelHoistedUse = true; |
| 1643 |
} |
1738 |
} |
| 1644 |
|
1739 |
|
| 1645 |
if (!pc->define(tokenStream, funName, pn, Definition::VAR)) |
1740 |
if (!pc->define(tokenStream, funName, pn, Definition::VAR)) |
| 1646 |
return false; |
1741 |
return false; |
| 1647 |
} |
1742 |
} |
| 1648 |
|
1743 |
|
| 1649 |
if (bodyLevel) { |
1744 |
if (bodyLevel) { |
| 1650 |
JS_ASSERT(pn->functionIsHoisted()); |
1745 |
JS_ASSERT(pn->functionIsHoisted()); |
|
Lines 1703-1719
Parser<FullParseHandler>::checkFunctionDefinition(HandlePropertyName funName,
|
Link Here
|
|---|
|
| 1703 |
if (LazyScript *lazyOuter = handler.lazyOuterFunction()) { |
1798 |
if (LazyScript *lazyOuter = handler.lazyOuterFunction()) { |
| 1704 |
JSFunction *fun = handler.nextLazyInnerFunction(); |
1799 |
JSFunction *fun = handler.nextLazyInnerFunction(); |
| 1705 |
JS_ASSERT(!fun->isLegacyGenerator()); |
1800 |
JS_ASSERT(!fun->isLegacyGenerator()); |
| 1706 |
FunctionBox *funbox = newFunctionBox(pn, fun, pc, Directives(/* strict = */ false), |
1801 |
FunctionBox *funbox = newFunctionBox(pn, fun, pc, Directives(/* strict = */ false), |
| 1707 |
fun->generatorKind()); |
1802 |
fun->generatorKind()); |
| 1708 |
if (!funbox) |
1803 |
if (!funbox) |
| 1709 |
return false; |
1804 |
return false; |
| 1710 |
|
1805 |
|
| 1711 |
if (!addFreeVariablesFromLazyFunction(fun, pc)) |
1806 |
if (!addFreeVariablesFromLazyFunction(fun, pc, *pbodyLevelHoistedUse)) |
| 1712 |
return false; |
1807 |
return false; |
| 1713 |
|
1808 |
|
| 1714 |
// The position passed to tokenStream.advance() is relative to |
1809 |
// The position passed to tokenStream.advance() is relative to |
| 1715 |
// userbuf.base() while LazyScript::{begin,end} offsets are relative to |
1810 |
// userbuf.base() while LazyScript::{begin,end} offsets are relative to |
| 1716 |
// the outermost script source. N.B: userbuf.base() is initialized |
1811 |
// the outermost script source. N.B: userbuf.base() is initialized |
| 1717 |
// (in TokenStream()) to begin() - column() so that column numbers in |
1812 |
// (in TokenStream()) to begin() - column() so that column numbers in |
| 1718 |
// the lazily parsed script are correct. |
1813 |
// the lazily parsed script are correct. |
| 1719 |
uint32_t userbufBase = lazyOuter->begin() - lazyOuter->column(); |
1814 |
uint32_t userbufBase = lazyOuter->begin() - lazyOuter->column(); |
|
Lines 1734-1786
PropagateTransitiveParseFlags(const T *inner, U *outer)
|
Link Here
|
|---|
|
| 1734 |
outer->setBindingsAccessedDynamically(); |
1829 |
outer->setBindingsAccessedDynamically(); |
| 1735 |
if (inner->hasDebuggerStatement()) |
1830 |
if (inner->hasDebuggerStatement()) |
| 1736 |
outer->setHasDebuggerStatement(); |
1831 |
outer->setHasDebuggerStatement(); |
| 1737 |
} |
1832 |
} |
| 1738 |
|
1833 |
|
| 1739 |
template <typename ParseHandler> |
1834 |
template <typename ParseHandler> |
| 1740 |
bool |
1835 |
bool |
| 1741 |
Parser<ParseHandler>::addFreeVariablesFromLazyFunction(JSFunction *fun, |
1836 |
Parser<ParseHandler>::addFreeVariablesFromLazyFunction(JSFunction *fun, |
| 1742 |
ParseContext<ParseHandler> *pc) |
1837 |
ParseContext<ParseHandler> *pc, |
|
|
1838 |
bool bodyLevelHoistedUse) |
| 1743 |
{ |
1839 |
{ |
|
|
1840 |
MOZ_ASSERT_IF(bodyLevelHoistedUse, fun->displayAtom() && pc->atBodyLevel()); |
| 1841 |
|
| 1744 |
// Update any definition nodes in this context according to free variables |
1842 |
// Update any definition nodes in this context according to free variables |
| 1745 |
// in a lazily parsed inner function. |
1843 |
// in a lazily parsed inner function. |
| 1746 |
|
1844 |
|
| 1747 |
LazyScript *lazy = fun->lazyScript(); |
1845 |
LazyScript *lazy = fun->lazyScript(); |
| 1748 |
HeapPtrAtom *freeVariables = lazy->freeVariables(); |
1846 |
LazyScript::FreeVariable *freeVariables = lazy->freeVariables(); |
| 1749 |
for (size_t i = 0; i < lazy->numFreeVariables(); i++) { |
1847 |
for (size_t i = 0; i < lazy->numFreeVariables(); i++) { |
| 1750 |
JSAtom *atom = freeVariables[i]; |
1848 |
JSAtom *atom = freeVariables[i].atom(); |
| 1751 |
|
1849 |
|
| 1752 |
// 'arguments' will be implicitly bound within the inner function. |
1850 |
// 'arguments' will be implicitly bound within the inner function. |
| 1753 |
if (atom == context->names().arguments) |
1851 |
if (atom == context->names().arguments) |
| 1754 |
continue; |
1852 |
continue; |
| 1755 |
|
1853 |
|
| 1756 |
DefinitionNode dn = pc->decls().lookupFirst(atom); |
1854 |
DefinitionNode dn = pc->decls().lookupFirst(atom); |
| 1757 |
|
1855 |
|
| 1758 |
if (!dn) { |
1856 |
if (!dn) { |
| 1759 |
dn = getOrCreateLexicalDependency(pc, atom); |
1857 |
dn = getOrCreateLexicalDependency(pc, atom); |
| 1760 |
if (!dn) |
1858 |
if (!dn) |
| 1761 |
return false; |
1859 |
return false; |
| 1762 |
} |
1860 |
} |
| 1763 |
|
1861 |
|
|
|
1862 |
// In ES6, lets are unaccessible before initialization. If the inner |
| 1863 |
// function closes over a placeholder definition, we need to mark the |
| 1864 |
// variable as maybe needing a dead zone check when we emit bytecode. |
| 1865 |
// |
| 1866 |
// Note that body-level function declaration statements are always |
| 1867 |
// hoisted to the top, so all accesses to free let variables need the |
| 1868 |
// dead zone check. |
| 1869 |
if (handler.isPlaceholderDefinition(dn) || bodyLevelHoistedUse) |
| 1870 |
freeVariables[i].setIsHoistedUse(); |
| 1871 |
|
| 1764 |
/* Mark the outer dn as escaping. */ |
1872 |
/* Mark the outer dn as escaping. */ |
| 1765 |
handler.setFlag(handler.getDefinitionNode(dn), PND_CLOSED); |
1873 |
handler.setFlag(handler.getDefinitionNode(dn), PND_CLOSED); |
| 1766 |
} |
1874 |
} |
| 1767 |
|
1875 |
|
| 1768 |
PropagateTransitiveParseFlags(lazy, pc->sc); |
1876 |
PropagateTransitiveParseFlags(lazy, pc->sc); |
| 1769 |
return true; |
1877 |
return true; |
| 1770 |
} |
1878 |
} |
| 1771 |
|
1879 |
|
| 1772 |
template <> |
1880 |
template <> |
| 1773 |
bool |
1881 |
bool |
| 1774 |
Parser<SyntaxParseHandler>::checkFunctionDefinition(HandlePropertyName funName, |
1882 |
Parser<SyntaxParseHandler>::checkFunctionDefinition(HandlePropertyName funName, |
| 1775 |
Node *pn, FunctionSyntaxKind kind, |
1883 |
Node *pn, FunctionSyntaxKind kind, |
| 1776 |
bool *pbodyProcessed) |
1884 |
bool *pbodyProcessed, |
|
|
1885 |
bool *pbodyLevelHoistedUse) |
| 1777 |
{ |
1886 |
{ |
| 1778 |
*pbodyProcessed = false; |
1887 |
*pbodyProcessed = false; |
|
|
1888 |
*pbodyLevelHoistedUse = false; |
| 1779 |
|
1889 |
|
| 1780 |
/* Function statements add a binding to the enclosing scope. */ |
1890 |
/* Function statements add a binding to the enclosing scope. */ |
| 1781 |
bool bodyLevel = pc->atBodyLevel(); |
1891 |
bool bodyLevel = pc->atBodyLevel(); |
| 1782 |
|
1892 |
|
| 1783 |
if (kind == Statement) { |
1893 |
if (kind == Statement) { |
| 1784 |
/* |
1894 |
/* |
| 1785 |
* Handle redeclaration and optimize cases where we can statically bind the |
1895 |
* Handle redeclaration and optimize cases where we can statically bind the |
| 1786 |
* function (thereby avoiding JSOP_DEFFUN and dynamic name lookup). |
1896 |
* function (thereby avoiding JSOP_DEFFUN and dynamic name lookup). |
|
Lines 1791-1808
Parser<SyntaxParseHandler>::checkFunctionDefinition(HandlePropertyName funName,
|
Link Here
|
|---|
|
| 1791 |
if (!AtomToPrintableString(context, funName, &name) || |
1901 |
if (!AtomToPrintableString(context, funName, &name) || |
| 1792 |
!report(ParseError, false, null(), JSMSG_REDECLARED_VAR, |
1902 |
!report(ParseError, false, null(), JSMSG_REDECLARED_VAR, |
| 1793 |
Definition::kindString(dn), name.ptr())) |
1903 |
Definition::kindString(dn), name.ptr())) |
| 1794 |
{ |
1904 |
{ |
| 1795 |
return false; |
1905 |
return false; |
| 1796 |
} |
1906 |
} |
| 1797 |
} |
1907 |
} |
| 1798 |
} else if (bodyLevel) { |
1908 |
} else if (bodyLevel) { |
| 1799 |
if (pc->lexdeps.lookupDefn<SyntaxParseHandler>(funName)) |
1909 |
if (pc->lexdeps.lookupDefn<SyntaxParseHandler>(funName)) { |
|
|
1910 |
*pbodyLevelHoistedUse = true; |
| 1800 |
pc->lexdeps->remove(funName); |
1911 |
pc->lexdeps->remove(funName); |
|
|
1912 |
} |
| 1801 |
|
1913 |
|
| 1802 |
if (!pc->define(tokenStream, funName, *pn, Definition::VAR)) |
1914 |
if (!pc->define(tokenStream, funName, *pn, Definition::VAR)) |
| 1803 |
return false; |
1915 |
return false; |
| 1804 |
} |
1916 |
} |
| 1805 |
|
1917 |
|
| 1806 |
if (!bodyLevel && funName == context->names().arguments) |
1918 |
if (!bodyLevel && funName == context->names().arguments) |
| 1807 |
pc->sc->setBindingsAccessedDynamically(); |
1919 |
pc->sc->setBindingsAccessedDynamically(); |
| 1808 |
} |
1920 |
} |
|
Lines 1891-1907
Parser<ParseHandler>::functionDef(HandlePropertyName funName, const TokenStream:
|
Link Here
|
|---|
|
| 1891 |
JS_ASSERT_IF(kind == Statement, funName); |
2003 |
JS_ASSERT_IF(kind == Statement, funName); |
| 1892 |
|
2004 |
|
| 1893 |
/* Make a TOK_FUNCTION node. */ |
2005 |
/* Make a TOK_FUNCTION node. */ |
| 1894 |
Node pn = handler.newFunctionDefinition(); |
2006 |
Node pn = handler.newFunctionDefinition(); |
| 1895 |
if (!pn) |
2007 |
if (!pn) |
| 1896 |
return null(); |
2008 |
return null(); |
| 1897 |
|
2009 |
|
| 1898 |
bool bodyProcessed; |
2010 |
bool bodyProcessed; |
| 1899 |
if (!checkFunctionDefinition(funName, &pn, kind, &bodyProcessed)) |
2011 |
bool bodyLevelHoistedUse; |
|
|
2012 |
if (!checkFunctionDefinition(funName, &pn, kind, &bodyProcessed, &bodyLevelHoistedUse)) |
| 1900 |
return null(); |
2013 |
return null(); |
| 1901 |
|
2014 |
|
| 1902 |
if (bodyProcessed) |
2015 |
if (bodyProcessed) |
| 1903 |
return pn; |
2016 |
return pn; |
| 1904 |
|
2017 |
|
| 1905 |
RootedObject proto(context); |
2018 |
RootedObject proto(context); |
| 1906 |
if (generatorKind == StarGenerator) { |
2019 |
if (generatorKind == StarGenerator) { |
| 1907 |
// If we are off the main thread, the generator meta-objects have |
2020 |
// If we are off the main thread, the generator meta-objects have |
|
Lines 1919-1935
Parser<ParseHandler>::functionDef(HandlePropertyName funName, const TokenStream:
|
Link Here
|
|---|
|
| 1919 |
// Speculatively parse using the directives of the parent parsing context. |
2032 |
// Speculatively parse using the directives of the parent parsing context. |
| 1920 |
// If a directive is encountered (e.g., "use strict") that changes how the |
2033 |
// If a directive is encountered (e.g., "use strict") that changes how the |
| 1921 |
// function should have been parsed, we backup and reparse with the new set |
2034 |
// function should have been parsed, we backup and reparse with the new set |
| 1922 |
// of directives. |
2035 |
// of directives. |
| 1923 |
Directives directives(pc); |
2036 |
Directives directives(pc); |
| 1924 |
Directives newDirectives = directives; |
2037 |
Directives newDirectives = directives; |
| 1925 |
|
2038 |
|
| 1926 |
while (true) { |
2039 |
while (true) { |
| 1927 |
if (functionArgsAndBody(pn, fun, type, kind, generatorKind, directives, &newDirectives)) |
2040 |
if (functionArgsAndBody(pn, fun, type, kind, generatorKind, directives, &newDirectives, |
|
|
2041 |
bodyLevelHoistedUse)) |
| 1928 |
break; |
2042 |
break; |
| 1929 |
if (tokenStream.hadError() || directives == newDirectives) |
2043 |
if (tokenStream.hadError() || directives == newDirectives) |
| 1930 |
return null(); |
2044 |
return null(); |
| 1931 |
|
2045 |
|
| 1932 |
// Assignment must be monotonic to prevent reparsing iloops |
2046 |
// Assignment must be monotonic to prevent reparsing iloops |
| 1933 |
JS_ASSERT_IF(directives.strict(), newDirectives.strict()); |
2047 |
JS_ASSERT_IF(directives.strict(), newDirectives.strict()); |
| 1934 |
JS_ASSERT_IF(directives.asmJS(), newDirectives.asmJS()); |
2048 |
JS_ASSERT_IF(directives.asmJS(), newDirectives.asmJS()); |
| 1935 |
directives = newDirectives; |
2049 |
directives = newDirectives; |
|
Lines 2010-2029
Parser<SyntaxParseHandler>::finishFunctionDefinition(Node pn, FunctionBox *funbo
|
Link Here
|
|---|
|
| 2010 |
|
2124 |
|
| 2011 |
RootedFunction fun(context, funbox->function()); |
2125 |
RootedFunction fun(context, funbox->function()); |
| 2012 |
LazyScript *lazy = LazyScript::CreateRaw(context, fun, numFreeVariables, numInnerFunctions, |
2126 |
LazyScript *lazy = LazyScript::CreateRaw(context, fun, numFreeVariables, numInnerFunctions, |
| 2013 |
versionNumber(), funbox->bufStart, funbox->bufEnd, |
2127 |
versionNumber(), funbox->bufStart, funbox->bufEnd, |
| 2014 |
funbox->startLine, funbox->startColumn); |
2128 |
funbox->startLine, funbox->startColumn); |
| 2015 |
if (!lazy) |
2129 |
if (!lazy) |
| 2016 |
return false; |
2130 |
return false; |
| 2017 |
|
2131 |
|
| 2018 |
HeapPtrAtom *freeVariables = lazy->freeVariables(); |
2132 |
LazyScript::FreeVariable *freeVariables = lazy->freeVariables(); |
| 2019 |
size_t i = 0; |
2133 |
size_t i = 0; |
| 2020 |
for (AtomDefnRange r = pc->lexdeps->all(); !r.empty(); r.popFront()) |
2134 |
for (AtomDefnRange r = pc->lexdeps->all(); !r.empty(); r.popFront()) |
| 2021 |
freeVariables[i++].init(r.front().key()); |
2135 |
freeVariables[i++] = LazyScript::FreeVariable(r.front().key()); |
| 2022 |
JS_ASSERT(i == numFreeVariables); |
2136 |
JS_ASSERT(i == numFreeVariables); |
| 2023 |
|
2137 |
|
| 2024 |
HeapPtrFunction *innerFunctions = lazy->innerFunctions(); |
2138 |
HeapPtrFunction *innerFunctions = lazy->innerFunctions(); |
| 2025 |
for (size_t i = 0; i < numInnerFunctions; i++) |
2139 |
for (size_t i = 0; i < numInnerFunctions; i++) |
| 2026 |
innerFunctions[i].init(pc->innerFunctions[i]); |
2140 |
innerFunctions[i].init(pc->innerFunctions[i]); |
| 2027 |
|
2141 |
|
| 2028 |
if (pc->sc->strict) |
2142 |
if (pc->sc->strict) |
| 2029 |
lazy->setStrict(); |
2143 |
lazy->setStrict(); |
|
Lines 2037-2053
Parser<SyntaxParseHandler>::finishFunctionDefinition(Node pn, FunctionBox *funbo
|
Link Here
|
|---|
|
| 2037 |
} |
2151 |
} |
| 2038 |
|
2152 |
|
| 2039 |
template <> |
2153 |
template <> |
| 2040 |
bool |
2154 |
bool |
| 2041 |
Parser<FullParseHandler>::functionArgsAndBody(ParseNode *pn, HandleFunction fun, |
2155 |
Parser<FullParseHandler>::functionArgsAndBody(ParseNode *pn, HandleFunction fun, |
| 2042 |
FunctionType type, FunctionSyntaxKind kind, |
2156 |
FunctionType type, FunctionSyntaxKind kind, |
| 2043 |
GeneratorKind generatorKind, |
2157 |
GeneratorKind generatorKind, |
| 2044 |
Directives inheritedDirectives, |
2158 |
Directives inheritedDirectives, |
| 2045 |
Directives *newDirectives) |
2159 |
Directives *newDirectives, |
|
|
2160 |
bool bodyLevelHoistedUse) |
| 2046 |
{ |
2161 |
{ |
| 2047 |
ParseContext<FullParseHandler> *outerpc = pc; |
2162 |
ParseContext<FullParseHandler> *outerpc = pc; |
| 2048 |
|
2163 |
|
| 2049 |
// Create box for fun->object early to protect against last-ditch GC. |
2164 |
// Create box for fun->object early to protect against last-ditch GC. |
| 2050 |
FunctionBox *funbox = newFunctionBox(pn, fun, pc, inheritedDirectives, generatorKind); |
2165 |
FunctionBox *funbox = newFunctionBox(pn, fun, pc, inheritedDirectives, generatorKind); |
| 2051 |
if (!funbox) |
2166 |
if (!funbox) |
| 2052 |
return false; |
2167 |
return false; |
| 2053 |
|
2168 |
|
|
Lines 2061-2078
Parser<FullParseHandler>::functionArgsAndBody(ParseNode *pn, HandleFunction fun,
|
Link Here
|
|---|
|
| 2061 |
// Move the syntax parser to the current position in the stream. |
2176 |
// Move the syntax parser to the current position in the stream. |
| 2062 |
TokenStream::Position position(keepAtoms); |
2177 |
TokenStream::Position position(keepAtoms); |
| 2063 |
tokenStream.tell(&position); |
2178 |
tokenStream.tell(&position); |
| 2064 |
if (!parser->tokenStream.seek(position, tokenStream)) |
2179 |
if (!parser->tokenStream.seek(position, tokenStream)) |
| 2065 |
return false; |
2180 |
return false; |
| 2066 |
|
2181 |
|
| 2067 |
ParseContext<SyntaxParseHandler> funpc(parser, outerpc, SyntaxParseHandler::null(), funbox, |
2182 |
ParseContext<SyntaxParseHandler> funpc(parser, outerpc, SyntaxParseHandler::null(), funbox, |
| 2068 |
newDirectives, outerpc->staticLevel + 1, |
2183 |
newDirectives, outerpc->staticLevel + 1, |
| 2069 |
outerpc->blockidGen, |
2184 |
outerpc->blockidGen, /* blockScopeDepth = */ 0); |
| 2070 |
/* blockScopeDepth = */ 0); |
|
|
| 2071 |
if (!funpc.init(tokenStream)) |
2185 |
if (!funpc.init(tokenStream)) |
| 2072 |
return false; |
2186 |
return false; |
| 2073 |
|
2187 |
|
| 2074 |
if (!parser->functionArgsAndBodyGeneric(SyntaxParseHandler::NodeGeneric, |
2188 |
if (!parser->functionArgsAndBodyGeneric(SyntaxParseHandler::NodeGeneric, |
| 2075 |
fun, type, kind, newDirectives)) |
2189 |
fun, type, kind, newDirectives)) |
| 2076 |
{ |
2190 |
{ |
| 2077 |
if (parser->hadAbortedSyntaxParse()) { |
2191 |
if (parser->hadAbortedSyntaxParse()) { |
| 2078 |
// Try again with a full parse. |
2192 |
// Try again with a full parse. |
|
Lines 2088-2104
Parser<FullParseHandler>::functionArgsAndBody(ParseNode *pn, HandleFunction fun,
|
Link Here
|
|---|
|
| 2088 |
parser->tokenStream.tell(&position); |
2202 |
parser->tokenStream.tell(&position); |
| 2089 |
if (!tokenStream.seek(position, parser->tokenStream)) |
2203 |
if (!tokenStream.seek(position, parser->tokenStream)) |
| 2090 |
return false; |
2204 |
return false; |
| 2091 |
|
2205 |
|
| 2092 |
// Update the end position of the parse node. |
2206 |
// Update the end position of the parse node. |
| 2093 |
pn->pn_pos.end = tokenStream.currentToken().pos.end; |
2207 |
pn->pn_pos.end = tokenStream.currentToken().pos.end; |
| 2094 |
} |
2208 |
} |
| 2095 |
|
2209 |
|
| 2096 |
if (!addFreeVariablesFromLazyFunction(fun, pc)) |
2210 |
if (!addFreeVariablesFromLazyFunction(fun, pc, bodyLevelHoistedUse)) |
| 2097 |
return false; |
2211 |
return false; |
| 2098 |
|
2212 |
|
| 2099 |
pn->pn_blockid = outerpc->blockid(); |
2213 |
pn->pn_blockid = outerpc->blockid(); |
| 2100 |
PropagateTransitiveParseFlags(funbox, outerpc->sc); |
2214 |
PropagateTransitiveParseFlags(funbox, outerpc->sc); |
| 2101 |
return true; |
2215 |
return true; |
| 2102 |
} while (false); |
2216 |
} while (false); |
| 2103 |
|
2217 |
|
| 2104 |
// Continue doing a full parse for this inner function. |
2218 |
// Continue doing a full parse for this inner function. |
|
Lines 2106-2122
Parser<FullParseHandler>::functionArgsAndBody(ParseNode *pn, HandleFunction fun,
|
Link Here
|
|---|
|
| 2106 |
outerpc->staticLevel + 1, outerpc->blockidGen, |
2220 |
outerpc->staticLevel + 1, outerpc->blockidGen, |
| 2107 |
/* blockScopeDepth = */ 0); |
2221 |
/* blockScopeDepth = */ 0); |
| 2108 |
if (!funpc.init(tokenStream)) |
2222 |
if (!funpc.init(tokenStream)) |
| 2109 |
return false; |
2223 |
return false; |
| 2110 |
|
2224 |
|
| 2111 |
if (!functionArgsAndBodyGeneric(pn, fun, type, kind, newDirectives)) |
2225 |
if (!functionArgsAndBodyGeneric(pn, fun, type, kind, newDirectives)) |
| 2112 |
return false; |
2226 |
return false; |
| 2113 |
|
2227 |
|
| 2114 |
if (!leaveFunction(pn, outerpc, kind)) |
2228 |
if (!leaveFunction(pn, outerpc, bodyLevelHoistedUse, kind)) |
| 2115 |
return false; |
2229 |
return false; |
| 2116 |
|
2230 |
|
| 2117 |
pn->pn_blockid = outerpc->blockid(); |
2231 |
pn->pn_blockid = outerpc->blockid(); |
| 2118 |
|
2232 |
|
| 2119 |
/* |
2233 |
/* |
| 2120 |
* Fruit of the poisonous tree: if a closure contains a dynamic name access |
2234 |
* Fruit of the poisonous tree: if a closure contains a dynamic name access |
| 2121 |
* (eval, with, etc), we consider the parent to do the same. The reason is |
2235 |
* (eval, with, etc), we consider the parent to do the same. The reason is |
| 2122 |
* that the deoptimizing effects of dynamic name access apply equally to |
2236 |
* that the deoptimizing effects of dynamic name access apply equally to |
|
Lines 2127-2143
Parser<FullParseHandler>::functionArgsAndBody(ParseNode *pn, HandleFunction fun,
|
Link Here
|
|---|
|
| 2127 |
} |
2241 |
} |
| 2128 |
|
2242 |
|
| 2129 |
template <> |
2243 |
template <> |
| 2130 |
bool |
2244 |
bool |
| 2131 |
Parser<SyntaxParseHandler>::functionArgsAndBody(Node pn, HandleFunction fun, |
2245 |
Parser<SyntaxParseHandler>::functionArgsAndBody(Node pn, HandleFunction fun, |
| 2132 |
FunctionType type, FunctionSyntaxKind kind, |
2246 |
FunctionType type, FunctionSyntaxKind kind, |
| 2133 |
GeneratorKind generatorKind, |
2247 |
GeneratorKind generatorKind, |
| 2134 |
Directives inheritedDirectives, |
2248 |
Directives inheritedDirectives, |
| 2135 |
Directives *newDirectives) |
2249 |
Directives *newDirectives, |
|
|
2250 |
bool bodyLevelHoistedUse) |
| 2136 |
{ |
2251 |
{ |
| 2137 |
ParseContext<SyntaxParseHandler> *outerpc = pc; |
2252 |
ParseContext<SyntaxParseHandler> *outerpc = pc; |
| 2138 |
|
2253 |
|
| 2139 |
// Create box for fun->object early to protect against last-ditch GC. |
2254 |
// Create box for fun->object early to protect against last-ditch GC. |
| 2140 |
FunctionBox *funbox = newFunctionBox(pn, fun, pc, inheritedDirectives, generatorKind); |
2255 |
FunctionBox *funbox = newFunctionBox(pn, fun, pc, inheritedDirectives, generatorKind); |
| 2141 |
if (!funbox) |
2256 |
if (!funbox) |
| 2142 |
return false; |
2257 |
return false; |
| 2143 |
|
2258 |
|
|
Lines 2146-2162
Parser<SyntaxParseHandler>::functionArgsAndBody(Node pn, HandleFunction fun,
|
Link Here
|
|---|
|
| 2146 |
outerpc->staticLevel + 1, outerpc->blockidGen, |
2261 |
outerpc->staticLevel + 1, outerpc->blockidGen, |
| 2147 |
/* blockScopeDepth = */ 0); |
2262 |
/* blockScopeDepth = */ 0); |
| 2148 |
if (!funpc.init(tokenStream)) |
2263 |
if (!funpc.init(tokenStream)) |
| 2149 |
return false; |
2264 |
return false; |
| 2150 |
|
2265 |
|
| 2151 |
if (!functionArgsAndBodyGeneric(pn, fun, type, kind, newDirectives)) |
2266 |
if (!functionArgsAndBodyGeneric(pn, fun, type, kind, newDirectives)) |
| 2152 |
return false; |
2267 |
return false; |
| 2153 |
|
2268 |
|
| 2154 |
if (!leaveFunction(pn, outerpc, kind)) |
2269 |
if (!leaveFunction(pn, outerpc, bodyLevelHoistedUse, kind)) |
| 2155 |
return false; |
2270 |
return false; |
| 2156 |
|
2271 |
|
| 2157 |
// This is a lazy function inner to another lazy function. Remember the |
2272 |
// This is a lazy function inner to another lazy function. Remember the |
| 2158 |
// inner function so that if the outer function is eventually parsed we do |
2273 |
// inner function so that if the outer function is eventually parsed we do |
| 2159 |
// not need any further parsing or processing of the inner function. |
2274 |
// not need any further parsing or processing of the inner function. |
| 2160 |
JS_ASSERT(fun->lazyScript()); |
2275 |
JS_ASSERT(fun->lazyScript()); |
| 2161 |
return outerpc->innerFunctions.append(fun); |
2276 |
return outerpc->innerFunctions.append(fun); |
| 2162 |
} |
2277 |
} |
|
Lines 2650-2707
Parser<FullParseHandler>::bindLet(BindData<FullParseHandler> *data,
|
Link Here
|
|---|
|
| 2650 |
HandlePropertyName name, Parser<FullParseHandler> *parser) |
2765 |
HandlePropertyName name, Parser<FullParseHandler> *parser) |
| 2651 |
{ |
2766 |
{ |
| 2652 |
ParseContext<FullParseHandler> *pc = parser->pc; |
2767 |
ParseContext<FullParseHandler> *pc = parser->pc; |
| 2653 |
ParseNode *pn = data->pn; |
2768 |
ParseNode *pn = data->pn; |
| 2654 |
if (!parser->checkStrictBinding(name, pn)) |
2769 |
if (!parser->checkStrictBinding(name, pn)) |
| 2655 |
return false; |
2770 |
return false; |
| 2656 |
|
2771 |
|
| 2657 |
ExclusiveContext *cx = parser->context; |
2772 |
ExclusiveContext *cx = parser->context; |
| 2658 |
|
|
|
| 2659 |
Rooted<StaticBlockObject *> blockObj(cx, data->let.blockObj); |
2773 |
Rooted<StaticBlockObject *> blockObj(cx, data->let.blockObj); |
| 2660 |
unsigned index = blockObj->numVariables(); |
2774 |
|
| 2661 |
if (index >= StaticBlockObject::LOCAL_INDEX_LIMIT) { |
2775 |
unsigned index; |
| 2662 |
parser->report(ParseError, false, pn, data->let.overflow); |
2776 |
if (blockObj) { |
| 2663 |
return false; |
2777 |
index = blockObj->numVariables(); |
|
|
2778 |
if (index >= StaticBlockObject::LOCAL_INDEX_LIMIT) { |
| 2779 |
parser->report(ParseError, false, pn, data->let.overflow); |
| 2780 |
return false; |
| 2781 |
} |
| 2782 |
} else { |
| 2783 |
// If we don't have a block object, we are parsing a body-level let, |
| 2784 |
// in which case we use a bogus index. See comment block below in |
| 2785 |
// setting the pn_cookie for explanation on how it gets adjusted. |
| 2786 |
index = 0; |
| 2664 |
} |
2787 |
} |
| 2665 |
|
2788 |
|
| 2666 |
/* |
2789 |
// For block-level lets, assign block-local index to pn->pn_cookie right |
| 2667 |
* Assign block-local index to pn->pn_cookie right away, encoding it as an |
2790 |
// away, encoding it as an upvar cookie whose skip tells the current |
| 2668 |
* upvar cookie whose skip tells the current static level. The emitter will |
2791 |
// static level. The emitter will adjust the node's slot based on its |
| 2669 |
* adjust the node's slot based on its stack depth model -- and, for global |
2792 |
// stack depth model -- and, for global and eval code, |
| 2670 |
* and eval code, js::frontend::CompileScript will adjust the slot |
2793 |
// js::frontend::CompileScript will adjust the slot again to include |
| 2671 |
* again to include script->nfixed. |
2794 |
// script->nfixed and body-level lets. |
| 2672 |
*/ |
2795 |
// |
|
|
2796 |
// For body-level lets, the index is bogus at this point and is adjusted |
| 2797 |
// when creating Bindings. See ParseContext::generateFunctionBindings. |
| 2673 |
if (!pn->pn_cookie.set(parser->tokenStream, pc->staticLevel, index)) |
2798 |
if (!pn->pn_cookie.set(parser->tokenStream, pc->staticLevel, index)) |
| 2674 |
return false; |
2799 |
return false; |
| 2675 |
|
2800 |
|
| 2676 |
/* |
2801 |
/* |
| 2677 |
* For bindings that are hoisted to the beginning of the block/function, |
2802 |
* For bindings that are hoisted to the beginning of the block/function, |
| 2678 |
* define() right now. Otherwise, delay define until PushLetScope. |
2803 |
* define() right now. Otherwise, delay define until PushLetScope. |
| 2679 |
*/ |
2804 |
*/ |
| 2680 |
if (data->let.varContext == HoistVars) { |
2805 |
if (data->let.varContext == HoistVars) { |
| 2681 |
JS_ASSERT(!pc->atBodyLevel()); |
|
|
| 2682 |
Definition *dn = pc->decls().lookupFirst(name); |
2806 |
Definition *dn = pc->decls().lookupFirst(name); |
| 2683 |
if (dn && dn->pn_blockid == pc->blockid()) |
2807 |
if (dn && dn->pn_blockid == pc->blockid()) |
| 2684 |
return parser->reportRedeclaration(pn, dn->isConst(), name); |
2808 |
return parser->reportRedeclaration(pn, dn->isConst(), name); |
| 2685 |
if (!pc->define(parser->tokenStream, name, pn, Definition::LET)) |
2809 |
if (!pc->define(parser->tokenStream, name, pn, Definition::LET)) |
| 2686 |
return false; |
2810 |
return false; |
| 2687 |
} |
2811 |
} |
| 2688 |
|
2812 |
|
| 2689 |
bool redeclared; |
2813 |
if (blockObj) { |
| 2690 |
RootedId id(cx, NameToId(name)); |
2814 |
bool redeclared; |
| 2691 |
RootedShape shape(cx, StaticBlockObject::addVar(cx, blockObj, id, index, &redeclared)); |
2815 |
RootedId id(cx, NameToId(name)); |
| 2692 |
if (!shape) { |
2816 |
RootedShape shape(cx, StaticBlockObject::addVar(cx, blockObj, id, index, &redeclared)); |
| 2693 |
if (redeclared) |
2817 |
if (!shape) { |
| 2694 |
parser->reportRedeclaration(pn, false, name); |
2818 |
if (redeclared) |
| 2695 |
return false; |
2819 |
parser->reportRedeclaration(pn, false, name); |
|
|
2820 |
return false; |
| 2821 |
} |
| 2822 |
|
| 2823 |
/* Store pn in the static block object. */ |
| 2824 |
blockObj->setDefinitionParseNode(index, reinterpret_cast<Definition *>(pn)); |
| 2825 |
} else { |
| 2826 |
// Body-level lets are hoisted and need to have been defined via |
| 2827 |
// pc->define above. |
| 2828 |
MOZ_ASSERT(data->let.varContext == HoistVars); |
| 2829 |
MOZ_ASSERT(pc->decls().lookupFirst(name)); |
| 2696 |
} |
2830 |
} |
| 2697 |
|
2831 |
|
| 2698 |
/* Store pn in the static block object. */ |
|
|
| 2699 |
blockObj->setDefinitionParseNode(index, reinterpret_cast<Definition *>(pn)); |
| 2700 |
return true; |
2832 |
return true; |
| 2701 |
} |
2833 |
} |
| 2702 |
|
2834 |
|
| 2703 |
template <> |
2835 |
template <> |
| 2704 |
/* static */ bool |
2836 |
/* static */ bool |
| 2705 |
Parser<SyntaxParseHandler>::bindLet(BindData<SyntaxParseHandler> *data, |
2837 |
Parser<SyntaxParseHandler>::bindLet(BindData<SyntaxParseHandler> *data, |
| 2706 |
HandlePropertyName name, Parser<SyntaxParseHandler> *parser) |
2838 |
HandlePropertyName name, Parser<SyntaxParseHandler> *parser) |
| 2707 |
{ |
2839 |
{ |
|
Lines 2978-2995
Parser<ParseHandler>::noteNameUse(HandlePropertyName name, Node pn)
|
Link Here
|
|---|
|
| 2978 |
*/ |
3110 |
*/ |
| 2979 |
dn = getOrCreateLexicalDependency(pc, name); |
3111 |
dn = getOrCreateLexicalDependency(pc, name); |
| 2980 |
if (!dn) |
3112 |
if (!dn) |
| 2981 |
return false; |
3113 |
return false; |
| 2982 |
} |
3114 |
} |
| 2983 |
|
3115 |
|
| 2984 |
handler.linkUseToDef(pn, dn); |
3116 |
handler.linkUseToDef(pn, dn); |
| 2985 |
|
3117 |
|
| 2986 |
if (stmt && stmt->type == STMT_WITH) |
3118 |
if (stmt) { |
| 2987 |
handler.setFlag(pn, PND_DEOPTIMIZED); |
3119 |
if (stmt->type == STMT_WITH) { |
|
|
3120 |
handler.setFlag(pn, PND_DEOPTIMIZED); |
| 3121 |
} else if (stmt->type == STMT_SWITCH && stmt->isBlockScope) { |
| 3122 |
// See comments above StmtInfoPC and switchStatement for how |
| 3123 |
// firstDominatingLetInCase is computed. |
| 3124 |
MOZ_ASSERT(stmt->firstDominatingLetInCase <= stmt->staticBlock().numVariables()); |
| 3125 |
handler.markMaybeUninitializedLetUseInSwitch(pn, dn, stmt->firstDominatingLetInCase); |
| 3126 |
} |
| 3127 |
} |
| 2988 |
|
3128 |
|
| 2989 |
return true; |
3129 |
return true; |
| 2990 |
} |
3130 |
} |
| 2991 |
|
3131 |
|
| 2992 |
template <> |
3132 |
template <> |
| 2993 |
bool |
3133 |
bool |
| 2994 |
Parser<FullParseHandler>::bindDestructuringVar(BindData<FullParseHandler> *data, ParseNode *pn) |
3134 |
Parser<FullParseHandler>::bindDestructuringVar(BindData<FullParseHandler> *data, ParseNode *pn) |
| 2995 |
{ |
3135 |
{ |
|
Lines 3000-3016
Parser<FullParseHandler>::bindDestructuringVar(BindData<FullParseHandler> *data,
|
Link Here
|
|---|
|
| 3000 |
data->pn = pn; |
3140 |
data->pn = pn; |
| 3001 |
if (!data->binder(data, name, this)) |
3141 |
if (!data->binder(data, name, this)) |
| 3002 |
return false; |
3142 |
return false; |
| 3003 |
|
3143 |
|
| 3004 |
/* |
3144 |
/* |
| 3005 |
* Select the appropriate name-setting opcode, respecting eager selection |
3145 |
* Select the appropriate name-setting opcode, respecting eager selection |
| 3006 |
* done by the data->binder function. |
3146 |
* done by the data->binder function. |
| 3007 |
*/ |
3147 |
*/ |
| 3008 |
if (pn->pn_dflags & PND_BOUND) |
3148 |
if (data->op == JSOP_INITLET) |
|
|
3149 |
pn->setOp(JSOP_INITLET); |
| 3150 |
else if (pn->pn_dflags & PND_BOUND) |
| 3009 |
pn->setOp(JSOP_SETLOCAL); |
3151 |
pn->setOp(JSOP_SETLOCAL); |
| 3010 |
else if (data->op == JSOP_DEFCONST) |
3152 |
else if (data->op == JSOP_DEFCONST) |
| 3011 |
pn->setOp(JSOP_SETCONST); |
3153 |
pn->setOp(JSOP_SETCONST); |
| 3012 |
else |
3154 |
else |
| 3013 |
pn->setOp(JSOP_SETNAME); |
3155 |
pn->setOp(JSOP_SETNAME); |
| 3014 |
|
3156 |
|
| 3015 |
if (data->op == JSOP_DEFCONST) |
3157 |
if (data->op == JSOP_DEFCONST) |
| 3016 |
pn->pn_dflags |= PND_CONST; |
3158 |
pn->pn_dflags |= PND_CONST; |
|
Lines 3394-3423
Parser<ParseHandler>::variables(ParseNodeKind kind, bool *psimple,
|
Link Here
|
|---|
|
| 3394 |
JS_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET || kind == PNK_CALL); |
3536 |
JS_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET || kind == PNK_CALL); |
| 3395 |
|
3537 |
|
| 3396 |
/* |
3538 |
/* |
| 3397 |
* The simple flag is set if the declaration has the form 'var x', with |
3539 |
* The simple flag is set if the declaration has the form 'var x', with |
| 3398 |
* only one variable declared and no initializer expression. |
3540 |
* only one variable declared and no initializer expression. |
| 3399 |
*/ |
3541 |
*/ |
| 3400 |
JS_ASSERT_IF(psimple, *psimple); |
3542 |
JS_ASSERT_IF(psimple, *psimple); |
| 3401 |
|
3543 |
|
| 3402 |
JSOp op = blockObj ? JSOP_NOP : kind == PNK_VAR ? JSOP_DEFVAR : JSOP_DEFCONST; |
3544 |
JSOp op = kind == PNK_LET ? JSOP_NOP : kind == PNK_VAR ? JSOP_DEFVAR : JSOP_DEFCONST; |
| 3403 |
|
3545 |
|
| 3404 |
Node pn = handler.newList(kind, null(), op); |
3546 |
Node pn = handler.newList(kind, null(), op); |
| 3405 |
if (!pn) |
3547 |
if (!pn) |
| 3406 |
return null(); |
3548 |
return null(); |
| 3407 |
|
3549 |
|
| 3408 |
/* |
3550 |
/* |
| 3409 |
* SpiderMonkey const is really "write once per initialization evaluation" |
3551 |
* SpiderMonkey const is really "write once per initialization evaluation" |
| 3410 |
* var, whereas let is block scoped. ES-Harmony wants block-scoped const so |
3552 |
* var, whereas let is block scoped. ES-Harmony wants block-scoped const so |
| 3411 |
* this code will change soon. |
3553 |
* this code will change soon. |
| 3412 |
*/ |
3554 |
*/ |
| 3413 |
BindData<ParseHandler> data(context); |
3555 |
BindData<ParseHandler> data(context); |
| 3414 |
if (blockObj) |
3556 |
if (kind == PNK_LET) |
| 3415 |
data.initLet(varContext, *blockObj, JSMSG_TOO_MANY_LOCALS); |
3557 |
data.initLet(varContext, blockObj, JSMSG_TOO_MANY_LOCALS); |
| 3416 |
else |
3558 |
else |
| 3417 |
data.initVarOrConst(op); |
3559 |
data.initVarOrConst(op); |
| 3418 |
|
3560 |
|
| 3419 |
bool first = true; |
3561 |
bool first = true; |
| 3420 |
Node pn2; |
3562 |
Node pn2; |
| 3421 |
do { |
3563 |
do { |
| 3422 |
if (psimple && !first) |
3564 |
if (psimple && !first) |
| 3423 |
*psimple = false; |
3565 |
*psimple = false; |
|
Lines 3429-3459
Parser<ParseHandler>::variables(ParseNodeKind kind, bool *psimple,
|
Link Here
|
|---|
|
| 3429 |
*psimple = false; |
3571 |
*psimple = false; |
| 3430 |
|
3572 |
|
| 3431 |
pc->inDeclDestructuring = true; |
3573 |
pc->inDeclDestructuring = true; |
| 3432 |
pn2 = primaryExpr(tt); |
3574 |
pn2 = primaryExpr(tt); |
| 3433 |
pc->inDeclDestructuring = false; |
3575 |
pc->inDeclDestructuring = false; |
| 3434 |
if (!pn2) |
3576 |
if (!pn2) |
| 3435 |
return null(); |
3577 |
return null(); |
| 3436 |
|
3578 |
|
| 3437 |
if (!checkDestructuring(&data, pn2)) |
|
|
| 3438 |
return null(); |
| 3439 |
bool ignored; |
3579 |
bool ignored; |
| 3440 |
if (pc->parsingForInit && matchInOrOf(&ignored)) { |
3580 |
bool parsingForInOrOfInit = pc->parsingForInit && matchInOrOf(&ignored); |
|
|
3581 |
|
| 3582 |
// See comment below for bindBeforeInitializer in the code that |
| 3583 |
// handles the non-destructuring case. |
| 3584 |
bool bindBeforeInitializer = kind != PNK_LET || parsingForInOrOfInit; |
| 3585 |
if (bindBeforeInitializer && !checkDestructuring(&data, pn2)) |
| 3586 |
return null(); |
| 3587 |
|
| 3588 |
if (parsingForInOrOfInit) { |
| 3441 |
tokenStream.ungetToken(); |
3589 |
tokenStream.ungetToken(); |
| 3442 |
handler.addList(pn, pn2); |
3590 |
handler.addList(pn, pn2); |
| 3443 |
continue; |
3591 |
continue; |
| 3444 |
} |
3592 |
} |
| 3445 |
|
3593 |
|
| 3446 |
MUST_MATCH_TOKEN(TOK_ASSIGN, JSMSG_BAD_DESTRUCT_DECL); |
3594 |
MUST_MATCH_TOKEN(TOK_ASSIGN, JSMSG_BAD_DESTRUCT_DECL); |
| 3447 |
|
3595 |
|
| 3448 |
Node init = assignExpr(); |
3596 |
Node init = assignExpr(); |
| 3449 |
if (!init) |
3597 |
if (!init) |
| 3450 |
return null(); |
3598 |
return null(); |
| 3451 |
|
3599 |
|
|
|
3600 |
if (!bindBeforeInitializer && !checkDestructuring(&data, pn2)) |
| 3601 |
return null(); |
| 3602 |
|
| 3452 |
pn2 = handler.newBinaryOrAppend(PNK_ASSIGN, pn2, init, pc); |
3603 |
pn2 = handler.newBinaryOrAppend(PNK_ASSIGN, pn2, init, pc); |
| 3453 |
if (!pn2) |
3604 |
if (!pn2) |
| 3454 |
return null(); |
3605 |
return null(); |
| 3455 |
handler.addList(pn, pn2); |
3606 |
handler.addList(pn, pn2); |
| 3456 |
continue; |
3607 |
continue; |
| 3457 |
} |
3608 |
} |
| 3458 |
|
3609 |
|
| 3459 |
if (tt != TOK_NAME) { |
3610 |
if (tt != TOK_NAME) { |
|
Lines 3469-3499
Parser<ParseHandler>::variables(ParseNodeKind kind, bool *psimple,
|
Link Here
|
|---|
|
| 3469 |
|
3620 |
|
| 3470 |
RootedPropertyName name(context, tokenStream.currentName()); |
3621 |
RootedPropertyName name(context, tokenStream.currentName()); |
| 3471 |
pn2 = newBindingNode(name, kind == PNK_VAR || kind == PNK_CONST, varContext); |
3622 |
pn2 = newBindingNode(name, kind == PNK_VAR || kind == PNK_CONST, varContext); |
| 3472 |
if (!pn2) |
3623 |
if (!pn2) |
| 3473 |
return null(); |
3624 |
return null(); |
| 3474 |
if (data.op == JSOP_DEFCONST) |
3625 |
if (data.op == JSOP_DEFCONST) |
| 3475 |
handler.setFlag(pn2, PND_CONST); |
3626 |
handler.setFlag(pn2, PND_CONST); |
| 3476 |
data.pn = pn2; |
3627 |
data.pn = pn2; |
| 3477 |
if (!data.binder(&data, name, this)) |
3628 |
|
| 3478 |
return null(); |
|
|
| 3479 |
handler.addList(pn, pn2); |
3629 |
handler.addList(pn, pn2); |
| 3480 |
|
3630 |
|
| 3481 |
if (tokenStream.matchToken(TOK_ASSIGN)) { |
3631 |
if (tokenStream.matchToken(TOK_ASSIGN)) { |
| 3482 |
if (psimple) |
3632 |
if (psimple) |
| 3483 |
*psimple = false; |
3633 |
*psimple = false; |
| 3484 |
|
3634 |
|
|
|
3635 |
// Per ES6, 'let' declarations may not be accessed until |
| 3636 |
// initialized. So a declaration of the form |let x = x| results in a |
| 3637 |
// ReferenceError, as the 'x' on the RHS is accessing the let binding |
| 3638 |
// before it is initialized. |
| 3639 |
// |
| 3640 |
// If we are not parsing a let declaration, bind the name |
| 3641 |
// now. Otherwise we must wait until after parsing the initializing |
| 3642 |
// assignment. |
| 3643 |
// |
| 3644 |
// Optimize the common case of recursive function calls, e.g., |
| 3645 |
// |
| 3646 |
// let f = function (...) { f(...); }; |
| 3647 |
// |
| 3648 |
// by binding early, since any uses of the binding inside the body of |
| 3649 |
// the function will be after initialization. |
| 3650 |
TokenKind nextToken = tokenStream.peekToken(TokenStream::Operand); |
| 3651 |
bool bindBeforeInitializer = kind != PNK_LET || nextToken == TOK_FUNCTION; |
| 3652 |
if (bindBeforeInitializer && !data.binder(&data, name, this)) |
| 3653 |
return null(); |
| 3654 |
|
| 3485 |
Node init = assignExpr(); |
3655 |
Node init = assignExpr(); |
| 3486 |
if (!init) |
3656 |
if (!init) |
| 3487 |
return null(); |
3657 |
return null(); |
| 3488 |
|
3658 |
|
|
|
3659 |
if (!bindBeforeInitializer && !data.binder(&data, name, this)) |
| 3660 |
return null(); |
| 3661 |
|
| 3489 |
if (!handler.finishInitializerAssignment(pn2, init, data.op)) |
3662 |
if (!handler.finishInitializerAssignment(pn2, init, data.op)) |
| 3490 |
return null(); |
3663 |
return null(); |
|
|
3664 |
} else { |
| 3665 |
if (!data.binder(&data, name, this)) |
| 3666 |
return null(); |
| 3491 |
} |
3667 |
} |
|
|
3668 |
|
| 3669 |
|
| 3492 |
} while (tokenStream.matchToken(TOK_COMMA)); |
3670 |
} while (tokenStream.matchToken(TOK_COMMA)); |
| 3493 |
|
3671 |
|
| 3494 |
return pn; |
3672 |
return pn; |
| 3495 |
} |
3673 |
} |
| 3496 |
|
3674 |
|
| 3497 |
template <> |
3675 |
template <> |
| 3498 |
ParseNode * |
3676 |
ParseNode * |
| 3499 |
Parser<FullParseHandler>::letDeclaration() |
3677 |
Parser<FullParseHandler>::letDeclaration() |
|
Lines 3530-3558
Parser<FullParseHandler>::letDeclaration()
|
Link Here
|
|---|
|
| 3530 |
* before the global object in the overall chain. This extra |
3708 |
* before the global object in the overall chain. This extra |
| 3531 |
* object is present in the scope chain for all code in that |
3709 |
* object is present in the scope chain for all code in that |
| 3532 |
* global, including self-hosted code. But self-hosted code |
3710 |
* global, including self-hosted code. But self-hosted code |
| 3533 |
* must be usable against *any* global object, including ones |
3711 |
* must be usable against *any* global object, including ones |
| 3534 |
* with other let variables -- variables possibly placed in |
3712 |
* with other let variables -- variables possibly placed in |
| 3535 |
* conflicting slots. Forbid top-level let declarations to |
3713 |
* conflicting slots. Forbid top-level let declarations to |
| 3536 |
* prevent such conflicts from ever occurring. |
3714 |
* prevent such conflicts from ever occurring. |
| 3537 |
*/ |
3715 |
*/ |
| 3538 |
if (options().selfHostingMode && |
3716 |
bool globalLet = !pc->sc->isFunctionBox() && stmt == pc->topScopeStmt; |
| 3539 |
!pc->sc->isFunctionBox() && |
3717 |
if (options().selfHostingMode && globalLet) { |
| 3540 |
stmt == pc->topScopeStmt) |
|
|
| 3541 |
{ |
| 3542 |
report(ParseError, false, null(), JSMSG_SELFHOSTED_TOP_LEVEL_LET); |
3718 |
report(ParseError, false, null(), JSMSG_SELFHOSTED_TOP_LEVEL_LET); |
| 3543 |
return null(); |
3719 |
return null(); |
| 3544 |
} |
3720 |
} |
| 3545 |
|
3721 |
|
| 3546 |
/* |
3722 |
/* |
| 3547 |
* ES4 specifies that let at top level and at body-block scope |
3723 |
* Parse body-level lets without a new block object. ES6 specs |
| 3548 |
* does not shadow var, so convert back to var. |
3724 |
* that an execution environment's initial lexical environment |
|
|
3725 |
* is the VariableEnvironment, i.e., body-level lets are in |
| 3726 |
* the same environment record as vars. |
| 3727 |
* |
| 3728 |
* However, they cannot be parsed exactly as vars, as ES6 |
| 3729 |
* requires that uninitialized lets throw ReferenceError on use. |
| 3730 |
* |
| 3731 |
* See 8.1.1.1.6 and the note in 13.2.1. |
| 3732 |
* |
| 3733 |
* FIXME global-level lets are still considered vars until |
| 3734 |
* other bugs are fixed. |
| 3549 |
*/ |
3735 |
*/ |
| 3550 |
pn = variables(PNK_VAR); |
3736 |
pn = variables(globalLet ? PNK_VAR : PNK_LET); |
| 3551 |
if (!pn) |
3737 |
if (!pn) |
| 3552 |
return null(); |
3738 |
return null(); |
| 3553 |
pn->pn_xflags |= PNX_POPVAR; |
3739 |
pn->pn_xflags |= PNX_POPVAR; |
| 3554 |
break; |
3740 |
break; |
| 3555 |
} |
3741 |
} |
| 3556 |
|
3742 |
|
| 3557 |
/* |
3743 |
/* |
| 3558 |
* Some obvious assertions here, but they may help clarify the |
3744 |
* Some obvious assertions here, but they may help clarify the |
|
Lines 4577-4592
Parser<ParseHandler>::switchStatement()
|
Link Here
|
|---|
|
| 4577 |
if (tt == TOK_ERROR) |
4763 |
if (tt == TOK_ERROR) |
| 4578 |
return null(); |
4764 |
return null(); |
| 4579 |
Node stmt = statement(); |
4765 |
Node stmt = statement(); |
| 4580 |
if (!stmt) |
4766 |
if (!stmt) |
| 4581 |
return null(); |
4767 |
return null(); |
| 4582 |
handler.addList(body, stmt); |
4768 |
handler.addList(body, stmt); |
| 4583 |
} |
4769 |
} |
| 4584 |
|
4770 |
|
|
|
4771 |
// In ES6, 'let' bindings canot be accessed until initialized. If |
| 4772 |
// there was a 'let' declaration in the case we just parsed, remember |
| 4773 |
// the slot starting at which new 'let' bindings will be |
| 4774 |
// assigned. Since 'let' bindings from previous cases will not |
| 4775 |
// dominate uses in the current case, any such uses will require a |
| 4776 |
// dead zone check. |
| 4777 |
if (pc->blockNode != caseList) |
| 4778 |
stmtInfo.firstDominatingLetInCase = stmtInfo.staticBlock().numVariables(); |
| 4779 |
|
| 4585 |
Node casepn = handler.newCaseOrDefault(caseBegin, caseExpr, body); |
4780 |
Node casepn = handler.newCaseOrDefault(caseBegin, caseExpr, body); |
| 4586 |
if (!casepn) |
4781 |
if (!casepn) |
| 4587 |
return null(); |
4782 |
return null(); |
| 4588 |
handler.addList(caseList, casepn); |
4783 |
handler.addList(caseList, casepn); |
| 4589 |
} |
4784 |
} |
| 4590 |
|
4785 |
|
| 4591 |
/* |
4786 |
/* |
| 4592 |
* Handle the case where there was a let declaration in any case in |
4787 |
* Handle the case where there was a let declaration in any case in |
|
Lines 5049-5065
Parser<ParseHandler>::tryStatement()
|
Link Here
|
|---|
|
| 5049 |
*/ |
5244 |
*/ |
| 5050 |
MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_CATCH); |
5245 |
MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_CATCH); |
| 5051 |
|
5246 |
|
| 5052 |
/* |
5247 |
/* |
| 5053 |
* Contrary to ECMA Ed. 3, the catch variable is lexically |
5248 |
* Contrary to ECMA Ed. 3, the catch variable is lexically |
| 5054 |
* scoped, not a property of a new Object instance. This is |
5249 |
* scoped, not a property of a new Object instance. This is |
| 5055 |
* an intentional change that anticipates ECMA Ed. 4. |
5250 |
* an intentional change that anticipates ECMA Ed. 4. |
| 5056 |
*/ |
5251 |
*/ |
| 5057 |
data.initLet(HoistVars, pc->staticScope->template as<StaticBlockObject>(), |
5252 |
data.initLet(HoistVars, &pc->staticScope->template as<StaticBlockObject>(), |
| 5058 |
JSMSG_TOO_MANY_CATCH_VARS); |
5253 |
JSMSG_TOO_MANY_CATCH_VARS); |
| 5059 |
JS_ASSERT(data.let.blockObj); |
5254 |
JS_ASSERT(data.let.blockObj); |
| 5060 |
|
5255 |
|
| 5061 |
tt = tokenStream.getToken(); |
5256 |
tt = tokenStream.getToken(); |
| 5062 |
Node catchName; |
5257 |
Node catchName; |
| 5063 |
switch (tt) { |
5258 |
switch (tt) { |
| 5064 |
case TOK_LB: |
5259 |
case TOK_LB: |
| 5065 |
case TOK_LC: |
5260 |
case TOK_LC: |
|
Lines 6097-6113
Parser<FullParseHandler>::legacyComprehensionTail(ParseNode *bodyStmt, unsigned
|
Link Here
|
|---|
|
| 6097 |
LegacyCompExprTransplanter transplanter(bodyStmt, this, outerpc, comprehensionKind, adjust); |
6292 |
LegacyCompExprTransplanter transplanter(bodyStmt, this, outerpc, comprehensionKind, adjust); |
| 6098 |
if (!transplanter.init()) |
6293 |
if (!transplanter.init()) |
| 6099 |
return null(); |
6294 |
return null(); |
| 6100 |
|
6295 |
|
| 6101 |
if (!transplanter.transplant(bodyStmt)) |
6296 |
if (!transplanter.transplant(bodyStmt)) |
| 6102 |
return null(); |
6297 |
return null(); |
| 6103 |
|
6298 |
|
| 6104 |
JS_ASSERT(pc->staticScope && pc->staticScope == pn->pn_objbox->object); |
6299 |
JS_ASSERT(pc->staticScope && pc->staticScope == pn->pn_objbox->object); |
| 6105 |
data.initLet(HoistVars, pc->staticScope->as<StaticBlockObject>(), JSMSG_ARRAY_INIT_TOO_BIG); |
6300 |
data.initLet(HoistVars, &pc->staticScope->as<StaticBlockObject>(), JSMSG_ARRAY_INIT_TOO_BIG); |
| 6106 |
|
6301 |
|
| 6107 |
do { |
6302 |
do { |
| 6108 |
/* |
6303 |
/* |
| 6109 |
* FOR node is binary, left is loop control and right is body. Use |
6304 |
* FOR node is binary, left is loop control and right is body. Use |
| 6110 |
* index to count each block-local let-variable on the left-hand side |
6305 |
* index to count each block-local let-variable on the left-hand side |
| 6111 |
* of the in/of. |
6306 |
* of the in/of. |
| 6112 |
*/ |
6307 |
*/ |
| 6113 |
pn2 = BinaryNode::create(PNK_FOR, &handler); |
6308 |
pn2 = BinaryNode::create(PNK_FOR, &handler); |
|
Lines 6213-6243
Parser<FullParseHandler>::legacyComprehensionTail(ParseNode *bodyStmt, unsigned
|
Link Here
|
|---|
|
| 6213 |
break; |
6408 |
break; |
| 6214 |
|
6409 |
|
| 6215 |
default:; |
6410 |
default:; |
| 6216 |
} |
6411 |
} |
| 6217 |
|
6412 |
|
| 6218 |
/* |
6413 |
/* |
| 6219 |
* Synthesize a declaration. Every definition must appear in the parse |
6414 |
* Synthesize a declaration. Every definition must appear in the parse |
| 6220 |
* tree in order for ComprehensionTranslator to work. |
6415 |
* tree in order for ComprehensionTranslator to work. |
|
|
6416 |
* |
| 6417 |
* These are lets to tell the bytecode emitter to emit initialization |
| 6418 |
* code for the temporal dead zone. |
| 6221 |
*/ |
6419 |
*/ |
| 6222 |
ParseNode *vars = ListNode::create(PNK_VAR, &handler); |
6420 |
ParseNode *lets = ListNode::create(PNK_LET, &handler); |
| 6223 |
if (!vars) |
6421 |
if (!lets) |
| 6224 |
return null(); |
6422 |
return null(); |
| 6225 |
vars->setOp(JSOP_NOP); |
6423 |
lets->setOp(JSOP_NOP); |
| 6226 |
vars->pn_pos = pn3->pn_pos; |
6424 |
lets->pn_pos = pn3->pn_pos; |
| 6227 |
vars->makeEmpty(); |
6425 |
lets->makeEmpty(); |
| 6228 |
vars->append(pn3); |
6426 |
lets->append(pn3); |
|
|
6427 |
lets->pn_xflags |= PNX_POPVAR; |
| 6229 |
|
6428 |
|
| 6230 |
/* Definitions can't be passed directly to EmitAssignment as lhs. */ |
6429 |
/* Definitions can't be passed directly to EmitAssignment as lhs. */ |
| 6231 |
pn3 = cloneLeftHandSide(pn3); |
6430 |
pn3 = cloneLeftHandSide(pn3); |
| 6232 |
if (!pn3) |
6431 |
if (!pn3) |
| 6233 |
return null(); |
6432 |
return null(); |
| 6234 |
|
6433 |
|
| 6235 |
pn2->pn_left = handler.newTernary(headKind, vars, pn3, pn4); |
6434 |
pn2->pn_left = handler.newTernary(headKind, lets, pn3, pn4); |
| 6236 |
if (!pn2->pn_left) |
6435 |
if (!pn2->pn_left) |
| 6237 |
return null(); |
6436 |
return null(); |
| 6238 |
*pnp = pn2; |
6437 |
*pnp = pn2; |
| 6239 |
pnp = &pn2->pn_right; |
6438 |
pnp = &pn2->pn_right; |
| 6240 |
} while (tokenStream.matchToken(TOK_FOR)); |
6439 |
} while (tokenStream.matchToken(TOK_FOR)); |
| 6241 |
|
6440 |
|
| 6242 |
if (tokenStream.matchToken(TOK_IF)) { |
6441 |
if (tokenStream.matchToken(TOK_IF)) { |
| 6243 |
pn2 = TernaryNode::create(PNK_IF, &handler); |
6442 |
pn2 = TernaryNode::create(PNK_IF, &handler); |
|
Lines 6393-6409
Parser<ParseHandler>::generatorComprehensionLambda(GeneratorKind comprehensionKi
|
Link Here
|
|---|
|
| 6393 |
|
6592 |
|
| 6394 |
// Note that if we ever start syntax-parsing generators, we will also |
6593 |
// Note that if we ever start syntax-parsing generators, we will also |
| 6395 |
// need to propagate the closed-over variable set to the inner |
6594 |
// need to propagate the closed-over variable set to the inner |
| 6396 |
// lazyscript, as in finishFunctionDefinition. |
6595 |
// lazyscript, as in finishFunctionDefinition. |
| 6397 |
handler.setFunctionBody(genfn, body); |
6596 |
handler.setFunctionBody(genfn, body); |
| 6398 |
|
6597 |
|
| 6399 |
PropagateTransitiveParseFlags(genFunbox, outerpc->sc); |
6598 |
PropagateTransitiveParseFlags(genFunbox, outerpc->sc); |
| 6400 |
|
6599 |
|
| 6401 |
if (!leaveFunction(genfn, outerpc)) |
6600 |
if (!leaveFunction(genfn, outerpc, /* bodyLevelHoistedUse = */ false)) |
| 6402 |
return null(); |
6601 |
return null(); |
| 6403 |
|
6602 |
|
| 6404 |
return genfn; |
6603 |
return genfn; |
| 6405 |
} |
6604 |
} |
| 6406 |
|
6605 |
|
| 6407 |
#if JS_HAS_GENERATOR_EXPRS |
6606 |
#if JS_HAS_GENERATOR_EXPRS |
| 6408 |
|
6607 |
|
| 6409 |
/* |
6608 |
/* |
|
Lines 6499-6515
Parser<ParseHandler>::comprehensionFor(GeneratorKind comprehensionKind)
|
Link Here
|
|---|
|
| 6499 |
|
6698 |
|
| 6500 |
TokenPos headPos(begin, pos().end); |
6699 |
TokenPos headPos(begin, pos().end); |
| 6501 |
|
6700 |
|
| 6502 |
StmtInfoPC stmtInfo(context); |
6701 |
StmtInfoPC stmtInfo(context); |
| 6503 |
BindData<ParseHandler> data(context); |
6702 |
BindData<ParseHandler> data(context); |
| 6504 |
RootedStaticBlockObject blockObj(context, StaticBlockObject::create(context)); |
6703 |
RootedStaticBlockObject blockObj(context, StaticBlockObject::create(context)); |
| 6505 |
if (!blockObj) |
6704 |
if (!blockObj) |
| 6506 |
return null(); |
6705 |
return null(); |
| 6507 |
data.initLet(DontHoistVars, *blockObj, JSMSG_TOO_MANY_LOCALS); |
6706 |
data.initLet(DontHoistVars, blockObj, JSMSG_TOO_MANY_LOCALS); |
| 6508 |
Node lhs = newName(name); |
6707 |
Node lhs = newName(name); |
| 6509 |
if (!lhs) |
6708 |
if (!lhs) |
| 6510 |
return null(); |
6709 |
return null(); |
| 6511 |
Node decls = handler.newList(PNK_LET, lhs, JSOP_NOP); |
6710 |
Node decls = handler.newList(PNK_LET, lhs, JSOP_NOP); |
| 6512 |
if (!decls) |
6711 |
if (!decls) |
| 6513 |
return null(); |
6712 |
return null(); |
| 6514 |
data.pn = lhs; |
6713 |
data.pn = lhs; |
| 6515 |
if (!data.binder(&data, name, this)) |
6714 |
if (!data.binder(&data, name, this)) |