📄 jsparse.c
字号:
} } } fun = js_NewFunction(cx, NULL, NULL, 0, lambda ? JSFUN_LAMBDA : 0, varobj, funAtom); if (!fun) return NULL;#if JS_HAS_GETTER_SETTER if (op != JSOP_NOP) fun->flags |= (op == JSOP_GETTER) ? JSPROP_GETTER : JSPROP_SETTER;#endif /* * Atomize fun->object early to protect against a last-ditch GC under * js_LookupHiddenProperty. * * Absent use of the new scoped local GC roots API around compiler calls, * we need to atomize here to protect against a GC activation. Atoms are * protected from GC during compilation by the JS_FRIEND_API entry points * in this file. There doesn't seem to be any gain in switching from the * atom-keeping method to the bulkier, slower scoped local roots method. */ objAtom = js_AtomizeObject(cx, fun->object, 0); if (!objAtom) return NULL; /* Initialize early for possible flags mutation via DestructuringExpr. */ TREE_CONTEXT_INIT(&funtc); /* Now parse formal argument list and compute fun->nargs. */ MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_FORMAL); if (!js_MatchToken(cx, ts, TOK_RP)) { BindData data; data.pn = NULL; data.ts = ts; data.obj = fun->object; data.op = JSOP_NOP; data.binder = BindArg; data.u.arg.fun = fun; do { tt = js_GetToken(cx, ts); switch (tt) {#if JS_HAS_DESTRUCTURING case TOK_LB: case TOK_LC: { JSParseNode *lhs, *rhs; jsint slot; /* * A destructuring formal parameter turns into one or more * local variables initialized from properties of a single * anonymous positional parameter, so here we must tweak our * binder and its data. */ data.op = JSOP_DEFVAR; data.binder = BindDestructuringArg; data.u.var.clasp = &js_FunctionClass; data.u.var.getter = js_GetLocalVariable; data.u.var.setter = js_SetLocalVariable; data.u.var.attrs = JSPROP_PERMANENT; /* * Temporarily transfer the owneship of the recycle list to * funtc. See bug 313967. */ funtc.nodeList = tc->nodeList; tc->nodeList = NULL; lhs = DestructuringExpr(cx, &data, &funtc, tt); tc->nodeList = funtc.nodeList; funtc.nodeList = NULL; if (!lhs) return NULL; /* * Restore the formal parameter binder in case there are more * non-destructuring formals in the parameter list. */ data.binder = BindArg; /* * Adjust fun->nargs to count the single anonymous positional * parameter that is to be destructured. */ slot = fun->nargs; if (!BumpFormalCount(cx, fun)) return NULL; /* * Synthesize a destructuring assignment from the single * anonymous positional parameter into the destructuring * left-hand-side expression and accumulate it in list. */ rhs = NewParseNode(cx, ts, PN_NAME, tc); if (!rhs) return NULL; rhs->pn_type = TOK_NAME; rhs->pn_op = JSOP_GETARG; rhs->pn_atom = cx->runtime->atomState.emptyAtom; rhs->pn_expr = NULL; rhs->pn_slot = slot; rhs->pn_attrs = 0; item = NewBinary(cx, TOK_ASSIGN, JSOP_NOP, lhs, rhs, tc); if (!item) return NULL; if (!list) { list = NewParseNode(cx, ts, PN_LIST, tc); if (!list) return NULL; list->pn_type = TOK_COMMA; PN_INIT_LIST(list); } PN_APPEND(list, item); break; }#endif /* JS_HAS_DESTRUCTURING */ case TOK_NAME: if (!data.binder(cx, &data, CURRENT_TOKEN(ts).t_atom, tc)) return NULL; break; default: js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR, JSMSG_MISSING_FORMAL); return NULL; } } while (js_MatchToken(cx, ts, TOK_COMMA)); MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FORMAL); } MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_BODY); pn->pn_pos.begin = CURRENT_TOKEN(ts).pos.begin; /* * Temporarily transfer the owneship of the recycle list to funtc. * See bug 313967. */ funtc.nodeList = tc->nodeList; tc->nodeList = NULL; body = FunctionBody(cx, ts, fun, &funtc); tc->nodeList = funtc.nodeList; funtc.nodeList = NULL; if (!body) return NULL; MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_BODY); pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end;#if JS_HAS_DESTRUCTURING /* * If there were destructuring formal parameters, prepend the initializing * comma expression that we synthesized to body. If the body is a lexical * scope node, we must make a special TOK_BODY node, to prepend the formal * parameter destructuring code without bracing the decompilation of the * function body's lexical scope. */ if (list) { if (body->pn_arity != PN_LIST) { JSParseNode *block; JS_ASSERT(body->pn_type == TOK_LEXICALSCOPE); JS_ASSERT(body->pn_arity == PN_NAME); block = NewParseNode(cx, ts, PN_LIST, tc); if (!block) return NULL; block->pn_type = TOK_BODY; block->pn_pos = body->pn_pos; PN_INIT_LIST_1(block, body); body = block; } item = NewParseNode(cx, ts, PN_UNARY, tc); if (!item) return NULL; item->pn_type = TOK_SEMI; item->pn_pos.begin = item->pn_pos.end = body->pn_pos.begin; item->pn_kid = list; item->pn_next = body->pn_head; body->pn_head = item; if (body->pn_tail == &body->pn_head) body->pn_tail = &item->pn_next; ++body->pn_count; }#endif /* * If we collected flags that indicate nested heavyweight functions, or * this function contains heavyweight-making statements (references to * __parent__ or __proto__; use of with, eval, import, or export; and * assignment to arguments), flag the function as heavyweight (requiring * a call object per invocation). */ if (funtc.flags & TCF_FUN_HEAVYWEIGHT) { fun->flags |= JSFUN_HEAVYWEIGHT; tc->flags |= TCF_FUN_HEAVYWEIGHT; } else { /* * If this function is a named statement function not at top-level * (i.e. a JSOP_CLOSURE, not a function definiton or expression), then * our enclosing function, if any, must be heavyweight. * * The TCF_FUN_USES_NONLOCALS flag is set only by the code generator, * so it won't be set here. Assert that it's not. We have to check * it later, in js_EmitTree, after js_EmitFunctionBody has traversed * the function's body */ JS_ASSERT(!(funtc.flags & TCF_FUN_USES_NONLOCALS)); if (!lambda && funAtom && !AT_TOP_LEVEL(tc)) tc->flags |= TCF_FUN_HEAVYWEIGHT; } result = pn; if (lambda) { /* * ECMA ed. 3 standard: function expression, possibly anonymous. */ op = funAtom ? JSOP_NAMEDFUNOBJ : JSOP_ANONFUNOBJ; } else if (!funAtom) { /* * If this anonymous function definition is *not* embedded within a * larger expression, we treat it as an expression statement, not as * a function declaration -- and not as a syntax error (as ECMA-262 * Edition 3 would have it). Backward compatibility trumps all. */ result = NewParseNode(cx, ts, PN_UNARY, tc); if (!result) return NULL; result->pn_type = TOK_SEMI; result->pn_pos = pn->pn_pos; result->pn_kid = pn; op = JSOP_ANONFUNOBJ; } else if (!AT_TOP_LEVEL(tc)) { /* * ECMA ed. 3 extension: a function expression statement not at the * top level, e.g., in a compound statement such as the "then" part * of an "if" statement, binds a closure only if control reaches that * sub-statement. */ op = JSOP_CLOSURE; } else { op = JSOP_NOP; } pn->pn_funAtom = objAtom; pn->pn_op = op; pn->pn_body = body; pn->pn_flags = funtc.flags & (TCF_FUN_FLAGS | TCF_HAS_DEFXMLNS); pn->pn_tryCount = funtc.tryCount; TREE_CONTEXT_FINISH(&funtc); return result;}static JSParseNode *FunctionStmt(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc){ return FunctionDef(cx, ts, tc, JS_FALSE);}static JSParseNode *FunctionExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc){ return FunctionDef(cx, ts, tc, JS_TRUE);}/* * Parse the statements in a block, creating a TOK_LC node that lists the * statements' trees. If called from block-parsing code, the caller must * match { before and } after. */static JSParseNode *Statements(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc){ JSParseNode *pn, *pn2, *saveBlock; JSTokenType tt; CHECK_RECURSION(); pn = NewParseNode(cx, ts, PN_LIST, tc); if (!pn) return NULL; saveBlock = tc->blockNode; tc->blockNode = pn; PN_INIT_LIST(pn); ts->flags |= TSF_OPERAND; while ((tt = js_PeekToken(cx, ts)) > TOK_EOF && tt != TOK_RC) { ts->flags &= ~TSF_OPERAND; pn2 = Statement(cx, ts, tc); if (!pn2) { if (ts->flags & TSF_EOF) ts->flags |= TSF_UNEXPECTED_EOF; return NULL; } ts->flags |= TSF_OPERAND; /* Detect a function statement for the TOK_LC case in Statement. */ if (pn2->pn_type == TOK_FUNCTION && !AT_TOP_LEVEL(tc)) tc->flags |= TCF_HAS_FUNCTION_STMT; /* If compiling top-level statements, emit as we go to save space. */ if (!tc->topStmt && (tc->flags & TCF_COMPILING)) { if (cx->fp->fun && JS_HAS_STRICT_OPTION(cx) && (tc->flags & TCF_RETURN_EXPR)) { /* * Check pn2 for lack of a final return statement if it is the * last statement in the block. */ tt = js_PeekToken(cx, ts); if ((tt == TOK_EOF || tt == TOK_RC) && !CheckFinalReturn(cx, ts, pn2)) { tt = TOK_ERROR; break; } /* * Clear TCF_RETURN_EXPR so FunctionBody doesn't try to * CheckFinalReturn again. */ tc->flags &= ~TCF_RETURN_EXPR; } if (!js_FoldConstants(cx, pn2, tc) || !js_AllocTryNotes(cx, (JSCodeGenerator *)tc) || !js_EmitTree(cx, (JSCodeGenerator *)tc, pn2)) { tt = TOK_ERROR; break; } RecycleTree(pn2, tc); } else { PN_APPEND(pn, pn2); } } /* * Handle the case where there was a let declaration under this block. If * it replaced tc->blockNode with a new block node then we must refresh pn * and then restore tc->blockNode. */ if (tc->blockNode != pn) pn = tc->blockNode; tc->blockNode = saveBlock; ts->flags &= ~TSF_OPERAND; if (tt == TOK_ERROR) return NULL; pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end; return pn;}static JSParseNode *Condition(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc){ JSParseNode *pn, *pn2; MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_COND); pn = Expr(cx, ts, tc); if (!pn) return NULL; MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_COND); /* * Check for (a = b) and "correct" it to (a == b) iff b's operator has * greater precedence than ==. * XXX not ECMA, but documented in several books -- now a strict warning. */ if (pn->pn_type == TOK_ASSIGN && pn->pn_op == JSOP_NOP && pn->pn_right->pn_type > TOK_EQOP) { JSBool rewrite = !JS_VERSION_IS_ECMA(cx); if (!js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_WARNING | JSREPORT_STRICT, JSMSG_EQUAL_AS_ASSIGN, rewrite
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -