1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.student.common.ui.client.widgets.table;
17
18 import java.util.ArrayList;
19 import java.util.List;
20 import java.util.Stack;
21
22 import org.kuali.student.common.ui.client.widgets.rules.Token;
23
24
25
26
27
28
29
30 public class ExpressionParser {
31
32
33
34 private List<String> errorMessageList = new ArrayList<String>();
35
36 public ExpressionParser() {
37 }
38
39
40
41
42
43 public boolean hasError(){
44 return errorMessageList.size() > 0;
45 }
46
47
48
49
50
51 public List<String> getErrorMessage(){
52 return errorMessageList;
53 }
54
55
56
57
58
59 public Node<Token> parse(String expression) {
60 errorMessageList = new ArrayList<String>();
61 List<String> tokenValueList = getTokenValue(expression);
62 List<Token> tokenList = getTokenList(tokenValueList);
63 errorCheck(tokenList);
64 if(hasError()){
65 return null;
66 }
67 List<Node<Token>> nodeList = toNodeList(tokenList);
68 List<Node<Token>> rpnList = getRPN(nodeList);
69
70 Node<Token> root = binaryTreeFromRPN(rpnList);
71
72
73 Node<Token> ruleRoot = mergeBinaryTree(root);
74
75
76
77 ruleRoot = orderLeafChildren(ruleRoot, tokenList );
78 ruleRoot = orderNonLeafChildren(ruleRoot, tokenList );
79 return ruleRoot;
80 }
81
82
83
84
85
86 public static String getExpressionString(Node root){
87 while(root.getChildCount()> 1){
88 List<List<Node>> level = root.toLevel();
89 for(Node<Token> n: level.get(level.size()-1)){
90 if(n.isLeaf() && n.getParent() != null){
91 Node parent = n.getParent();
92 StringBuilder sb = new StringBuilder();
93 if(parent.getChildAt(0).getUserObject() instanceof ExpressionNode
94 && parent.getChildAt(0).getUserObject() instanceof ExpressionNode
95 && (( ExpressionNode)parent.getChildAt(0).getUserObject()).token.type == Token.Or
96 && (( Token)parent.getUserObject()).type == Token.And){
97 sb.append(" ( "+parent.getChildAt(0).getUserObject().toString()+" ) ");
98 }else{
99 sb.append(" "+parent.getChildAt(0).getUserObject().toString()+" ");
100 }
101
102
103 for(int i=1;i<parent.getChildCount();i++){
104 Node child = parent.getChildAt(i);
105
106 if(parent.getChildAt(i).getUserObject() instanceof ExpressionNode
107 && parent.getChildAt(i).getUserObject() instanceof ExpressionNode
108 && (( ExpressionNode)parent.getChildAt(i).getUserObject()).token.type == Token.Or
109 && (( Token)parent.getUserObject()).type == Token.And){
110 sb.append(parent.getUserObject().toString()+ " ( "+
111 child.getUserObject().toString()+" ) ");
112
113 }else{
114 sb.append(" "+parent.getUserObject().toString()+ " "+
115 child.getUserObject().toString()+" ");
116 }
117 }
118 ExpressionNode expressionNode = new ExpressionNode();
119 expressionNode.token = (Token)parent.getUserObject();
120 expressionNode.expression = sb.toString();
121 parent.setUserObject(expressionNode);
122 parent.removeAllChildren();
123 break;
124 }
125 }
126
127 }
128
129
130 return root.getUserObject().toString();
131 }
132
133
134
135 private Node<Token> orderNonLeafChildren(Node<Token> binaryTree,List<Token> tokenList ) {
136 List<Node> list = binaryTree.getNonLeafChildren();
137 if(list.size() > 1){
138 sequeceNonLeaves(list, tokenList);
139 binaryTree.children().removeAll(list);
140 for(Node n: list){
141 binaryTree.addNode(n);
142 }
143 }
144 for(Node n: binaryTree.children()){
145 if(n.isLeaf() == false){
146 orderNonLeafChildren(n,tokenList );
147 }
148 }
149
150 List<Node> nonLeafChildList = binaryTree.getNonLeafChildren();
151 List<Node> leafChildList = binaryTree.getLeafChildren();
152 binaryTree.children().removeAll(nonLeafChildList);
153 binaryTree.children().removeAll(leafChildList);
154 for(Node n: nonLeafChildList){
155 binaryTree.addNode(n);
156 }
157
158 for(Node n: leafChildList){
159 binaryTree.addNode(n);
160 }
161 return binaryTree;
162 }
163
164
165
166 private void sequeceNonLeaves(List<Node> nonLeafChildList, List<Token> list){
167 if(nonLeafChildList.size() == 2){
168 if (indexInInputTokenList((Token)nonLeafChildList.get(0).getFirstLeafDescendant().getUserObject(), list)>
169 indexInInputTokenList((Token)nonLeafChildList.get(1).getFirstLeafDescendant().getUserObject(), list)) {
170 Node buffer = nonLeafChildList.get(0);
171 nonLeafChildList.remove(0);
172 nonLeafChildList.add(buffer);
173 }
174 }
175 for (int out = nonLeafChildList.size() - 1; out > 1; out--){
176 for (int in = 0; in < out; in++){
177
178 if (indexInInputTokenList((Token)nonLeafChildList.get(in).getFirstLeafDescendant().getUserObject(), list)>
179 indexInInputTokenList((Token)nonLeafChildList.get(in + 1).getFirstLeafDescendant().getUserObject(), list)) {
180
181 Node node = nonLeafChildList.get(in);
182 nonLeafChildList.remove(in);
183 nonLeafChildList.add(in+1, node);
184 }
185 }
186 }
187 }
188
189
190
191 private Node<Token> orderLeafChildren(Node<Token> binaryTree,List<Token> tokenList ) {
192 List<Node> list = binaryTree.getLeafChildren();
193 if(list.size() > 1){
194 sequeceLeaves(list, tokenList);
195 binaryTree.children().removeAll(list);
196 for(Node n: list){
197 binaryTree.addNode(n);
198 }
199 }
200 for(Node n: binaryTree.children()){
201 if(n.isLeaf() == false){
202 orderLeafChildren(n,tokenList );
203 }
204 }
205 return binaryTree;
206 }
207
208 private void sequeceLeaves(List<Node> leafChildList, List<Token> list){
209 if(leafChildList.size() == 2){
210 if (indexInInputTokenList((Token)leafChildList.get(0).getUserObject(), list)>
211 indexInInputTokenList((Token)leafChildList.get(1).getUserObject(), list)) {
212
213 Token buffer = (Token)leafChildList.get(0).getUserObject();
214 leafChildList.get(0).setUserObject(leafChildList.get(1).getUserObject());
215 leafChildList.get(1).setUserObject(buffer);
216 }
217
218 }
219
220 for (int out = leafChildList.size() - 1; out > 1; out--){
221 for (int in = 0; in < out; in++){
222
223 if (indexInInputTokenList((Token)leafChildList.get(in).getUserObject(), list)>
224 indexInInputTokenList((Token)leafChildList.get(in + 1).getUserObject(), list)) {
225
226 Token buffer = (Token)leafChildList.get(in).getUserObject();
227 leafChildList.get(in).setUserObject(leafChildList.get(in + 1).getUserObject());
228 leafChildList.get(in + 1).setUserObject(buffer);
229 }
230 }
231 }
232 }
233
234 private int indexInInputTokenList(Token token, List<Token> list){
235 int i = -1;
236 for(Token n: list){
237 if(n.value != null && token.value != null && n.value.equals(token.value)){
238 return i;
239 }
240 i++;
241 }
242 return i;
243 }
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265 private static Node getDeeperNode(List<Node> nodeList) {
266 int childCount = 0;
267 for (Node node : nodeList) {
268 if (childCount < node.getAllChildren().size()) {
269 childCount = node.getAllChildren().size();
270 }
271 }
272 for (Node node : nodeList) {
273 if (childCount == node.getAllChildren().size()) {
274 return node;
275 }
276 }
277
278 return null;
279 }
280
281 public static Node<Token> mergeBinaryTree(Node<Token> binaryTree) {
282 while (parentEqualsGrandParent(binaryTree)) {
283 List<Node<Token>> list = binaryTree.getAllChildren();
284
285 for (Node node : list) {
286 if (node.getParent() != null && node.getParent().getParent() != null) {
287 Node parentNode = node.getParent();
288 Node grandParentNode = node.getParent().getParent();
289 Token parentToken = (Token) parentNode.getUserObject();
290 Token grandParentToken = (Token) grandParentNode.getUserObject();
291
292 if (parentToken.type == grandParentToken.type) {
293 for (int i = 0; i < parentNode.getChildCount(); i++) {
294 Node n = parentNode.getChildAt(i);
295 grandParentNode.addNode(n);
296 }
297 grandParentNode.remove(parentNode);
298 }
299 }
300 }
301 }
302 return binaryTree;
303 }
304
305 private static boolean parentEqualsGrandParent(Node<Token> binaryTree) {
306 List<Node<Token>> list = binaryTree.getAllChildren();
307
308 for (Node node : list) {
309 if (node.getParent() != null && node.getParent().getParent() != null) {
310
311 Token parentToken = (Token) node.getParent().getUserObject();
312 Token grandParentToken = (Token) node.getParent().getParent().getUserObject();
313 if (parentToken.type == grandParentToken.type) {
314 return true;
315 }
316 }
317 }
318
319 return false;
320 }
321
322 private Node<Token> binaryTreeFromRPN(List<Node<Token>> rpnList) {
323 Stack<Node<Token>> conditionStack = new Stack<Node<Token>>();
324 for (Node<Token> node : rpnList) {
325 if (node.getUserObject().type == Token.Condition) {
326 conditionStack.push(node);
327 } else if (node.getUserObject().type == Token.And || node.getUserObject().type == Token.Or) {
328 Node<Token> left = conditionStack.pop();
329 Node<Token> right = conditionStack.pop();
330 node.addNode(left);
331 node.addNode(right);
332 conditionStack.push(node);
333 }
334 }
335
336 return conditionStack.pop();
337 }
338
339
340
341
342
343
344
345
346 private List<Node<Token>> getRPN(List<Node<Token>> nodeList) {
347 List<Node<Token>> rpnList = new ArrayList<Node<Token>>();
348 Stack<Node<Token>> operatorStack = new Stack<Node<Token>>();
349
350 for (Node<Token> node : nodeList) {
351 if (node.getUserObject().type == Token.Condition) {
352 rpnList.add(node);
353
354 } else if (node.getUserObject().type == Token.And) {
355 operatorStack.push(node);
356 } else if (node.getUserObject().type == Token.StartParenthesis) {
357 operatorStack.push(node);
358 } else if (node.getUserObject().type == Token.Or) {
359
360 if (operatorStack.isEmpty() == false && operatorStack.peek().getUserObject().type == Token.And) {
361 do {
362 rpnList.add(operatorStack.pop());
363 } while (operatorStack.isEmpty() == false && operatorStack.peek().getUserObject().type == Token.And);
364 }
365
366 operatorStack.push(node);
367 } else if (node.getUserObject().type == Token.EndParenthesis) {
368 while (operatorStack.peek().getUserObject().type != Token.StartParenthesis) {
369 rpnList.add(operatorStack.pop());
370 }
371 operatorStack.pop();
372 }
373 }
374 if (operatorStack.isEmpty() == false) {
375 do {
376 rpnList.add(operatorStack.pop());
377 } while (operatorStack.isEmpty() == false);
378 }
379 return rpnList;
380 }
381
382 private int findNodeIndex(List<Node<Token>> nodeList, int type) {
383 int index = -1;
384 for (Node<Token> node : nodeList) {
385 index++;
386 if (node.getUserObject().type == type) {
387 return index;
388 }
389 }
390 return index;
391 }
392
393 private boolean hasParenthesis(List<Node<Token>> nodeList) {
394 boolean has = false;
395 for (Node<Token> node : nodeList) {
396 if (node.getUserObject().type == Token.StartParenthesis) {
397 return true;
398 }
399 }
400 return has;
401 }
402
403 private List<Node<Token>> toNodeList(List<Token> tokenList) {
404 List<Node<Token>> nodeList = new ArrayList<Node<Token>>();
405 for (Token token : tokenList) {
406 Node<Token> node = new Node<Token>();
407 node.setUserObject(token);
408 nodeList.add(node);
409 }
410 return nodeList;
411 }
412
413 private void errorCheck(List<Token> tokenList) {
414 if (tokenList.size() == 0) {
415 errorMessageList.add("empty input");
416 return;
417 }
418 if (tokenList.size() <= 2) {
419 errorMessageList.add("input not complete");
420 return;
421 }
422 if ((tokenList.get(0).type == Token.StartParenthesis
423 || tokenList.get(0).type == Token.Condition) == false) {
424 errorMessageList.add("must start with ( or condition");
425 return;
426 }
427 int lastIndex = tokenList.size() - 1;
428 if ((tokenList.get(lastIndex).type == Token.EndParenthesis || tokenList.get(lastIndex).type == Token.Condition) == false) {
429 errorMessageList.add("must end with ) or condition");
430 return;
431 }
432 if (countToken(tokenList, Token.StartParenthesis) != countToken(tokenList, Token.EndParenthesis)) {
433 errorMessageList.add("() not in pair");
434 return;
435 }
436
437 for (int i = 1; i < tokenList.size(); i++) {
438 Token token = tokenList.get(i);
439 if (token.type == Token.And) {
440 checkAnd(tokenList, i);
441 } else if (token.type == Token.Or) {
442 checkOr(tokenList, i);
443 } else if (token.type == Token.StartParenthesis) {
444 checkStartParenthesis(tokenList, i);
445 } else if (token.type == Token.EndParenthesis) {
446 checkEndParenthesis(tokenList, i);
447 } else if (token.type == Token.Condition) {
448 checkCondition(tokenList, i);
449 }
450 }
451 }
452
453 private int countToken(List<Token> tokenList, int type) {
454 int count = 0;
455 for (Token t : tokenList) {
456 if (t.type == type) {
457 count++;
458 }
459 }
460 return count;
461 }
462
463 private void checkAnd(List<Token> tokenList, int currentIndex) {
464 if ((tokenList.get(currentIndex - 1).type == Token.Condition || tokenList.get(currentIndex - 1).type == Token.EndParenthesis) == false) {
465 errorMessageList.add("only ) and condition could sit before and");
466 }
467 if (currentIndex == tokenList.size() - 1) {
468 return;
469 }
470 if ((tokenList.get(currentIndex + 1).type == Token.Condition || tokenList.get(currentIndex + 1).type == Token.StartParenthesis) == false) {
471 errorMessageList.add("only ( and condition could sit after and");
472 }
473
474 }
475
476 private void checkOr(List<Token> tokenList, int currentIndex) {
477 if ((tokenList.get(currentIndex - 1).type == Token.Condition || tokenList.get(currentIndex - 1).type == Token.EndParenthesis) == false) {
478 errorMessageList.add("only ) and condition could sit before or");
479 }
480 if (currentIndex == tokenList.size() - 1) {
481 return;
482 }
483 if ((tokenList.get(currentIndex + 1).type == Token.Condition || tokenList.get(currentIndex + 1).type == Token.StartParenthesis) == false) {
484 errorMessageList.add("only ( and condition could sit after or");
485 }
486 }
487
488 private void checkStartParenthesis(List<Token> tokenList, int currentIndex) {
489 if ((tokenList.get(currentIndex - 1).type == Token.And || tokenList.get(currentIndex - 1).type == Token.Or || tokenList.get(currentIndex - 1).type == Token.StartParenthesis) == false) {
490 errorMessageList.add("only and, or, ( could sit before (");
491 }
492 if (currentIndex == tokenList.size() - 1) {
493 return;
494 }
495 if ((tokenList.get(currentIndex + 1).type == Token.Condition || tokenList.get(currentIndex + 1).type == Token.StartParenthesis) == false) {
496 errorMessageList.add("only ( and condition could sit after (");
497 }
498
499 }
500
501 private void checkEndParenthesis(List<Token> tokenList, int currentIndex) {
502 if ((tokenList.get(currentIndex - 1).type == Token.Condition || tokenList.get(currentIndex - 1).type == Token.EndParenthesis) == false) {
503 errorMessageList.add("only condition and ) could sit before )");
504 }
505 if (currentIndex == tokenList.size() - 1) {
506 return;
507 }
508 if ((tokenList.get(currentIndex + 1).type == Token.Or || tokenList.get(currentIndex + 1).type == Token.And || tokenList.get(currentIndex + 1).type == Token.EndParenthesis) == false) {
509 errorMessageList.add("only ), and, or could sit after )");
510 }
511
512 }
513
514 private void checkCondition(List<Token> tokenList, int currentIndex) {
515 if ((tokenList.get(currentIndex - 1).type == Token.And || tokenList.get(currentIndex - 1).type == Token.Or || tokenList.get(currentIndex - 1).type == Token.StartParenthesis) == false) {
516 errorMessageList.add("only and, or could sit before condition");
517 }
518 if (currentIndex == tokenList.size() - 1) {
519 return;
520 }
521 if ((tokenList.get(currentIndex + 1).type == Token.Or || tokenList.get(currentIndex + 1).type == Token.And || tokenList.get(currentIndex + 1).type == Token.EndParenthesis) == false) {
522 errorMessageList.add("only ), and, or could sit after condition");
523 }
524
525 }
526
527 private List<Token> getTokenList(List<String> tokenValueList) {
528 List<Token> tokenList = new ArrayList<Token>();
529 for (String value : tokenValueList) {
530 if (value.isEmpty()) {
531 continue;
532 }
533 if ("(".equals(value)) {
534 Token t = new Token();
535 t.type = Token.StartParenthesis;
536 tokenList.add(t);
537 } else if (")".equals(value)) {
538 Token t = new Token();
539 t.type = Token.EndParenthesis;
540 tokenList.add(t);
541
542 } else if ("and".equals(value)) {
543 Token t = new Token();
544 t.type = Token.And;
545 tokenList.add(t);
546
547 } else if ("or".equals(value)) {
548 Token t = new Token();
549 t.type = Token.Or;
550 tokenList.add(t);
551
552 } else {
553 Token t = new Token();
554 t.type = Token.Condition;
555 t.value = value;
556 tokenList.add(t);
557
558 }
559 }
560 return tokenList;
561 }
562
563 private List<String> getTokenValue(String expression) {
564 expression = expression.toLowerCase();
565 List<String> tokenValueList = new ArrayList<String>();
566 StringBuffer tokenValue = new StringBuffer();
567 for (int i = 0; i < expression.length(); i++) {
568
569 char ch = expression.charAt(i);
570 if (ch == ' ') {
571 tokenValueList.add(tokenValue.toString());
572 tokenValue = new StringBuffer();
573 } else if (ch == '(' || ch == ')') {
574 tokenValueList.add(tokenValue.toString());
575 tokenValue = new StringBuffer();
576 tokenValueList.add(String.valueOf(ch));
577 } else {
578 tokenValue.append(ch);
579 }
580 }
581 tokenValueList.add(tokenValue.toString());
582 return tokenValueList;
583 }
584 }
585