[gnome-calculator] GCalc: adding Parameter recognition capabilities
- From: Daniel Espinosa Ortiz <despinosa src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-calculator] GCalc: adding Parameter recognition capabilities
- Date: Thu, 17 Oct 2019 00:01:23 +0000 (UTC)
commit a322a7a824b86fea1bf84abbc43a4fd44f971038
Author: Daniel Espinosa <esodan gmail com>
Date: Wed Oct 16 18:53:45 2019 -0500
GCalc: adding Parameter recognition capabilities
gcalc/gcalc-expression.vala | 15 +++++++++
gcalc/gcalc-gparameter.vala | 46 +++++++++++++++++++++++++++
gcalc/gcalc-gparser.vala | 37 ++++++++++++++++++----
gcalc/gcalc-gvariable.vala | 8 ++---
gcalc/gcalc-parameter.vala | 31 ++++++++++++++++++
gcalc/gcalc-variable.vala | 6 ++++
gcalc/meson.build | 2 ++
tests/gcalc-parsing.vala | 76 +++++++++++++++++++++++++++++++++++++++++++++
8 files changed, 211 insertions(+), 10 deletions(-)
---
diff --git a/gcalc/gcalc-expression.vala b/gcalc/gcalc-expression.vala
index 6b83c5d5..b83315db 100644
--- a/gcalc/gcalc-expression.vala
+++ b/gcalc/gcalc-expression.vala
@@ -18,10 +18,25 @@
* Authors:
* Daniel Espinosa <esodan gmail com>
*/
+/**
+ * A part of a math equation
+ */
public interface GCalc.Expression : Object {
+ /**
+ * Parent of the expression
+ */
public abstract weak Expression parent { get; set; }
+ /**
+ * Child expressions
+ */
public abstract ExpressionContainer expressions { get; }
+ /**
+ * Creates a string representation of the expression
+ */
public abstract string to_string ();
+ /**
+ * Solves the expression and returning a {@link Result}
+ */
public abstract Result solve ();
}
diff --git a/gcalc/gcalc-gparameter.vala b/gcalc/gcalc-gparameter.vala
new file mode 100644
index 00000000..6192fbac
--- /dev/null
+++ b/gcalc/gcalc-gparameter.vala
@@ -0,0 +1,46 @@
+/* gcalc-gparameter.vala
+ *
+ * Copyright (C) 2019 Daniel Espinosa <esodan gmail com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Daniel Espinosa <esodan gmail com>
+ */
+public class GCalc.GParameter : GCalc.GVariable, Parameter {
+
+ public GParameter (string name) {
+ base (name);
+ }
+
+ internal void set_value (GLib.Value val) throws GLib.Error {
+ Constant c = new GConstant.integer (0);
+ if (val.holds (GLib.Type.INT)) {
+ c = new GConstant.integer ((int) val);
+ } else if (val.holds (GLib.Type.DOUBLE)) {
+ c = new GConstant.@double ((double) val);
+ } else if (val.holds (GLib.Type.FLOAT)) {
+ c = new GConstant.@double ((double) ((float) val));
+ } else if (val.type ().is_a (typeof (GCalc.Constant))) {
+ c = (GCalc.Constant) ((Object) val);
+ }
+ @value = c;
+ }
+
+ internal GLib.Value get_value () {
+ var v = GLib.Value (typeof (GCalc.Constant));
+ v = @value;
+ return v;
+ }
+}
diff --git a/gcalc/gcalc-gparser.vala b/gcalc/gcalc-gparser.vala
index 35467f34..9c95d685 100644
--- a/gcalc/gcalc-gparser.vala
+++ b/gcalc/gcalc-gparser.vala
@@ -18,11 +18,15 @@
* Authors:
* Daniel Espinosa <esodan gmail com>
*/
-
+/**
+ * Takes a string an create a tree of {@link Expression} objects representing
+ * a math equation.
+ */
public class GCalc.GParser : Object {
Expression current = null;
Expression current_parent = null;
Expression top_parent = null;
+ bool enable_parameter = false;
Gee.ArrayList<TokenType> expected = new Gee.ArrayList<TokenType> ();
GLib.Scanner scanner;
@@ -40,7 +44,11 @@ public class GCalc.GParser : Object {
scanner.config.scan_hex_dollar = false;
scanner.config.numbers_2_int = false;
}
-
+ /**
+ * Creates a {@link MathEquation} and adds it to given
+ * {@link MathEquationManager} including all Variables and
+ * parameters found in the parser expression.
+ */
public void parse (string str, MathEquationManager eqman) throws GLib.Error {
TokenType token = TokenType.NONE;
GMathEquation eq = new GMathEquation ();
@@ -48,6 +56,7 @@ public class GCalc.GParser : Object {
current = null;
current_parent = null;
top_parent = null;
+ enable_parameter = false;
while (token != TokenType.EOF) {
token = read_token ();
if (token == TokenType.EOF) {
@@ -90,6 +99,10 @@ public class GCalc.GParser : Object {
throw new ParserError.INVALID_TOKEN_ERROR ("Found an unexpected function definition expression");
} else {
var v = new GVariable (n) as Expression;
+ if (enable_parameter) {
+ v = new GParameter (n) as Expression;
+ enable_parameter = false;
+ }
var sv = eqman.find_variable (n) as Variable;
if (sv == null) {
sv = eq.variables.find_named (n) as Variable;
@@ -313,7 +326,10 @@ public class GCalc.GParser : Object {
case TokenType.INTERR:
// Hash
case TokenType.HASH:
- throw new ParserError.INVALID_TOKEN_ERROR ("Found an unexpected expression");
+ throw new ParserError.INVALID_TOKEN_ERROR ("Found an unexpected expression: '%s'", token.to_string
());
+ case TokenType.CURRENCY_SYMBOL:
+ enable_parameter = true;
+ break;
}
}
eqman.equations.add (eq);
@@ -395,7 +411,10 @@ public class GCalc.GParser : Object {
expected.clear ();
}
}
- public TokenType read_token () {
+ /**
+ * Reads a token at a given position
+ */
+ protected TokenType read_token () {
GLib.TokenType t = scanner.get_next_token ();
switch (t) {
case GLib.TokenType.IDENTIFIER:
@@ -438,12 +457,17 @@ public class GCalc.GParser : Object {
return TokenType.OPEN_BRACKET;
case ']':
return TokenType.CLOSE_BRACKET;
+ case '$':
+ return TokenType.CURRENCY_SYMBOL;
}
break;
}
return TokenType.NONE;
}
- public string token_to_string () {
+ /**
+ * Creates a string representation of the current {@link TokenType}
+ */
+ protected string token_to_string () {
GLib.TokenType t = scanner.cur_token ();
switch (t) {
case GLib.TokenType.IDENTIFIER:
@@ -504,7 +528,8 @@ public class GCalc.GParser : Object {
DOT,
ELLIPSIS,
INTERR,
- HASH
+ HASH,
+ CURRENCY_SYMBOL
}
}
diff --git a/gcalc/gcalc-gvariable.vala b/gcalc/gcalc-gvariable.vala
index bd9b3a3d..72c202f4 100644
--- a/gcalc/gcalc-gvariable.vala
+++ b/gcalc/gcalc-gvariable.vala
@@ -21,8 +21,8 @@
public class GCalc.GVariable : GExpression, Variable, Hashable {
public string name { get; construct set; }
- public Constant value { get; set; }
- public Variable bind { get; set; }
+ internal Constant value { get; set; }
+ internal Variable bind { get; set; }
construct {
_value = new GConstant.@double (0.0);
@@ -31,11 +31,11 @@ public class GCalc.GVariable : GExpression, Variable, Hashable {
this.name = name;
}
// Expression
- public override string to_string () {
+ internal override string to_string () {
return name;
}
// Hashable
- public uint hash () {
+ internal uint hash () {
return name.hash ();
}
}
diff --git a/gcalc/gcalc-parameter.vala b/gcalc/gcalc-parameter.vala
new file mode 100644
index 00000000..80c26c3d
--- /dev/null
+++ b/gcalc/gcalc-parameter.vala
@@ -0,0 +1,31 @@
+/* gcalc-expresion.vala
+ *
+ * Copyright (C) 2019 Daniel Espinosa <esodan gmail com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Daniel Espinosa <esodan gmail com>
+ */
+/**
+ * A parameter is a {@link Variable} holding a value, that is not
+ * expected to be resolved as part of an {@link Expression} evaluation,
+ * but by asigning its value.
+ *
+ * Currently the value will be converted to a {@link Constant} if possible.
+ */
+public interface GCalc.Parameter : Object, Variable {
+ public abstract void set_value (GLib.Value val) throws GLib.Error;
+ public abstract GLib.Value get_value ();
+}
diff --git a/gcalc/gcalc-variable.vala b/gcalc/gcalc-variable.vala
index 7a70bb10..721136b8 100644
--- a/gcalc/gcalc-variable.vala
+++ b/gcalc/gcalc-variable.vala
@@ -18,6 +18,9 @@
* Authors:
* Daniel Espinosa <esodan gmail com>
*/
+/**
+ * A variable that can be evaluated from an {@link Expression}
+ */
public interface GCalc.Variable : Object, Expression {
public abstract string name { get; construct set; }
public abstract Constant @value { get; set; }
@@ -28,6 +31,9 @@ public interface GCalc.Variable : Object, Expression {
if (bind != null) {
return bind.evaluate ();
}
+ if (this is Parameter) {
+ return @value;
+ }
if (parent == null) {
throw new VariableError.INVALID_PARENT ("Can't access to Variable's expression definition. Invalid
parent. Expected Assign operator");
}
diff --git a/gcalc/meson.build b/gcalc/meson.build
index 0992a95a..a4cdfbb4 100644
--- a/gcalc/meson.build
+++ b/gcalc/meson.build
@@ -90,6 +90,7 @@ sources = files([
'gcalc-gmath-equation-manager.vala',
'gcalc-gminus.vala',
'gcalc-gmultiply.vala',
+ 'gcalc-gparameter.vala',
'gcalc-gparser.vala',
'gcalc-gplus.vala',
'gcalc-gpolynomial.vala',
@@ -106,6 +107,7 @@ sources = files([
'gcalc-minus.vala',
'gcalc-multiply.vala',
'gcalc-operator.vala',
+ 'gcalc-parameter.vala',
'gcalc-plus.vala',
'gcalc-polynomial.vala',
'gcalc-pow.vala',
diff --git a/tests/gcalc-parsing.vala b/tests/gcalc-parsing.vala
index e71e8380..843a0017 100644
--- a/tests/gcalc-parsing.vala
+++ b/tests/gcalc-parsing.vala
@@ -1071,6 +1071,82 @@ class Tests {
warning ("Error: %s", error.message);
}
});
+ Test.add_func ("/gcalc/parser/parameter/equations",
+ ()=>{
+ try {
+ var parser = new GParser ();
+ var eqman = new GMathEquationManager ();
+ parser.parse ("x=$param1", eqman);
+ parser.parse ("x", eqman);
+ assert (eqman.equations.get_n_items () == 2);
+ var eq = eqman.equations.get_item (0) as MathEquation;
+ assert (eq != null);
+ assert (eq.expressions.get_n_items () == 1);
+ var a = eq.expressions.get_item (0) as Assign;
+ assert (a != null);
+ assert (a.expressions.get_n_items () == 2);
+ var v = a.expressions.get_item (0) as Variable;
+ assert (v != null);
+ assert (v.name == "x");
+ var e = a.expressions.get_item (1) as Polynomial;
+ assert (e != null);
+ assert (e.expressions.get_n_items () == 1);
+ var t = e.expressions.get_item (0) as Term;
+ assert (t != null);
+ var ev = t.expressions.get_item (0) as Variable;
+ assert (ev != null);
+ var p = ev as GCalc.Parameter;
+ assert (p != null);
+ assert (p.name == "param1");
+ var eq2 = eqman.equations.get_item (1) as MathEquation;
+ assert (eq2 != null);
+ message (eq2.to_string ());
+ assert (eq2.expressions.get_n_items () == 1);
+ var e2 = eq2.expressions.get_item (0) as Polynomial;
+ assert (e2 != null);
+ assert (e2.expressions.get_n_items () == 1);
+ var t2 = e2.expressions.get_item (0) as Term;
+ assert (t2 != null);
+ var v2 = t2.expressions.get_item (0) as Variable;
+ assert (v2 != null);
+ } catch (GLib.Error error) {
+ warning ("Error: %s", error.message);
+ }
+ });
+ Test.add_func ("/gcalc/parser/parameter/equations/evaluate",
+ ()=>{
+ try {
+ var parser = new GParser ();
+ var eqman = new GMathEquationManager ();
+ parser.parse ("x=$param1", eqman);
+ parser.parse ("x", eqman);
+ assert (eqman.equations.get_n_items () == 2);
+ var eq = eqman.equations.get_item (0) as MathEquation;
+ assert (eq != null);
+ var r = eq.solve ();
+ assert (r.expression != null);
+ assert (r.expression is Constant);
+ var cr = r.expression as Constant;
+ assert (cr != null);
+ assert (cr.real () == 0.0);
+ var p = eq.variables.find_named ("param1") as GCalc.Parameter;
+ assert (p != null);
+ p.set_value (10.0);
+ r = eq.solve ();
+ assert (r.expression != null);
+ assert (r.expression is Constant);
+ cr = r.expression as Constant;
+ assert (cr != null);
+ assert (cr.real () == 10.0);
+ var eq2 = eqman.equations.get_item (1) as MathEquation;
+ assert (eq2 != null);
+ var cr2 = r.expression as Constant;
+ assert (cr2 != null);
+ assert (cr2.real () == 10.0);
+ } catch (GLib.Error error) {
+ warning ("Error: %s", error.message);
+ }
+ });
return Test.run ();
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]