net.paoding.rose.jade.statement.jexl.Jexl3Analysis Maven / Gradle / Ivy
package net.paoding.rose.jade.statement.jexl;
import net.paoding.rose.jade.excetion.JadeException;
import net.paoding.rose.jade.statement.jexl.analysis.Analysis;
import net.paoding.rose.jade.statement.jexl.analysis.impl.ForAnalysis;
import net.paoding.rose.jade.statement.jexl.analysis.impl.IfElseAnalysis;
import net.paoding.rose.jade.statement.jexl.analysis.impl.JoinAnalysis;
import net.paoding.rose.jade.statement.jexl.analysis.impl.TxtAnalysis;
import net.paoding.rose.jade.statement.jexl.analysis.impl.VariableAnalysis;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.regex.Matcher;
/**
* jexl3 表达式解析
* @author fusheng.zhang
* @date 2022-03-03 14:48:35
*/
public class Jexl3Analysis {
/**
* 带解析语句 源语
*/
private final String sourceLanguage;
/**
* 编译位置
*/
private int position;
/**
* 组装位置
*/
private int fromIndex;
private final Matcher sourceLanguageMatcher;
/**
* #else Matcher
*/
private final Matcher elseMatcher;
private final List result = new ArrayList<>();
public Jexl3Analysis(String sourceLanguage) {
this.sourceLanguage = sourceLanguage;
this.sourceLanguageMatcher = Jexl3Constant.PATTERN_KEYWORD.matcher(this.sourceLanguage);
this.elseMatcher = Jexl3Constant.PATTERN_ELSE.matcher(sourceLanguage);
}
public List compile() {
try {
while (sourceLanguageMatcher.find(position)) {
position = sourceLanguageMatcher.end();
String expr = sourceLanguageMatcher.group(1),
group = sourceLanguageMatcher.group(2),
keyword = sourceLanguageMatcher.group(3);
boolean isIn = false;
if (Objects.nonNull(expr)) {
if (sourceLanguageMatcher.start() > fromIndex) {
TxtAnalysis txtAnalysis = new TxtAnalysis(sourceLanguage.substring(fromIndex, sourceLanguageMatcher.start()));
isIn = Jexl3Constant.PATTERN_IN.matcher(txtAnalysis.getTxt()).find();
this.result.add(txtAnalysis);
}
// 创建 :expr | $expr 形式的子句
if (expr.charAt(0) == Jexl3Constant.KEYWORD_$_) {
this.result.add(new JoinAnalysis().setJoinExp(expr));
} else {
this.result.add(new VariableAnalysis(expr, isIn));
}
} else if (Objects.nonNull(group)) {
this.result.addAll(new Jexl3Analysis(group).compile());
} else if (Objects.isNull(keyword)) {
expr = parentheses();
if (Objects.nonNull(expr)) {
if (sourceLanguageMatcher.start() > fromIndex) {
TxtAnalysis txtAnalysis = new TxtAnalysis(sourceLanguage.substring(fromIndex, sourceLanguageMatcher.start()));
isIn = Jexl3Constant.PATTERN_IN.matcher(txtAnalysis.getTxt()).find();
this.result.add(txtAnalysis);
}
this.result.add(new VariableAnalysis(expr, isIn));
}
} else {
switch (keyword) {
case Jexl3Constant.KEYWORD_IF: ifElse();
break;
case Jexl3Constant.KEYWORD_FOR: forLoop();
break;
case Jexl3Constant.KEYWORD_SHARP: case Jexl3Constant.KEYWORD_JOIN: join();
break;
}
}
fromIndex = position;
}
// 写入 PREFIX 字符后的内容。
if (fromIndex < sourceLanguage.length()) {
this.result.add(new TxtAnalysis(sourceLanguage.substring(fromIndex)));
}
} catch (Exception e) {
throw new JadeException(e.getMessage(), e);
}
return this.result;
}
private void join() {
String joinStr = parentheses();
if (Objects.nonNull(joinStr)) {
if (sourceLanguageMatcher.start() > fromIndex) {
this.result.add(new TxtAnalysis(sourceLanguage.substring(fromIndex, sourceLanguageMatcher.start())));
}
this.result.add(new JoinAnalysis().setJoinExp(joinStr));
}
}
private void forLoop() {
// 获取括号内容
String forCondition = parentheses();
if (Objects.nonNull(forCondition)) {
if (sourceLanguageMatcher.start() > fromIndex) {
this.result.add(new TxtAnalysis(sourceLanguage.substring(fromIndex, sourceLanguageMatcher.start())));
}
ForAnalysis forAnalysis = new ForAnalysis();
// 解析 variant in :expr 表达式
Matcher matcherIn = Jexl3Constant.PATTERN_IN.matcher(forCondition);
if (matcherIn.matches()) {
forAnalysis.setVariable(matcherIn.group(1));
forCondition = matcherIn.group(2);
}
forAnalysis.setForCondition(forCondition);
// for 执行语句{}
String forExecute = braces();
if (Objects.nonNull(forExecute)) {
List analysisResult = new Jexl3Analysis(forExecute).compile();
if (analysisResult.isEmpty()) {
forAnalysis.setForExecute(forExecute);
} else {
forAnalysis.setForAnalyses(analysisResult);
}
}
this.result.add(forAnalysis);
}
}
private void ifElse() {
// 获取if条件语句 ()
String ifCondition = parentheses();
if (Objects.nonNull(ifCondition)) {
if (sourceLanguageMatcher.start() > fromIndex) {
this.result.add(new TxtAnalysis(sourceLanguage.substring(fromIndex, sourceLanguageMatcher.start())));
}
// 构建 if 表达式
IfElseAnalysis ifElseAnalysis = new IfElseAnalysis();
ifElseAnalysis.setIfCondition(ifCondition);
// 获取if执行语句 {}
String ifExecute = braces();
if (Objects.nonNull(ifExecute)) {
List analysisResult = new Jexl3Analysis(ifExecute).compile();
if (analysisResult.isEmpty()) {
ifElseAnalysis.setIfExecute(ifExecute);
} else {
ifElseAnalysis.setIfAnalyses(analysisResult);
}
}
// 判断是否存在 else,如果是则步进5
if (this.startElse()) {
this.position += 5;
// 获取 else执行语句{}
String elseExecute = braces();
if (Objects.nonNull(elseExecute)) {
List analysesResult = new Jexl3Analysis(elseExecute).compile();
if (analysesResult.isEmpty()) {
ifElseAnalysis.setElseExecute(elseExecute);
} else {
ifElseAnalysis.setElseAnalyses(analysesResult);
}
} else {
this.position -= 5;
}
}
this.result.add(ifElseAnalysis);
}
}
public boolean startElse() {
return elseMatcher.find(this.position) && elseMatcher.group().equals(Jexl3Constant.KEYWORD_ELSE);
}
/**
* 匹配大括号
* @return
*/
private String braces() {
return findBrace('{', '}');
}
/**
* 匹配小括号
* @return
*/
private String parentheses() {
return findBrace('(', ')');
}
/**
* 查找匹配的左括号, 忽略之前的空白字符。
*
* 如果未找到匹配的左括号,函数返回 -1.
* @param chLeft - 匹配的左括号
* @param fromIndex - 查找的起始位置
* @return 左括号的位置, 如果未找到匹配的左括号,函数返回 -1.
*/
private int findLeftBrace(char chLeft, int fromIndex) {
// 查找出现的左括号。
for (int index = fromIndex; index < sourceLanguage.length(); index++) {
char ch = sourceLanguage.charAt(index);
// 如果出现左括号,返回。 如果出现非空白字符,返回 - 1.
if (ch == chLeft) {
return index;
} else if (!Character.isWhitespace(ch)) {
return -1;
}
}
// 没有找到匹配的括号。
return -1;
}
/**
* 查找匹配的右括号, 可以用于匹配 '{}', '[]', '()' 括号对。
*
* 如果未找到匹配的右括号,函数返回 -1.
* @param chLeft - 匹配的左括号
* @param chRight - 匹配的右括号
* @param fromIndex - 查找的起始位置
* @return 右括号的位置, 如果未找到匹配的右括号,函数返回 -1.
*/
private int findRightBrace(char chLeft, char chRight, int fromIndex) {
// 记录括号层级。
int level = 0;
// 查找匹配的右括号。
for (int index = fromIndex; index < sourceLanguage.length(); index++) {
char ch = sourceLanguage.charAt(index);
// 如果出现左括号,重叠级别增加。如果出现右括号,重叠级别降低。
if (ch == chLeft) {
level++;
} else if (ch == chRight) {
// 找到右括号。
if (level == 0) return index;
level--;
}
}
// 没有找到匹配的括号。
return -1;
}
/**
* 从当前位置查找匹配的一对括号, 并返回内容。
*
* 如果有匹配的括号, 返回后的当前位置指向匹配的右括号后一个字符。
* @param chLeft - 匹配的左括号
* @param chRight - 匹配的右括号
* @return 返回括号内容, 如果没有括号匹配, 返回 null
.
*/
private String findBrace(char chLeft, char chRight) {
// 从当前位置查找查找匹配的 (...)
int left = findLeftBrace(chLeft, position);
if (left >= position) {
int start = left + 1;
int end = findRightBrace(chLeft, chRight, start);
if (end >= start) {
// 当前位置指向匹配的右括号后一个字符
position = end + 1;
// 返回匹配的括号内容
return sourceLanguage.substring(start, end);
}
}
return null; // 没有 (...) 匹配
}
}