refactor + version changed

This commit is contained in:
serso 2011-10-23 13:24:43 +04:00
parent c5f8633940
commit 4c59822396
5 changed files with 116 additions and 74 deletions

View File

@ -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"/>

View File

@ -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;

View File

@ -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();
}
}
} }

View File

@ -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 + "\");";
} }

View File

@ -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