support for symbolic computations
This commit is contained in:
		| @@ -8,7 +8,7 @@ | |||||||
| 	<uses-sdk android:minSdkVersion="8"/> | 	<uses-sdk android:minSdkVersion="8"/> | ||||||
|  |  | ||||||
| 	<application android:icon="@drawable/icon" | 	<application android:icon="@drawable/icon" | ||||||
| 				 android:label="@string/c_app_icon_name"> | 				 android:label="@string/c_app_name"> | ||||||
|  |  | ||||||
| 		<activity android:name=".CalculatorActivity" | 		<activity android:name=".CalculatorActivity" | ||||||
| 				  android:label="@string/c_app_name"> | 				  android:label="@string/c_app_name"> | ||||||
|   | |||||||
| @@ -14,7 +14,6 @@ | |||||||
|  |  | ||||||
| 		<include layout="@layout/calc_editor"/> | 		<include layout="@layout/calc_editor"/> | ||||||
|  |  | ||||||
|  |  | ||||||
| 		<LinearLayout a:layout_weight="1" a:layout_width="match_parent" a:layout_height="0dp"> | 		<LinearLayout a:layout_weight="1" a:layout_width="match_parent" a:layout_height="0dp"> | ||||||
|  |  | ||||||
| 			<include layout="@layout/calc_display" | 			<include layout="@layout/calc_display" | ||||||
|   | |||||||
| @@ -49,7 +49,7 @@ | |||||||
| 	<string name="c_var_create_var">Создать переменную</string> | 	<string name="c_var_create_var">Создать переменную</string> | ||||||
| 	<string name="c_var_edit_var">Редактировать переменную</string> | 	<string name="c_var_edit_var">Редактировать переменную</string> | ||||||
|  |  | ||||||
| 	<string name="c_value.is.not.a.number">Значение - не число!</string> | 	<string name="c_value.is.not.a.number">Значение должно либо оставаться пустым либо быть числом!</string> | ||||||
| 	<string name="c_var.name.clashes">Имя переменной не может быть зарезервированным системным именем!</string> | 	<string name="c_var.name.clashes">Имя переменной не может быть зарезервированным системным именем!</string> | ||||||
| 	<string name="c_var.already.exists">Переменная с таким именем уже существует!</string> | 	<string name="c_var.already.exists">Переменная с таким именем уже существует!</string> | ||||||
| 	<string name="c_name.is.empty">Имя не может быть пустым!</string> | 	<string name="c_name.is.empty">Имя не может быть пустым!</string> | ||||||
| @@ -84,4 +84,5 @@ | |||||||
| 	<string name="c_calc_color_display_summary">Включает/выключает подсветку синтаксиса в поле редактирования калькулятора</string> | 	<string name="c_calc_color_display_summary">Включает/выключает подсветку синтаксиса в поле редактирования калькулятора</string> | ||||||
| 	<string name="c_calc_theme_summary">Устанавливает тему оформления приложения</string> | 	<string name="c_calc_theme_summary">Устанавливает тему оформления приложения</string> | ||||||
| 	<string name="c_clear_history">Очистить историю</string> | 	<string name="c_clear_history">Очистить историю</string> | ||||||
|  | 	<string name="c_simplify_instead_of_numeric">Следующие константы не определены: {0}!</string> | ||||||
| </resources> | </resources> | ||||||
|   | |||||||
| @@ -52,7 +52,7 @@ | |||||||
| 	<string name="c_var_create_var">Create variable</string> | 	<string name="c_var_create_var">Create variable</string> | ||||||
| 	<string name="c_var_edit_var">Edit variable</string> | 	<string name="c_var_edit_var">Edit variable</string> | ||||||
|  |  | ||||||
| 	<string name="c_value.is.not.a.number">Value is not a number!</string> | 	<string name="c_value.is.not.a.number">Value must be either number or empty!</string> | ||||||
| 	<string name="c_var.name.clashes">Variable name clashes with function name!</string> | 	<string name="c_var.name.clashes">Variable name clashes with function name!</string> | ||||||
| 	<string name="c_var.already.exists">Variable with same name already exists!</string> | 	<string name="c_var.already.exists">Variable with same name already exists!</string> | ||||||
| 	<string name="c_name.is.empty">Name is empty!</string> | 	<string name="c_name.is.empty">Name is empty!</string> | ||||||
| @@ -84,4 +84,5 @@ | |||||||
| 	<string name="c_calc_color_display_summary">Enables/disables colouring and styling in calculator editor</string> | 	<string name="c_calc_color_display_summary">Enables/disables colouring and styling in calculator editor</string> | ||||||
| 	<string name="c_calc_theme_summary">Sets the theme for calculator</string> | 	<string name="c_calc_theme_summary">Sets the theme for calculator</string> | ||||||
| 	<string name="c_clear_history">Clear history</string> | 	<string name="c_clear_history">Clear history</string> | ||||||
|  | 	<string name="c_simplify_instead_of_numeric">Next constants are undefined: {0}!</string> | ||||||
| </resources> | </resources> | ||||||
|   | |||||||
| @@ -24,6 +24,7 @@ import bsh.EvalError; | |||||||
| 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.model.CalculatorEngine; | import org.solovyev.android.calculator.model.CalculatorEngine; | ||||||
|  | import org.solovyev.android.msg.AndroidMessageRegistry; | ||||||
| import org.solovyev.android.view.FontSizeAdjuster; | import org.solovyev.android.view.FontSizeAdjuster; | ||||||
| import org.solovyev.android.view.widgets.*; | import org.solovyev.android.view.widgets.*; | ||||||
| import org.solovyev.common.BooleanMapper; | import org.solovyev.common.BooleanMapper; | ||||||
| @@ -364,9 +365,18 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh | |||||||
|  |  | ||||||
| 		calculatorModel = CalculatorModel.instance.init(this, preferences, CalculatorEngine.instance); | 		calculatorModel = CalculatorModel.instance.init(this, preferences, CalculatorEngine.instance); | ||||||
|  |  | ||||||
|  | 		AndroidMessageRegistry.instance.init(this); | ||||||
|  |  | ||||||
| 		this.calculatorModel.evaluate(); | 		this.calculatorModel.evaluate(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	@Override | ||||||
|  | 	protected void onDestroy() { | ||||||
|  | 		super.onDestroy(); | ||||||
|  |  | ||||||
|  | 		AndroidMessageRegistry.instance.finish(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| 	public void onSharedPreferenceChanged(SharedPreferences preferences, @Nullable String s) { | 	public void onSharedPreferenceChanged(SharedPreferences preferences, @Nullable String s) { | ||||||
| 		dpclRegister.announce().onDragPreferencesChange(SimpleOnDragListener.getPreferences(preferences, this)); | 		dpclRegister.announce().onDragPreferencesChange(SimpleOnDragListener.getPreferences(preferences, this)); | ||||||
|   | |||||||
| @@ -26,7 +26,7 @@ public class CalculatorEditor extends EditText { | |||||||
| 	private boolean highlightText = true; | 	private boolean highlightText = true; | ||||||
|  |  | ||||||
| 	@NotNull | 	@NotNull | ||||||
| 	private final static TextProcessor textHighlighter = new TextHighlighter(Color.WHITE); | 	private final static TextProcessor<String> textHighlighter = new TextHighlighter(Color.WHITE); | ||||||
|  |  | ||||||
| 	public CalculatorEditor(Context context) { | 	public CalculatorEditor(Context context) { | ||||||
| 		super(context); | 		super(context); | ||||||
|   | |||||||
| @@ -18,6 +18,7 @@ import android.widget.Toast; | |||||||
| import bsh.EvalError; | import bsh.EvalError; | ||||||
| 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.math.MathType; | import org.solovyev.android.calculator.math.MathType; | ||||||
| import org.solovyev.android.calculator.model.CalculatorEngine; | import org.solovyev.android.calculator.model.CalculatorEngine; | ||||||
| import org.solovyev.android.calculator.model.ParseException; | import org.solovyev.android.calculator.model.ParseException; | ||||||
|   | |||||||
| @@ -119,7 +119,9 @@ public class CalculatorVarsActivity extends ListActivity { | |||||||
| 			}); | 			}); | ||||||
|  |  | ||||||
| 			final EditText editValue = (EditText) editView.findViewById(R.id.var_edit_value); | 			final EditText editValue = (EditText) editView.findViewById(R.id.var_edit_value); | ||||||
|  | 			if (!StringUtils.isEmpty(value)) { | ||||||
| 				editValue.setText(value); | 				editValue.setText(value); | ||||||
|  | 			} | ||||||
|  |  | ||||||
| 			final EditText editDescription = (EditText) editView.findViewById(R.id.var_edit_description); | 			final EditText editDescription = (EditText) editView.findViewById(R.id.var_edit_description); | ||||||
| 			editDescription.setText(description); | 			editDescription.setText(description); | ||||||
| @@ -198,6 +200,15 @@ public class CalculatorVarsActivity extends ListActivity { | |||||||
| 						final MathType.Result mathType = MathType.getType(name, 0); | 						final MathType.Result mathType = MathType.getType(name, 0); | ||||||
|  |  | ||||||
| 						if (mathType.getMathType() == MathType.text || mathType.getMathType() == MathType.constant) { | 						if (mathType.getMathType() == MathType.text || mathType.getMathType() == MathType.constant) { | ||||||
|  |  | ||||||
|  | 							if (StringUtils.isEmpty(value)) { | ||||||
|  | 								// value is empty => undefined variable | ||||||
|  | 								varBuilder.setName(name); | ||||||
|  | 								varBuilder.setDescription(description); | ||||||
|  | 								varBuilder.setValue(null); | ||||||
|  | 								error = null; | ||||||
|  | 							} else { | ||||||
|  | 								// value is not empty => must be a number | ||||||
| 								boolean correctDouble = true; | 								boolean correctDouble = true; | ||||||
| 								try { | 								try { | ||||||
| 									Double.valueOf(value); | 									Double.valueOf(value); | ||||||
| @@ -207,12 +218,13 @@ public class CalculatorVarsActivity extends ListActivity { | |||||||
|  |  | ||||||
| 								if (correctDouble) { | 								if (correctDouble) { | ||||||
| 									varBuilder.setName(name); | 									varBuilder.setName(name); | ||||||
| 								varBuilder.setValue(value); |  | ||||||
| 									varBuilder.setDescription(description); | 									varBuilder.setDescription(description); | ||||||
|  | 									varBuilder.setValue(value); | ||||||
| 									error = null; | 									error = null; | ||||||
| 								} else { | 								} else { | ||||||
| 									error = R.string.c_value_is_not_a_number; | 									error = R.string.c_value_is_not_a_number; | ||||||
| 								} | 								} | ||||||
|  | 							} | ||||||
| 						} else { | 						} else { | ||||||
| 							error = R.string.c_var_name_clashes; | 							error = R.string.c_var_name_clashes; | ||||||
| 						} | 						} | ||||||
|   | |||||||
| @@ -1,15 +0,0 @@ | |||||||
| /* |  | ||||||
|  * Copyright (c) 2009-2011. Created by serso aka se.solovyev. |  | ||||||
|  * For more information, please, contact se.solovyev@gmail.com |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| package org.solovyev.android.calculator; |  | ||||||
|  |  | ||||||
| public enum JsclOperation { |  | ||||||
|  |  | ||||||
| 	simplify, |  | ||||||
| 	elementary, |  | ||||||
| 	importCommands, |  | ||||||
| 	numeric; |  | ||||||
| 	 |  | ||||||
| } |  | ||||||
| @@ -17,7 +17,7 @@ import org.solovyev.android.calculator.model.TextProcessor; | |||||||
|  * Date: 10/12/11 |  * Date: 10/12/11 | ||||||
|  * Time: 9:47 PM |  * Time: 9:47 PM | ||||||
|  */ |  */ | ||||||
| public class TextHighlighter implements TextProcessor { | public class TextHighlighter implements TextProcessor<String> { | ||||||
|  |  | ||||||
| 	private final int color; | 	private final int color; | ||||||
| 	private final int colorRed; | 	private final int colorRed; | ||||||
|   | |||||||
| @@ -4,10 +4,13 @@ | |||||||
|  * or visit http://se.solovyev.org |  * or visit http://se.solovyev.org | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| package org.solovyev.android.calculator.model; | package org.solovyev.android.calculator.jscl; | ||||||
| 
 | 
 | ||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
| import org.solovyev.android.calculator.math.MathType; | import org.solovyev.android.calculator.math.MathType; | ||||||
|  | import org.solovyev.android.calculator.model.CalculatorEngine; | ||||||
|  | import org.solovyev.android.calculator.model.ParseException; | ||||||
|  | import org.solovyev.android.calculator.model.TextProcessor; | ||||||
| import org.solovyev.common.utils.MathUtils; | import org.solovyev.common.utils.MathUtils; | ||||||
| import org.solovyev.util.math.Complex; | import org.solovyev.util.math.Complex; | ||||||
| 
 | 
 | ||||||
| @@ -16,7 +19,7 @@ import org.solovyev.util.math.Complex; | |||||||
|  * Date: 10/6/11 |  * Date: 10/6/11 | ||||||
|  * Time: 9:48 PM |  * Time: 9:48 PM | ||||||
|  */ |  */ | ||||||
| class FromJsclTextProcessor implements TextProcessor { | class FromJsclNumericTextProcessor implements TextProcessor<String> { | ||||||
| 
 | 
 | ||||||
| 	@NotNull | 	@NotNull | ||||||
| 	@Override | 	@Override | ||||||
| @@ -0,0 +1,31 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright (c) 2009-2011. Created by serso aka se.solovyev. | ||||||
|  |  * For more information, please, contact se.solovyev@gmail.com | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package org.solovyev.android.calculator.jscl; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | import org.jetbrains.annotations.NotNull; | ||||||
|  | import org.solovyev.android.calculator.model.DummyTextProcessor; | ||||||
|  | import org.solovyev.android.calculator.model.TextProcessor; | ||||||
|  |  | ||||||
|  | public enum JsclOperation { | ||||||
|  |  | ||||||
|  | 	simplify(DummyTextProcessor.instance), | ||||||
|  | 	elementary(DummyTextProcessor.instance), | ||||||
|  | 	importCommands(DummyTextProcessor.instance), | ||||||
|  | 	numeric(new FromJsclNumericTextProcessor()); | ||||||
|  |  | ||||||
|  | 	@NotNull | ||||||
|  | 	private final TextProcessor<String> fromProcessor; | ||||||
|  |  | ||||||
|  | 	JsclOperation(@NotNull TextProcessor<String> fromProcessor) { | ||||||
|  | 		this.fromProcessor = fromProcessor; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@NotNull | ||||||
|  | 	public TextProcessor<String> getFromProcessor() { | ||||||
|  | 		return fromProcessor; | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @@ -11,8 +11,14 @@ import bsh.EvalError; | |||||||
| import bsh.Interpreter; | import bsh.Interpreter; | ||||||
| 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.JsclOperation; | import org.solovyev.android.calculator.R; | ||||||
|  | import org.solovyev.android.calculator.jscl.JsclOperation; | ||||||
|  | import org.solovyev.android.msg.AndroidMessage; | ||||||
| import org.solovyev.common.NumberMapper; | import org.solovyev.common.NumberMapper; | ||||||
|  | import org.solovyev.common.msg.MessageRegistry; | ||||||
|  | import org.solovyev.common.msg.MessageType; | ||||||
|  | import org.solovyev.common.utils.CollectionsUtils; | ||||||
|  | import org.solovyev.common.utils.Formatter; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * User: serso |  * User: serso | ||||||
| @@ -36,25 +42,46 @@ public enum CalculatorEngine { | |||||||
| 	private int numberOfFractionDigits = 5; | 	private int numberOfFractionDigits = 5; | ||||||
|  |  | ||||||
| 	@NotNull | 	@NotNull | ||||||
| 	public final TextProcessor preprocessor = new ToJsclTextProcessor(); | 	public final TextProcessor<PreparedExpression> preprocessor = new ToJsclTextProcessor(); | ||||||
|  |  | ||||||
| 	@NotNull |  | ||||||
| 	public final TextProcessor postprocessor = new FromJsclTextProcessor(); |  | ||||||
|  |  | ||||||
| 	@NotNull | 	@NotNull | ||||||
| 	private final VarsRegisterImpl varsRegister = new VarsRegisterImpl(); | 	private final VarsRegisterImpl varsRegister = new VarsRegisterImpl(); | ||||||
|  |  | ||||||
| 	public String evaluate(@NotNull JsclOperation operation, @NotNull String expression) throws EvalError, ParseException { | 	public String evaluate(@NotNull JsclOperation operation, | ||||||
|  | 						   @NotNull String expression) throws EvalError, ParseException { | ||||||
|  | 		return evaluate(operation, expression, null); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public String evaluate(@NotNull JsclOperation operation, | ||||||
|  | 						   @NotNull String expression, | ||||||
|  | 						   @Nullable MessageRegistry<AndroidMessage> mr) throws EvalError, ParseException { | ||||||
| 		synchronized (lock) { | 		synchronized (lock) { | ||||||
| 			final StringBuilder sb = new StringBuilder(); | 			final StringBuilder sb = new StringBuilder(); | ||||||
|  |  | ||||||
| 			sb.append(preprocessor.process(expression)); | 			final PreparedExpression preparedExpression = preprocessor.process(expression); | ||||||
|  | 			sb.append(preparedExpression); | ||||||
|  |  | ||||||
| 			//Log.d(CalculatorEngine.class.getName(), "Preprocessed expression: " + preprocessedExpression); | 			//Log.d(CalculatorEngine.class.getName(), "Preprocessed expression: " + preprocessedExpression); | ||||||
|  | 			if (operation == JsclOperation.numeric && preparedExpression.isExistsUndefinedVar()) { | ||||||
|  | 				operation = JsclOperation.simplify; | ||||||
|  |  | ||||||
|  | 				if (mr != null) { | ||||||
|  | 					final String undefinedVars = CollectionsUtils.formatValue(preparedExpression.getUndefinedVars(), ", ", new Formatter<Var>() { | ||||||
|  | 						@Override | ||||||
|  | 						public String formatValue(@Nullable Var var) throws IllegalArgumentException { | ||||||
|  | 							return var != null ? var.getName() : ""; | ||||||
|  | 						} | ||||||
|  | 					}); | ||||||
|  |  | ||||||
|  | 					mr.addMessage(new AndroidMessage(R.string.c_simplify_instead_of_numeric, MessageType.info, undefinedVars)); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  |  | ||||||
| 			final Object evaluationObject = interpreter.eval(ToJsclTextProcessor.wrap(operation, sb.toString())); | 			final Object evaluationObject = interpreter.eval(ToJsclTextProcessor.wrap(operation, sb.toString())); | ||||||
|  |  | ||||||
| 			return postprocessor.process(String.valueOf(evaluationObject).trim()); | 			final String result = String.valueOf(evaluationObject).trim(); | ||||||
|  |  | ||||||
|  | 			return operation.getFromProcessor().process(result); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -0,0 +1,25 @@ | |||||||
|  | /* | ||||||
|  |  * 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.model; | ||||||
|  |  | ||||||
|  | import org.jetbrains.annotations.NotNull; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * User: serso | ||||||
|  |  * Date: 10/18/11 | ||||||
|  |  * Time: 10:39 PM | ||||||
|  |  */ | ||||||
|  | public enum DummyTextProcessor implements TextProcessor<String> { | ||||||
|  |  | ||||||
|  | 	instance; | ||||||
|  |  | ||||||
|  | 	@NotNull | ||||||
|  | 	@Override | ||||||
|  | 	public String process(@NotNull String s) throws ParseException { | ||||||
|  | 		return s.replace(ToJsclTextProcessor.SPECIAL_STRING, ""); | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @@ -0,0 +1,64 @@ | |||||||
|  | /* | ||||||
|  |  * 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.model; | ||||||
|  |  | ||||||
|  | import org.jetbrains.annotations.NotNull; | ||||||
|  |  | ||||||
|  | import java.util.List; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * User: serso | ||||||
|  |  * Date: 10/18/11 | ||||||
|  |  * Time: 10:07 PM | ||||||
|  |  */ | ||||||
|  | public class PreparedExpression implements CharSequence{ | ||||||
|  |  | ||||||
|  | 	@NotNull | ||||||
|  | 	private String expression; | ||||||
|  |  | ||||||
|  | 	@NotNull | ||||||
|  | 	private List<Var> undefinedVars; | ||||||
|  |  | ||||||
|  | 	public PreparedExpression(@NotNull String expression, @NotNull List<Var> undefinedVars) { | ||||||
|  | 		this.expression = expression; | ||||||
|  | 		this.undefinedVars = undefinedVars; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@NotNull | ||||||
|  | 	public String getExpression() { | ||||||
|  | 		return expression; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public boolean isExistsUndefinedVar() { | ||||||
|  | 		return !this.undefinedVars.isEmpty(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@NotNull | ||||||
|  | 	public List<Var> getUndefinedVars() { | ||||||
|  | 		return undefinedVars; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@Override | ||||||
|  | 	public int length() { | ||||||
|  | 		return expression.length(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@Override | ||||||
|  | 	public char charAt(int i) { | ||||||
|  | 		return expression.charAt(i); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@Override | ||||||
|  | 	public CharSequence subSequence(int i, int i1) { | ||||||
|  | 		return expression.subSequence(i, i1); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@Override | ||||||
|  | 	public String toString() { | ||||||
|  | 		return this.expression; | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @@ -7,8 +7,8 @@ import org.jetbrains.annotations.NotNull; | |||||||
|  * Date: 9/26/11 |  * Date: 9/26/11 | ||||||
|  * Time: 12:12 PM |  * Time: 12:12 PM | ||||||
|  */ |  */ | ||||||
| public interface TextProcessor { | public interface TextProcessor<T extends CharSequence> { | ||||||
|  |  | ||||||
| 	@NotNull | 	@NotNull | ||||||
| 	String process(@NotNull String s) throws ParseException; | 	T process(@NotNull String s) throws ParseException; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -8,7 +8,7 @@ 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.JsclOperation; | 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.math.Functions; | ||||||
| import org.solovyev.android.calculator.math.MathType; | import org.solovyev.android.calculator.math.MathType; | ||||||
| @@ -16,11 +16,16 @@ import org.solovyev.common.utils.CollectionsUtils; | |||||||
| import org.solovyev.common.utils.FilterType; | import org.solovyev.common.utils.FilterType; | ||||||
| import org.solovyev.common.utils.Finder; | import org.solovyev.common.utils.Finder; | ||||||
|  |  | ||||||
| class ToJsclTextProcessor implements TextProcessor { | import java.util.ArrayList; | ||||||
|  | import java.util.List; | ||||||
|  |  | ||||||
|  | class ToJsclTextProcessor implements TextProcessor<PreparedExpression> { | ||||||
|  |  | ||||||
|  | 	public static final String SPECIAL_STRING = "☀☀☀"; | ||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| 	@NotNull | 	@NotNull | ||||||
| 	public String process(@NotNull String s) { | 	public PreparedExpression process(@NotNull String s) { | ||||||
|  |  | ||||||
| 		final StartsWithFinder startsWithFinder = new StartsWithFinder(s, 0); | 		final StartsWithFinder startsWithFinder = new StartsWithFinder(s, 0); | ||||||
| 		final StringBuilder sb = new StringBuilder(); | 		final StringBuilder sb = new StringBuilder(); | ||||||
| @@ -47,7 +52,7 @@ class ToJsclTextProcessor implements TextProcessor { | |||||||
| 				startsWithFinder.setI(i + 1); | 				startsWithFinder.setI(i + 1); | ||||||
| 				if ( i < s.length() && CollectionsUtils.get(MathType.groupSymbols, startsWithFinder) != null) { | 				if ( i < s.length() && CollectionsUtils.get(MathType.groupSymbols, startsWithFinder) != null) { | ||||||
| 					i += 2; | 					i += 2; | ||||||
| 					sb.append("(foo)"); | 					sb.append("(" + SPECIAL_STRING + ")"); | ||||||
| 					mathTypeResult = new MathType.Result(MathType.close_group_symbol, ")"); | 					mathTypeResult = new MathType.Result(MathType.close_group_symbol, ")"); | ||||||
| 				} | 				} | ||||||
| 			} else if (mathType == MathType.constant) { | 			} else if (mathType == MathType.constant) { | ||||||
| @@ -61,9 +66,12 @@ class ToJsclTextProcessor implements TextProcessor { | |||||||
| 		return replaceVariables(sb.toString()); | 		return replaceVariables(sb.toString()); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	private String replaceVariables(@NotNull final String s) { | 	@NotNull | ||||||
|  | 	private PreparedExpression replaceVariables(@NotNull final String s) { | ||||||
| 		final StartsWithFinder startsWithFinder = new StartsWithFinder(s, 0); | 		final StartsWithFinder startsWithFinder = new StartsWithFinder(s, 0); | ||||||
|  |  | ||||||
|  | 		final List<Var> undefinedVars = new ArrayList<Var>(); | ||||||
|  |  | ||||||
| 		final StringBuilder result = new StringBuilder(); | 		final StringBuilder result = new StringBuilder(); | ||||||
| 		for (int i = 0; i < s.length(); i++) { | 		for (int i = 0; i < s.length(); i++) { | ||||||
| 			startsWithFinder.setI(i); | 			startsWithFinder.setI(i); | ||||||
| @@ -75,10 +83,16 @@ class ToJsclTextProcessor implements TextProcessor { | |||||||
| 				if (varName != null) { | 				if (varName != null) { | ||||||
| 					final Var var = CalculatorEngine.instance.getVarsRegister().getVar(varName); | 					final Var var = CalculatorEngine.instance.getVarsRegister().getVar(varName); | ||||||
| 					if (var != null) { | 					if (var != null) { | ||||||
|  | 						if (var.isUndefined()) { | ||||||
|  | 							undefinedVars.add(var); | ||||||
|  | 							result.append(varName); | ||||||
|  | 							offset = varName.length(); | ||||||
|  | 						} else { | ||||||
| 							result.append(var.getValue()); | 							result.append(var.getValue()); | ||||||
| 							offset = varName.length(); | 							offset = varName.length(); | ||||||
| 						} | 						} | ||||||
| 					} | 					} | ||||||
|  | 				} | ||||||
| 			} else { | 			} else { | ||||||
| 				result.append(functionName); | 				result.append(functionName); | ||||||
| 				offset = functionName.length(); | 				offset = functionName.length(); | ||||||
| @@ -92,7 +106,7 @@ class ToJsclTextProcessor implements TextProcessor { | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		return result.toString(); | 		return new PreparedExpression(result.toString(), undefinedVars); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	private void replaceVariables(StringBuilder sb, String s, int i, @NotNull StartsWithFinder startsWithFinder) { | 	private void replaceVariables(StringBuilder sb, String s, int i, @NotNull StartsWithFinder startsWithFinder) { | ||||||
|   | |||||||
| @@ -10,6 +10,7 @@ import org.jetbrains.annotations.NotNull; | |||||||
| import org.jetbrains.annotations.Nullable; | import org.jetbrains.annotations.Nullable; | ||||||
| import org.simpleframework.xml.Element; | import org.simpleframework.xml.Element; | ||||||
| import org.simpleframework.xml.Root; | import org.simpleframework.xml.Root; | ||||||
|  | import org.solovyev.common.utils.StringUtils; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * User: serso |  * User: serso | ||||||
| @@ -24,8 +25,8 @@ public class Var { | |||||||
| 	@NotNull | 	@NotNull | ||||||
| 	private String name; | 	private String name; | ||||||
|  |  | ||||||
| 	@Element | 	@Element(required = false) | ||||||
| 	@NotNull | 	@Nullable | ||||||
| 	private String value; | 	private String value; | ||||||
|  |  | ||||||
| 	@Element | 	@Element | ||||||
| @@ -40,7 +41,7 @@ public class Var { | |||||||
| 		@NotNull | 		@NotNull | ||||||
| 		private String name; | 		private String name; | ||||||
|  |  | ||||||
| 		@NotNull | 		@Nullable | ||||||
| 		private String value; | 		private String value; | ||||||
|  |  | ||||||
| 		private boolean system = false; | 		private boolean system = false; | ||||||
| @@ -62,7 +63,7 @@ public class Var { | |||||||
| 			this(name, String.valueOf(value)); | 			this(name, String.valueOf(value)); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		public Builder(@NotNull String name, @NotNull String value) { | 		public Builder(@NotNull String name, @Nullable String value) { | ||||||
| 			this.name = name; | 			this.name = name; | ||||||
| 			this.value = value; | 			this.value = value; | ||||||
| 		} | 		} | ||||||
| @@ -71,7 +72,7 @@ public class Var { | |||||||
| 			this.name = name; | 			this.name = name; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		public void setValue(@NotNull String value) { | 		public void setValue(@Nullable String value) { | ||||||
| 			this.value = value; | 			this.value = value; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| @@ -107,7 +108,7 @@ public class Var { | |||||||
| 		this.system = var.system; | 		this.system = var.system; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	@NotNull | 	@Nullable | ||||||
| 	public String getValue() { | 	public String getValue() { | ||||||
| 		return value; | 		return value; | ||||||
| 	} | 	} | ||||||
| @@ -121,18 +122,22 @@ public class Var { | |||||||
| 		return name; | 		return name; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	public boolean isUndefined() { | ||||||
|  | 		return StringUtils.isEmpty(this.value); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	@Nullable | 	@Nullable | ||||||
| 	public String getDescription() { | 	public String getDescription() { | ||||||
| 		return description; | 		return description; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	public void setDescription(@Nullable String description) { |  | ||||||
| 		this.description = description; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| 	public String toString() { | 	public String toString() { | ||||||
|  | 		if (value != null) { | ||||||
| 			return getName() + " = " + value; | 			return getName() + " = " + value; | ||||||
|  | 		} else { | ||||||
|  | 			return getName(); | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
|   | |||||||
							
								
								
									
										33
									
								
								src/main/java/org/solovyev/android/msg/AndroidMessage.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/main/java/org/solovyev/android/msg/AndroidMessage.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | |||||||
|  | /* | ||||||
|  |  * 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.msg; | ||||||
|  |  | ||||||
|  | import org.jetbrains.annotations.NotNull; | ||||||
|  | import org.solovyev.common.msg.AbstractMessage; | ||||||
|  | import org.solovyev.common.msg.MessageType; | ||||||
|  |  | ||||||
|  | import java.util.List; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * User: serso | ||||||
|  |  * Date: 10/18/11 | ||||||
|  |  * Time: 11:57 PM | ||||||
|  |  */ | ||||||
|  | public class AndroidMessage extends AbstractMessage<Integer> { | ||||||
|  |  | ||||||
|  | 	public AndroidMessage(@NotNull Integer messageCode, | ||||||
|  | 							 @NotNull MessageType messageType, | ||||||
|  | 							 @org.jetbrains.annotations.Nullable Object... arguments) { | ||||||
|  | 		super(messageCode, messageType, arguments); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public AndroidMessage(@NotNull Integer messageCode, | ||||||
|  | 							 @NotNull MessageType messageType, | ||||||
|  | 							 @org.jetbrains.annotations.Nullable List<?> arguments) { | ||||||
|  | 		super(messageCode, messageType, arguments); | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @@ -0,0 +1,66 @@ | |||||||
|  | /* | ||||||
|  |  * 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.msg; | ||||||
|  |  | ||||||
|  | import android.content.Context; | ||||||
|  | import android.widget.Toast; | ||||||
|  | import org.jetbrains.annotations.NotNull; | ||||||
|  | import org.solovyev.common.msg.MessageRegistry; | ||||||
|  |  | ||||||
|  | import java.util.Locale; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * User: serso | ||||||
|  |  * Date: 10/18/11 | ||||||
|  |  * Time: 11:49 PM | ||||||
|  |  */ | ||||||
|  | public enum AndroidMessageRegistry implements MessageRegistry<AndroidMessage> { | ||||||
|  |  | ||||||
|  | 	instance; | ||||||
|  |  | ||||||
|  | 	private Context context; | ||||||
|  |  | ||||||
|  | 	public void init(@NotNull Context context) { | ||||||
|  | 		this.context = context; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@Override | ||||||
|  | 	public void addMessage(@NotNull AndroidMessage message) { | ||||||
|  | 		if (context != null) { | ||||||
|  | 			Toast.makeText(context, formatMessage(message), Toast.LENGTH_SHORT).show(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@NotNull | ||||||
|  | 	@Override | ||||||
|  | 	public AndroidMessage getMessage() { | ||||||
|  | 		throw new UnsupportedOperationException(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@Override | ||||||
|  | 	public boolean hasMessage() { | ||||||
|  | 		throw new UnsupportedOperationException(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@NotNull | ||||||
|  | 	public String formatMessage(@NotNull AndroidMessage message) { | ||||||
|  | 		final String messagePattern = context.getString(message.getMessageCode()); | ||||||
|  |  | ||||||
|  | 		final String result; | ||||||
|  | 		if (messagePattern != null) { | ||||||
|  | 			result = message.formatMessage(messagePattern, Locale.getDefault()); | ||||||
|  | 		} else { | ||||||
|  | 			result = ""; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return result; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public void finish() { | ||||||
|  | 		this.context = null; | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @@ -0,0 +1,28 @@ | |||||||
|  | /* | ||||||
|  |  * 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.jscl; | ||||||
|  |  | ||||||
|  | import org.junit.Assert; | ||||||
|  | import org.junit.Test; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * User: serso | ||||||
|  |  * Date: 10/18/11 | ||||||
|  |  * Time: 10:42 PM | ||||||
|  |  */ | ||||||
|  | public class FromJsclNumericTextProcessorTest { | ||||||
|  |  | ||||||
|  | 	@Test | ||||||
|  | 	public void testCreateResultForComplexNumber() throws Exception { | ||||||
|  | 		final FromJsclNumericTextProcessor cm = new FromJsclNumericTextProcessor(); | ||||||
|  |  | ||||||
|  | 		Assert.assertEquals("1.22133+23123.0i", cm.createResultForComplexNumber("1.22133232+23123*i")); | ||||||
|  | 		Assert.assertEquals("1.22133+1.2i", cm.createResultForComplexNumber("1.22133232+1.2*i")); | ||||||
|  | 		Assert.assertEquals("1.22i", cm.createResultForComplexNumber("1.22*i")); | ||||||
|  | 		Assert.assertEquals("i", cm.createResultForComplexNumber("i")); | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @@ -10,7 +10,7 @@ import org.junit.Assert; | |||||||
| import org.junit.BeforeClass; | import org.junit.BeforeClass; | ||||||
| import org.junit.Test; | import org.junit.Test; | ||||||
| import org.simpleframework.xml.Attribute; | import org.simpleframework.xml.Attribute; | ||||||
| import org.solovyev.android.calculator.JsclOperation; | import org.solovyev.android.calculator.jscl.JsclOperation; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * User: serso |  * User: serso | ||||||
| @@ -81,17 +81,12 @@ public class CalculatorEngineTest { | |||||||
| 		CalculatorEngine.instance.getVarsRegister().addVar(null, new Var.Builder("k", 3.5d)); | 		CalculatorEngine.instance.getVarsRegister().addVar(null, new Var.Builder("k", 3.5d)); | ||||||
| 		CalculatorEngine.instance.getVarsRegister().addVar(null, new Var.Builder("k1", 4d)); | 		CalculatorEngine.instance.getVarsRegister().addVar(null, new Var.Builder("k1", 4d)); | ||||||
| 		Assert.assertEquals("4.0", cm.evaluate(JsclOperation.numeric, "k11")); | 		Assert.assertEquals("4.0", cm.evaluate(JsclOperation.numeric, "k11")); | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@Test |  | ||||||
| 	public void testComplexNumbers() throws Exception { |  | ||||||
| 		final FromJsclTextProcessor cm = new FromJsclTextProcessor(); |  | ||||||
|  |  | ||||||
| 		Assert.assertEquals("1.22133+23123.0i", cm.createResultForComplexNumber("1.22133232+23123*i")); |  | ||||||
| 		Assert.assertEquals("1.22133+1.2i", cm.createResultForComplexNumber("1.22133232+1.2*i")); |  | ||||||
| 		Assert.assertEquals("1.22i", cm.createResultForComplexNumber("1.22*i")); |  | ||||||
| 		Assert.assertEquals("i", cm.createResultForComplexNumber("i")); |  | ||||||
|  |  | ||||||
|  | 		CalculatorEngine.instance.getVarsRegister().addVar(null, new Var.Builder("t", (String)null)); | ||||||
|  | 		Assert.assertEquals("11*t", cm.evaluate(JsclOperation.numeric, "t11")); | ||||||
|  | 		Assert.assertEquals("11*2.718281828459045*t", cm.evaluate(JsclOperation.numeric, "t11e")); | ||||||
|  | 		Assert.assertEquals("11*Infinity*t", cm.evaluate(JsclOperation.numeric, "t11∞")); | ||||||
|  | 		Assert.assertEquals("-t+t^3", cm.evaluate(JsclOperation.numeric, "t(t-1)(t+1)")); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	public interface TestInterface { | 	public interface TestInterface { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 serso
					serso