diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 92d223ac..21af707e 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -3,7 +3,7 @@ + a:versionName="1.1.1"> diff --git a/src/main/java/org/solovyev/android/calculator/math/MathType.java b/src/main/java/org/solovyev/android/calculator/math/MathType.java index 3e1b6752..170343e8 100644 --- a/src/main/java/org/solovyev/android/calculator/math/MathType.java +++ b/src/main/java/org/solovyev/android/calculator/math/MathType.java @@ -6,13 +6,17 @@ package org.solovyev.android.calculator.math; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.solovyev.android.calculator.CharacterAtPositionFinder; import org.solovyev.android.calculator.StartsWithFinder; import org.solovyev.android.calculator.model.CalculatorEngine; import org.solovyev.common.utils.CollectionsUtils; 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; @@ -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), 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, "[", "(", "{") { @Override public boolean isNeedMultiplicationSignBefore(@NotNull MathType mathTypeBefore) { return super.isNeedMultiplicationSignBefore(mathTypeBefore) && mathTypeBefore != function; } + + @Override + protected String getSubstitute(@NotNull String match) { + return "("; + } }, + close_group_symbol(900, false, true, "]", ")", "}") { @Override public boolean isNeedMultiplicationSignBefore(@NotNull MathType mathTypeBefore) { 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) { @NotNull @Override @@ -104,6 +151,16 @@ public enum MathType { 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 openGroupSymbols = Arrays.asList("[]", "()", "{}"); @@ -186,6 +243,10 @@ public enum MathType { this.match = match; } + public int process(@NotNull StringBuilder result, int i) { + return mathType.process(result, i, match); + } + @NotNull public String getMatch() { return match; diff --git a/src/main/java/org/solovyev/android/calculator/model/CalculatorEngine.java b/src/main/java/org/solovyev/android/calculator/model/CalculatorEngine.java index ee6f78a4..3082e3d7 100644 --- a/src/main/java/org/solovyev/android/calculator/model/CalculatorEngine.java +++ b/src/main/java/org/solovyev/android/calculator/model/CalculatorEngine.java @@ -63,6 +63,9 @@ public enum CalculatorEngine { @NotNull private DecimalFormatSymbols decimalGroupSymbols = new DecimalFormatSymbols(Locale.getDefault()); + @NotNull + private ThreadKiller threadKiller = new AndroidThreadKiller(); + @NotNull public String format(@NotNull Double value) { if (!value.isInfinite() && !value.isNaN()) { @@ -150,8 +153,7 @@ public enum CalculatorEngine { if (calculationThreadLocal != null) { // todo serso: interrupt doesn't stop the thread but it MUST be killed - calculationThreadLocal.setPriority(Thread.MIN_PRIORITY); - calculationThreadLocal.interrupt(); + threadKiller.killThread(calculationThreadLocal); //calculationThreadLocal.stop(); resetInterpreter(); } @@ -251,4 +253,29 @@ public enum CalculatorEngine { } 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(); + } + } } diff --git a/src/main/java/org/solovyev/android/calculator/model/ToJsclTextProcessor.java b/src/main/java/org/solovyev/android/calculator/model/ToJsclTextProcessor.java index a71dcd6b..bc339503 100644 --- a/src/main/java/org/solovyev/android/calculator/model/ToJsclTextProcessor.java +++ b/src/main/java/org/solovyev/android/calculator/model/ToJsclTextProcessor.java @@ -8,9 +8,8 @@ package org.solovyev.android.calculator.model; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.solovyev.android.calculator.jscl.JsclOperation; 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.common.utils.CollectionsUtils; import org.solovyev.common.utils.FilterType; @@ -26,49 +25,39 @@ class ToJsclTextProcessor implements TextProcessor { public PreparedExpression process(@NotNull String s) throws ParseException { final StartsWithFinder startsWithFinder = new StartsWithFinder(s, 0); - final StringBuilder sb = new StringBuilder(); + final StringBuilder result = new StringBuilder(); MathType.Result mathTypeResult = null; + MathType mathTypeBefore; + for (int i = 0; i < s.length(); i++) { - char ch = s.charAt(i); startsWithFinder.setI(i); - if ( Character.isWhitespace(ch)) { + if ( Character.isWhitespace(s.charAt(i))) { continue; } - mathTypeResult = checkMultiplicationSignBeforeFunction(sb, s, i, mathTypeResult); + mathTypeBefore = mathTypeResult == null ? null : mathTypeResult.getMathType(); - final MathType mathType = mathTypeResult.getMathType(); - 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; + mathTypeResult = MathType.getType(s, i); - // NOTE: fix for jscl for EMPTY functions processing (see tests) - startsWithFinder.setI(i + 1); - if ( i < s.length() && CollectionsUtils.get(MathType.openGroupSymbols, startsWithFinder) != null) { - throw new ParseException("Empty function: " + mathTypeResult.getMatch()); - /*i += 2; - sb.append("(" + SPECIAL_STRING + ")"); - mathTypeResult = new MathType.Result(MathType.close_group_symbol, ")");*/ + if (mathTypeBefore != null) { + + final MathType current = mathTypeResult.getMathType(); + + if (current.isNeedMultiplicationSignBefore(mathTypeBefore)) { + result.append("*"); } - } else if (mathType == MathType.constant) { - sb.append(mathTypeResult.getMatch()); - i += mathTypeResult.getMatch().length() - 1; - } else { - sb.append(ch); } + + if (mathTypeBefore == MathType.function && CollectionsUtils.get(MathType.openGroupSymbols, startsWithFinder) != null) { + throw new ParseException("Empty function: " + mathTypeResult.getMatch()); + } + + i = mathTypeResult.process(result, i); } - return replaceVariables(sb.toString()); + return replaceVariables(result.toString()); } @NotNull @@ -167,21 +156,6 @@ class ToJsclTextProcessor implements TextProcessor { 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 { private int i; @@ -203,27 +177,6 @@ class ToJsclTextProcessor implements TextProcessor { } } - @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) { return operation.name() + "(\"" + s + "\");"; } diff --git a/src/test/java/org/solovyev/android/calculator/model/CalculatorEngineTest.java b/src/test/java/org/solovyev/android/calculator/model/CalculatorEngineTest.java index 8d6b7e50..0f533914 100644 --- a/src/test/java/org/solovyev/android/calculator/model/CalculatorEngineTest.java +++ b/src/test/java/org/solovyev/android/calculator/model/CalculatorEngineTest.java @@ -25,6 +25,7 @@ public class CalculatorEngineTest { public static void setUp() throws Exception { CalculatorEngine.instance.init(null, null); CalculatorEngine.instance.setPrecision(3); + CalculatorEngine.instance.setThreadKiller(new CalculatorEngine.ThreadKillerImpl()); } @Test