Skip to content

Commit 51f2dbb

Browse files
authored
Begone mXparser (#188)
* replace mxparser * . * fix postfix op overwriting infix op * use X instead of E for exa si prefix to avoid variable clashing * some big decimal things * fix
1 parent 0816127 commit 51f2dbb

143 files changed

Lines changed: 9749 additions & 49 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

dependencies.gradle

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,14 @@
2323
*/
2424

2525
dependencies {
26-
embed2 'org.mariuszgromada.math:MathParser.org-mXparser:6.1.0'
2726
embed2('org.joml:joml:1.10.8') { transitive = false }
2827
embedSources("org.joml:joml:1.10.8:sources") { transitive = false }
2928

29+
compileOnly("org.projectlombok:lombok:1.18.42")
30+
annotationProcessor("org.projectlombok:lombok:1.18.42")
31+
testCompileOnly("org.projectlombok:lombok:1.18.42")
32+
testAnnotationProcessor("org.projectlombok:lombok:1.18.42")
33+
3034
compileOnlyApi rfg.deobf("curse.maven:inventory-bogosorter-632327:7403680-sources-7403683")
3135
if (project.debug_bogo.toBoolean()) {
3236
runtimeOnly rfg.deobf("curse.maven:inventory-bogosorter-632327:7403680-sources-7403683")

src/main/java/com/cleanroommc/modularui/ModularUI.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
import org.apache.logging.log4j.LogManager;
1212
import org.apache.logging.log4j.Logger;
1313
import org.jetbrains.annotations.Nullable;
14-
import org.mariuszgromada.math.mxparser.License;
1514

1615
import java.util.function.Predicate;
1716

@@ -40,11 +39,6 @@ public class ModularUI {
4039
@Mod.Instance
4140
public static ModularUI INSTANCE;
4241

43-
static {
44-
// confirm mXparser license
45-
License.iConfirmNonCommercialUse("CleanroomMC");
46-
}
47-
4842
@Mod.EventHandler
4943
public void preInit(FMLPreInitializationEvent event) {
5044
proxy.preInit(event);

src/main/java/com/cleanroommc/modularui/api/drawable/IDrawable.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,6 @@ default void drawAtZeroPadded(GuiContext context, Area area, WidgetTheme widgetT
111111
draw(context, area.getPadding().getLeft(), area.getPadding().getTop(), area.paddedWidth(), area.paddedHeight(), widgetTheme);
112112
}
113113

114-
115114
/**
116115
* @return if theme color can be applied on this drawable
117116
*/

src/main/java/com/cleanroommc/modularui/utils/MathUtils.java

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
package com.cleanroommc.modularui.utils;
22

3+
import com.cleanroommc.modularui.utils.math.PostfixPercentOperator;
4+
35
import net.minecraft.util.math.MathHelper;
46

5-
import org.mariuszgromada.math.mxparser.Constant;
6-
import org.mariuszgromada.math.mxparser.Expression;
7+
import com.ezylang.evalex.BaseException;
8+
import com.ezylang.evalex.Expression;
9+
import com.ezylang.evalex.config.ExpressionConfiguration;
10+
import com.ezylang.evalex.data.EvaluationValue;
11+
import org.apache.commons.lang3.tuple.Pair;
12+
13+
import java.math.BigDecimal;
714

815
public class MathUtils {
916

@@ -12,23 +19,12 @@ public class MathUtils {
1219
public static final float PI_HALF = PI / 2f;
1320
public static final float PI_QUART = PI / 4f;
1421

15-
// SI prefixes
16-
public static final Constant k = new Constant("k", 1e3);
17-
public static final Constant M = new Constant("M", 1e6);
18-
public static final Constant G = new Constant("G", 1e9);
19-
public static final Constant T = new Constant("T", 1e12);
20-
public static final Constant P = new Constant("P", 1e15);
21-
public static final Constant E = new Constant("E", 1e18);
22-
public static final Constant Z = new Constant("Z", 1e21);
23-
public static final Constant Y = new Constant("Y", 1e24);
24-
public static final Constant m = new Constant("m", 1e-3);
25-
public static final Constant u = new Constant("u", 1e-6);
26-
public static final Constant n = new Constant("n", 1e-9);
27-
public static final Constant p = new Constant("p", 1e-12);
28-
public static final Constant f = new Constant("f", 1e-15);
29-
public static final Constant a = new Constant("a", 1e-18);
30-
public static final Constant z = new Constant("z", 1e-21);
31-
public static final Constant y = new Constant("y", 1e-24);
22+
public static final ExpressionConfiguration MATH_CFG = ExpressionConfiguration.builder()
23+
.arraysAllowed(false)
24+
.structuresAllowed(false)
25+
.stripTrailingZeros(true)
26+
.build()
27+
.withAdditionalOperators(Pair.of("%", new PostfixPercentOperator()));
3228

3329
public static ParseResult parseExpression(String expression) {
3430
return parseExpression(expression, Double.NaN, false);
@@ -43,16 +39,19 @@ public static ParseResult parseExpression(String expression, double defaultValue
4339
}
4440

4541
public static ParseResult parseExpression(String expression, double defaultValue, boolean useSiPrefixes) {
46-
if (expression == null || expression.isEmpty()) return ParseResult.success(defaultValue);
47-
Expression e = new Expression(expression);
42+
if (expression == null || expression.isEmpty()) {
43+
return ParseResult.success(EvaluationValue.numberValue(new BigDecimal(defaultValue)));
44+
}
45+
46+
Expression e = new Expression(expression, MATH_CFG);
4847
if (useSiPrefixes) {
49-
e.addConstants(k, M, G, T, P, E, Z, Y, m, u, n, p, f, a, z, y);
48+
SIPrefix.addAllToExpression(e);
5049
}
51-
double result = e.calculate();
52-
if (Double.isNaN(result)) {
53-
return ParseResult.failure(defaultValue, e.getErrorMessage());
50+
try {
51+
return ParseResult.success(e.evaluate());
52+
} catch (BaseException exception) {
53+
return ParseResult.failure(exception);
5454
}
55-
return ParseResult.success(result);
5655
}
5756

5857
public static int clamp(int v, int min, int max) {

src/main/java/com/cleanroommc/modularui/utils/NumberFormat.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.cleanroommc.modularui.utils;
22

3+
import java.math.BigDecimal;
34
import java.math.RoundingMode;
45
import java.text.DecimalFormat;
56
import java.text.DecimalFormatSymbols;
@@ -10,6 +11,8 @@
1011
*/
1112
public class NumberFormat {
1213

14+
public static final BigDecimal TEN_THOUSAND = new BigDecimal(10_000);
15+
1316
public static final Params DEFAULT = paramsBuilder()
1417
.roundingMode(RoundingMode.HALF_UP)
1518
.maxLength(4)
@@ -205,6 +208,32 @@ public static SIPrefix findBestPrefix(double number) {
205208
return prefix;
206209
}
207210

211+
public static SIPrefix findBestPrefix(BigDecimal number) {
212+
if (number.compareTo(BigDecimal.ONE) >= 0 && number.compareTo(TEN_THOUSAND) < 0) return SIPrefix.One;
213+
SIPrefix[] high = SIPrefix.HIGH;
214+
SIPrefix[] low = SIPrefix.LOW;
215+
int n = high.length - 1;
216+
SIPrefix prefix;
217+
if (number.compareTo(TEN_THOUSAND) >= 0) {
218+
int index;
219+
for (index = 0; index < n; index++) {
220+
if (number.compareTo(high[index + 1].bigFactor) < 0) {
221+
break;
222+
}
223+
}
224+
prefix = high[index];
225+
} else {
226+
int index;
227+
for (index = 0; index < n; index++) {
228+
if (number.compareTo(low[index].bigFactor) >= 0) {
229+
break;
230+
}
231+
}
232+
prefix = low[index];
233+
}
234+
return prefix;
235+
}
236+
208237
private static String formatInternal(double number, int maxLength, Params params) {
209238
SIPrefix prefix = findBestPrefix(number);
210239
return formatToString(number * prefix.oneOverFactor, prefix.symbol, maxLength, params);
Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,27 @@
11
package com.cleanroommc.modularui.utils;
22

3+
import com.ezylang.evalex.BaseException;
4+
import com.ezylang.evalex.data.EvaluationValue;
35
import org.jetbrains.annotations.NotNull;
46

57
public class ParseResult {
68

7-
private final double result;
8-
private final String error;
9+
private final EvaluationValue result;
10+
private final BaseException error;
911

10-
public static ParseResult success(double result) {
12+
public static ParseResult success(EvaluationValue result) {
1113
return new ParseResult(result, null);
1214
}
1315

14-
public static ParseResult failure(@NotNull String error) {
15-
return failure(Double.NaN, error);
16+
public static ParseResult failure(@NotNull BaseException error) {
17+
return failure(null, error);
1618
}
1719

18-
public static ParseResult failure(double value, @NotNull String error) {
20+
public static ParseResult failure(EvaluationValue value, @NotNull BaseException error) {
1921
return new ParseResult(value, error);
2022
}
2123

22-
private ParseResult(double result, String error) {
24+
private ParseResult(EvaluationValue result, BaseException error) {
2325
this.result = result;
2426
this.error = error;
2527
}
@@ -33,14 +35,21 @@ public boolean isFailure() {
3335
}
3436

3537
public boolean hasValue() {
36-
return !Double.isNaN(this.result);
38+
return this.result != null;
3739
}
3840

39-
public double getResult() {
41+
public EvaluationValue getResult() {
4042
return result;
4143
}
4244

43-
public String getError() {
45+
public BaseException getError() {
4446
return error;
4547
}
48+
49+
public String getErrorMessage() {
50+
return isFailure() ?
51+
String.format("%s for Token %s at %d:%d",
52+
this.error.getMessage(), this.error.getTokenString(),
53+
this.error.getStartPosition(), this.error.getEndPosition()) : null;
54+
}
4655
}

src/main/java/com/cleanroommc/modularui/utils/SIPrefix.java

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
package com.cleanroommc.modularui.utils;
22

3+
import com.ezylang.evalex.Expression;
4+
5+
import java.math.BigDecimal;
6+
37
public enum SIPrefix {
48

59
Quetta('Q', 30),
610
Ronna('R', 27),
711
Yotta('Y', 24),
812
Zetta('Z', 21),
9-
Exa('E', 18),
13+
Exa('X', 18), // this should actually be E, but this clashes with euler's number e = 2.71...
1014
Peta('P', 15),
1115
Tera('T', 12),
1216
Giga('G', 9),
@@ -24,23 +28,31 @@ public enum SIPrefix {
2428
Ronto('r', -27),
2529
Quecto('q', -30);
2630

27-
2831
public final char symbol;
2932
public final String stringSymbol;
3033
public final double factor;
3134
public final double oneOverFactor;
35+
public final BigDecimal bigFactor;
36+
public final BigDecimal bigOneOverFactor;
3237

3338
SIPrefix(char symbol, int powerOfTen) {
3439
this.symbol = symbol;
3540
this.stringSymbol = symbol != Character.MIN_VALUE ? Character.toString(symbol) : "";
3641
this.factor = Math.pow(10, powerOfTen);
3742
this.oneOverFactor = 1 / this.factor;
43+
this.bigFactor = new BigDecimal(this.factor);
44+
this.bigOneOverFactor = new BigDecimal(this.oneOverFactor);
3845
}
3946

4047
public boolean isOne() {
4148
return this == One;
4249
}
4350

51+
public void addToExpression(Expression e) {
52+
e.with(String.valueOf(this.symbol), this.factor);
53+
}
54+
55+
public static final SIPrefix[] VALUES = values();
4456
public static final SIPrefix[] HIGH = new SIPrefix[values().length / 2];
4557
public static final SIPrefix[] LOW = new SIPrefix[values().length / 2];
4658

@@ -51,4 +63,10 @@ public boolean isOne() {
5163
LOW[i] = values[HIGH.length + 1 + i];
5264
}
5365
}
66+
67+
public static void addAllToExpression(Expression e) {
68+
for (SIPrefix siPrefix : VALUES) {
69+
siPrefix.addToExpression(e);
70+
}
71+
}
5472
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.cleanroommc.modularui.utils.math;
2+
3+
import com.ezylang.evalex.EvaluationException;
4+
import com.ezylang.evalex.Expression;
5+
import com.ezylang.evalex.data.EvaluationValue;
6+
import com.ezylang.evalex.operators.AbstractOperator;
7+
import com.ezylang.evalex.operators.OperatorIfc;
8+
import com.ezylang.evalex.operators.PostfixOperator;
9+
import com.ezylang.evalex.parser.Token;
10+
11+
import java.math.BigDecimal;
12+
13+
@PostfixOperator(precedence = OperatorIfc.OPERATOR_PRECEDENCE_MULTIPLICATIVE - 1)
14+
public class PostfixPercentOperator extends AbstractOperator {
15+
16+
public static final BigDecimal HUNDRED = new BigDecimal(100);
17+
18+
@Override
19+
public EvaluationValue evaluate(Expression expression, Token operatorToken, EvaluationValue... operands) throws EvaluationException {
20+
EvaluationValue operand = operands[0];
21+
22+
if (operand.isNumberValue()) {
23+
return expression.convertValue(
24+
operand.getNumberValue().divide(HUNDRED, expression.getConfiguration().getMathContext()));
25+
} else {
26+
throw EvaluationException.ofUnsupportedDataTypeInOperation(operatorToken);
27+
}
28+
}
29+
}

src/main/java/com/cleanroommc/modularui/widgets/textfield/TextFieldWidget.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,12 @@ public class TextFieldWidget extends BaseTextFieldWidget<TextFieldWidget> {
3535

3636
public double parse(String num) {
3737
ParseResult result = MathUtils.parseExpression(num, this.defaultNumber, true);
38-
double value = result.getResult();
3938
if (result.isFailure()) {
40-
this.mathFailMessage = result.getError();
39+
this.mathFailMessage = result.getErrorMessage();
4140
ModularUI.LOGGER.error("Math expression error in {}: {}", this, this.mathFailMessage);
41+
return defaultNumber;
4242
}
43-
return value;
43+
return result.getResult().getNumberValue().doubleValue();
4444
}
4545

4646
public IStringValue<?> createMathFailMessageValue() {
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
Copyright 2012-2022 Udo Klimaschewski
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
package com.ezylang.evalex;
17+
18+
import lombok.EqualsAndHashCode;
19+
import lombok.Getter;
20+
import lombok.ToString;
21+
22+
/**
23+
* Base exception class used in EvalEx.
24+
*/
25+
@EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false)
26+
@ToString
27+
@Getter
28+
public class BaseException extends Exception {
29+
30+
@EqualsAndHashCode.Include private final int startPosition;
31+
@EqualsAndHashCode.Include private final int endPosition;
32+
@EqualsAndHashCode.Include private final String tokenString;
33+
@EqualsAndHashCode.Include private final String message;
34+
35+
public BaseException(int startPosition, int endPosition, String tokenString, String message) {
36+
super(message);
37+
this.startPosition = startPosition;
38+
this.endPosition = endPosition;
39+
this.tokenString = tokenString;
40+
this.message = super.getMessage();
41+
}
42+
}

0 commit comments

Comments
 (0)