Skip to content

Commit

Permalink
Allowed multi parameter function calling (fixed numbers not being all…
Browse files Browse the repository at this point in the history
…owed in variable/function names; bumped to 1.1.0)

Signed-off-by: AndyNoob <comfortableandy9082@gmail.com>
  • Loading branch information
AndyNoob committed Dec 4, 2023
1 parent 24b6718 commit 71ad48d
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 20 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>me.comfortable_andy</groupId>
<artifactId>math-expressions</artifactId>
<version>1.0.0</version>
<version>1.1.0</version>

<properties>
<maven.compiler.source>17</maven.compiler.source>
Expand Down
36 changes: 21 additions & 15 deletions src/main/java/me/comfortable_andy/math/MathExpression.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiFunction;
import java.util.regex.Matcher;
Expand Down Expand Up @@ -125,7 +122,7 @@ public static MathExpression parse(String expression, Map<String, Double> variab
.map(Part.Operator.OperatorType::getSymbol)
.map(chara -> "\\" + chara)
.collect(Collectors.joining());
final Pattern pattern = Pattern.compile("([A-Za-z]+)|(\\(.+\\))|([" + operators + "])|(-?\\d+(?>\\.\\d+|\\.)?)");
final Pattern pattern = Pattern.compile("([A-Za-z0-9]+)|(\\(.+\\))|([" + operators + "])|(-?\\d+(?>\\.\\d+|\\.)?)");
final Matcher matcher = pattern.matcher(expression);

final List<Part> parts = new ArrayList<>();
Expand All @@ -152,16 +149,18 @@ else if (group.startsWith("(")) {
// there must be an operator in between, or else it would be treated as
// a function.
final String parenthesisStr = group.substring(1, group.length() - 1);
final MathExpression inner = MathExpression.parse(parenthesisStr, variables);

final Part.Parenthesis parenthesis = new Part.Parenthesis(inner);
if (onHold == null) {
part = parenthesis;
part = new Part.Parenthesis(MathExpression.parse(parenthesisStr, variables));
if (last instanceof Part.Evaluable)
parts.add(new Part.Operator(Part.Operator.OperatorType.MULTIPLY));
parts.add(last = new Part.Operator(Part.Operator.OperatorType.MULTIPLY));
}
else {
part = new Part.Function(onHold, parenthesis);
final List<MathExpression> expressions = new ArrayList<>();
for (String s : parenthesisStr.split(",\\s*")) {
expressions.add(MathExpression.parse(s, variables));
}
part = new Part.Function(onHold, expressions);
onHold = null;
}
} else if (group.length() == 1 && operators.contains(group))
Expand Down Expand Up @@ -305,7 +304,7 @@ public double evaluate(Map<String, Double> variables) {
}
}

record Function(String name, Parenthesis parenthesis) implements Part, Evaluable {
record Function(String name, List<MathExpression> expressions) implements Part, Evaluable {

@Override
public List<Class<? extends Part>> validNextParts() {
Expand All @@ -319,12 +318,19 @@ public boolean isComplete() {

@Override
public double evaluate(Map<String, Double> variables) {
final double evaluatedParenthesis = this.parenthesis().evaluate(variables);
final Object[] evaluatedValues = new Object[this.expressions.size()];
for (int i = 0; i < this.expressions.size(); i++) {
evaluatedValues[i] = this.expressions.get(i).evaluate();
}
final Class<?>[] classes = new Class<?>[evaluatedValues.length];
Arrays.fill(classes, double.class);
try {
final Method mathMethod = Math.class.getMethod(this.name, double.class);
return (double) mathMethod.invoke(null, evaluatedParenthesis);
final Method mathMethod = Math.class.getMethod(this.name, classes);
return (double) mathMethod.invoke(null, evaluatedValues);
} catch (ReflectiveOperationException e) {
return this.parenthesis().evaluate(variables);
throw new IllegalStateException("Unknown math function " + this.name + " " + Arrays.toString(classes));
} catch (IllegalArgumentException e) {
throw new IllegalStateException("Argument mismatch for math function " + this.name + " " + Arrays.toString(classes) + " (supplied " + Arrays.toString(evaluatedValues) + ")");
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ public class MathExpressionTest {
"2^(sin(pi))", 1.0,
"sin(toRadians(77))", 0.9743700648,
"sqrt((99*10^2)/(314*455)", 0.263237,
"sqrt(99*10^2/314/455)", 0.263237
"sqrt(99*10^2/314/455)", 0.263237,
"atan2(sqrt(25), 1 * 3 * 10 / 10)", 1.0303768265243125
);

private static final List<String> FAILS = List.of(
Expand All @@ -54,9 +55,9 @@ public void testEvaluatePass() {
expression.setVariable("x", 0);
System.out.println("Expecting: " + colorize(String.valueOf(entry.getValue()), BRIGHT_BLACK_BACK()));
final double evaluated = expression.evaluate();
System.out.println("Evaluated: " + colorize(String.valueOf(evaluated), BLACK_TEXT(), BRIGHT_WHITE_BACK()));
System.out.print("Evaluated: " + colorize(String.valueOf(evaluated), BLACK_TEXT(), BRIGHT_WHITE_BACK()) + " ... ");
assertTrue(Math.abs(entry.getValue() - evaluated) < 0.000001);
System.out.println("Done in " + colorize(System.currentTimeMillis() - time + "", BOLD()) + "ms");
System.out.println(colorize("✓", BRIGHT_GREEN_TEXT()) + " (" + colorize(System.currentTimeMillis() - time + "", BOLD()) + "ms)");
System.out.println();
}
}
Expand All @@ -76,7 +77,7 @@ private static String syntaxHighlight(MathExpression expression) {
if (part instanceof MathExpression.Part.Number number) return colorize(number.number() + "", BRIGHT_WHITE_TEXT());
else if (part instanceof MathExpression.Part.Operator operator) return colorize(operator.operator().getSymbol() + "", BOLD());
else if (part instanceof MathExpression.Part.Parenthesis parenthesis) return "(" + syntaxHighlight(parenthesis.expression()) + ")";
else if (part instanceof MathExpression.Part.Function function) return colorize(function.name(), ITALIC()) + "(" + syntaxHighlight(function.parenthesis().expression()) + ")";
else if (part instanceof MathExpression.Part.Function function) return colorize(function.name(), ITALIC()) + "(" + function.expressions().stream().map(MathExpressionTest::syntaxHighlight).collect(Collectors.joining(", ")) + ")";
else if (part instanceof MathExpression.Part.Variable variable) return colorize(variable.name(), BRIGHT_WHITE_TEXT());
return "UNKNOWN_PART";
}).collect(Collectors.joining(" "));
Expand Down

0 comments on commit 71ad48d

Please sign in to comment.