var activity

This commit is contained in:
serso 2011-10-03 02:02:14 +04:00
parent 39986c0c14
commit ef74d2c584
12 changed files with 376 additions and 131 deletions

View File

@ -37,7 +37,7 @@
<EditText a:id="@+id/var_edit_value" <EditText a:id="@+id/var_edit_value"
a:layout_width="match_parent" a:layout_width="match_parent"
a:layout_height="wrap_content" a:layout_height="wrap_content"
a:inputType="number" a:inputType="numberDecimal"
a:textSize="20dp"> a:textSize="20dp">
</EditText> </EditText>

View File

@ -26,7 +26,10 @@ import org.solovyev.util.math.Complex;
public class CalculatorModel { public class CalculatorModel {
@NotNull @NotNull
private final Interpreter interpreter; private Interpreter interpreter;
@NotNull
private final Object interpreterMonitor = new Object();
private int numberOfFractionDigits = 5; private int numberOfFractionDigits = 5;
@ -38,30 +41,41 @@ public class CalculatorModel {
private static CalculatorModel instance; private static CalculatorModel instance;
private CalculatorModel(@Nullable Context context) throws EvalError { private CalculatorModel(@Nullable Context context) {
load(context); load(context);
interpreter = new Interpreter(); reset();
interpreter.eval(ToJsclPreprocessor.wrap(JsclOperation.importCommands, "/jscl/editorengine/commands")); }
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 { public String evaluate(@NotNull JsclOperation operation, @NotNull String expression) throws EvalError, ParseException {
final StringBuilder sb = new StringBuilder(); 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)); sb.append(preprocessor.process(expression));
//Log.d(CalculatorModel.class.getName(), "Preprocessed expression: " + preprocessedExpression); //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(); String result = String.valueOf(evaluationObject).trim();
try { try {
@ -120,7 +134,7 @@ public class CalculatorModel {
return MathUtils.round(dResult, numberOfFractionDigits); return MathUtils.round(dResult, numberOfFractionDigits);
} }
public synchronized void load(@Nullable Context context) { public synchronized void load(@Nullable Context context) {
if (context != null) { if (context != null) {
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
@ -154,7 +168,7 @@ public class CalculatorModel {
} }
public static CalculatorModel getInstance() { public static CalculatorModel getInstance() {
if (!isLoaded()) { if (!isLoaded()) {
throw new RuntimeException("CalculatorModel must be instantiated!"); throw new RuntimeException("CalculatorModel must be instantiated!");
} }
@ -165,8 +179,34 @@ public class CalculatorModel {
return instance != null; 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 @NotNull
public VarsRegister getVarsRegister() { public VarsRegister getVarsRegister() {
return varsRegister; 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"};
} }

View File

@ -177,10 +177,10 @@ public class CalculatorVarsActivity extends ListActivity {
Toast.makeText(CalculatorVarsActivity.this, error, Toast.LENGTH_LONG).show(); Toast.makeText(CalculatorVarsActivity.this, error, Toast.LENGTH_LONG).show();
createEditVariableDialog(editedInstance, name, value, description); createEditVariableDialog(editedInstance, name, value, description);
} else { } else {
if (editedInstance != null && !editedInstance.getName().equals(name)) { if ( editedInstance == null ) {
varsRegister.addVar(editedInstance.getName(), varBuilder);
} else {
CalculatorVarsActivity.this.adapter.add(varsRegister.addVar(null, varBuilder)); CalculatorVarsActivity.this.adapter.add(varsRegister.addVar(null, varBuilder));
} else {
varsRegister.addVar(editedInstance.getName(), varBuilder);
} }
varsRegister.save(CalculatorVarsActivity.this); varsRegister.save(CalculatorVarsActivity.this);

View File

@ -192,7 +192,7 @@ public class CalculatorView implements CursorControl, HistoryControl<CalculatorH
@Override @Override
public void doOperation(@NotNull EditText editor) { public void doOperation(@NotNull EditText editor) {
final MathEntityType type = MathEntityType.getType(text); final MathEntityType type = MathEntityType.getType(text, 0);
int cursorPositionOffset = 0; int cursorPositionOffset = 0;
final StringBuilder textToBeInserted = new StringBuilder(text); final StringBuilder textToBeInserted = new StringBuilder(text);

View File

@ -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:54 AM
*/
public class CharacterAtPositionFinder implements Finder<Character> {
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;
}
}

View File

@ -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<String> {
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;
}
}

View File

@ -19,46 +19,88 @@ public class ToJsclPreprocessor implements Preprocessor {
@Override @Override
@NotNull @NotNull
public String process(@NotNull String s) { public String process(@NotNull String s) {
final StartsWithFinder startsWithFinder = new StartsWithFinder(s, 0);
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
boolean constantBefore = false;
for (int i = 0; i < s.length(); i++) { for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i); char ch = s.charAt(i);
if ( MathEntityType.getType(ch) == MathEntityType.postfix_function ) { startsWithFinder.setI(i);
int start = getPostfixFunctionStart(s, i - 1);
}
}
final StartsWithFinder startsWithFinder = new StartsWithFinder(s); checkMultiplicationSignBeforeFunction(sb, s, i, constantBefore);
for (int i = 0; i < s.length(); i++) { constantBefore = false;
char ch = s.charAt(i);
checkMultiplicationSignBeforeFunction(sb, s, i);
if (MathEntityType.openGroupSymbols.contains(ch)) { if (MathEntityType.openGroupSymbols.contains(ch)) {
sb.append('('); sb.append('(');
} else if (MathEntityType.closeGroupSymbols.contains(ch)) { } else if (MathEntityType.closeGroupSymbols.contains(ch)) {
sb.append(')'); sb.append(')');
} else if (ch == 'π') {
sb.append("pi");
} else if (ch == '×' || ch == '∙') { } else if (ch == '×' || ch == '∙') {
sb.append("*"); sb.append("*");
} else { } else {
startsWithFinder.setI(i); String entity = CollectionsUtils.get(MathEntityType.prefixFunctions, startsWithFinder);
final String function = CollectionsUtils.get(MathEntityType.prefixFunctions, startsWithFinder); if (entity == null) {
if (function != null) { entity = CollectionsUtils.get(CalculatorModel.getInstance().getVarsRegister().getVarNames(), startsWithFinder);
sb.append(toJsclFunction(function)); if (entity == null) {
i += function.length() - 1; sb.append(ch);
} else if (ch == 'e') { } else {
sb.append("exp(1)"); sb.append(entity);
} else if (ch == 'i') { i += entity.length() - 1;
sb.append("sqrt(-1)"); constantBefore = true;
}
} else { } 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) { public int getPostfixFunctionStart(@NotNull String s, int position) {
@ -66,17 +108,16 @@ public class ToJsclPreprocessor implements Preprocessor {
int numberOfOpenGroups = 0; int numberOfOpenGroups = 0;
int result = position; int result = position;
for ( ; result >= 0; result-- ) { for (; result >= 0; result--) {
char ch = s.charAt(result);
final MathEntityType mathEntityType = MathEntityType.getType(ch); final MathEntityType mathEntityType = MathEntityType.getType(s, result);
if ( mathEntityType != null ) { if (mathEntityType != null) {
if ( CollectionsUtils.contains(mathEntityType, MathEntityType.digit, MathEntityType.dot) ) { if (CollectionsUtils.contains(mathEntityType, MathEntityType.digit, MathEntityType.dot)) {
// continue // continue
} else if (MathEntityType.closeGroupSymbols.contains(ch)) { } else if (MathEntityType.closeGroupSymbols.contains(s.charAt(result))) {
numberOfOpenGroups++; numberOfOpenGroups++;
} else if (MathEntityType.openGroupSymbols.contains(ch)) { } else if (MathEntityType.openGroupSymbols.contains(s.charAt(result))) {
numberOfOpenGroups--; numberOfOpenGroups--;
} else { } else {
if (stop(s, numberOfOpenGroups, result)) break; if (stop(s, numberOfOpenGroups, result)) break;
@ -90,12 +131,12 @@ public class ToJsclPreprocessor implements Preprocessor {
} }
private boolean stop(String s, int numberOfOpenGroups, int i) { private boolean stop(String s, int numberOfOpenGroups, int i) {
if ( numberOfOpenGroups == 0 ) { if (numberOfOpenGroups == 0) {
if (i > 0) { if (i > 0) {
final EndsWithFinder endsWithFinder = new EndsWithFinder(s); final EndsWithFinder endsWithFinder = new EndsWithFinder(s);
endsWithFinder.setI(i+1); endsWithFinder.setI(i + 1);
if ( !CollectionsUtils.contains(MathEntityType.prefixFunctions, FilterType.included, endsWithFinder) ) { if (!CollectionsUtils.contains(MathEntityType.prefixFunctions, FilterType.included, endsWithFinder)) {
MathEntityType type = MathEntityType.getType(s.charAt(i)); MathEntityType type = MathEntityType.getType(s, i);
if (type != null && type != MathEntityType.constant) { if (type != null && type != MathEntityType.constant) {
return true; return true;
} }
@ -123,27 +164,6 @@ public class ToJsclPreprocessor implements Preprocessor {
return result; return result;
} }
private static class StartsWithFinder implements Finder<String> {
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<String> { private static class EndsWithFinder implements Finder<String> {
private int i; 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) { if (i > 0) {
// get character before function // get character before function
char chBefore = s.charAt(i - 1); char chBefore = s.charAt(i - 1);
char ch = s.charAt(i); char ch = s.charAt(i);
final MathEntityType mathTypeBefore = MathEntityType.getType(String.valueOf(chBefore)); 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.unary_operation &&
mathTypeBefore != MathEntityType.function && mathTypeBefore != MathEntityType.function &&
!MathEntityType.openGroupSymbols.contains(chBefore)) { !MathEntityType.openGroupSymbols.contains(chBefore))) {
if (mathType == MathEntityType.constant) { if (mathType == MathEntityType.constant) {
sb.append("*"); sb.append("*");
} else if (MathEntityType.openGroupSymbols.contains(ch) && mathTypeBefore != null) { } else if (MathEntityType.openGroupSymbols.contains(ch) && mathTypeBefore != null) {
sb.append("*"); 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("*"); sb.append("*");
} else { } else {
for (String function : MathEntityType.prefixFunctions) { for (String function : MathEntityType.prefixFunctions) {

View File

@ -13,6 +13,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.simpleframework.xml.Serializer; import org.simpleframework.xml.Serializer;
import org.simpleframework.xml.core.Persister; import org.simpleframework.xml.core.Persister;
import org.solovyev.android.calculator.math.MathEntityComparator;
import org.solovyev.android.calculator.math.MathEntityType; import org.solovyev.android.calculator.math.MathEntityType;
import org.solovyev.common.utils.CollectionsUtils; import org.solovyev.common.utils.CollectionsUtils;
import org.solovyev.common.utils.Finder; import org.solovyev.common.utils.Finder;
@ -46,20 +47,34 @@ public class VarsRegister {
public Var addVar(@Nullable String name, @NotNull Var.Builder builder) { public Var addVar(@Nullable String name, @NotNull Var.Builder builder) {
final Var var = builder.create(); 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) { if (varFromRegister == null) {
varFromRegister = var;
vars.add(var); vars.add(var);
} else { } else {
varFromRegister.copy(var); varFromRegister.copy(var);
} }
return var; return varFromRegister;
} }
public void remove (@NotNull Var var) { public void remove (@NotNull Var var) {
this.vars.remove(var); this.vars.remove(var);
} }
@NotNull
public List<String> getVarNames () {
final List<String> result = new ArrayList<String>();
for (Var var : vars) {
result.add(var.getName());
}
Collections.sort(result, new MathEntityComparator());
return result;
}
@Nullable @Nullable
public Var getVar(@NotNull final String name) { public Var getVar(@NotNull final String name) {
return CollectionsUtils.get(vars, new Finder<Var>() { return CollectionsUtils.get(vars, new Finder<Var>() {
@ -121,7 +136,7 @@ public class VarsRegister {
} else if (systemVarName.equals("π")) { } else if (systemVarName.equals("π")) {
systemVar = new Var.Builder(systemVarName, Math.PI).setSystem(true).create(); systemVar = new Var.Builder(systemVarName, Math.PI).setSystem(true).create();
} else if (systemVarName.equals("i")) { } 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 { } else {
throw new IllegalArgumentException(systemVarName + " is not supported yet!"); throw new IllegalArgumentException(systemVarName + " is not supported yet!");
} }
@ -157,7 +172,7 @@ public class VarsRegister {
throw new RuntimeException(e); 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(); editor.commit();
} }

View File

@ -5,41 +5,48 @@
package org.solovyev.android.calculator.math; package org.solovyev.android.calculator.math;
import org.jetbrains.annotations.NonNls; import java.util.*;
import java.util.Arrays;
import java.util.List;
/** /**
* User: serso * User: serso
* Date: 9/17/11 * Date: 9/17/11
* Time: 10:01 PM * Time: 10:01 PM
*/ */
public interface Functions { public class Functions {
String SIN = "sin"; public final static String SIN = "sin";
String SINH = "sinh"; public final static String SINH = "sinh";
String ASIN = "asin"; public final static String ASIN = "asin";
String ASINH = "asinh"; public final static String ASINH = "asinh";
String COS = "cos"; public final static String COS = "cos";
String COSH = "cosh"; public final static String COSH = "cosh";
String ACOS = "acos"; public final static String ACOS = "acos";
String ACOSH = "acosh"; public final static String ACOSH = "acosh";
String TAN = "tan"; public final static String TAN = "tan";
String TANH = "tanh"; public final static String TANH = "tanh";
String ATAN = "atan"; public final static String ATAN = "atan";
String ATANH = "atanh"; public final static String ATANH = "atanh";
String LOG = "log"; public final static String LOG = "log";
String LN = "ln"; public final static String LN = "ln";
String MOD = "mod"; public final static String MOD = "mod";
String EXP = "exp"; public final static String EXP = "exp";
String SQRT_SIGN = ""; public final static String SQRT_SIGN = "";
String SQRT = "sqrt"; public final static String SQRT = "sqrt";
public static final List<String> 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<String> allPrefix;
Character FACT = '!'; static {
Character DEGREE = '°'; final List<String> functions = new ArrayList<String>(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<Character> allPostfix = Arrays.asList(FACT, DEGREE); public static final List<Character> allPostfix = Arrays.asList(FACT, DEGREE);
private Functions() {
throw new AssertionError("Not allowed!");
}
} }

View File

@ -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<String> {
@Override
public int compare(String s, String s1) {
return s1.length() - s.length();
}
}

View File

@ -8,6 +8,8 @@ package org.solovyev.android.calculator.math;
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.CalculatorModel; 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.android.calculator.Var;
import org.solovyev.common.utils.CollectionsUtils; import org.solovyev.common.utils.CollectionsUtils;
import org.solovyev.common.utils.Finder; import org.solovyev.common.utils.Finder;
@ -31,11 +33,12 @@ public enum MathEntityType {
public static final List<String> constants = Arrays.asList("e", "π", "i"); public static final List<String> constants = Arrays.asList("e", "π", "i");
public static final List<String> digits = Arrays.asList("0", "1", "2", "3", "4", "5", "6", "7", "8", "9");
public static final List<Character> dots = Arrays.asList('.'); public static final List<Character> dots = Arrays.asList('.');
public static final List<Character> unaryOperations = Arrays.asList('-', '=', '!'); public static final List<Character> unaryOperations = Arrays.asList('-', '=', '!');
public static final List<Character> binaryOperations = Arrays.asList('-', '+', '*', '×', '∙', '/', '^' ); public static final List<Character> binaryOperations = Arrays.asList('-', '+', '*', '×', '∙', '/', '^');
public static final List<String> prefixFunctions = Functions.allPrefix; public static final List<String> prefixFunctions = Functions.allPrefix;
@ -48,6 +51,7 @@ public enum MathEntityType {
public static final List<Character> closeGroupSymbols = Arrays.asList(']', ')', '}'); public static final List<Character> closeGroupSymbols = Arrays.asList(']', ')', '}');
public static final List<Character> singleGroupSymbols; public static final List<Character> singleGroupSymbols;
static { static {
final List<Character> list = new ArrayList<Character>(); final List<Character> list = new ArrayList<Character>();
list.addAll(openGroupSymbols); list.addAll(openGroupSymbols);
@ -56,19 +60,19 @@ public enum MathEntityType {
} }
@Nullable @Nullable
public static MathEntityType getType( @NotNull String s ) { public static MathEntityType getType(@NotNull String s) {
MathEntityType result = null; MathEntityType result = null;
if ( s.length() == 1 ) { if (s.length() == 1) {
result = getType(s.charAt(0)); result = getType(s.charAt(0));
} }
if ( result == null ) { if (result == null) {
if ( isConstant(s) ) { if (prefixFunctions.contains(s)) {
result = MathEntityType.constant;
} else if ( prefixFunctions.contains(s) ) {
result = MathEntityType.function; result = MathEntityType.function;
} else if ( groupSymbols.contains(s) ) { } else if (isConstant(s)) {
result = MathEntityType.constant;
} else if (groupSymbols.contains(s)) {
result = MathEntityType.group_symbols; result = MathEntityType.group_symbols;
} }
} }
@ -81,19 +85,19 @@ public enum MathEntityType {
public static MathEntityType getType(final char ch) { public static MathEntityType getType(final char ch) {
MathEntityType result = null; MathEntityType result = null;
if ( Character.isDigit(ch) ) { if (Character.isDigit(ch)) {
result = MathEntityType.digit; result = MathEntityType.digit;
} else if ( postfixFunctions.contains(ch) ) { } else if (postfixFunctions.contains(ch)) {
result = MathEntityType.postfix_function; result = MathEntityType.postfix_function;
} else if ( unaryOperations.contains(ch) ) { } else if (unaryOperations.contains(ch)) {
result = MathEntityType.unary_operation; result = MathEntityType.unary_operation;
} else if ( binaryOperations.contains(ch) ) { } else if (binaryOperations.contains(ch)) {
result = MathEntityType.binary_operation; result = MathEntityType.binary_operation;
} else if ( singleGroupSymbols.contains(ch) ) { } else if (singleGroupSymbols.contains(ch)) {
result = MathEntityType.group_symbol; result = MathEntityType.group_symbol;
} else if (isConstant(ch)) { } else if (isConstant(ch)) {
result = MathEntityType.constant; result = MathEntityType.constant;
} else if ( dots.contains(ch) ) { } else if (dots.contains(ch)) {
result = MathEntityType.dot; result = MathEntityType.dot;
} }
return result; return result;
@ -113,4 +117,46 @@ public enum MathEntityType {
} }
}) != null; }) != 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<String> 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<String> list, @NotNull final Finder<String> startsWithFinder) {
return CollectionsUtils.get(list, startsWithFinder) != null;
}
private static boolean contains(@NotNull List<Character> list, @NotNull final CharacterAtPositionFinder atPositionFinder) {
return CollectionsUtils.get(list, atPositionFinder) != null;
}
} }

View File

@ -5,8 +5,8 @@
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import bsh.EvalError;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; 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("-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)")); 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 @Test