📄 jsparse.c
字号:
switch (pn->pn_op) { case JSOP_GETPROP: pn->pn_op = JSOP_IMPORTPROP; break; case JSOP_GETELEM: pn->pn_op = JSOP_IMPORTELEM; break; case JSOP_IMPORTALL: break; default: goto bad_import; } return pn; bad_import: js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_BAD_IMPORT); return NULL;}#endif /* JS_HAS_EXPORT_IMPORT */extern const char js_with_statement_str[];static JSParseNode *Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc){ JSTokenType tt; JSParseNode *pn, *pn1, *pn2, *pn3, *pn4; JSStmtInfo stmtInfo, *stmt, *stmt2; JSAtom *label; CHECK_RECURSION(); ts->flags |= TSF_REGEXP; tt = js_GetToken(cx, ts); ts->flags &= ~TSF_REGEXP;#if JS_HAS_GETTER_SETTER if (tt == TOK_NAME) { tt = CheckGetterOrSetter(cx, ts, TOK_FUNCTION); if (tt == TOK_ERROR) return NULL; }#endif switch (tt) {#if JS_HAS_EXPORT_IMPORT case TOK_EXPORT: pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST, tc); if (!pn) return NULL; PN_INIT_LIST(pn); if (js_MatchToken(cx, ts, TOK_STAR)) { pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY, tc); if (!pn2) return NULL; PN_APPEND(pn, pn2); } else { do { MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_EXPORT_NAME); pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NAME, tc); if (!pn2) return NULL; pn2->pn_op = JSOP_NAME; pn2->pn_atom = CURRENT_TOKEN(ts).t_atom; pn2->pn_expr = NULL; pn2->pn_slot = -1; pn2->pn_attrs = 0; PN_APPEND(pn, pn2); } while (js_MatchToken(cx, ts, TOK_COMMA)); } pn->pn_pos.end = PN_LAST(pn)->pn_pos.end; tc->flags |= TCF_FUN_HEAVYWEIGHT; break; case TOK_IMPORT: pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST, tc); if (!pn) return NULL; PN_INIT_LIST(pn); do { pn2 = ImportExpr(cx, ts, tc); if (!pn2) return NULL; PN_APPEND(pn, pn2); } while (js_MatchToken(cx, ts, TOK_COMMA)); pn->pn_pos.end = PN_LAST(pn)->pn_pos.end; tc->flags |= TCF_FUN_HEAVYWEIGHT; break;#endif /* JS_HAS_EXPORT_IMPORT */ case TOK_FUNCTION: return FunctionStmt(cx, ts, tc); case TOK_IF: /* An IF node has three kids: condition, then, and optional else. */ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_TERNARY, tc); if (!pn) return NULL; pn1 = Condition(cx, ts, tc); if (!pn1) return NULL; js_PushStatement(tc, &stmtInfo, STMT_IF, -1); pn2 = Statement(cx, ts, tc); if (!pn2) return NULL; if (js_MatchToken(cx, ts, TOK_ELSE)) { stmtInfo.type = STMT_ELSE; pn3 = Statement(cx, ts, tc); if (!pn3) return NULL; pn->pn_pos.end = pn3->pn_pos.end; } else { pn3 = NULL; pn->pn_pos.end = pn2->pn_pos.end; } js_PopStatement(tc); pn->pn_kid1 = pn1; pn->pn_kid2 = pn2; pn->pn_kid3 = pn3; return pn;#if JS_HAS_SWITCH_STATEMENT case TOK_SWITCH: { JSParseNode *pn5; JSBool seenDefault = JS_FALSE; pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY, tc); if (!pn) return NULL; MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_SWITCH); /* pn1 points to the switch's discriminant. */ pn1 = Expr(cx, ts, tc); if (!pn1) return NULL; MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_SWITCH); MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_SWITCH); /* pn2 is a list of case nodes. The default case has pn_left == NULL */ pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST, tc); if (!pn2) return NULL; PN_INIT_LIST(pn2); js_PushStatement(tc, &stmtInfo, STMT_SWITCH, -1); while ((tt = js_GetToken(cx, ts)) != TOK_RC) { switch (tt) { case TOK_DEFAULT: if (seenDefault) { js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_TOO_MANY_DEFAULTS); return NULL; } seenDefault = JS_TRUE; /* fall through */ case TOK_CASE: pn3 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY, tc); if (!pn3) return NULL; if (tt == TOK_DEFAULT) { pn3->pn_left = NULL; } else { pn3->pn_left = Expr(cx, ts, tc); if (!pn3->pn_left) return NULL; } PN_APPEND(pn2, pn3); if (pn2->pn_count == JS_BIT(16)) { js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_TOO_MANY_CASES); return NULL; } break; case TOK_ERROR: return NULL; default: js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_BAD_SWITCH); return NULL; } MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_AFTER_CASE); pn4 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_LIST, tc); if (!pn4) return NULL; pn4->pn_type = TOK_LC; PN_INIT_LIST(pn4); while ((tt = js_PeekToken(cx, ts)) != TOK_RC && tt != TOK_CASE && tt != TOK_DEFAULT) { if (tt == TOK_ERROR) return NULL; pn5 = Statement(cx, ts, tc); if (!pn5) return NULL; pn4->pn_pos.end = pn5->pn_pos.end; PN_APPEND(pn4, pn5); } /* Fix the PN_LIST so it doesn't begin at the TOK_COLON. */ if (pn4->pn_head) pn4->pn_pos.begin = pn4->pn_head->pn_pos.begin; pn3->pn_pos.end = pn4->pn_pos.end; pn3->pn_right = pn4; } js_PopStatement(tc); pn->pn_pos.end = pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end; pn->pn_kid1 = pn1; pn->pn_kid2 = pn2; return pn; }#endif /* JS_HAS_SWITCH_STATEMENT */ case TOK_WHILE: pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY, tc); if (!pn) return NULL; js_PushStatement(tc, &stmtInfo, STMT_WHILE_LOOP, -1); pn2 = Condition(cx, ts, tc); if (!pn2) return NULL; pn->pn_left = pn2; pn2 = Statement(cx, ts, tc); if (!pn2) return NULL; js_PopStatement(tc); pn->pn_pos.end = pn2->pn_pos.end; pn->pn_right = pn2; return pn;#if JS_HAS_DO_WHILE_LOOP case TOK_DO: pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY, tc); if (!pn) return NULL; js_PushStatement(tc, &stmtInfo, STMT_DO_LOOP, -1); pn2 = Statement(cx, ts, tc); if (!pn2) return NULL; pn->pn_left = pn2; MUST_MATCH_TOKEN(TOK_WHILE, JSMSG_WHILE_AFTER_DO); pn2 = Condition(cx, ts, tc); if (!pn2) return NULL; js_PopStatement(tc); pn->pn_pos.end = pn2->pn_pos.end; pn->pn_right = pn2; if (cx->version != JSVERSION_ECMA_3) { /* * All legacy and extended versions must do automatic semicolon * insertion after do-while. See the testcase and discussion in * http://bugzilla.mozilla.org/show_bug.cgi?id=238945. */ (void) js_MatchToken(cx, ts, TOK_SEMI); return pn; } break;#endif /* JS_HAS_DO_WHILE_LOOP */ case TOK_FOR: /* A FOR node is binary, left is loop control and right is the body. */ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY, tc); if (!pn) return NULL; js_PushStatement(tc, &stmtInfo, STMT_FOR_LOOP, -1); MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR); ts->flags |= TSF_REGEXP; tt = js_PeekToken(cx, ts); ts->flags &= ~TSF_REGEXP; if (tt == TOK_SEMI) { /* No initializer -- set first kid of left sub-node to null. */ pn1 = NULL; } else { /* Set pn1 to a var list or an initializing expression. */#if JS_HAS_IN_OPERATOR /* * Set the TCF_IN_FOR_INIT flag during parsing of the first clause * of the for statement. This flag will be used by the RelExpr * production; if it is set, then the 'in' keyword will not be * recognized as an operator, leaving it available to be parsed as * part of a for/in loop. A side effect of this restriction is * that (unparenthesized) expressions involving an 'in' operator * are illegal in the init clause of an ordinary for loop. */ tc->flags |= TCF_IN_FOR_INIT;#endif /* JS_HAS_IN_OPERATOR */ if (tt == TOK_VAR) { (void) js_GetToken(cx, ts); pn1 = Variables(cx, ts, tc); } else { pn1 = Expr(cx, ts, tc); }#if JS_HAS_IN_OPERATOR tc->flags &= ~TCF_IN_FOR_INIT;#endif /* JS_HAS_IN_OPERATOR */ if (!pn1) return NULL; } /* * We can be sure that it's a for/in loop if there's still an 'in' * keyword here, even if JavaScript recognizes 'in' as an operator, * as we've excluded 'in' from being parsed in RelExpr by setting * the TCF_IN_FOR_INIT flag in our JSTreeContext. */ if (pn1 && js_MatchToken(cx, ts, TOK_IN)) { stmtInfo.type = STMT_FOR_IN_LOOP; /* Check that the left side of the 'in' is valid. */ if ((pn1->pn_type == TOK_VAR) ? (pn1->pn_count > 1 || pn1->pn_op == JSOP_DEFCONST) : (pn1->pn_type != TOK_NAME && pn1->pn_type != TOK_DOT && pn1->pn_type != TOK_LB)) { js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_BAD_FOR_LEFTSIDE); return NULL; } if (pn1->pn_type == TOK_VAR) { /* Tell js_EmitTree(TOK_VAR) that pn1 is part of a for/in. */ pn1->pn_extra |= PNX_FORINVAR; /* Generate a final POP only if the var has an initializer. */ pn2 = pn1->pn_head; if (pn2->pn_expr) pn1->pn_extra |= PNX_POPVAR; } else { pn2 = pn1; } /* Beware 'for (arguments in ...)' with or without a 'var'. */ if (pn2->pn_type == TOK_NAME && pn2->pn_atom == cx->runtime->atomState.argumentsAtom) { tc->flags |= TCF_FUN_HEAVYWEIGHT; } /* Parse the object expression as the right operand of 'in'. */ pn2 = NewBinary(cx, TOK_IN, JSOP_NOP, pn1, Expr(cx, ts, tc), tc); if (!pn2) return NULL; pn->pn_left = pn2; } else { /* Parse the loop condition or null into pn2. */ MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_INIT); ts->flags |= TSF_REGEXP; tt = js_PeekToken(cx, ts); ts->flags &= ~TSF_REGEXP; if (tt == TOK_SEMI) { pn2 = NULL; } else { pn2 = Expr(cx, ts, tc); if (!pn2) return NULL; } /* Parse the update expression or null into pn3. */ MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_COND); ts->flags |= TSF_REGEXP; tt = js_PeekToken(cx, ts); ts->flags &= ~TSF_REGEXP; if (tt == TOK_RP) { pn3 = NULL; } else { pn3 = Expr(cx, ts, tc); if (!pn3) return NULL; } /* Build the RESERVED node to use as the left kid of pn. */ pn4 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_TERNARY, tc); if (!pn4) return NULL; pn4->pn_type = TOK_RESERVED; pn4->pn_op = JSOP_NOP; pn4->pn_kid1 = pn1; pn4->pn_kid2 = pn2; pn4->pn_kid3 = pn3; pn->pn_left = pn4; } MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FOR_CTRL); /* Parse the loop body into pn->pn_right. */ pn2 = Statement(cx, ts, tc); if (!pn2) return NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -