From ef74d2c584c984a00f7157b72b7046ab151e8908 Mon Sep 17 00:00:00 2001 From: serso Date: Mon, 3 Oct 2011 02:02:14 +0400 Subject: [PATCH] var activity --- res/layout/var_edit.xml | 2 +- .../android/calculator/CalculatorModel.java | 70 +++++++-- .../calculator/CalculatorVarsActivity.java | 6 +- .../android/calculator/CalculatorView.java | 2 +- .../calculator/CharacterAtPositionFinder.java | 38 +++++ .../android/calculator/StartsWithFinder.java | 38 +++++ .../calculator/ToJsclPreprocessor.java | 140 ++++++++++-------- .../android/calculator/VarsRegister.java | 23 ++- .../android/calculator/math/Functions.java | 59 ++++---- .../calculator/math/MathEntityComparator.java | 22 +++ .../calculator/math/MathEntityType.java | 86 ++++++++--- .../calculator/CalculatorModelTest.java | 21 ++- 12 files changed, 376 insertions(+), 131 deletions(-) create mode 100644 src/main/java/org/solovyev/android/calculator/CharacterAtPositionFinder.java create mode 100644 src/main/java/org/solovyev/android/calculator/StartsWithFinder.java create mode 100644 src/main/java/org/solovyev/android/calculator/math/MathEntityComparator.java diff --git a/res/layout/var_edit.xml b/res/layout/var_edit.xml index c7910d30..6d5edfad 100644 --- a/res/layout/var_edit.xml +++ b/res/layout/var_edit.xml @@ -37,7 +37,7 @@ diff --git a/src/main/java/org/solovyev/android/calculator/CalculatorModel.java b/src/main/java/org/solovyev/android/calculator/CalculatorModel.java index 3f195c86..d6798c56 100644 --- a/src/main/java/org/solovyev/android/calculator/CalculatorModel.java +++ b/src/main/java/org/solovyev/android/calculator/CalculatorModel.java @@ -26,7 +26,10 @@ import org.solovyev.util.math.Complex; public class CalculatorModel { @NotNull - private final Interpreter interpreter; + private Interpreter interpreter; + + @NotNull + private final Object interpreterMonitor = new Object(); private int numberOfFractionDigits = 5; @@ -38,30 +41,41 @@ public class CalculatorModel { private static CalculatorModel instance; - private CalculatorModel(@Nullable Context context) throws EvalError { + private CalculatorModel(@Nullable Context context) { load(context); - interpreter = new Interpreter(); - interpreter.eval(ToJsclPreprocessor.wrap(JsclOperation.importCommands, "/jscl/editorengine/commands")); + reset(); + } + + public void reset() { + synchronized (interpreterMonitor) { + try { + interpreter = new Interpreter(); + interpreter.eval(ToJsclPreprocessor.wrap(JsclOperation.importCommands, "/jscl/editorengine/commands")); + + /*for (Var var : varsRegister.getVars()) { + if (!var.isSystem()) { + exec(var.getName() + "=" + var.getValue() + ";"); + } + }*/ + } catch (EvalError evalError) { + throw new RuntimeException(evalError); + } + } } public String evaluate(@NotNull JsclOperation operation, @NotNull String expression) throws EvalError, ParseException { final StringBuilder sb = new StringBuilder(); -/* - for (Var var : varsRegister.getVars()) { - if (!var.isSystem()) { - sb.append(var.getName()).append("=").append(var.getValue()).append(";"); - } - } -*/ - sb.append(preprocessor.process(expression)); //Log.d(CalculatorModel.class.getName(), "Preprocessed expression: " + preprocessedExpression); - Object evaluationObject = interpreter.eval(ToJsclPreprocessor.wrap(operation, sb.toString())); + final Object evaluationObject; + synchronized (interpreterMonitor) { + evaluationObject = interpreter.eval(ToJsclPreprocessor.wrap(operation, sb.toString())); + } String result = String.valueOf(evaluationObject).trim(); try { @@ -120,7 +134,7 @@ public class CalculatorModel { return MathUtils.round(dResult, numberOfFractionDigits); } - public synchronized void load(@Nullable Context context) { + public synchronized void load(@Nullable Context context) { if (context != null) { final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); @@ -154,7 +168,7 @@ public class CalculatorModel { } public static CalculatorModel getInstance() { - if (!isLoaded()) { + if (!isLoaded()) { throw new RuntimeException("CalculatorModel must be instantiated!"); } @@ -165,8 +179,34 @@ public class CalculatorModel { return instance != null; } + + private void exec(String str) throws EvalError { + interpreter.eval(str); + } + + private String eval(String str) throws EvalError { + return interpreter.eval(commands(str)).toString(); + } + + @NotNull public VarsRegister getVarsRegister() { return varsRegister; } + + String commands(String str) { + return commands(str, false); + } + + String commands(String str, boolean found) { + for (int i = 0; i < cmds.length; i++) { + int n = str.length() - cmds[i].length() - 1; + if (n >= 0 && (" " + cmds[i].toLowerCase()).equals(str.substring(n))) + return commands(str.substring(0, n), true) + "." + cmds[i] + "()"; + } + str = str.replaceAll("\n", ""); + return found ? "jscl.math.Expression.valueOf(\"" + str + "\")" : str; + } + + static final String cmds[] = new String[]{"expand", "factorize", "elementary", "simplify", "numeric", "toMathML", "toJava"}; } diff --git a/src/main/java/org/solovyev/android/calculator/CalculatorVarsActivity.java b/src/main/java/org/solovyev/android/calculator/CalculatorVarsActivity.java index 3a898056..2d0a36b5 100644 --- a/src/main/java/org/solovyev/android/calculator/CalculatorVarsActivity.java +++ b/src/main/java/org/solovyev/android/calculator/CalculatorVarsActivity.java @@ -177,10 +177,10 @@ public class CalculatorVarsActivity extends ListActivity { Toast.makeText(CalculatorVarsActivity.this, error, Toast.LENGTH_LONG).show(); createEditVariableDialog(editedInstance, name, value, description); } else { - if (editedInstance != null && !editedInstance.getName().equals(name)) { - varsRegister.addVar(editedInstance.getName(), varBuilder); - } else { + if ( editedInstance == null ) { CalculatorVarsActivity.this.adapter.add(varsRegister.addVar(null, varBuilder)); + } else { + varsRegister.addVar(editedInstance.getName(), varBuilder); } varsRegister.save(CalculatorVarsActivity.this); diff --git a/src/main/java/org/solovyev/android/calculator/CalculatorView.java b/src/main/java/org/solovyev/android/calculator/CalculatorView.java index 8c929e9e..bc6c63b6 100644 --- a/src/main/java/org/solovyev/android/calculator/CalculatorView.java +++ b/src/main/java/org/solovyev/android/calculator/CalculatorView.java @@ -192,7 +192,7 @@ public class CalculatorView implements CursorControl, HistoryControl { + + private int i; + + @NotNull + private final String targetString; + + public CharacterAtPositionFinder(@NotNull String targetString, int i) { + this.targetString = targetString; + this.i = i; + } + + @Override + public boolean isFound(@Nullable Character s) { + return s != null && s.equals(targetString.charAt(i)); + } + + public void setI(int i) { + this.i = i; + } +} diff --git a/src/main/java/org/solovyev/android/calculator/StartsWithFinder.java b/src/main/java/org/solovyev/android/calculator/StartsWithFinder.java new file mode 100644 index 00000000..c4e7b94e --- /dev/null +++ b/src/main/java/org/solovyev/android/calculator/StartsWithFinder.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2009-2011. Created by serso aka se.solovyev. + * For more information, please, contact se.solovyev@gmail.com + * or visit http://se.solovyev.org + */ + +package org.solovyev.android.calculator; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.solovyev.common.utils.Finder; + +/** +* User: serso +* Date: 10/3/11 +* Time: 12:49 AM +*/ +public class StartsWithFinder implements Finder { + + private int i; + + @NotNull + private final String targetString; + + public StartsWithFinder(@NotNull String targetString, int i) { + this.targetString = targetString; + this.i = i; + } + + @Override + public boolean isFound(@Nullable String s) { + return targetString.startsWith(s, i); + } + + public void setI(int i) { + this.i = i; + } +} diff --git a/src/main/java/org/solovyev/android/calculator/ToJsclPreprocessor.java b/src/main/java/org/solovyev/android/calculator/ToJsclPreprocessor.java index 116a2862..0b510d7c 100644 --- a/src/main/java/org/solovyev/android/calculator/ToJsclPreprocessor.java +++ b/src/main/java/org/solovyev/android/calculator/ToJsclPreprocessor.java @@ -19,46 +19,88 @@ public class ToJsclPreprocessor implements Preprocessor { @Override @NotNull public String process(@NotNull String s) { + + final StartsWithFinder startsWithFinder = new StartsWithFinder(s, 0); final StringBuilder sb = new StringBuilder(); + boolean constantBefore = false; for (int i = 0; i < s.length(); i++) { char ch = s.charAt(i); - if ( MathEntityType.getType(ch) == MathEntityType.postfix_function ) { - int start = getPostfixFunctionStart(s, i - 1); - } - } + startsWithFinder.setI(i); - final StartsWithFinder startsWithFinder = new StartsWithFinder(s); - for (int i = 0; i < s.length(); i++) { - char ch = s.charAt(i); - - checkMultiplicationSignBeforeFunction(sb, s, i); + checkMultiplicationSignBeforeFunction(sb, s, i, constantBefore); + constantBefore = false; if (MathEntityType.openGroupSymbols.contains(ch)) { sb.append('('); } else if (MathEntityType.closeGroupSymbols.contains(ch)) { sb.append(')'); - } else if (ch == 'π') { - sb.append("pi"); } else if (ch == '×' || ch == '∙') { sb.append("*"); } else { - startsWithFinder.setI(i); - final String function = CollectionsUtils.get(MathEntityType.prefixFunctions, startsWithFinder); - if (function != null) { - sb.append(toJsclFunction(function)); - i += function.length() - 1; - } else if (ch == 'e') { - sb.append("exp(1)"); - } else if (ch == 'i') { - sb.append("sqrt(-1)"); + String entity = CollectionsUtils.get(MathEntityType.prefixFunctions, startsWithFinder); + if (entity == null) { + entity = CollectionsUtils.get(CalculatorModel.getInstance().getVarsRegister().getVarNames(), startsWithFinder); + if (entity == null) { + sb.append(ch); + } else { + sb.append(entity); + i += entity.length() - 1; + constantBefore = true; + } } else { - sb.append(ch); + sb.append(toJsclFunction(entity)); + i += entity.length() - 1; } } } - return sb.toString(); + return replaceVariables(sb.toString()); + } + + private String replaceVariables(@NotNull final String s) { + final StartsWithFinder startsWithFinder = new StartsWithFinder(s, 0); + + final StringBuilder result = new StringBuilder(); + for (int i = 0; i < s.length(); i++) { + startsWithFinder.setI(i); + + int offset = 0; + String functionName = CollectionsUtils.get(MathEntityType.prefixFunctions, startsWithFinder); + if (functionName == null) { + String varName = CollectionsUtils.get(CalculatorModel.getInstance().getVarsRegister().getVarNames(), startsWithFinder); + if (varName != null) { + final Var var = CalculatorModel.getInstance().getVarsRegister().getVar(varName); + if (var != null) { + result.append(var.getValue()); + offset = varName.length(); + } + } + } else { + result.append(functionName); + offset = functionName.length(); + } + + + if (offset == 0) { + result.append(s.charAt(i)); + } else { + i += offset - 1; + } + } + + return result.toString(); + } + + private void replaceVariables(StringBuilder sb, String s, int i, @NotNull StartsWithFinder startsWithFinder) { + for (Var var : CalculatorModel.getInstance().getVarsRegister().getVars()) { + if (!var.isSystem()) { + if (s.startsWith(var.getName(), i)) { + if (CollectionsUtils.get(MathEntityType.prefixFunctions, startsWithFinder) == null) { + } + } + } + } } public int getPostfixFunctionStart(@NotNull String s, int position) { @@ -66,17 +108,16 @@ public class ToJsclPreprocessor implements Preprocessor { int numberOfOpenGroups = 0; int result = position; - for ( ; result >= 0; result-- ) { - char ch = s.charAt(result); + for (; result >= 0; result--) { - final MathEntityType mathEntityType = MathEntityType.getType(ch); + final MathEntityType mathEntityType = MathEntityType.getType(s, result); - if ( mathEntityType != null ) { - if ( CollectionsUtils.contains(mathEntityType, MathEntityType.digit, MathEntityType.dot) ) { + if (mathEntityType != null) { + if (CollectionsUtils.contains(mathEntityType, MathEntityType.digit, MathEntityType.dot)) { // continue - } else if (MathEntityType.closeGroupSymbols.contains(ch)) { + } else if (MathEntityType.closeGroupSymbols.contains(s.charAt(result))) { numberOfOpenGroups++; - } else if (MathEntityType.openGroupSymbols.contains(ch)) { + } else if (MathEntityType.openGroupSymbols.contains(s.charAt(result))) { numberOfOpenGroups--; } else { if (stop(s, numberOfOpenGroups, result)) break; @@ -90,12 +131,12 @@ public class ToJsclPreprocessor implements Preprocessor { } private boolean stop(String s, int numberOfOpenGroups, int i) { - if ( numberOfOpenGroups == 0 ) { + if (numberOfOpenGroups == 0) { if (i > 0) { final EndsWithFinder endsWithFinder = new EndsWithFinder(s); - endsWithFinder.setI(i+1); - if ( !CollectionsUtils.contains(MathEntityType.prefixFunctions, FilterType.included, endsWithFinder) ) { - MathEntityType type = MathEntityType.getType(s.charAt(i)); + endsWithFinder.setI(i + 1); + if (!CollectionsUtils.contains(MathEntityType.prefixFunctions, FilterType.included, endsWithFinder)) { + MathEntityType type = MathEntityType.getType(s, i); if (type != null && type != MathEntityType.constant) { return true; } @@ -123,27 +164,6 @@ public class ToJsclPreprocessor implements Preprocessor { return result; } - private static class StartsWithFinder implements Finder { - - private int i; - - @NotNull - private final String targetString; - - private StartsWithFinder(@NotNull String targetString) { - this.targetString = targetString; - } - - @Override - public boolean isFound(@Nullable String s) { - return targetString.startsWith(s, i); - } - - public void setI(int i) { - this.i = i; - } - } - private static class EndsWithFinder implements Finder { private int i; @@ -165,25 +185,25 @@ public class ToJsclPreprocessor implements Preprocessor { } } - private static void checkMultiplicationSignBeforeFunction(@NotNull StringBuilder sb, @NotNull String s, int i) { + private static void checkMultiplicationSignBeforeFunction(@NotNull StringBuilder sb, @NotNull String s, int i, boolean constantBefore) { if (i > 0) { // get character before function char chBefore = s.charAt(i - 1); char ch = s.charAt(i); final MathEntityType mathTypeBefore = MathEntityType.getType(String.valueOf(chBefore)); - final MathEntityType mathType = MathEntityType.getType(String.valueOf(ch)); + final MathEntityType mathType = MathEntityType.getType(s, i); - if (mathTypeBefore != MathEntityType.binary_operation && + if (constantBefore || (mathTypeBefore != MathEntityType.binary_operation && mathTypeBefore != MathEntityType.unary_operation && - mathTypeBefore != MathEntityType.function && - !MathEntityType.openGroupSymbols.contains(chBefore)) { + mathTypeBefore != MathEntityType.function && + !MathEntityType.openGroupSymbols.contains(chBefore))) { if (mathType == MathEntityType.constant) { sb.append("*"); } else if (MathEntityType.openGroupSymbols.contains(ch) && mathTypeBefore != null) { sb.append("*"); - } else if (mathType == MathEntityType.digit && mathTypeBefore != MathEntityType.digit && mathTypeBefore != MathEntityType.dot) { + } else if (mathType == MathEntityType.digit && ((mathTypeBefore != MathEntityType.digit && mathTypeBefore != MathEntityType.dot) || constantBefore) ) { sb.append("*"); } else { for (String function : MathEntityType.prefixFunctions) { diff --git a/src/main/java/org/solovyev/android/calculator/VarsRegister.java b/src/main/java/org/solovyev/android/calculator/VarsRegister.java index 9441d79e..1962aab2 100644 --- a/src/main/java/org/solovyev/android/calculator/VarsRegister.java +++ b/src/main/java/org/solovyev/android/calculator/VarsRegister.java @@ -13,6 +13,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.simpleframework.xml.Serializer; import org.simpleframework.xml.core.Persister; +import org.solovyev.android.calculator.math.MathEntityComparator; import org.solovyev.android.calculator.math.MathEntityType; import org.solovyev.common.utils.CollectionsUtils; import org.solovyev.common.utils.Finder; @@ -46,20 +47,34 @@ public class VarsRegister { public Var addVar(@Nullable String name, @NotNull Var.Builder builder) { final Var var = builder.create(); - final Var varFromRegister = getVar(name == null ? var.getName() : name); + Var varFromRegister = getVar(name == null ? var.getName() : name); if (varFromRegister == null) { + varFromRegister = var; vars.add(var); } else { varFromRegister.copy(var); } - return var; + return varFromRegister; } public void remove (@NotNull Var var) { this.vars.remove(var); } + @NotNull + public List getVarNames () { + final List result = new ArrayList(); + + for (Var var : vars) { + result.add(var.getName()); + } + + Collections.sort(result, new MathEntityComparator()); + + return result; + } + @Nullable public Var getVar(@NotNull final String name) { return CollectionsUtils.get(vars, new Finder() { @@ -121,7 +136,7 @@ public class VarsRegister { } else if (systemVarName.equals("π")) { systemVar = new Var.Builder(systemVarName, Math.PI).setSystem(true).create(); } else if (systemVarName.equals("i")) { - systemVar = new Var.Builder(systemVarName, "√(-1)").setSystem(true).create(); + systemVar = new Var.Builder(systemVarName, "sqrt(-1)").setSystem(true).create(); } else { throw new IllegalArgumentException(systemVarName + " is not supported yet!"); } @@ -157,7 +172,7 @@ public class VarsRegister { throw new RuntimeException(e); } - editor.putString(context.getString(R.string.p_calc_vars),sw.toString()); + editor.putString(context.getString(R.string.p_calc_vars), sw.toString()); editor.commit(); } diff --git a/src/main/java/org/solovyev/android/calculator/math/Functions.java b/src/main/java/org/solovyev/android/calculator/math/Functions.java index 4907efe6..98d0ace0 100644 --- a/src/main/java/org/solovyev/android/calculator/math/Functions.java +++ b/src/main/java/org/solovyev/android/calculator/math/Functions.java @@ -5,41 +5,48 @@ package org.solovyev.android.calculator.math; -import org.jetbrains.annotations.NonNls; - -import java.util.Arrays; -import java.util.List; +import java.util.*; /** * User: serso * Date: 9/17/11 * Time: 10:01 PM */ -public interface Functions { +public class Functions { - String SIN = "sin"; - String SINH = "sinh"; - String ASIN = "asin"; - String ASINH = "asinh"; - String COS = "cos"; - String COSH = "cosh"; - String ACOS = "acos"; - String ACOSH = "acosh"; - String TAN = "tan"; - String TANH = "tanh"; - String ATAN = "atan"; - String ATANH = "atanh"; - String LOG = "log"; - String LN = "ln"; - String MOD = "mod"; - String EXP = "exp"; - String SQRT_SIGN = "√"; - String SQRT = "sqrt"; + public final static String SIN = "sin"; + public final static String SINH = "sinh"; + public final static String ASIN = "asin"; + public final static String ASINH = "asinh"; + public final static String COS = "cos"; + public final static String COSH = "cosh"; + public final static String ACOS = "acos"; + public final static String ACOSH = "acosh"; + public final static String TAN = "tan"; + public final static String TANH = "tanh"; + public final static String ATAN = "atan"; + public final static String ATANH = "atanh"; + public final static String LOG = "log"; + public final static String LN = "ln"; + public final static String MOD = "mod"; + public final static String EXP = "exp"; + public final static String SQRT_SIGN = "√"; + public final static String SQRT = "sqrt"; - public static final List allPrefix = Arrays.asList(SIN, SINH, ASIN, ASINH, COS, COSH, ACOS, ACOSH, TAN, TANH, ATAN, ATANH, LOG, LN, MOD, SQRT, SQRT_SIGN, EXP); + public static final List allPrefix; - Character FACT = '!'; - Character DEGREE = '°'; + static { + final List functions = new ArrayList(Arrays.asList(SIN, SINH, ASIN, ASINH, COS, COSH, ACOS, ACOSH, TAN, TANH, ATAN, ATANH, LOG, LN, MOD, SQRT, SQRT_SIGN, EXP)); + Collections.sort(functions, new MathEntityComparator()); + allPrefix = functions; + } + + public final static Character FACT = '!'; + public final static Character DEGREE = '°'; public static final List allPostfix = Arrays.asList(FACT, DEGREE); + + private Functions() { + throw new AssertionError("Not allowed!"); + } } diff --git a/src/main/java/org/solovyev/android/calculator/math/MathEntityComparator.java b/src/main/java/org/solovyev/android/calculator/math/MathEntityComparator.java new file mode 100644 index 00000000..49aac482 --- /dev/null +++ b/src/main/java/org/solovyev/android/calculator/math/MathEntityComparator.java @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2009-2011. Created by serso aka se.solovyev. + * For more information, please, contact se.solovyev@gmail.com + * or visit http://se.solovyev.org + */ + +package org.solovyev.android.calculator.math; + +import java.util.Comparator; + +/** + * User: serso + * Date: 10/3/11 + * Time: 12:30 AM + */ +public class MathEntityComparator implements Comparator { + + @Override + public int compare(String s, String s1) { + return s1.length() - s.length(); + } +} diff --git a/src/main/java/org/solovyev/android/calculator/math/MathEntityType.java b/src/main/java/org/solovyev/android/calculator/math/MathEntityType.java index 50c00dc0..a18d216b 100644 --- a/src/main/java/org/solovyev/android/calculator/math/MathEntityType.java +++ b/src/main/java/org/solovyev/android/calculator/math/MathEntityType.java @@ -8,6 +8,8 @@ package org.solovyev.android.calculator.math; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.solovyev.android.calculator.CalculatorModel; +import org.solovyev.android.calculator.CharacterAtPositionFinder; +import org.solovyev.android.calculator.StartsWithFinder; import org.solovyev.android.calculator.Var; import org.solovyev.common.utils.CollectionsUtils; import org.solovyev.common.utils.Finder; @@ -22,20 +24,21 @@ public enum MathEntityType { digit, constant, dot, - function, + function, postfix_function, unary_operation, binary_operation, group_symbols, group_symbol; - + public static final List constants = Arrays.asList("e", "π", "i"); + public static final List digits = Arrays.asList("0", "1", "2", "3", "4", "5", "6", "7", "8", "9"); public static final List dots = Arrays.asList('.'); public static final List unaryOperations = Arrays.asList('-', '=', '!'); - public static final List binaryOperations = Arrays.asList('-', '+', '*', '×', '∙', '/', '^' ); + public static final List binaryOperations = Arrays.asList('-', '+', '*', '×', '∙', '/', '^'); public static final List prefixFunctions = Functions.allPrefix; @@ -48,6 +51,7 @@ public enum MathEntityType { public static final List closeGroupSymbols = Arrays.asList(']', ')', '}'); public static final List singleGroupSymbols; + static { final List list = new ArrayList(); list.addAll(openGroupSymbols); @@ -56,24 +60,24 @@ public enum MathEntityType { } @Nullable - public static MathEntityType getType( @NotNull String s ) { + public static MathEntityType getType(@NotNull String s) { MathEntityType result = null; - - if ( s.length() == 1 ) { + + if (s.length() == 1) { result = getType(s.charAt(0)); } - - if ( result == null ) { - if ( isConstant(s) ) { - result = MathEntityType.constant; - } else if ( prefixFunctions.contains(s) ) { + + if (result == null) { + if (prefixFunctions.contains(s)) { result = MathEntityType.function; - } else if ( groupSymbols.contains(s) ) { + } else if (isConstant(s)) { + result = MathEntityType.constant; + } else if (groupSymbols.contains(s)) { result = MathEntityType.group_symbols; } } - - + + return result; } @@ -81,19 +85,19 @@ public enum MathEntityType { public static MathEntityType getType(final char ch) { MathEntityType result = null; - if ( Character.isDigit(ch) ) { + if (Character.isDigit(ch)) { result = MathEntityType.digit; - } else if ( postfixFunctions.contains(ch) ) { + } else if (postfixFunctions.contains(ch)) { result = MathEntityType.postfix_function; - } else if ( unaryOperations.contains(ch) ) { + } else if (unaryOperations.contains(ch)) { result = MathEntityType.unary_operation; - } else if ( binaryOperations.contains(ch) ) { + } else if (binaryOperations.contains(ch)) { result = MathEntityType.binary_operation; - } else if ( singleGroupSymbols.contains(ch) ) { + } else if (singleGroupSymbols.contains(ch)) { result = MathEntityType.group_symbol; } else if (isConstant(ch)) { result = MathEntityType.constant; - } else if ( dots.contains(ch) ) { + } else if (dots.contains(ch)) { result = MathEntityType.dot; } return result; @@ -113,4 +117,46 @@ public enum MathEntityType { } }) != null; } + + public static MathEntityType getType(String s, int i) { + final StartsWithFinder startsWithFinder = new StartsWithFinder(s, i); + final CharacterAtPositionFinder characterStartWithFinder = new CharacterAtPositionFinder(s, i); + + return getType(startsWithFinder, characterStartWithFinder); + } + + @Nullable + private static MathEntityType getType(@NotNull Finder finder, @NotNull CharacterAtPositionFinder characterStartWithFinder) { + MathEntityType result = null; + + if (contains(digits, finder)) { + result = MathEntityType.digit; + } else if (contains(postfixFunctions, characterStartWithFinder)) { + result = MathEntityType.postfix_function; + } else if (contains(unaryOperations, characterStartWithFinder)) { + result = MathEntityType.unary_operation; + } else if (contains(binaryOperations, characterStartWithFinder)) { + result = MathEntityType.binary_operation; + } else if (contains(groupSymbols, finder)) { + result = MathEntityType.group_symbols; + } else if (contains(singleGroupSymbols, characterStartWithFinder)) { + result = MathEntityType.group_symbol; + } else if (contains(prefixFunctions, finder)) { + result = MathEntityType.function; + } else if (contains(CalculatorModel.getInstance().getVarsRegister().getVarNames(), finder)) { + result = MathEntityType.constant; + } else if (contains(dots, characterStartWithFinder)) { + result = MathEntityType.dot; + } + + return result; + } + + private static boolean contains(@NotNull List list, @NotNull final Finder startsWithFinder) { + return CollectionsUtils.get(list, startsWithFinder) != null; + } + + private static boolean contains(@NotNull List list, @NotNull final CharacterAtPositionFinder atPositionFinder) { + return CollectionsUtils.get(list, atPositionFinder) != null; + } } diff --git a/src/test/java/org/solovyev/android/calculator/CalculatorModelTest.java b/src/test/java/org/solovyev/android/calculator/CalculatorModelTest.java index ff2930bb..d11cb326 100644 --- a/src/test/java/org/solovyev/android/calculator/CalculatorModelTest.java +++ b/src/test/java/org/solovyev/android/calculator/CalculatorModelTest.java @@ -5,8 +5,8 @@ package org.solovyev.android.calculator; +import bsh.EvalError; import org.junit.Assert; -import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; @@ -47,6 +47,25 @@ public class CalculatorModelTest { Assert.assertEquals("-3.41007+3.41007i", cm.evaluate(JsclOperation.numeric, "(5tan(2i)+2i)/(1-i)")); Assert.assertEquals("-0.1-0.2i", cm.evaluate(JsclOperation.numeric, "(1-i)/(2+6i)")); + CalculatorModel.getInstance().getVarsRegister().addVar(null, new Var.Builder("si", 5d)); + Assert.assertEquals("5.0", cm.evaluate(JsclOperation.numeric, "si")); + try { + cm.evaluate(JsclOperation.numeric, "sin"); + Assert.fail(); + } catch (EvalError e) { + } + Assert.assertEquals("-0.95892", cm.evaluate(JsclOperation.numeric, "sin(5)")); + Assert.assertEquals("-4.79462", cm.evaluate(JsclOperation.numeric, "sin(5)si")); + Assert.assertEquals("-23.97311", cm.evaluate(JsclOperation.numeric, "sisin(5)si")); + Assert.assertEquals("-23.97311", cm.evaluate(JsclOperation.numeric, "si*sin(5)si")); + Assert.assertEquals("-3.30879", cm.evaluate(JsclOperation.numeric, "sisin(5si)si")); + + CalculatorModel.getInstance().getVarsRegister().addVar(null, new Var.Builder("s", 1d)); + Assert.assertEquals("5.0", cm.evaluate(JsclOperation.numeric, "si")); + + CalculatorModel.getInstance().getVarsRegister().addVar(null, new Var.Builder("k", 3.5d)); + CalculatorModel.getInstance().getVarsRegister().addVar(null, new Var.Builder("k1", 4d)); + Assert.assertEquals("4.0", cm.evaluate(JsclOperation.numeric, "k11")); } @Test