|
2 | 2 |
|
3 | 3 | import net.marcellperger.mathexpr.*; |
4 | 4 | import net.marcellperger.mathexpr.util.Pair; |
| 5 | +import net.marcellperger.mathexpr.util.Util; |
5 | 6 | import net.marcellperger.mathexpr.util.UtilCollectors; |
6 | 7 | import org.jetbrains.annotations.NotNull; |
7 | 8 | import org.jetbrains.annotations.Nullable; |
|
15 | 16 | import java.util.stream.Collectors; |
16 | 17 |
|
17 | 18 |
|
18 | | - |
19 | 19 | public class Parser { |
20 | 20 | protected String src; |
21 | 21 | /** Next index to parse */ |
@@ -92,38 +92,42 @@ public MathSymbol parseInfixPrecedenceLevel(int level) throws ExprParseException |
92 | 92 | Function.identity())); |
93 | 93 | String[] infixesToFind = sortedByLength(infixToSymbolInfo.keySet().toArray(String[]::new)); |
94 | 94 | MathSymbol left = parseInfixPrecedenceLevel(level - 1); |
95 | | - String op; |
96 | | - |
97 | 95 | if(dirn == GroupingDirection.RightToLeft) { |
98 | | - // TODO: refactor this mess - 2 separate loops? |
99 | | - // I feel like it should be doable w/ one loop but that may involve risking NullPointerException |
100 | | - // by setting some members of LeftRightBinaryOperation to null |
101 | | - // Actually, this first loop could be common between them if we make the other path 2 loops as well |
102 | | - List<Pair<SymbolInfo, MathSymbol>> otherOps = new ArrayList<>(); |
| 96 | + return parseInfixPrecedenceLevel_RTL(left, level, infixesToFind, infixToSymbolInfo); |
| 97 | + } |
| 98 | + return parseInfixPrecedenceLevel_LTR(left, level, infixesToFind, infixToSymbolInfo); |
| 99 | + // TODO what if dirn == null? Maybe just disallow the ambiguous case of > 2 operands in same level |
| 100 | + } |
| 101 | + |
| 102 | + private MathSymbol parseInfixPrecedenceLevel_RTL(MathSymbol left, int level, String[] infixesToFind, |
| 103 | + Map<String, SymbolInfo> infixToSymbolInfo) throws ExprParseException { |
| 104 | + // TODO: refactor this mess - 2 separate loops? |
| 105 | + // I feel like it should be doable w/ one loop but that may involve risking NullPointerException |
| 106 | + // by setting some members of LeftRightBinaryOperation to null |
| 107 | + // Actually, this first loop could be common between them if we make the other path 2 loops as well |
| 108 | + String op; |
| 109 | + List<Pair<SymbolInfo, MathSymbol>> otherOps = new ArrayList<>(); |
| 110 | + discardWhitespace(); |
| 111 | + while((op = discardMatchesNextAny_optionsSorted(infixesToFind)) != null) { |
| 112 | + otherOps.add(new Pair<>(Util.getNotNull(infixToSymbolInfo, op), parseInfixPrecedenceLevel(level - 1))); |
103 | 113 | discardWhitespace(); |
104 | | - while((op = discardMatchesNextAny_optionsSorted(infixesToFind)) != null) { |
105 | | - SymbolInfo opInfo = Objects.requireNonNull(infixToSymbolInfo.get(op)); |
106 | | - MathSymbol sym = parseInfixPrecedenceLevel(level - 1); |
107 | | - otherOps.add(new Pair<>(opInfo, sym)); |
108 | | - discardWhitespace(); |
109 | | - } |
110 | | - if(otherOps.isEmpty()) return left; |
111 | | - MathSymbol javaIsAnIdiot_left = left; |
112 | | - return otherOps.reversed().stream().reduce((rightpair, leftpair) -> |
113 | | - leftpair.asVars((preOp, argL) -> |
114 | | - new Pair<>(preOp, rightpair.asVars((midOp, argR) -> midOp.getBiConstructor().construct(argL, argR)))) |
115 | | - ).map(p -> p.asVars((midOp, argR) -> midOp.getBiConstructor().construct(javaIsAnIdiot_left, argR))).orElse(left); |
116 | 114 | } |
| 115 | + return otherOps.reversed().stream().reduce((rightpair, leftpair) -> |
| 116 | + leftpair.asVars((preOp, argL) -> |
| 117 | + new Pair<>(preOp, rightpair.asVars((midOp, argR) -> midOp.getBiConstructor().construct(argL, argR)))) |
| 118 | + ).map(p -> p.asVars((midOp, argR) -> midOp.getBiConstructor().construct(left, argR))).orElse(left); |
| 119 | + } |
| 120 | + |
| 121 | + private MathSymbol parseInfixPrecedenceLevel_LTR(MathSymbol left, int level, String[] infixesToFind, |
| 122 | + Map<String, SymbolInfo> infixToSymbolInfo) throws ExprParseException { |
| 123 | + String op; |
117 | 124 | discardWhitespace(); |
118 | 125 | while((op = discardMatchesNextAny_optionsSorted(infixesToFind)) != null) { |
119 | | - SymbolInfo opInfo = Objects.requireNonNull(infixToSymbolInfo.get(op)); |
120 | | - MathSymbol right = parseInfixPrecedenceLevel(level - 1); |
121 | | - BinOpBiConstructor ctor = opInfo.getBiConstructor(); |
122 | | - left = ctor.construct(left, right); |
| 126 | + left = Util.getNotNull(infixToSymbolInfo, op).getBiConstructor() |
| 127 | + .construct(left, parseInfixPrecedenceLevel(level - 1)); |
123 | 128 | discardWhitespace(); |
124 | 129 | } |
125 | 130 | return left; |
126 | | - // TODO what if dirn == null? Maybe just disallow the ambiguous case of > 2 operands in same level |
127 | 131 | } |
128 | 132 |
|
129 | 133 | // region utils |
|
0 commit comments