|
|
|
|
| 36 |
#include "jslock.h" |
36 |
#include "jslock.h" |
| 37 |
#include "jsnum.h" |
37 |
#include "jsnum.h" |
| 38 |
#include "jsobj.h" |
38 |
#include "jsobj.h" |
| 39 |
#include "jsopcode.h" |
39 |
#include "jsopcode.h" |
| 40 |
#include "jsscope.h" |
40 |
#include "jsscope.h" |
| 41 |
#include "jsscript.h" |
41 |
#include "jsscript.h" |
| 42 |
#include "jsstr.h" |
42 |
#include "jsstr.h" |
| 43 |
|
43 |
|
|
|
44 |
#include "builtin/Module.h" |
| 44 |
#include "frontend/FoldConstants.h" |
45 |
#include "frontend/FoldConstants.h" |
| 45 |
#include "frontend/ParseMaps.h" |
46 |
#include "frontend/ParseMaps.h" |
| 46 |
#include "frontend/Parser.h" |
47 |
#include "frontend/Parser.h" |
| 47 |
#include "frontend/TokenStream.h" |
48 |
#include "frontend/TokenStream.h" |
| 48 |
#include "gc/Marking.h" |
49 |
#include "gc/Marking.h" |
| 49 |
|
50 |
|
| 50 |
#if JS_HAS_XML_SUPPORT |
51 |
#if JS_HAS_XML_SUPPORT |
| 51 |
#include "jsxml.h" |
52 |
#include "jsxml.h" |
|
Lines 164-181
ParseContext::define(JSContext *cx, Prop
|
Link Here
|
|---|
|
| 164 |
if (name == cx->names().empty) |
165 |
if (name == cx->names().empty) |
| 165 |
break; |
166 |
break; |
| 166 |
if (!decls_.addUnique(name, dn)) |
167 |
if (!decls_.addUnique(name, dn)) |
| 167 |
return false; |
168 |
return false; |
| 168 |
break; |
169 |
break; |
| 169 |
|
170 |
|
| 170 |
case Definition::CONST: |
171 |
case Definition::CONST: |
| 171 |
case Definition::VAR: |
172 |
case Definition::VAR: |
| 172 |
if (sc->isFunctionBox()) { |
173 |
if (sc->isModuleBox() || sc->isFunctionBox()) { |
| 173 |
dn->setOp(JSOP_GETLOCAL); |
174 |
dn->setOp(JSOP_GETLOCAL); |
|
|
175 |
/* Modules don't have local variables */ |
| 176 |
if (sc->isModuleBox()) |
| 177 |
dn->pn_dflags |= PND_CLOSED; |
| 174 |
dn->pn_dflags |= PND_BOUND; |
178 |
dn->pn_dflags |= PND_BOUND; |
| 175 |
if (!dn->pn_cookie.set(cx, staticLevel, vars_.length())) |
179 |
if (!dn->pn_cookie.set(cx, staticLevel, vars_.length())) |
| 176 |
return false; |
180 |
return false; |
| 177 |
if (!vars_.append(dn)) |
181 |
if (!vars_.append(dn)) |
| 178 |
return false; |
182 |
return false; |
| 179 |
} |
183 |
} |
| 180 |
if (!decls_.addUnique(name, dn)) |
184 |
if (!decls_.addUnique(name, dn)) |
| 181 |
return false; |
185 |
return false; |
|
Lines 278-296
AppendPackedBindings(const ParseContext
|
Link Here
|
|---|
|
| 278 |
(pc->sc->bindingsAccessedDynamically() && |
282 |
(pc->sc->bindingsAccessedDynamically() && |
| 279 |
pc->decls().lookupFirst(name) == dn); |
283 |
pc->decls().lookupFirst(name) == dn); |
| 280 |
|
284 |
|
| 281 |
*dst = Binding(name, kind, aliased); |
285 |
*dst = Binding(name, kind, aliased); |
| 282 |
} |
286 |
} |
| 283 |
} |
287 |
} |
| 284 |
|
288 |
|
| 285 |
bool |
289 |
bool |
| 286 |
ParseContext::generateFunctionBindings(JSContext *cx, InternalHandle<Bindings*> bindings) const |
290 |
ParseContext::generateBindings(JSContext *cx, InternalHandle<Bindings*> bindings) const |
| 287 |
{ |
291 |
{ |
| 288 |
JS_ASSERT(sc->isFunctionBox()); |
292 |
JS_ASSERT(sc->isModuleBox() || sc->isFunctionBox()); |
|
|
293 |
JS_ASSERT_IF(sc->isModuleBox(), args_.length() == 0); |
| 289 |
|
294 |
|
| 290 |
unsigned count = args_.length() + vars_.length(); |
295 |
unsigned count = args_.length() + vars_.length(); |
| 291 |
Binding *packedBindings = cx->tempLifoAlloc().newArrayUninitialized<Binding>(count); |
296 |
Binding *packedBindings = cx->tempLifoAlloc().newArrayUninitialized<Binding>(count); |
| 292 |
if (!packedBindings) { |
297 |
if (!packedBindings) { |
| 293 |
js_ReportOutOfMemory(cx); |
298 |
js_ReportOutOfMemory(cx); |
| 294 |
return false; |
299 |
return false; |
| 295 |
} |
300 |
} |
| 296 |
|
301 |
|
|
Lines 298-316
ParseContext::generateFunctionBindings(J
|
Link Here
|
|---|
|
| 298 |
AppendPackedBindings(this, vars_, packedBindings + args_.length()); |
303 |
AppendPackedBindings(this, vars_, packedBindings + args_.length()); |
| 299 |
|
304 |
|
| 300 |
if (!Bindings::initWithTemporaryStorage(cx, bindings, args_.length(), vars_.length(), |
305 |
if (!Bindings::initWithTemporaryStorage(cx, bindings, args_.length(), vars_.length(), |
| 301 |
packedBindings)) |
306 |
packedBindings)) |
| 302 |
{ |
307 |
{ |
| 303 |
return false; |
308 |
return false; |
| 304 |
} |
309 |
} |
| 305 |
|
310 |
|
| 306 |
FunctionBox *funbox = sc->asFunctionBox(); |
311 |
if (sc->isFunctionBox()) { |
| 307 |
if (bindings->hasAnyAliasedBindings() || funbox->hasExtensibleScope()) |
312 |
FunctionBox *funbox = sc->asFunctionBox(); |
| 308 |
funbox->function()->setIsHeavyweight(); |
313 |
if (bindings->hasAnyAliasedBindings() || funbox->hasExtensibleScope()) |
|
|
314 |
funbox->function()->setIsHeavyweight(); |
| 315 |
} |
| 309 |
|
316 |
|
| 310 |
return true; |
317 |
return true; |
| 311 |
} |
318 |
} |
| 312 |
|
319 |
|
| 313 |
Parser::Parser(JSContext *cx, const CompileOptions &options, |
320 |
Parser::Parser(JSContext *cx, const CompileOptions &options, |
| 314 |
StableCharPtr chars, size_t length, bool foldConstants) |
321 |
StableCharPtr chars, size_t length, bool foldConstants) |
| 315 |
: AutoGCRooter(cx, PARSER), |
322 |
: AutoGCRooter(cx, PARSER), |
| 316 |
context(cx), |
323 |
context(cx), |
|
Lines 758-774
Parser::standaloneFunctionBody(HandleFun
|
Link Here
|
|---|
|
| 758 |
reportError(NULL, JSMSG_SYNTAX_ERROR); |
765 |
reportError(NULL, JSMSG_SYNTAX_ERROR); |
| 759 |
return NULL; |
766 |
return NULL; |
| 760 |
} |
767 |
} |
| 761 |
|
768 |
|
| 762 |
if (!FoldConstants(context, pn, this)) |
769 |
if (!FoldConstants(context, pn, this)) |
| 763 |
return NULL; |
770 |
return NULL; |
| 764 |
|
771 |
|
| 765 |
InternalHandle<Bindings*> bindings(script, &script->bindings); |
772 |
InternalHandle<Bindings*> bindings(script, &script->bindings); |
| 766 |
if (!funpc.generateFunctionBindings(context, bindings)) |
773 |
if (!funpc.generateBindings(context, bindings)) |
| 767 |
return NULL; |
774 |
return NULL; |
| 768 |
|
775 |
|
| 769 |
return pn; |
776 |
return pn; |
| 770 |
} |
777 |
} |
| 771 |
|
778 |
|
| 772 |
ParseNode * |
779 |
ParseNode * |
| 773 |
Parser::functionBody(FunctionBodyType type) |
780 |
Parser::functionBody(FunctionBodyType type) |
| 774 |
{ |
781 |
{ |
|
Lines 1162-1236
DeoptimizeUsesWithin(Definition *dn, con
|
Link Here
|
|---|
|
| 1162 |
|
1169 |
|
| 1163 |
/* |
1170 |
/* |
| 1164 |
* Beware: this function is called for functions nested in other functions or |
1171 |
* Beware: this function is called for functions nested in other functions or |
| 1165 |
* global scripts but not for functions compiled through the Function |
1172 |
* global scripts but not for functions compiled through the Function |
| 1166 |
* constructor or JSAPI. To always execute code when a function has finished |
1173 |
* constructor or JSAPI. To always execute code when a function has finished |
| 1167 |
* parsing, use Parser::functionBody. |
1174 |
* parsing, use Parser::functionBody. |
| 1168 |
*/ |
1175 |
*/ |
| 1169 |
static bool |
1176 |
static bool |
| 1170 |
LeaveFunction(ParseNode *fn, Parser *parser, PropertyName *funName = NULL, |
1177 |
LeaveContext(ParseNode *pn, Parser *parser, PropertyName *funName = NULL, |
| 1171 |
FunctionSyntaxKind kind = Expression) |
1178 |
FunctionSyntaxKind kind = Expression) |
| 1172 |
{ |
1179 |
{ |
| 1173 |
JSContext *cx = parser->context; |
1180 |
JSContext *cx = parser->context; |
| 1174 |
ParseContext *funpc = parser->pc; |
1181 |
ParseContext *pc = parser->pc; |
| 1175 |
ParseContext *pc = funpc->parent; |
1182 |
ParseContext *outerpc = pc->parent; |
| 1176 |
pc->blockidGen = funpc->blockidGen; |
1183 |
outerpc->blockidGen = pc->blockidGen; |
| 1177 |
|
1184 |
|
| 1178 |
FunctionBox *funbox = fn->pn_funbox; |
1185 |
if (!outerpc->topStmt || outerpc->topStmt->type == STMT_BLOCK) |
| 1179 |
JS_ASSERT(funbox == funpc->sc->asFunctionBox()); |
1186 |
pn->pn_dflags |= PND_BLOCKCHILD; |
| 1180 |
|
|
|
| 1181 |
if (!pc->topStmt || pc->topStmt->type == STMT_BLOCK) |
| 1182 |
fn->pn_dflags |= PND_BLOCKCHILD; |
| 1183 |
|
1187 |
|
| 1184 |
/* Propagate unresolved lexical names up to pc->lexdeps. */ |
1188 |
/* Propagate unresolved lexical names up to pc->lexdeps. */ |
| 1185 |
if (funpc->lexdeps->count()) { |
1189 |
if (pc->lexdeps->count()) { |
| 1186 |
for (AtomDefnRange r = funpc->lexdeps->all(); !r.empty(); r.popFront()) { |
1190 |
for (AtomDefnRange r = pc->lexdeps->all(); !r.empty(); r.popFront()) { |
| 1187 |
JSAtom *atom = r.front().key(); |
1191 |
JSAtom *atom = r.front().key(); |
| 1188 |
Definition *dn = r.front().value(); |
1192 |
Definition *dn = r.front().value(); |
| 1189 |
JS_ASSERT(dn->isPlaceholder()); |
1193 |
JS_ASSERT(dn->isPlaceholder()); |
| 1190 |
|
1194 |
|
| 1191 |
if (atom == funName && kind == Expression) { |
1195 |
if (pc->sc->isFunctionBox()) { |
| 1192 |
dn->setOp(JSOP_CALLEE); |
1196 |
if (atom == funName && kind == Expression) { |
| 1193 |
if (!dn->pn_cookie.set(cx, funpc->staticLevel, |
1197 |
dn->setOp(JSOP_CALLEE); |
| 1194 |
UpvarCookie::CALLEE_SLOT)) |
1198 |
if (!dn->pn_cookie.set(cx, pc->staticLevel, |
| 1195 |
return false; |
1199 |
UpvarCookie::CALLEE_SLOT)) |
| 1196 |
dn->pn_dflags |= PND_BOUND; |
1200 |
return false; |
| 1197 |
JS_ASSERT(dn->kind() == Definition::NAMED_LAMBDA); |
1201 |
dn->pn_dflags |= PND_BOUND; |
| 1198 |
|
1202 |
JS_ASSERT(dn->kind() == Definition::NAMED_LAMBDA); |
| 1199 |
/* |
1203 |
|
| 1200 |
* Since 'dn' is a placeholder, it has not been defined in the |
1204 |
/* |
| 1201 |
* ParseContext and hence we must manually flag a closed-over |
1205 |
* Since 'dn' is a placeholder, it has not been defined in the |
| 1202 |
* callee name as needing a dynamic scope (this is done for all |
1206 |
* ParseContext and hence we must manually flag a closed-over |
| 1203 |
* definitions in the ParseContext by generateFunctionBindings). |
1207 |
* callee name as needing a dynamic scope (this is done for all |
| 1204 |
* |
1208 |
* definitions in the ParseContext by generateBindings). |
| 1205 |
* If 'dn' has been assigned to, then we also flag the function |
1209 |
* |
| 1206 |
* scope has needing a dynamic scope so that dynamic scope |
1210 |
* If 'dn' has been assigned to, then we also flag the function |
| 1207 |
* setter can either ignore the set (in non-strict mode) or |
1211 |
* scope has needing a dynamic scope so that dynamic scope |
| 1208 |
* produce an error (in strict mode). |
1212 |
* setter can either ignore the set (in non-strict mode) or |
| 1209 |
*/ |
1213 |
* produce an error (in strict mode). |
| 1210 |
if (dn->isClosed() || dn->isAssigned()) |
1214 |
*/ |
| 1211 |
funbox->function()->setIsHeavyweight(); |
1215 |
if (dn->isClosed() || dn->isAssigned()) |
| 1212 |
continue; |
1216 |
pc->sc->asFunctionBox()->function()->setIsHeavyweight(); |
|
|
1217 |
continue; |
| 1218 |
} |
| 1213 |
} |
1219 |
} |
| 1214 |
|
1220 |
|
| 1215 |
Definition *outer_dn = pc->decls().lookupFirst(atom); |
1221 |
Definition *outerdn = outerpc->decls().lookupFirst(atom); |
| 1216 |
|
1222 |
|
| 1217 |
/* |
1223 |
/* |
| 1218 |
* Make sure to deoptimize lexical dependencies that are polluted |
1224 |
* Make sure to deoptimize lexical dependencies that are polluted |
| 1219 |
* by eval and function statements (which both flag the function as |
1225 |
* by eval and function statements (which both flag the function as |
| 1220 |
* having an extensible scope) or any enclosing 'with'. |
1226 |
* having an extensible scope) or any enclosing 'with'. |
| 1221 |
*/ |
1227 |
*/ |
| 1222 |
if (funbox->hasExtensibleScope() || pc->parsingWith) |
1228 |
if ((pc->sc->isFunctionBox() && pc->sc->asFunctionBox()->hasExtensibleScope()) || |
| 1223 |
DeoptimizeUsesWithin(dn, fn->pn_pos); |
1229 |
outerpc->parsingWith) |
| 1224 |
|
1230 |
DeoptimizeUsesWithin(dn, pn->pn_pos); |
| 1225 |
if (!outer_dn) { |
1231 |
|
| 1226 |
AtomDefnAddPtr p = pc->lexdeps->lookupForAdd(atom); |
1232 |
if (!outerdn) { |
|
|
1233 |
AtomDefnAddPtr p = outerpc->lexdeps->lookupForAdd(atom); |
| 1227 |
if (p) { |
1234 |
if (p) { |
| 1228 |
outer_dn = p.value(); |
1235 |
outerdn = p.value(); |
| 1229 |
} else { |
1236 |
} else { |
| 1230 |
/* |
1237 |
/* |
| 1231 |
* Create a new placeholder for our outer lexdep. We could |
1238 |
* Create a new placeholder for our outer lexdep. We could |
| 1232 |
* simply re-use the inner placeholder, but that introduces |
1239 |
* simply re-use the inner placeholder, but that introduces |
| 1233 |
* subtleties in the case where we find a later definition |
1240 |
* subtleties in the case where we find a later definition |
| 1234 |
* that captures an existing lexdep. For example: |
1241 |
* that captures an existing lexdep. For example: |
| 1235 |
* |
1242 |
* |
| 1236 |
* function f() { function g() { x; } let x; } |
1243 |
* function f() { function g() { x; } let x; } |
|
Lines 1243-1304
LeaveFunction(ParseNode *fn, Parser *par
|
Link Here
|
|---|
|
| 1243 |
* function f() { x; { function g() { x; } let x; } } |
1250 |
* function f() { x; { function g() { x; } let x; } } |
| 1244 |
* |
1251 |
* |
| 1245 |
* Here, the 'let' must not capture all the uses of f's |
1252 |
* Here, the 'let' must not capture all the uses of f's |
| 1246 |
* lexdep entry for x, but it must capture the x node |
1253 |
* lexdep entry for x, but it must capture the x node |
| 1247 |
* referred to from g's TOK_UPVARS node. Always turning |
1254 |
* referred to from g's TOK_UPVARS node. Always turning |
| 1248 |
* inherited lexdeps into uses of a new outer definition |
1255 |
* inherited lexdeps into uses of a new outer definition |
| 1249 |
* allows us to handle both these cases in a natural way. |
1256 |
* allows us to handle both these cases in a natural way. |
| 1250 |
*/ |
1257 |
*/ |
| 1251 |
outer_dn = MakePlaceholder(dn, parser, pc); |
1258 |
outerdn = MakePlaceholder(dn, parser, outerpc); |
| 1252 |
if (!outer_dn || !pc->lexdeps->add(p, atom, outer_dn)) |
1259 |
if (!outerdn || !outerpc->lexdeps->add(p, atom, outerdn)) |
| 1253 |
return false; |
1260 |
return false; |
| 1254 |
} |
1261 |
} |
| 1255 |
} |
1262 |
} |
| 1256 |
|
1263 |
|
| 1257 |
/* |
1264 |
/* |
| 1258 |
* Insert dn's uses list at the front of outer_dn's list. |
1265 |
* Insert dn's uses list at the front of outerdn's list. |
| 1259 |
* |
1266 |
* |
| 1260 |
* Without loss of generality or correctness, we allow a dn to |
1267 |
* Without loss of generality or correctness, we allow a dn to |
| 1261 |
* be in inner and outer lexdeps, since the purpose of lexdeps |
1268 |
* be in inner and outer lexdeps, since the purpose of lexdeps |
| 1262 |
* is one-pass coordination of name use and definition across |
1269 |
* is one-pass coordination of name use and definition across |
| 1263 |
* functions, and if different dn's are used we'll merge lists |
1270 |
* functions, and if different dn's are used we'll merge lists |
| 1264 |
* when leaving the inner function. |
1271 |
* when leaving the inner function. |
| 1265 |
* |
1272 |
* |
| 1266 |
* The dn == outer_dn case arises with generator expressions |
1273 |
* The dn == outerdn case arises with generator expressions |
| 1267 |
* (see CompExprTransplanter::transplant, the PN_FUNC/PN_NAME |
1274 |
* (see CompExprTransplanter::transplant, the PN_FUNC/PN_NAME |
| 1268 |
* case), and nowhere else, currently. |
1275 |
* case), and nowhere else, currently. |
| 1269 |
*/ |
1276 |
*/ |
| 1270 |
if (dn != outer_dn) { |
1277 |
if (dn != outerdn) { |
| 1271 |
if (ParseNode *pnu = dn->dn_uses) { |
1278 |
if (ParseNode *pnu = dn->dn_uses) { |
| 1272 |
while (true) { |
1279 |
while (true) { |
| 1273 |
pnu->pn_lexdef = outer_dn; |
1280 |
pnu->pn_lexdef = outerdn; |
| 1274 |
if (!pnu->pn_link) |
1281 |
if (!pnu->pn_link) |
| 1275 |
break; |
1282 |
break; |
| 1276 |
pnu = pnu->pn_link; |
1283 |
pnu = pnu->pn_link; |
| 1277 |
} |
1284 |
} |
| 1278 |
pnu->pn_link = outer_dn->dn_uses; |
1285 |
pnu->pn_link = outerdn->dn_uses; |
| 1279 |
outer_dn->dn_uses = dn->dn_uses; |
1286 |
outerdn->dn_uses = dn->dn_uses; |
| 1280 |
dn->dn_uses = NULL; |
1287 |
dn->dn_uses = NULL; |
| 1281 |
} |
1288 |
} |
| 1282 |
|
1289 |
|
| 1283 |
outer_dn->pn_dflags |= dn->pn_dflags & ~PND_PLACEHOLDER; |
1290 |
outerdn->pn_dflags |= dn->pn_dflags & ~PND_PLACEHOLDER; |
| 1284 |
} |
1291 |
} |
| 1285 |
|
1292 |
|
| 1286 |
/* Mark the outer dn as escaping. */ |
1293 |
/* Mark the outer dn as escaping. */ |
| 1287 |
outer_dn->pn_dflags |= PND_CLOSED; |
1294 |
outerdn->pn_dflags |= PND_CLOSED; |
| 1288 |
} |
1295 |
} |
| 1289 |
} |
1296 |
} |
| 1290 |
|
1297 |
|
| 1291 |
InternalHandle<Bindings*> bindings = |
1298 |
InternalHandle<Bindings*> bindings = pc->sc->isModuleBox() |
| 1292 |
InternalHandle<Bindings*>::fromMarkedLocation(&funbox->bindings); |
1299 |
? InternalHandle<Bindings*>::fromMarkedLocation(&pc->sc->asModuleBox()->bindings) |
| 1293 |
if (!funpc->generateFunctionBindings(cx, bindings)) |
1300 |
: InternalHandle<Bindings*>::fromMarkedLocation(&pc->sc->asFunctionBox()->bindings); |
|
|
1301 |
if (!pc->generateBindings(cx, bindings)) |
| 1294 |
return false; |
1302 |
return false; |
| 1295 |
|
1303 |
|
| 1296 |
funpc->lexdeps.releaseMap(cx); |
1304 |
pc->lexdeps.releaseMap(cx); |
| 1297 |
return true; |
1305 |
return true; |
| 1298 |
} |
1306 |
} |
| 1299 |
|
1307 |
|
| 1300 |
/* |
1308 |
/* |
| 1301 |
* DefineArg is called for both the arguments of a regular function definition |
1309 |
* DefineArg is called for both the arguments of a regular function definition |
| 1302 |
* and the arguments specified by the Function constructor. |
1310 |
* and the arguments specified by the Function constructor. |
| 1303 |
* |
1311 |
* |
| 1304 |
* The 'disallowDuplicateArgs' bool indicates whether the use of another |
1312 |
* The 'disallowDuplicateArgs' bool indicates whether the use of another |
|
Lines 1611-1628
Parser::functionDef(HandlePropertyName f
|
Link Here
|
|---|
|
| 1611 |
* As a SpiderMonkey-specific extension, non-body-level function |
1619 |
* As a SpiderMonkey-specific extension, non-body-level function |
| 1612 |
* statements (e.g., functions in an "if" or "while" block) are |
1620 |
* statements (e.g., functions in an "if" or "while" block) are |
| 1613 |
* dynamically bound when control flow reaches the statement. The |
1621 |
* dynamically bound when control flow reaches the statement. The |
| 1614 |
* emitter normally emits functions in two passes (see PNK_ARGSBODY). |
1622 |
* emitter normally emits functions in two passes (see PNK_ARGSBODY). |
| 1615 |
* To distinguish |
1623 |
* To distinguish |
| 1616 |
*/ |
1624 |
*/ |
| 1617 |
if (bodyLevel) { |
1625 |
if (bodyLevel) { |
| 1618 |
JS_ASSERT(pn->functionIsHoisted()); |
1626 |
JS_ASSERT(pn->functionIsHoisted()); |
| 1619 |
JS_ASSERT_IF(pc->sc->isFunctionBox(), !pn->pn_cookie.isFree()); |
1627 |
JS_ASSERT_IF(pc->sc->isGlobalSharedContext(), pn->pn_cookie.isFree()); |
| 1620 |
JS_ASSERT_IF(!pc->sc->isFunctionBox(), pn->pn_cookie.isFree()); |
1628 |
JS_ASSERT_IF(pc->sc->isModuleBox() || pc->sc->isFunctionBox(), !pn->pn_cookie.isFree()); |
| 1621 |
} else { |
1629 |
} else { |
| 1622 |
JS_ASSERT(!pc->sc->strict); |
1630 |
JS_ASSERT(!pc->sc->strict); |
| 1623 |
JS_ASSERT(pn->pn_cookie.isFree()); |
1631 |
JS_ASSERT(pn->pn_cookie.isFree()); |
| 1624 |
if (pc->sc->isFunctionBox()) { |
1632 |
if (pc->sc->isFunctionBox()) { |
| 1625 |
FunctionBox *funbox = pc->sc->asFunctionBox(); |
1633 |
FunctionBox *funbox = pc->sc->asFunctionBox(); |
| 1626 |
funbox->setMightAliasLocals(); |
1634 |
funbox->setMightAliasLocals(); |
| 1627 |
funbox->setHasExtensibleScope(); |
1635 |
funbox->setHasExtensibleScope(); |
| 1628 |
} |
1636 |
} |
|
Lines 1814-1836
Parser::functionArgsAndBody(ParseNode *p
|
Link Here
|
|---|
|
| 1814 |
outerpc->sc->setBindingsAccessedDynamically(); |
1822 |
outerpc->sc->setBindingsAccessedDynamically(); |
| 1815 |
|
1823 |
|
| 1816 |
|
1824 |
|
| 1817 |
pn->pn_funbox = funbox; |
1825 |
pn->pn_funbox = funbox; |
| 1818 |
pn->pn_body->append(body); |
1826 |
pn->pn_body->append(body); |
| 1819 |
pn->pn_body->pn_pos = body->pn_pos; |
1827 |
pn->pn_body->pn_pos = body->pn_pos; |
| 1820 |
pn->pn_blockid = outerpc->blockid(); |
1828 |
pn->pn_blockid = outerpc->blockid(); |
| 1821 |
|
1829 |
|
| 1822 |
if (!LeaveFunction(pn, this, funName, kind)) |
1830 |
if (!LeaveContext(pn, this, funName, kind)) |
| 1823 |
return false; |
1831 |
return false; |
| 1824 |
|
1832 |
|
| 1825 |
return true; |
1833 |
return true; |
| 1826 |
} |
1834 |
} |
| 1827 |
|
1835 |
|
| 1828 |
ParseNode * |
1836 |
ParseNode * |
|
|
1837 |
Parser::moduleStmt() |
| 1838 |
{ |
| 1839 |
JS_ASSERT(versionNumber() == JSVERSION_ECMA_5); |
| 1840 |
JS_ASSERT(tokenStream.currentToken().name() == context->names().module); |
| 1841 |
JS_ALWAYS_TRUE(tokenStream.matchToken(TOK_NAME)); |
| 1842 |
|
| 1843 |
if (pc->sc->isFunctionBox() || !pc->atBodyLevel()) { |
| 1844 |
reportError(NULL, JSMSG_MODULE_STATEMENT); |
| 1845 |
return NULL; |
| 1846 |
} |
| 1847 |
RootedPropertyName name(context, tokenStream.currentToken().name()); |
| 1848 |
ParseNode *pn = NameNode::create(PNK_MODULE, name, this, pc); |
| 1849 |
if (!pn) |
| 1850 |
return NULL; |
| 1851 |
if (Definition *dn = pc->lexdeps.lookupDefn(name)) { |
| 1852 |
JS_ASSERT(dn->isDefn()); |
| 1853 |
dn->setKind(PNK_MODULE); |
| 1854 |
dn->setArity(PN_NAME); |
| 1855 |
dn->pn_pos.begin = pn->pn_pos.begin; |
| 1856 |
dn->pn_pos.end = pn->pn_pos.end; |
| 1857 |
|
| 1858 |
dn->pn_body = NULL; |
| 1859 |
dn->pn_cookie.makeFree(); |
| 1860 |
|
| 1861 |
pc->lexdeps->remove(name); |
| 1862 |
freeTree(pn); |
| 1863 |
pn = dn; |
| 1864 |
} |
| 1865 |
if (!pc->define(context, name, pn, Definition::VAR)) |
| 1866 |
return NULL; |
| 1867 |
|
| 1868 |
Module *module = js_NewModule(context, name); |
| 1869 |
if (!module) |
| 1870 |
return NULL; |
| 1871 |
ModuleBox *modulebox = context->tempLifoAlloc().new_<ModuleBox>(context, pc, module, traceListHead); |
| 1872 |
if (!modulebox) { |
| 1873 |
js_ReportOutOfMemory(context); |
| 1874 |
return NULL; |
| 1875 |
} |
| 1876 |
pn->pn_modulebox = modulebox; |
| 1877 |
|
| 1878 |
ParseContext modulepc(this, modulebox, pc->staticLevel + 1, pc->blockidGen); |
| 1879 |
if (!modulepc.init()) |
| 1880 |
return NULL; |
| 1881 |
|
| 1882 |
MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_MODULE); |
| 1883 |
modulebox->bufStart = tokenStream.offsetOfToken(tokenStream.currentToken()); |
| 1884 |
pn->pn_body = statements(); |
| 1885 |
MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_MODULE); |
| 1886 |
pn->pn_modulebox->bufEnd = tokenStream.offsetOfToken(tokenStream.currentToken()) + 1; |
| 1887 |
|
| 1888 |
if (!LeaveContext(pn, this)) |
| 1889 |
return NULL; |
| 1890 |
return pn; |
| 1891 |
} |
| 1892 |
|
| 1893 |
ParseNode * |
| 1829 |
Parser::functionStmt() |
1894 |
Parser::functionStmt() |
| 1830 |
{ |
1895 |
{ |
| 1831 |
JS_ASSERT(tokenStream.currentToken().type == TOK_FUNCTION); |
1896 |
JS_ASSERT(tokenStream.currentToken().type == TOK_FUNCTION); |
| 1832 |
RootedPropertyName name(context); |
1897 |
RootedPropertyName name(context); |
| 1833 |
if (tokenStream.getToken(TSF_KEYWORD_IS_NAME) == TOK_NAME) { |
1898 |
if (tokenStream.getToken(TSF_KEYWORD_IS_NAME) == TOK_NAME) { |
| 1834 |
name = tokenStream.currentToken().name(); |
1899 |
name = tokenStream.currentToken().name(); |
| 1835 |
} else { |
1900 |
} else { |
| 1836 |
/* Unnamed function expressions are forbidden in statement context. */ |
1901 |
/* Unnamed function expressions are forbidden in statement context. */ |
|
Lines 1967-1983
Parser::statements(bool *hasFunctionStmt
|
Link Here
|
|---|
|
| 1967 |
return NULL; |
2032 |
return NULL; |
| 1968 |
} |
2033 |
} |
| 1969 |
|
2034 |
|
| 1970 |
if (canHaveDirectives) { |
2035 |
if (canHaveDirectives) { |
| 1971 |
if (!maybeParseDirective(next, &canHaveDirectives)) |
2036 |
if (!maybeParseDirective(next, &canHaveDirectives)) |
| 1972 |
return NULL; |
2037 |
return NULL; |
| 1973 |
} |
2038 |
} |
| 1974 |
|
2039 |
|
| 1975 |
if (next->isKind(PNK_FUNCTION)) { |
2040 |
if (next->isKind(PNK_MODULE)) { |
|
|
2041 |
JS_ASSERT(pc->atBodyLevel()); |
| 2042 |
pn->pn_xflags |= PNX_MODULEDEFS; |
| 2043 |
} else if (next->isKind(PNK_FUNCTION)) { |
| 1976 |
/* |
2044 |
/* |
| 1977 |
* PNX_FUNCDEFS notifies the emitter that the block contains body- |
2045 |
* PNX_FUNCDEFS notifies the emitter that the block contains body- |
| 1978 |
* level function definitions that should be processed before the |
2046 |
* level function definitions that should be processed before the |
| 1979 |
* rest of nodes. |
2047 |
* rest of nodes. |
| 1980 |
* |
2048 |
* |
| 1981 |
* |hasFunctionStmt| is for the TOK_LC case in Statement. It |
2049 |
* |hasFunctionStmt| is for the TOK_LC case in Statement. It |
| 1982 |
* is relevant only for function definitions not at body-level, |
2050 |
* is relevant only for function definitions not at body-level, |
| 1983 |
* which we call function statements. |
2051 |
* which we call function statements. |
|
Lines 3690-3705
Parser::letStatement()
|
Link Here
|
|---|
|
| 3690 |
} while (0); |
3758 |
} while (0); |
| 3691 |
|
3759 |
|
| 3692 |
/* Check termination of this primitive statement. */ |
3760 |
/* Check termination of this primitive statement. */ |
| 3693 |
return MatchOrInsertSemicolon(context, &tokenStream) ? pn : NULL; |
3761 |
return MatchOrInsertSemicolon(context, &tokenStream) ? pn : NULL; |
| 3694 |
} |
3762 |
} |
| 3695 |
#endif |
3763 |
#endif |
| 3696 |
|
3764 |
|
| 3697 |
ParseNode * |
3765 |
ParseNode * |
|
|
3766 |
Parser::exportStatement() |
| 3767 |
{ |
| 3768 |
if (!pc->sc->isModuleBox()) { |
| 3769 |
reportError(NULL, JSMSG_EXPORT_STATEMENT); |
| 3770 |
return NULL; |
| 3771 |
} |
| 3772 |
ParseNode *pn = UnaryNode::create(PNK_EXPORT, this); |
| 3773 |
if (!pn) |
| 3774 |
return NULL; |
| 3775 |
StmtInfoPC stmtInfo(context); |
| 3776 |
PushStatementPC(pc, &stmtInfo, STMT_EXPORT); |
| 3777 |
pn->pn_kid = statement(); |
| 3778 |
PopStatementPC(context, pc); |
| 3779 |
if (!pn->pn_kid) |
| 3780 |
return NULL; |
| 3781 |
return pn; |
| 3782 |
} |
| 3783 |
|
| 3784 |
ParseNode * |
| 3698 |
Parser::expressionStatement() |
3785 |
Parser::expressionStatement() |
| 3699 |
{ |
3786 |
{ |
| 3700 |
tokenStream.ungetToken(); |
3787 |
tokenStream.ungetToken(); |
| 3701 |
ParseNode *pn2 = expr(); |
3788 |
ParseNode *pn2 = expr(); |
| 3702 |
if (!pn2) |
3789 |
if (!pn2) |
| 3703 |
return NULL; |
3790 |
return NULL; |
| 3704 |
|
3791 |
|
| 3705 |
if (tokenStream.peekToken() == TOK_COLON) { |
3792 |
if (tokenStream.peekToken() == TOK_COLON) { |
|
Lines 4000-4015
Parser::statement()
|
Link Here
|
|---|
|
| 4000 |
pn->pn_xflags |= PNX_POPVAR; |
4087 |
pn->pn_xflags |= PNX_POPVAR; |
| 4001 |
break; |
4088 |
break; |
| 4002 |
|
4089 |
|
| 4003 |
#if JS_HAS_BLOCK_SCOPE |
4090 |
#if JS_HAS_BLOCK_SCOPE |
| 4004 |
case TOK_LET: |
4091 |
case TOK_LET: |
| 4005 |
return letStatement(); |
4092 |
return letStatement(); |
| 4006 |
#endif /* JS_HAS_BLOCK_SCOPE */ |
4093 |
#endif /* JS_HAS_BLOCK_SCOPE */ |
| 4007 |
|
4094 |
|
|
|
4095 |
case TOK_EXPORT: |
| 4096 |
return exportStatement(); |
| 4097 |
|
| 4008 |
case TOK_RETURN: |
4098 |
case TOK_RETURN: |
| 4009 |
pn = returnOrYield(false); |
4099 |
pn = returnOrYield(false); |
| 4010 |
if (!pn) |
4100 |
if (!pn) |
| 4011 |
return NULL; |
4101 |
return NULL; |
| 4012 |
break; |
4102 |
break; |
| 4013 |
|
4103 |
|
| 4014 |
case TOK_LC: |
4104 |
case TOK_LC: |
| 4015 |
{ |
4105 |
{ |
|
Lines 4078-4093
Parser::statement()
|
Link Here
|
|---|
|
| 4078 |
pn->pn_kid = pn2; |
4168 |
pn->pn_kid = pn2; |
| 4079 |
break; |
4169 |
break; |
| 4080 |
} |
4170 |
} |
| 4081 |
#endif |
4171 |
#endif |
| 4082 |
|
4172 |
|
| 4083 |
case TOK_ERROR: |
4173 |
case TOK_ERROR: |
| 4084 |
return NULL; |
4174 |
return NULL; |
| 4085 |
|
4175 |
|
|
|
4176 |
case TOK_NAME: |
| 4177 |
if (versionNumber() == JSVERSION_ECMA_5 && |
| 4178 |
tokenStream.currentToken().name() == context->names().module && |
| 4179 |
tokenStream.peekTokenSameLine(TSF_OPERAND) == TOK_NAME) |
| 4180 |
{ |
| 4181 |
return moduleStmt(); |
| 4182 |
} |
| 4183 |
|
| 4086 |
default: |
4184 |
default: |
| 4087 |
return expressionStatement(); |
4185 |
return expressionStatement(); |
| 4088 |
} |
4186 |
} |
| 4089 |
|
4187 |
|
| 4090 |
/* Check termination of this primitive statement. */ |
4188 |
/* Check termination of this primitive statement. */ |
| 4091 |
return MatchOrInsertSemicolon(context, &tokenStream) ? pn : NULL; |
4189 |
return MatchOrInsertSemicolon(context, &tokenStream) ? pn : NULL; |
| 4092 |
} |
4190 |
} |
| 4093 |
|
4191 |
|
|
Lines 5388-5404
Parser::generatorExpr(ParseNode *kid)
|
Link Here
|
|---|
|
| 5388 |
|
5486 |
|
| 5389 |
if (AtomDefnPtr p = genpc.lexdeps->lookup(context->names().arguments)) { |
5487 |
if (AtomDefnPtr p = genpc.lexdeps->lookup(context->names().arguments)) { |
| 5390 |
Definition *dn = p.value(); |
5488 |
Definition *dn = p.value(); |
| 5391 |
ParseNode *errorNode = dn->dn_uses ? dn->dn_uses : body; |
5489 |
ParseNode *errorNode = dn->dn_uses ? dn->dn_uses : body; |
| 5392 |
reportError(errorNode, JSMSG_BAD_GENEXP_BODY, js_arguments_str); |
5490 |
reportError(errorNode, JSMSG_BAD_GENEXP_BODY, js_arguments_str); |
| 5393 |
return NULL; |
5491 |
return NULL; |
| 5394 |
} |
5492 |
} |
| 5395 |
|
5493 |
|
| 5396 |
if (!LeaveFunction(genfn, this)) |
5494 |
if (!LeaveContext(genfn, this)) |
| 5397 |
return NULL; |
5495 |
return NULL; |
| 5398 |
} |
5496 |
} |
| 5399 |
|
5497 |
|
| 5400 |
/* |
5498 |
/* |
| 5401 |
* Our result is a call expression that invokes the anonymous generator |
5499 |
* Our result is a call expression that invokes the anonymous generator |
| 5402 |
* function object. |
5500 |
* function object. |
| 5403 |
*/ |
5501 |
*/ |
| 5404 |
ParseNode *result = ListNode::create(PNK_CALL, this); |
5502 |
ParseNode *result = ListNode::create(PNK_CALL, this); |