📄 jsparse.c
字号:
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;
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;
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);
tt = js_PeekToken(cx, ts);
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) to generate a final POP. */
pn1->pn_extra = JS_TRUE;
pn2 = pn1->pn_head;
} 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);
if (js_PeekToken(cx, ts) == 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);
if (js_PeekToken(cx, ts) == 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;
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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -