📄 jsparse.c
字号:
pn->pn_right = pn2; js_PopStatement(tc); /* Record the absolute line number for source note emission. */ pn->pn_pos.end = pn2->pn_pos.end; return pn;#if JS_HAS_EXCEPTIONS case TOK_TRY: { JSParseNode *catchtail = NULL; /* * try nodes are ternary. * kid1 is the try Statement * kid2 is the catch node * kid3 is the finally Statement * * catch nodes are ternary. * kid1 is the discriminant * kid2 is the next catch node, or NULL * kid3 is the catch block (on kid3 so that we can always append a * new catch pn on catchtail->kid2) * * catch discriminant nodes are binary * atom is the receptacle * expr is the discriminant code * * finally nodes are unary (just the finally expression) */ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_TERNARY, tc); pn->pn_op = JSOP_NOP; MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_TRY); js_PushStatement(tc, &stmtInfo, STMT_TRY, -1); pn->pn_kid1 = Statements(cx, ts, tc); if (!pn->pn_kid1) return NULL; MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_TRY); js_PopStatement(tc); catchtail = pn; while (js_PeekToken(cx, ts) == TOK_CATCH) { /* check for another catch after unconditional catch */ if (catchtail != pn && !catchtail->pn_kid1->pn_expr) { js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_CATCH_AFTER_GENERAL); return NULL; } /* * legal catch forms are: * catch (v) * catch (v if <boolean_expression>) * (the latter is legal only #ifdef JS_HAS_CATCH_GUARD) */ (void) js_GetToken(cx, ts); /* eat `catch' */ pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_TERNARY, tc); if (!pn2) return NULL; /* * We use a PN_NAME for the discriminant (catchguard) node * with the actual discriminant code in the initializer spot */ MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_CATCH); MUST_MATCH_TOKEN(TOK_NAME, JSMSG_CATCH_IDENTIFIER); pn3 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NAME, tc); if (!pn3) return NULL; pn3->pn_atom = CURRENT_TOKEN(ts).t_atom; pn3->pn_expr = NULL;#if JS_HAS_CATCH_GUARD /* * We use `catch (x if x === 5)' (not `catch (x : x === 5)') to * avoid conflicting with the JS2/ECMA2 proposed catchguard syntax. */ if (js_PeekToken(cx, ts) == TOK_IF) { (void)js_GetToken(cx, ts); /* eat `if' */ pn3->pn_expr = Expr(cx, ts, tc); if (!pn3->pn_expr) return NULL; }#endif pn2->pn_kid1 = pn3; MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_CATCH); MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_CATCH); js_PushStatement(tc, &stmtInfo, STMT_CATCH, -1); stmtInfo.label = pn3->pn_atom; pn2->pn_kid3 = Statements(cx, ts, tc); if (!pn2->pn_kid3) return NULL; MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_CATCH); js_PopStatement(tc); catchtail = catchtail->pn_kid2 = pn2; } catchtail->pn_kid2 = NULL; if (js_MatchToken(cx, ts, TOK_FINALLY)) { tc->tryCount++; MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_FINALLY); js_PushStatement(tc, &stmtInfo, STMT_FINALLY, -1); pn->pn_kid3 = Statements(cx, ts, tc); if (!pn->pn_kid3) return NULL; MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_FINALLY); js_PopStatement(tc); } else { pn->pn_kid3 = NULL; } if (!pn->pn_kid2 && !pn->pn_kid3) { js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_CATCH_OR_FINALLY); return NULL; } tc->tryCount++; return pn; } case TOK_THROW: pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY, tc); if (!pn) return NULL; pn2 = Expr(cx, ts, tc); if (!pn2) return NULL; pn->pn_pos.end = pn2->pn_pos.end; pn->pn_op = JSOP_THROW; pn->pn_kid = pn2; break; /* TOK_CATCH and TOK_FINALLY are both handled in the TOK_TRY case */ case TOK_CATCH: js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_CATCH_WITHOUT_TRY); return NULL; case TOK_FINALLY: js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_FINALLY_WITHOUT_TRY); return NULL;#endif /* JS_HAS_EXCEPTIONS */ case TOK_BREAK: pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY, tc); if (!pn) return NULL; if (!MatchLabel(cx, ts, pn)) return NULL; stmt = tc->topStmt; label = pn->pn_atom; if (label) { for (; ; stmt = stmt->down) { if (!stmt) { js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_LABEL_NOT_FOUND); return NULL; } if (stmt->type == STMT_LABEL && stmt->label == label) break; } } else { for (; ; stmt = stmt->down) { if (!stmt) { js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_TOUGH_BREAK); return NULL; } if (STMT_IS_LOOP(stmt) || stmt->type == STMT_SWITCH) break; } } if (label) pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end; break; case TOK_CONTINUE: pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY, tc); if (!pn) return NULL; if (!MatchLabel(cx, ts, pn)) return NULL; stmt = tc->topStmt; label = pn->pn_atom; if (label) { for (stmt2 = NULL; ; stmt = stmt->down) { if (!stmt) { js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_LABEL_NOT_FOUND); return NULL; } if (stmt->type == STMT_LABEL) { if (stmt->label == label) { if (!stmt2 || !STMT_IS_LOOP(stmt2)) { js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_BAD_CONTINUE); return NULL; } break; } } else { stmt2 = stmt; } } } else { for (; ; stmt = stmt->down) { if (!stmt) { js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_BAD_CONTINUE); return NULL; } if (STMT_IS_LOOP(stmt)) break; } } if (label) pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end; break; case TOK_WITH: pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_BINARY, tc); if (!pn) return NULL; MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_WITH); pn2 = Expr(cx, ts, tc); if (!pn2) return NULL; MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_WITH); pn->pn_left = pn2; js_PushStatement(tc, &stmtInfo, STMT_WITH, -1); pn2 = Statement(cx, ts, tc); if (!pn2) return NULL; js_PopStatement(tc); /* Deprecate after parsing, in case of WERROR option. */ if (!js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_WARNING | JSREPORT_STRICT, JSMSG_DEPRECATED_USAGE, js_with_statement_str)) { return NULL; } pn->pn_pos.end = pn2->pn_pos.end; pn->pn_right = pn2; tc->flags |= TCF_FUN_HEAVYWEIGHT; return pn; case TOK_VAR: pn = Variables(cx, ts, tc); if (!pn) return NULL; /* Tell js_EmitTree to generate a final POP. */ pn->pn_extra |= PNX_POPVAR; break; case TOK_RETURN: if (!(tc->flags & TCF_IN_FUNCTION)) { js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_BAD_RETURN); return NULL; } pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY, tc); if (!pn) return NULL; /* This is ugly, but we don't want to require a semicolon. */ ts->flags |= TSF_REGEXP; tt = js_PeekTokenSameLine(cx, ts); ts->flags &= ~TSF_REGEXP; if (tt == TOK_ERROR) return NULL; if (tt != TOK_EOF && tt != TOK_EOL && tt != TOK_SEMI && tt != TOK_RC) { pn2 = Expr(cx, ts, tc); if (!pn2) return NULL; tc->flags |= TCF_RETURN_EXPR; pn->pn_pos.end = pn2->pn_pos.end; pn->pn_kid = pn2; } else { tc->flags |= TCF_RETURN_VOID; pn->pn_kid = NULL; } if (JS_HAS_STRICT_OPTION(cx) && (~tc->flags & (TCF_RETURN_EXPR | TCF_RETURN_VOID)) == 0) { /* * We must be in a frame with a non-native function, because * we're compiling one. */ if (!ReportNoReturnValue(cx, ts)) return NULL; } break; case TOK_LC: js_PushStatement(tc, &stmtInfo, STMT_BLOCK, -1); pn = Statements(cx, ts, tc); if (!pn) return NULL; MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_IN_COMPOUND); js_PopStatement(tc); return pn; case TOK_EOL: case TOK_SEMI: pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY, tc); if (!pn) return NULL; pn->pn_type = TOK_SEMI; pn->pn_kid = NULL; return pn;#if JS_HAS_DEBUGGER_KEYWORD case TOK_DEBUGGER: pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY, tc); if (!pn) return NULL; pn->pn_type = TOK_DEBUGGER; tc->flags |= TCF_FUN_HEAVYWEIGHT; break;#endif /* JS_HAS_DEBUGGER_KEYWORD */ case TOK_ERROR: return NULL; default: js_UngetToken(ts); pn2 = Expr(cx, ts, tc); if (!pn2) return NULL; if (js_PeekToken(cx, ts) == TOK_COLON) { if (pn2->pn_type != TOK_NAME) { js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_BAD_LABEL); return NULL; } label = pn2->pn_atom; for (stmt = tc->topStmt; stmt; stmt = stmt->down) { if (stmt->type == STMT_LABEL && stmt->label == label) { js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_DUPLICATE_LABEL); return NULL; } } (void) js_GetToken(cx, ts); /* Push a label struct and parse the statement. */ js_PushStatement(tc, &stmtInfo, STMT_LABEL, -1); stmtInfo.label = label; pn = Statement(cx, ts, tc); if (!pn) return NULL; /* Pop the label, set pn_expr, and return early. */ js_PopStatement(tc); pn2->pn_type = TOK_COLON; pn2->pn_pos.end = pn->pn_pos.end; pn2->pn_expr = pn; return pn2; } pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_UNARY, tc); if (!pn) return NULL; pn->pn_type = TOK_SEMI; pn->pn_pos = pn2->pn_pos; pn->pn_kid = pn2; break; } /* Check termination of this primitive statement. */ if (ON_CURRENT_LINE(ts, pn->pn_pos)) { tt = js_PeekTokenSameLine(cx, ts); if (tt == TOK_ERROR) return NULL; if (tt != TOK_EOF && tt != TOK_EOL && tt != TOK_SEMI && tt != TOK_RC) { js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_SEMI_BEFORE_STMNT); return NULL; } } (v
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -