Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

* 修复:ExpressRunner.executeRule 不支持语句 if(){}else{} 这种最后包含else语句的问题。 #105

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions src/main/java/com/ql/util/express/rule/EmptyCondition.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.ql.util.express.rule;

/**
* <p>
* used for else statement <br>
* Created by hongkai.wang on 2020/11/12.
* </p>
*/
public class EmptyCondition extends Condition {
public static EmptyCondition INSTANCE = new EmptyCondition();

@Override
public String getText() {
return "";
}

@Override
public String toString() {
return "empty condition";
}
}
8 changes: 6 additions & 2 deletions src/main/java/com/ql/util/express/rule/Rule.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public String toQl()
sb.append(this.ruleCaseToScript("ql",oneCase));
first = false;
}else{
sb.append("else ").append(this.ruleCaseToScript("ql",oneCase));
sb.append(" else ").append(this.ruleCaseToScript("ql", oneCase));
}
}
return sb.toString();
Expand Down Expand Up @@ -113,7 +113,11 @@ private String ruleCaseToScript(String scriptType, RuleCase ruleCase)
for(Action action : ruleCase.getActions()){
sb.append(action.getText()).append(";\n");
}
return String.format("if(%s)\n{\n%s}", ruleCase.getCondition().toString(), sb);
if (ruleCase.getCondition() instanceof EmptyCondition) {
return String.format("{\n%s}", sb);
} else {
return String.format("if(%s)\n{\n%s}", ruleCase.getCondition().toString(), sb);
}
}else if(scriptType.equals("skylight")){
for(Action action : ruleCase.getActions()){
sb.append(action.getText()).append("\n");
Expand Down
91 changes: 53 additions & 38 deletions src/main/java/com/ql/util/express/rule/RuleManager.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
package com.ql.util.express.rule;

import com.ql.util.express.ExpressRunner;
import com.ql.util.express.IExpressContext;
import com.ql.util.express.parse.ExpressNode;
import com.ql.util.express.parse.Word;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.ql.util.express.ExpressRunner;
import com.ql.util.express.IExpressContext;
import com.ql.util.express.parse.ExpressNode;
import com.ql.util.express.parse.Word;

/**
* Created by tianqiao on 16/12/8.
*/
Expand Down Expand Up @@ -68,28 +69,32 @@ private static Boolean calculateCondition(ExpressRunner runner, IExpressContext<


Boolean unionLogicResult = null;
ConditionType rootType = root.getType();
if(root.getChildren()!=null) {
for (Condition sub : root.getChildren()) {
Boolean subResult = calculateCondition(runner,context,sub,traceMap,isCache,isTrace, result);
if(unionLogicResult==null){
unionLogicResult = subResult;
}else{
if (rootType == ConditionType.And) {
unionLogicResult = unionLogicResult && subResult;
}else if (rootType == ConditionType.Or) {
unionLogicResult = unionLogicResult || subResult;
}
}
if(isShortCircuit) {
if (rootType == ConditionType.And) {
if(unionLogicResult==false){
break;
if (root instanceof EmptyCondition) {
unionLogicResult = true;
} else {
ConditionType rootType = root.getType();
if (root.getChildren() != null) {
for (Condition sub : root.getChildren()) {
Boolean subResult = calculateCondition(runner, context, sub, traceMap, isCache, isTrace, result);
if (unionLogicResult == null) {
unionLogicResult = subResult;
} else {
if (rootType == ConditionType.And) {
unionLogicResult = unionLogicResult && subResult;
} else if (rootType == ConditionType.Or) {
unionLogicResult = unionLogicResult || subResult;
}
}
if (rootType == ConditionType.Or) {
if(unionLogicResult==true){
break;
if (isShortCircuit) {
if (rootType == ConditionType.And) {
if (unionLogicResult == false) {
break;
}
}
if (rootType == ConditionType.Or) {
if (unionLogicResult == true) {
break;
}
}
}
}
Expand Down Expand Up @@ -165,18 +170,26 @@ private static void addRuleCaseByExpress(ExpressNode ifNode, Rule rule, Word[] w
action = children[point];
point++;

//[3]"else"
// add a pair of ruleCase
rule.addRuleCases(createRuleCase(condtion, action, words));

// [3]"else" here just care about else{} or else if{}
if (point < children.length && isNodeType(children[point], "else")) {
point++;

//[4]IfNode
// [4]IfNode : mean else if(){}
if (point < children.length && isNodeType(children[point], "if")) {
nextCase = children[point];
if (nextCase != null) {
addRuleCaseByExpress(nextCase, rule, words);
}
}
// [4] ActionNode : mean else{}
else if (point < children.length && isNodeType(children[point], "STAT_BLOCK")) {
rule.addRuleCases(createRuleCase(EmptyCondition.INSTANCE, children[point], words));
} else {
// do nothing ,not support
}
}
rule.addRuleCases(createRuleCase(condtion, action, words));
if (nextCase != null) {
addRuleCaseByExpress(nextCase, rule, words);
}
}

Expand All @@ -196,20 +209,22 @@ private static ExpressNode getIfRootNode(ExpressNode parent) {
}

private static RuleCase createRuleCase(ExpressNode condition, ExpressNode action, Word[] words) {

Condition ruleCondition = new Condition();
transferCondition(condition, ruleCondition, words);
return createRuleCase(ruleCondition, action, words);
}

private static RuleCase createRuleCase(Condition condition, ExpressNode action, Word[] words) {
List<Action> actions = new ArrayList<Action>();
if (isNodeType(action, "STAT_BLOCK")) {
ExpressNode[] children = action.getChildren();
for (ExpressNode actionChild : children) {
actions.add(new Action(makeActionString(actionChild,words)));
actions.add(new Action(makeActionString(actionChild, words)));
}
} else {
actions.add(new Action(makeActionString(action,words)));
actions.add(new Action(makeActionString(action, words)));
}
RuleCase ruleCase = new RuleCase(ruleCondition, actions);
return ruleCase;
return new RuleCase(condition, actions);
}

private static void transferCondition(ExpressNode express, Condition condition, Word[] words) {
Expand Down
54 changes: 54 additions & 0 deletions src/test/java/com/ql/util/express/ExpressRunnerTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.ql.util.express;

import org.junit.Test;

import com.ql.util.express.rule.Rule;
import com.ql.util.express.rule.RuleResult;

import junit.framework.TestCase;

/**
* Created by hongkai.wang on 2020/11/12.
*/
public class ExpressRunnerTest extends TestCase {
@Test
public void testParseRule() throws Exception {
ExpressRunner expressRunner = new ExpressRunner(true, false);
String script =
"if(age>=18){resultCode=\"成年\";}else if(age>=10 and age<18){resultCode=\"未成年\";}else{resultCode=\"幼儿\";}";
System.out.println(expressRunner.parseRule(script).toQl());
}

@Test
public void testExecuteRule() throws Exception {
ExpressRunner expressRunner = new ExpressRunner(true, false);
DefaultContext<String, Object> context = new DefaultContext<String, Object>();

String script =
"if(age>=18){resultCode=\"成年\";}else if(age>=10 and age<18){resultCode=\"未成年\";}else{resultCode=\"幼儿\";}";
Rule rule = expressRunner.parseRule(script);
System.err.println("rule.toTree:\n" + rule.toTree());

// 场景1,age>18,预计结果:成年人
context.put("age", 20);
// 初始化变量进去,为了可以get数据出来
context.put("resultCode", null);
// 后面有使用 ruleResult.getTraceMap() 分析条件的命中情况,来做数据分析,所以选择了 executeRule 而不是 execute
RuleResult ruleResult = expressRunner.executeRule(script, context, true, false);
System.err.println("期待if 条件命中,返回成年人,结果resultCode===" + context.get("resultCode"));
System.err.println("成年人traceMap===" + ruleResult.getTraceMap());

// 场景2,age<18,预计结果:未成年,实际为null
context.put("age", 12);
context.put("resultCode", null);
ruleResult = expressRunner.executeRule(script, context, true, false);
System.err.println("期望 else if条件命中,返回未成年,结果resultCode===" + context.get("resultCode"));
System.err.println("未成年traceMap===" + ruleResult.getTraceMap());

context.put("age", 9);
context.put("resultCode", null);
ruleResult = expressRunner.executeRule(script, context, true, false);
System.err.println("期望 else 条件命中,返回幼儿,结果resultCode===" + context.get("resultCode"));
System.err.println("幼儿traceMap===" + ruleResult.getTraceMap());
}
}