📄 jsparse.c
字号:
OBJ_DROP_PROPERTY(cx, pobj, prop); if (!ok) return NULL; prop = NULL; } if (!js_AddNativeProperty(cx, fun->object, (jsid)argAtom, js_GetArgument, js_SetArgument, SPROP_INVALID_SLOT, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, SPROP_HAS_SHORTID | dupflag, fun->nargs)) { return NULL; } fun->nargs++; } 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; TREE_CONTEXT_INIT(&funtc); body = FunctionBody(cx, ts, fun, &funtc); 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_LEXICAL_CLOSURE /* * 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), or if it refers to unqualified names that * are not local args or vars (TCF_FUN_USES_NONLOCALS), then our * enclosing function, if any, must be heavyweight. */ if ((!lambda && funAtom && tc->topStmt) || (funtc.flags & TCF_FUN_USES_NONLOCALS)) { tc->flags |= TCF_FUN_HEAVYWEIGHT; } }#endif /* * Record names for function statements in tc->decls so we know when to * avoid optimizing variable references that might name a function. */ if (!lambda && funAtom) { ATOM_LIST_SEARCH(ale, &tc->decls, funAtom); if (ale) { prevop = ALE_JSOP(ale); if (JS_HAS_STRICT_OPTION(cx) || prevop == JSOP_DEFCONST) { const char *name = js_AtomToPrintableString(cx, funAtom); if (!name || !js_ReportCompileErrorNumber(cx, ts, NULL, (prevop != JSOP_DEFCONST) ? JSREPORT_WARNING | JSREPORT_STRICT : JSREPORT_ERROR, JSMSG_REDECLARED_VAR, (prevop == JSOP_DEFFUN || prevop == JSOP_CLOSURE) ? js_function_str : (prevop == JSOP_DEFCONST) ? js_const_str : js_var_str, name)) { return NULL; } } if (tc->topStmt && prevop == JSOP_DEFVAR) tc->flags |= TCF_FUN_CLOSURE_VS_VAR; } else { ale = js_IndexAtom(cx, funAtom, &tc->decls); if (!ale) return NULL; } ALE_SET_JSOP(ale, tc->topStmt ? JSOP_CLOSURE : JSOP_DEFFUN);#if JS_HAS_LEXICAL_CLOSURE /* * A function nested at top level inside another's body needs only a * local variable to bind its name to its value, and not an activation * object property (it might also need the activation property, if the * outer function contains with statements, e.g., but the stack slot * wins when jsemit.c's LookupArgOrVar can optimize a JSOP_NAME into a * JSOP_GETVAR bytecode). */ if (!tc->topStmt && (tc->flags & TCF_IN_FUNCTION)) { JSStackFrame *fp; JSObject *varobj; /* * Define a property on the outer function so that LookupArgOrVar * can properly optimize accesses. * * XXX Here and in Variables, we use the function object's scope, * XXX arguably polluting it, when we could use a compiler-private * XXX scope structure. Tradition! */ fp = cx->fp; varobj = fp->varobj; JS_ASSERT(OBJ_GET_CLASS(cx, varobj) == &js_FunctionClass); JS_ASSERT(fp->fun == (JSFunction *) JS_GetPrivate(cx, varobj)); if (!js_LookupProperty(cx, varobj, (jsid)funAtom, &pobj, &prop)) return NULL; if (prop) OBJ_DROP_PROPERTY(cx, pobj, prop); if (!prop || pobj != varobj) { if (!js_DefineNativeProperty(cx, varobj, (jsid)funAtom, OBJECT_TO_JSVAL(fun->object), js_GetLocalVariable, js_SetLocalVariable, JSPROP_ENUMERATE, SPROP_HAS_SHORTID, fp->fun->nvars, NULL)) { return NULL; } fp->fun->nvars++; } }#endif }#if JS_HAS_LEXICAL_CLOSURE if (lambda || !funAtom) { /* * ECMA ed. 3 standard: function expression, possibly anonymous (even * if at top-level, an unnamed function is an expression statement, not * a function declaration). */ op = fun->atom ? JSOP_NAMEDFUNOBJ : JSOP_ANONFUNOBJ; } else if (tc->topStmt) { /* * 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#endif op = JSOP_NOP; /* * Pending a better automatic GC root management scheme (see Mozilla bug * 40757, http://bugzilla.mozilla.org/show_bug.cgi?id=40757), we need to * atomize here to protect against a GC activation. */ pn->pn_funAtom = js_AtomizeObject(cx, fun->object, 0); if (!pn->pn_funAtom) return NULL; pn->pn_op = op; pn->pn_body = body; pn->pn_flags = funtc.flags & TCF_FUN_FLAGS; pn->pn_tryCount = funtc.tryCount; TREE_CONTEXT_FINISH(&funtc); return pn;}static JSParseNode *FunctionStmt(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc){ return FunctionDef(cx, ts, tc, JS_FALSE);}#if JS_HAS_LEXICAL_CLOSUREstatic JSParseNode *FunctionExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc){ return FunctionDef(cx, ts, tc, JS_TRUE);}#endif/* * 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; JSTokenType tt; CHECK_RECURSION(); pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST, tc); if (!pn) return NULL; PN_INIT_LIST(pn); ts->flags |= TSF_REGEXP; while ((tt = js_PeekToken(cx, ts)) > TOK_EOF && tt != TOK_RC) { ts->flags &= ~TSF_REGEXP; pn2 = Statement(cx, ts, tc); if (!pn2) return NULL; ts->flags |= TSF_REGEXP; /* 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); } } ts->flags &= ~TSF_REGEXP; 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 = !JSVERSION_IS_ECMA(cx->version); if (!js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_WARNING | JSREPORT_STRICT, JSMSG_EQUAL_AS_ASSIGN, rewrite ? "\nAssuming equality test" : "")) { return NULL; } if (rewrite) { pn->pn_type = TOK_EQOP; pn->pn_op = (JSOp)cx->jsop_eq; pn2 = pn->pn_left; switch (pn2->pn_op) { case JSOP_SETNAME: pn2->pn_op = JSOP_NAME; break; case JSOP_SETPROP: pn2->pn_op = JSOP_GETPROP; break; case JSOP_SETELEM: pn2->pn_op = JSOP_GETELEM; break; default: JS_ASSERT(0); } } } return pn;}static JSBoolMatchLabel(JSContext *cx, JSTokenStream *ts, JSParseNode *pn){ JSAtom *label;#if JS_HAS_LABEL_STATEMENT JSTokenType tt; tt = js_PeekTokenSameLine(cx, ts); if (tt == TOK_ERROR) return JS_FALSE; if (tt == TOK_NAME) { (void) js_GetToken(cx, ts); label = CURRENT_TOKEN(ts).t_atom; } else { label = NULL; }#else label = NULL;#endif pn->pn_atom = label; return JS_TRUE;}#if JS_HAS_EXPORT_IMPORTstatic JSParseNode *ImportExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc){ JSParseNode *pn, *pn2, *pn3; JSTokenType tt; MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_IMPORT_NAME); pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NAME, tc); if (!pn) return NULL; pn->pn_op = JSOP_NAME; pn->pn_atom = CURRENT_TOKEN(ts).t_atom; pn->pn_expr = NULL; pn->pn_slot = -1; pn->pn_attrs = 0; ts->flags |= TSF_REGEXP; while ((tt = js_GetToken(cx, ts)) == TOK_DOT || tt == TOK_LB) { ts->flags &= ~TSF_REGEXP; if (pn->pn_op == JSOP_IMPORTALL) goto bad_import; if (tt == TOK_DOT) { pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NAME, tc); if (!pn2) return NULL; if (js_MatchToken(cx, ts, TOK_STAR)) { pn2->pn_op = JSOP_IMPORTALL; pn2->pn_atom = NULL; } else { MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NAME_AFTER_DOT); pn2->pn_op = JSOP_GETPROP; pn2->pn_atom = CURRENT_TOKEN(ts).t_atom; pn2->pn_slot = -1; pn2->pn_attrs = 0; } pn2->pn_expr = pn; pn2->pn_pos.begin = pn->pn_pos.begin; pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end; } else { /* Make a TOK_LB node. */ pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY, tc); if (!pn2) return NULL; pn3 = Expr(cx, ts, tc); if (!pn3) return NULL; MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_IN_INDEX); pn2->pn_pos.begin = pn->pn_pos.begin; pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end; pn2->pn_op = JSOP_GETELEM; pn2->pn_left = pn; pn2->pn_right = pn3; } pn = pn2; ts->flags |= TSF_REGEXP; } ts->flags &= ~TSF_REGEXP; if (tt == TOK_ERROR) return NULL; js_UngetToken(ts);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -