com.jfinal.template.expr.ExprParser Maven / Gradle / Ivy
The newest version!
/**
* Copyright (c) 2011-2023, James Zhan 詹波 ([email protected]).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jfinal.template.expr;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import com.jfinal.template.EngineConfig;
import com.jfinal.template.expr.ast.*;
import com.jfinal.template.stat.Location;
import com.jfinal.template.stat.ParaToken;
import com.jfinal.template.stat.ParseException;
/**
* ExprParser
*/
public class ExprParser {
static final Tok EOF = new Tok(Sym.EOF, -1);
Tok peek = null;
int forward = 0;
List tokenList;
Location location;
ParaToken paraToken;
EngineConfig engineConfig;
public ExprParser(ParaToken paraToken, EngineConfig engineConfig, String fileName) {
this.paraToken = paraToken;
this.engineConfig = engineConfig;
this.location = new Location(fileName, paraToken.getRow());
}
void initPeek() {
peek = tokenList.get(forward);
}
Tok peek() {
return peek;
}
Tok move() {
peek = tokenList.get(++forward);
return peek;
}
void resetForward(int position) {
forward = position;
peek = tokenList.get(forward);
}
Tok match(Sym sym) {
Tok current = peek();
if (current.sym == sym) {
move();
return current;
}
throw new ParseException("Expression error: can not match the symbol \"" + sym.value() + "\"", location);
}
public ExprList parseExprList() {
return (ExprList)parse(true);
}
public ForCtrl parseForCtrl() {
Expr forCtrl = parse(false);
// 可能返回 ExprList.NULL_EXPR_LIST,必须做判断
if (forCtrl instanceof ForCtrl) {
return (ForCtrl)forCtrl;
} else {
throw new ParseException("The expression of #for directive is error", location);
}
}
Expr parse(boolean isExprList) {
tokenList = new ExprLexer(paraToken, location).scan();
if (tokenList.size() == 0) {
return ExprList.NULL_EXPR_LIST;
}
tokenList.add(EOF);
initPeek();
Expr expr = isExprList ? exprList() : forCtrl();
if (peek() != EOF) {
throw new ParseException("Expression error: can not match \"" + peek().value() + "\"", location);
}
return expr;
}
/**
* exprList : expr (',' expr)*
*/
ExprList exprList() {
List exprList = new ArrayList();
while (true) {
Expr expr = expr();
if (expr != null) {
exprList.add(expr);
if (peek().sym == Sym.COMMA) {
move();
if (peek() == EOF) {
throw new ParseException("Expression error: can not match the char of comma ','", location);
}
continue ;
}
}
break ;
}
return new ExprList(exprList);
}
Expr expr() {
return assign();
}
/**
* assign : ID ( '[' expr ']' )? '=' expr
*/
Expr assign() {
Tok idTok = peek();
if (idTok.sym != Sym.ID) {
return ternary();
}
int begin = forward;
// ID = expr
if (move().sym == Sym.ASSIGN) {
move();
return new Assign(idTok.value(), expr(), location);
}
// array、map 赋值:ID [ expr ] = expr
if (peek().sym == Sym.LBRACK) {
move();
Expr index = expr();
match(Sym.RBRACK);
if (peek().sym == Sym.ASSIGN) {
move();
return new Assign(idTok.value(), index, expr(), location); // 右结合无限连
}
}
resetForward(begin);
return ternary();
}
/**
* ternary : expr '?' expr ':' expr
*/
Expr ternary() {
Expr cond = or();
if (peek().sym == Sym.QUESTION) {
move();
Expr exprOne = expr();
match(Sym.COLON);
return new Ternary(cond, exprOne, expr(), location);
}
return cond;
}
/**
* or : expr '||' expr
*/
Expr or() {
Expr expr = and();
for (Tok tok=peek(); tok.sym==Sym.OR; tok=peek()) {
move();
expr = new Logic(Sym.OR, expr, and(), location);
}
return expr;
}
/**
* and : expr '&&' expr
*/
Expr and() {
Expr expr = equalNotEqual();
for (Tok tok=peek(); tok.sym==Sym.AND; tok=peek()) {
move();
expr = new Logic(Sym.AND, expr, equalNotEqual(), location);
}
return expr;
}
/**
* equalNotEqual : expr ('==' | '!=') expr
*/
Expr equalNotEqual() {
Expr expr = greaterLess();
for (Tok tok=peek(); tok.sym==Sym.EQUAL || tok.sym==Sym.NOTEQUAL; tok=peek()) {
move();
expr = new Compare(tok.sym, expr, greaterLess(), location);
}
return expr;
}
/**
* compare expr ('<=' | '>=' | '>' | '<') expr
* 不支持无限连: > >= < <=
*/
Expr greaterLess() {
Expr expr = addSub();
Tok tok = peek();
if (tok.sym == Sym.LT || tok.sym == Sym.LE || tok.sym == Sym.GT || tok.sym == Sym.GE) {
move();
return new Compare(tok.sym, expr, addSub(), location);
}
return expr;
}
/**
* addSub : expr ('+'|'-') expr
*/
Expr addSub() {
Expr expr = mulDivMod();
for (Tok tok=peek(); tok.sym==Sym.ADD || tok.sym==Sym.SUB; tok=peek()) {
move();
expr = new Arith(tok.sym, expr, mulDivMod(), location);
}
return expr;
}
/**
* mulDivMod : expr ('*'|'/'|'%') expr
*/
Expr mulDivMod() {
Expr expr = nullSafe();
for (Tok tok=peek(); tok.sym==Sym.MUL || tok.sym==Sym.DIV || tok.sym==Sym.MOD; tok=peek()) {
move();
expr = new Arith(tok.sym, expr, nullSafe(), location);
}
return expr;
}
/**
* nullSafe : expr '??' expr
*/
Expr nullSafe() {
Expr expr = unary();
for (Tok tok=peek(); tok.sym==Sym.NULL_SAFE; tok=peek()) {
move();
expr = new NullSafe(expr, unary(), location);
}
return expr;
}
/**
* unary : ('!' | '+' | '-'| '++' | '--') expr
*/
Expr unary() {
Tok tok = peek();
switch (tok.sym) {
case NOT:
move();
return new Logic(tok.sym, unary(), location);
case ADD:
case SUB:
move();
return new Unary(tok.sym, unary(), location).toConstIfPossible();
case INC:
case DEC:
move();
return new IncDec(tok.sym, false, incDec(), location);
default:
return incDec();
}
}
/**
* incDec : expr ('++' | '--')
*/
Expr incDec() {
Expr expr = staticMember();
Tok tok = peek();
if (tok.sym == Sym.INC || tok.sym == Sym.DEC) {
move();
return new IncDec(tok.sym, true, expr, location);
}
return expr;
}
/**
* staticMember
* : ID_list '::' ID
* | ID_list '::' ID '(' exprList? ')'
*/
Expr staticMember() {
if (peek().sym != Sym.ID) {
return sharedMethod();
}
int begin = forward;
while (move().sym == Sym.DOT && move().sym == Sym.ID) {
;
}
// ID.ID.ID::
if (peek().sym != Sym.STATIC || tokenList.get(forward - 1).sym != Sym.ID) {
resetForward(begin);
return sharedMethod();
}
String clazz = getClazz(begin);
match(Sym.STATIC);
String memberName = match(Sym.ID).value();
// com.jfinal.kit.StrKit::isBlank(str)
if (peek().sym == Sym.LPAREN) {
move();
if (peek().sym == Sym.RPAREN) {
move();
if (! engineConfig.isStaticMethodExpressionEnabled()) {
throw new ParseException("Static Method expression is not enabled", location);
}
return new StaticMethod(clazz, memberName, location);
}
ExprList exprList = exprList();
match(Sym.RPAREN);
if (! engineConfig.isStaticMethodExpressionEnabled()) {
throw new ParseException("Static Method expression is not enabled", location);
}
return new StaticMethod(clazz, memberName, exprList, location);
}
if (! engineConfig.isStaticFieldExpressionEnabled()) {
throw new ParseException("Static Field expression is not enabled", location);
}
// com.jfinal.core.Const::JFINAL_VERSION
return new StaticField(clazz, memberName, location);
}
String getClazz(int begin) {
StringBuilder clazz = new StringBuilder();
for (int i=begin; i mapEntry = new LinkedHashMap
© 2015 - 2024 Weber Informatics LLC | Privacy Policy