in src/core/xfa/formcalc_parser.js [277:469]
parse(tok) {
tok ||= this.lexer.next();
while (true) {
// Token ids (see form_lexer.js) are consecutive in order
// to have switch table with no holes.
switch (tok.id) {
case TOKEN.and:
if (this.last === OPERAND) {
this.pushOperator(Operators.and);
break;
}
return [tok, this.getNode()];
case TOKEN.divide:
if (this.last === OPERAND) {
this.pushOperator(Operators.div);
break;
}
return [tok, this.getNode()];
case TOKEN.dot:
if (this.last === OPERAND) {
this.pushOperator(Operators.dot);
break;
}
return [tok, this.getNode()];
case TOKEN.dotDot:
if (this.last === OPERAND) {
this.pushOperator(Operators.dotDot);
break;
}
return [tok, this.getNode()];
case TOKEN.dotHash:
if (this.last === OPERAND) {
this.pushOperator(Operators.dotHash);
break;
}
return [tok, this.getNode()];
case TOKEN.dotStar:
if (this.last === OPERAND) {
this.pushOperator(Operators.dot);
this.pushOperand(new AstEveryOccurence());
break;
}
return [tok, this.getNode()];
case TOKEN.eq:
if (this.last === OPERAND) {
this.pushOperator(Operators.eq);
break;
}
return [tok, this.getNode()];
case TOKEN.ge:
if (this.last === OPERAND) {
this.pushOperator(Operators.ge);
break;
}
return [tok, this.getNode()];
case TOKEN.gt:
if (this.last === OPERAND) {
this.pushOperator(Operators.gt);
break;
}
return [tok, this.getNode()];
case TOKEN.le:
if (this.last === OPERAND) {
this.pushOperator(Operators.le);
break;
}
return [tok, this.getNode()];
case TOKEN.leftBracket:
if (this.last === OPERAND) {
this.flushWithOperator(Operators.subscript);
const operand = this.operands.pop();
const index = SimpleExprParser.parseIndex(this.lexer);
this.operands.push(new AstSubscript(operand, index));
this.last = OPERAND;
break;
}
return [tok, this.getNode()];
case TOKEN.leftParen:
if (this.last === OPERAND) {
const lastOperand = this.operands.at(-1);
if (!(lastOperand instanceof AstIdentifier)) {
return [tok, this.getNode()];
}
lastOperand.toLowerCase();
const name = lastOperand.id;
this.flushWithOperator(Operators.call);
const callee = this.operands.pop();
const params = SimpleExprParser.parseParams(this.lexer);
if (callee instanceof AstIdentifier && BUILTINS.has(name)) {
this.operands.push(new AstBuiltinCall(name, params));
} else {
this.operands.push(new AstCall(callee, params));
}
this.last = OPERAND;
} else {
this.operators.push(Operators.paren);
this.last = OPERATOR;
}
break;
case TOKEN.lt:
if (this.last === OPERAND) {
this.pushOperator(Operators.lt);
break;
}
return [tok, this.getNode()];
case TOKEN.minus:
if (this.last === OPERATOR) {
this.pushOperator(Operators.minus);
} else {
this.pushOperator(Operators.sub);
}
break;
case TOKEN.ne:
if (this.last === OPERAND) {
this.pushOperator(Operators.ne);
break;
}
return [tok, this.getNode()];
case TOKEN.not:
if (this.last === OPERAND) {
this.pushOperator(Operators.not);
break;
}
return [tok, this.getNode()];
case TOKEN.null:
if (this.last === OPERATOR) {
this.pushOperand(new AstNull());
break;
}
return [tok, this.getNode()];
case TOKEN.number:
if (this.last === OPERATOR) {
this.pushOperand(new AstNumber(tok.value));
break;
}
return [tok, this.getNode()];
case TOKEN.or:
if (this.last === OPERAND) {
this.pushOperator(Operators.or);
break;
}
return [tok, this.getNode()];
case TOKEN.plus:
if (this.last === OPERATOR) {
this.pushOperator(Operators.plus);
} else {
this.pushOperator(Operators.add);
}
break;
case TOKEN.rightBracket:
if (!this.flushUntil(Operators.subscript.id)) {
return [tok, this.getNode()];
}
break;
case TOKEN.rightParen:
if (!this.flushUntil(Operators.paren.id)) {
return [tok, this.getNode()];
}
break;
case TOKEN.string:
if (this.last === OPERATOR) {
this.pushOperand(new AstString(tok.value));
break;
}
return [tok, this.getNode()];
case TOKEN.this:
if (this.last === OPERATOR) {
this.pushOperand(new AstThis());
break;
}
return [tok, this.getNode()];
case TOKEN.times:
if (this.last === OPERAND) {
this.pushOperator(Operators.mul);
break;
}
return [tok, this.getNode()];
case TOKEN.identifier:
if (this.last === OPERATOR) {
this.pushOperand(new AstIdentifier(tok.value));
break;
}
return [tok, this.getNode()];
default:
return [tok, this.getNode()];
}
tok = this.lexer.next();
}
}