refactor + version changed
This commit is contained in:
parent
be2ff3d56d
commit
7d3d421017
@ -3,7 +3,7 @@
|
|||||||
<manifest xmlns:a="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:a="http://schemas.android.com/apk/res/android"
|
||||||
package="org.solovyev.android.calculator"
|
package="org.solovyev.android.calculator"
|
||||||
a:versionCode="2"
|
a:versionCode="2"
|
||||||
a:versionName="1.1.0">
|
a:versionName="1.1.1">
|
||||||
|
|
||||||
<uses-sdk a:minSdkVersion="4"
|
<uses-sdk a:minSdkVersion="4"
|
||||||
a:targetSdkVersion="8"/>
|
a:targetSdkVersion="8"/>
|
||||||
|
@ -6,13 +6,17 @@
|
|||||||
package org.solovyev.android.calculator.math;
|
package org.solovyev.android.calculator.math;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.solovyev.android.calculator.CharacterAtPositionFinder;
|
import org.solovyev.android.calculator.CharacterAtPositionFinder;
|
||||||
import org.solovyev.android.calculator.StartsWithFinder;
|
import org.solovyev.android.calculator.StartsWithFinder;
|
||||||
import org.solovyev.android.calculator.model.CalculatorEngine;
|
import org.solovyev.android.calculator.model.CalculatorEngine;
|
||||||
import org.solovyev.common.utils.CollectionsUtils;
|
import org.solovyev.common.utils.CollectionsUtils;
|
||||||
import org.solovyev.common.utils.Finder;
|
import org.solovyev.common.utils.Finder;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import static org.solovyev.common.utils.CollectionsUtils.get;
|
import static org.solovyev.common.utils.CollectionsUtils.get;
|
||||||
|
|
||||||
@ -32,24 +36,67 @@ public enum MathType {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
power_10(300, true, false, "E"),
|
power_10(300, true, false, "E") {
|
||||||
|
@Override
|
||||||
|
protected String getSubstitute(@NotNull String match) {
|
||||||
|
return POWER_10_JSCL;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
postfix_function(400, true, false, Functions.allPostfix),
|
postfix_function(400, true, false, Functions.allPostfix),
|
||||||
unary_operation(500, false, false, "-", "=", "!"),
|
unary_operation(500, false, false, "-", "=", "!"),
|
||||||
binary_operation(600, false, false, "-", "+", "*", "×", "∙", "/", "^"),
|
binary_operation(600, false, false, "-", "+", "*", "×", "∙", "/", "^") {
|
||||||
|
@Override
|
||||||
|
protected String getSubstitute(@NotNull String match) {
|
||||||
|
if ( match.equals("×") || match.equals("∙") ) {
|
||||||
|
return "*";
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
open_group_symbol(800, true, false, "[", "(", "{") {
|
open_group_symbol(800, true, false, "[", "(", "{") {
|
||||||
@Override
|
@Override
|
||||||
public boolean isNeedMultiplicationSignBefore(@NotNull MathType mathTypeBefore) {
|
public boolean isNeedMultiplicationSignBefore(@NotNull MathType mathTypeBefore) {
|
||||||
return super.isNeedMultiplicationSignBefore(mathTypeBefore) && mathTypeBefore != function;
|
return super.isNeedMultiplicationSignBefore(mathTypeBefore) && mathTypeBefore != function;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getSubstitute(@NotNull String match) {
|
||||||
|
return "(";
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
close_group_symbol(900, false, true, "]", ")", "}") {
|
close_group_symbol(900, false, true, "]", ")", "}") {
|
||||||
@Override
|
@Override
|
||||||
public boolean isNeedMultiplicationSignBefore(@NotNull MathType mathTypeBefore) {
|
public boolean isNeedMultiplicationSignBefore(@NotNull MathType mathTypeBefore) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getSubstitute(@NotNull String match) {
|
||||||
|
return ")";
|
||||||
|
}
|
||||||
},
|
},
|
||||||
function(1000, true, true, Functions.allPrefix),
|
|
||||||
|
function(1000, true, true, Functions.allPrefix) {
|
||||||
|
@Override
|
||||||
|
protected String getSubstitute(@NotNull String match) {
|
||||||
|
final String result;
|
||||||
|
|
||||||
|
if (match.equals(Functions.LN)) {
|
||||||
|
result = Functions.LN_JSCL;
|
||||||
|
} else if (match.equals(Functions.SQRT)) {
|
||||||
|
result = Functions.SQRT_JSCL;
|
||||||
|
} else {
|
||||||
|
result = match;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
constant(1100, true, true) {
|
constant(1100, true, true) {
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
@ -104,6 +151,16 @@ public enum MathType {
|
|||||||
return needMultiplicationSignBefore && mathTypeBefore.isNeedMultiplicationSignAfter();
|
return needMultiplicationSignBefore && mathTypeBefore.isNeedMultiplicationSignAfter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int process(@NotNull StringBuilder result, int i, @NotNull String match) {
|
||||||
|
final String substitute = getSubstitute(match);
|
||||||
|
result.append(substitute == null ? match : substitute);
|
||||||
|
return i + match.length() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
protected String getSubstitute(@NotNull String match) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public static final List<String> openGroupSymbols = Arrays.asList("[]", "()", "{}");
|
public static final List<String> openGroupSymbols = Arrays.asList("[]", "()", "{}");
|
||||||
|
|
||||||
@ -186,6 +243,10 @@ public enum MathType {
|
|||||||
this.match = match;
|
this.match = match;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int process(@NotNull StringBuilder result, int i) {
|
||||||
|
return mathType.process(result, i, match);
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public String getMatch() {
|
public String getMatch() {
|
||||||
return match;
|
return match;
|
||||||
|
@ -63,6 +63,9 @@ public enum CalculatorEngine {
|
|||||||
@NotNull
|
@NotNull
|
||||||
private DecimalFormatSymbols decimalGroupSymbols = new DecimalFormatSymbols(Locale.getDefault());
|
private DecimalFormatSymbols decimalGroupSymbols = new DecimalFormatSymbols(Locale.getDefault());
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private ThreadKiller threadKiller = new AndroidThreadKiller();
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public String format(@NotNull Double value) {
|
public String format(@NotNull Double value) {
|
||||||
if (!value.isInfinite() && !value.isNaN()) {
|
if (!value.isInfinite() && !value.isNaN()) {
|
||||||
@ -150,8 +153,7 @@ public enum CalculatorEngine {
|
|||||||
|
|
||||||
if (calculationThreadLocal != null) {
|
if (calculationThreadLocal != null) {
|
||||||
// todo serso: interrupt doesn't stop the thread but it MUST be killed
|
// todo serso: interrupt doesn't stop the thread but it MUST be killed
|
||||||
calculationThreadLocal.setPriority(Thread.MIN_PRIORITY);
|
threadKiller.killThread(calculationThreadLocal);
|
||||||
calculationThreadLocal.interrupt();
|
|
||||||
//calculationThreadLocal.stop();
|
//calculationThreadLocal.stop();
|
||||||
resetInterpreter();
|
resetInterpreter();
|
||||||
}
|
}
|
||||||
@ -251,4 +253,29 @@ public enum CalculatorEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static final String cmds[] = new String[]{"expand", "factorize", "elementary", "simplify", "numeric", "toMathML", "toJava"};*/
|
private static final String cmds[] = new String[]{"expand", "factorize", "elementary", "simplify", "numeric", "toMathML", "toJava"};*/
|
||||||
|
|
||||||
|
// for tests only
|
||||||
|
void setThreadKiller(@NotNull ThreadKiller threadKiller) {
|
||||||
|
this.threadKiller = threadKiller;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static interface ThreadKiller {
|
||||||
|
void killThread(@NotNull Thread thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class AndroidThreadKiller implements ThreadKiller {
|
||||||
|
@Override
|
||||||
|
public void killThread(@NotNull Thread thread) {
|
||||||
|
thread.setPriority(Thread.MIN_PRIORITY);
|
||||||
|
thread.interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ThreadKillerImpl implements ThreadKiller {
|
||||||
|
@Override
|
||||||
|
public void killThread(@NotNull Thread thread) {
|
||||||
|
thread.setPriority(Thread.MIN_PRIORITY);
|
||||||
|
thread.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,9 +8,8 @@ package org.solovyev.android.calculator.model;
|
|||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.solovyev.android.calculator.jscl.JsclOperation;
|
|
||||||
import org.solovyev.android.calculator.StartsWithFinder;
|
import org.solovyev.android.calculator.StartsWithFinder;
|
||||||
import org.solovyev.android.calculator.math.Functions;
|
import org.solovyev.android.calculator.jscl.JsclOperation;
|
||||||
import org.solovyev.android.calculator.math.MathType;
|
import org.solovyev.android.calculator.math.MathType;
|
||||||
import org.solovyev.common.utils.CollectionsUtils;
|
import org.solovyev.common.utils.CollectionsUtils;
|
||||||
import org.solovyev.common.utils.FilterType;
|
import org.solovyev.common.utils.FilterType;
|
||||||
@ -26,49 +25,39 @@ class ToJsclTextProcessor implements TextProcessor<PreparedExpression> {
|
|||||||
public PreparedExpression process(@NotNull String s) throws ParseException {
|
public PreparedExpression process(@NotNull String s) throws ParseException {
|
||||||
|
|
||||||
final StartsWithFinder startsWithFinder = new StartsWithFinder(s, 0);
|
final StartsWithFinder startsWithFinder = new StartsWithFinder(s, 0);
|
||||||
final StringBuilder sb = new StringBuilder();
|
final StringBuilder result = new StringBuilder();
|
||||||
|
|
||||||
MathType.Result mathTypeResult = null;
|
MathType.Result mathTypeResult = null;
|
||||||
|
MathType mathTypeBefore;
|
||||||
|
|
||||||
for (int i = 0; i < s.length(); i++) {
|
for (int i = 0; i < s.length(); i++) {
|
||||||
char ch = s.charAt(i);
|
|
||||||
startsWithFinder.setI(i);
|
startsWithFinder.setI(i);
|
||||||
|
|
||||||
if ( Character.isWhitespace(ch)) {
|
if ( Character.isWhitespace(s.charAt(i))) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
mathTypeResult = checkMultiplicationSignBeforeFunction(sb, s, i, mathTypeResult);
|
mathTypeBefore = mathTypeResult == null ? null : mathTypeResult.getMathType();
|
||||||
|
|
||||||
final MathType mathType = mathTypeResult.getMathType();
|
mathTypeResult = MathType.getType(s, i);
|
||||||
if (mathType == MathType.open_group_symbol) {
|
|
||||||
sb.append('(');
|
|
||||||
} else if (mathType == MathType.close_group_symbol) {
|
|
||||||
sb.append(')');
|
|
||||||
} else if (ch == '×' || ch == '∙') {
|
|
||||||
sb.append("*");
|
|
||||||
} else if (mathType == MathType.power_10) {
|
|
||||||
sb.append(MathType.POWER_10_JSCL);
|
|
||||||
} else if (mathType == MathType.function) {
|
|
||||||
sb.append(toJsclFunction(mathTypeResult.getMatch()));
|
|
||||||
i += mathTypeResult.getMatch().length() - 1;
|
|
||||||
|
|
||||||
// NOTE: fix for jscl for EMPTY functions processing (see tests)
|
if (mathTypeBefore != null) {
|
||||||
startsWithFinder.setI(i + 1);
|
|
||||||
if ( i < s.length() && CollectionsUtils.get(MathType.openGroupSymbols, startsWithFinder) != null) {
|
final MathType current = mathTypeResult.getMathType();
|
||||||
|
|
||||||
|
if (current.isNeedMultiplicationSignBefore(mathTypeBefore)) {
|
||||||
|
result.append("*");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mathTypeBefore == MathType.function && CollectionsUtils.get(MathType.openGroupSymbols, startsWithFinder) != null) {
|
||||||
throw new ParseException("Empty function: " + mathTypeResult.getMatch());
|
throw new ParseException("Empty function: " + mathTypeResult.getMatch());
|
||||||
/*i += 2;
|
|
||||||
sb.append("(" + SPECIAL_STRING + ")");
|
|
||||||
mathTypeResult = new MathType.Result(MathType.close_group_symbol, ")");*/
|
|
||||||
}
|
|
||||||
} else if (mathType == MathType.constant) {
|
|
||||||
sb.append(mathTypeResult.getMatch());
|
|
||||||
i += mathTypeResult.getMatch().length() - 1;
|
|
||||||
} else {
|
|
||||||
sb.append(ch);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return replaceVariables(sb.toString());
|
i = mathTypeResult.process(result, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return replaceVariables(result.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@ -167,21 +156,6 @@ class ToJsclTextProcessor implements TextProcessor<PreparedExpression> {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static String toJsclFunction(@NotNull String function) {
|
|
||||||
final String result;
|
|
||||||
|
|
||||||
if (function.equals(Functions.LN)) {
|
|
||||||
result = Functions.LN_JSCL;
|
|
||||||
} else if (function.equals(Functions.SQRT)) {
|
|
||||||
result = Functions.SQRT_JSCL;
|
|
||||||
} else {
|
|
||||||
result = function;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class EndsWithFinder implements Finder<String> {
|
private static class EndsWithFinder implements Finder<String> {
|
||||||
|
|
||||||
private int i;
|
private int i;
|
||||||
@ -203,27 +177,6 @@ class ToJsclTextProcessor implements TextProcessor<PreparedExpression> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static MathType.Result checkMultiplicationSignBeforeFunction(@NotNull StringBuilder sb,
|
|
||||||
@NotNull String s,
|
|
||||||
int i,
|
|
||||||
@Nullable MathType.Result mathTypeBeforeResult) {
|
|
||||||
final MathType.Result result = MathType.getType(s, i);
|
|
||||||
|
|
||||||
if (i > 0) {
|
|
||||||
|
|
||||||
final MathType current = result.getMathType();
|
|
||||||
assert mathTypeBeforeResult != null;
|
|
||||||
final MathType before = mathTypeBeforeResult.getMathType();
|
|
||||||
|
|
||||||
if (current.isNeedMultiplicationSignBefore(before)) {
|
|
||||||
sb.append("*");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String wrap(@NotNull JsclOperation operation, @NotNull String s) {
|
public static String wrap(@NotNull JsclOperation operation, @NotNull String s) {
|
||||||
return operation.name() + "(\"" + s + "\");";
|
return operation.name() + "(\"" + s + "\");";
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ public class CalculatorEngineTest {
|
|||||||
public static void setUp() throws Exception {
|
public static void setUp() throws Exception {
|
||||||
CalculatorEngine.instance.init(null, null);
|
CalculatorEngine.instance.init(null, null);
|
||||||
CalculatorEngine.instance.setPrecision(3);
|
CalculatorEngine.instance.setPrecision(3);
|
||||||
|
CalculatorEngine.instance.setThreadKiller(new CalculatorEngine.ThreadKillerImpl());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
Loading…
Reference in New Issue
Block a user