parseParenExpression
可以看到, 除了前后的要求()外, 整体调用了parseExpression进行解析
/**
* 解析表达式语句, 类似while (aaa > bbb)的括号部分
* @returns {Node}
*/
pp.parseParenExpression = function() {
this.expect(tt.parenL)
let val = this.parseExpression()
this.expect(tt.parenR)
return val
}
parseExpression
- 调用
parseMaybeAssign解析出expr - 如果往下读到了
,, 则此时循环使用parseMaybeAssign读出并且完成为SequenceExpression - 如果没有读到
,, 则此时直接返回为expr
/**
* 解析单条表达式, 主要是赋值表达式.
* @param {string | boolean} forInit let/const/var
* @param {*} refDestructuringErrors
* @returns
*/
pp.parseExpression = function(forInit, refDestructuringErrors) {
let startPos = this.start, startLoc = this.startLoc
// let a = b;
let expr = this.parseMaybeAssign(forInit, refDestructuringErrors)
if (this.type === tt.comma) {
// let a,b,c = xxx;
let node = this.startNodeAt(startPos, startLoc)
node.expressions = [expr]
while (this.eat(tt.comma)) node.expressions.push(this.parseMaybeAssign(forInit, refDestructuringErrors))
return this.finishNode(node, "SequenceExpression")
}
return expr
}
parseMaybeAssign
- 判断是否在yield上下文中, 如果是则调用
parseYield返回 - 调用
parseMaybeConditional解读出左式. - 然后判断this.type是否assign(如
a = b), 如果是 - 将node.operator设置为this.value, 然后调用
toAssignable设置转化left的类型, 将node.left设置为left, 然后继续调用parseMaybeAssign解析并设置为right. - 如果不是, 则直接检查错误, 并返回
/**
* 解析 a = b; a += b; xxx -= xxxx;
* 同时兼容三元表达式a?b:c
* 解析时, 表达式支持逻辑运算符等
* @param {string | boolean} forInit
* @param {*} refDestructuringErrors
* @param {Function} afterLeftParse
* @returns
*/
pp.parseMaybeAssign = function(forInit, refDestructuringErrors, afterLeftParse) {
if (this.isContextual("yield")) {
if (this.inGenerator) return this.parseYield(forInit)
// The tokenizer will assume an expression is allowed after
// `yield`, but this isn't that kind of yield
else this.exprAllowed = false
}
let ownDestructuringErrors = false, oldParenAssign = -1, oldTrailingComma = -1, oldDoubleProto = -1
if (refDestructuringErrors) {
oldParenAssign = refDestructuringErrors.parenthesizedAssign
oldTrailingComma = refDestructuringErrors.trailingComma
oldDoubleProto = refDestructuringErrors.doubleProto
refDestructuringErrors.parenthesizedAssign = refDestructuringErrors.trailingComma = -1
} else {
refDestructuringErrors = new DestructuringErrors
ownDestructuringErrors = true
}
let startPos = this.start, startLoc = this.startLoc
if (this.type === tt.parenL || this.type === tt.name) {
this.potentialArrowAt = this.start
this.potentialArrowInForAwait = forInit === "await"
}
let left = this.parseMaybeConditional(forInit, refDestructuringErrors)
if (afterLeftParse) left = afterLeftParse.call(this, left, startPos, startLoc)
if (this.type.isAssign) {
let node = this.startNodeAt(startPos, startLoc)
node.operator = this.value
if (this.type === tt.eq)
left = this.toAssignable(left, false, refDestructuringErrors)
if (!ownDestructuringErrors) {
refDestructuringErrors.parenthesizedAssign = refDestructuringErrors.trailingComma = refDestructuringErrors.doubleProto = -1
}
if (refDestructuringErrors.shorthandAssign >= left.start)
refDestructuringErrors.shorthandAssign = -1 // reset because shorthand default was used correctly
if (this.type === tt.eq)
this.checkLValPattern(left)
else
this.checkLValSimple(left)
node.left = left
this.next()
node.right = this.parseMaybeAssign(forInit)
if (oldDoubleProto > -1) refDestructuringErrors.doubleProto = oldDoubleProto
return this.finishNode(node, NodeTypes.AssignmentExpression)
} else {
if (ownDestructuringErrors) this.checkExpressionErrors(refDestructuringErrors, true)
}
if (oldParenAssign > -1) refDestructuringErrors.parenthesizedAssign = oldParenAssign
if (oldTrailingComma > -1) refDestructuringErrors.trailingComma = oldTrailingComma
return left
}
parseYield
简单的调用parseMaybeAssign进行解析, 它需要单独处理的原因是语法上可以有yield *这种可迭代对象
参考yield*
/**
* parseMaybeAssign中调用
* @param {*} forInit
* @returns
*/
pp.parseYield = function(forInit) {
if (!this.yieldPos) this.yieldPos = this.start
let node = this.startNode()
this.next()
if (this.type === tt.semi || this.canInsertSemicolon() || (this.type !== tt.star && !this.type.startsExpr)) {
node.delegate = false
node.argument = null
} else {
node.delegate = this.eat(tt.star)
node.argument = this.parseMaybeAssign(forInit)
}
return this.finishNode(node, "YieldExpression")
}