Skip to content

Commit 1dacab9

Browse files
Start to tidy up parseInfixPrecedenceLevel
1 parent 2b52c88 commit 1dacab9

3 files changed

Lines changed: 44 additions & 11 deletions

File tree

src/main/java/net/marcellperger/mathexpr/BinOpBiConstructor.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,20 @@
11
package net.marcellperger.mathexpr;
22

33

4+
// TODO: this is stupid - it should not be generic!!! It should return a MathSymbol always
5+
// (not a specific subclass but exactly a `impl MathSymbol` that MUST BE CAST)
6+
// i.e. we want this to be like `MathSymbol construct(MathSymbol left, MathSymbol right)`
7+
// similar to `List<T> of(T... values)` is NOT `(? extends List<T>) of(T... values)`
8+
// (or maybe could be generic on method? but probably bad idea)
9+
// This is NOT rust, you don't need to make it explicit `impl MathSymbol`
10+
// i.e. currently:
11+
// trait BinOpBinConstructor<R: MathSymbol> {
12+
// fn construct(MS left, MS right) -> R;
13+
// }
14+
// and we want:
15+
// trait BinOpBiConstructor {
16+
// fn construct(MS left, MS right) -> (dyn?) impl MS;
17+
// }
418
@FunctionalInterface
519
public interface BinOpBiConstructor<R extends MathSymbol> {
620
R construct(MathSymbol left, MathSymbol right);

src/main/java/net/marcellperger/mathexpr/parser/Parser.java

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -98,24 +98,21 @@ public MathSymbol parseInfixPrecedenceLevel(int level) throws ExprParseException
9898
// TODO: refactor this mess - 2 separate loops?
9999
// I feel like it should be doable w/ one loop but that may involve risking NullPointerException
100100
// 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
101102
List<Pair<SymbolInfo, MathSymbol>> otherOps = new ArrayList<>();
102103
discardWhitespace();
103104
while((op = discardMatchesNextAny_optionsSorted(infixesToFind)) != null) {
104105
SymbolInfo opInfo = Objects.requireNonNull(infixToSymbolInfo.get(op));
105-
MathSymbol right = parseInfixPrecedenceLevel(level - 1);
106-
otherOps.add(new Pair<>(opInfo, right));
106+
MathSymbol sym = parseInfixPrecedenceLevel(level - 1);
107+
otherOps.add(new Pair<>(opInfo, sym));
107108
discardWhitespace();
108109
}
109110
if(otherOps.isEmpty()) return left;
110-
SymbolInfo currOp = otherOps.getLast().left;
111-
MathSymbol right = otherOps.removeLast().right;
112-
while(!otherOps.isEmpty()) {
113-
Pair<SymbolInfo, MathSymbol> currPair = otherOps.removeLast();
114-
MathSymbol leftLocal = currPair.right;
115-
right = currOp.getBiConstructor().construct(leftLocal, right);
116-
currOp = currPair.left;
117-
}
118-
return currOp.getBiConstructor().construct(left, right);
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.<MathSymbol>asVars((midOp, argR) -> midOp.getBiConstructor().construct(javaIsAnIdiot_left, argR))).orElse(left);
119116
}
120117
discardWhitespace();
121118
while((op = discardMatchesNextAny_optionsSorted(infixesToFind)) != null) {

src/main/java/net/marcellperger/mathexpr/util/Pair.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
package net.marcellperger.mathexpr.util;
22

3+
import org.jetbrains.annotations.NotNull;
4+
5+
import java.util.function.BiFunction;
6+
37
public class Pair<T, U> {
48
public T left;
59
public U right;
@@ -8,4 +12,22 @@ public Pair(T left, U right) {
812
this.left = left;
913
this.right = right;
1014
}
15+
16+
/**
17+
* This is a workaround for Java not having parameter unpacking/similar.
18+
* So anything that uses the unpacked variables goes inside, this is
19+
* very Haskell-y ({@code let ... in ...})
20+
* <p>
21+
* Java: <pre>{@code pair.asVars((myLeft, myRight) -> {<function body>})}</pre>
22+
* Python: <pre>{@code
23+
* myLeft, myRight = pair
24+
* <function body>
25+
* }</pre>
26+
* Haskell: <pre>{@code
27+
* let (myLeft, myRight)=pair in <function body>
28+
* }</pre>
29+
*/
30+
public <R> R asVars(@NotNull BiFunction<? super T, ? super U, ? extends R> fn) {
31+
return fn.apply(left, right);
32+
}
1133
}

0 commit comments

Comments
 (0)