[gnome-calculator/60-split-out-a-backend-library: 2/2] gcalc: add new library for math parsing/solving



commit 5816d7ef05170a201f85c2356312968ec3f5f80c
Author: Daniel Espinosa Ortiz <esodan gmail com>
Date:   Sun Jan 6 17:17:14 2019 -0600

    gcalc: add new library for math parsing/solving
    
    Fix issue #60
    
    This new library is independent from the internal one.
    
    GCalc provides following features:
    
    * Parse complicated constant equations
    * Parse pre-defined functions (equivalent to the ones in Calculator)
    * Parse complicated equations with pre-defined functions in them
    * Parsing expressions to an Object Oriented tree representation using GObject classes
    * Define arbitrary variables using complicated expressions, with both other variables or constants
    * Evaluate expressions using defined variables
    * Uses MPC as back end for calculation so complex numbers will be available soon
    * No Gtk+ dependencies

 .gitlab-ci.yml                          |    6 +-
 gcalc/gcalc-assign.vala                 |   46 +
 gcalc/gcalc-binary-operator.vala        |   22 +
 gcalc/gcalc-constant.vala               |   31 +
 gcalc/gcalc-division.vala               |   22 +
 gcalc/gcalc-error-result.vala           |   24 +
 gcalc/gcalc-expression-container.vala   |   77 ++
 gcalc/gcalc-expression-hash-map.vala    |   36 +
 gcalc/gcalc-expression.vala             |   30 +
 gcalc/gcalc-function-acos.vala          |   55 ++
 gcalc/gcalc-function-acosh.vala         |   55 ++
 gcalc/gcalc-function-asin.vala          |   55 ++
 gcalc/gcalc-function-asinh.vala         |   55 ++
 gcalc/gcalc-function-atan.vala          |   55 ++
 gcalc/gcalc-function-atanh.vala         |   55 ++
 gcalc/gcalc-function-cos.vala           |   55 ++
 gcalc/gcalc-function-cosh.vala          |   55 ++
 gcalc/gcalc-function-exp.vala           |   55 ++
 gcalc/gcalc-function-log.vala           |   55 ++
 gcalc/gcalc-function-sin.vala           |   55 ++
 gcalc/gcalc-function-sinh.vala          |   55 ++
 gcalc/gcalc-function-sqrt.vala          |   55 ++
 gcalc/gcalc-function-tan.vala           |   55 ++
 gcalc/gcalc-function-tanh.vala          |   55 ++
 gcalc/gcalc-function.vala               |   40 +
 gcalc/gcalc-gassign.vala                |   46 +
 gcalc/gcalc-gconstant.vala              |  125 +++
 gcalc/gcalc-gdivision.vala              |   26 +
 gcalc/gcalc-gerror-result.vala          |   35 +
 gcalc/gcalc-gexpression.vala            |   43 +
 gcalc/gcalc-gfunction.vala              |   60 ++
 gcalc/gcalc-ggroup.vala                 |   54 ++
 gcalc/gcalc-gmath-equation-manager.vala |   46 +
 gcalc/gcalc-gmath-equation.vala         |   38 +
 gcalc/gcalc-gminus.vala                 |   26 +
 gcalc/gcalc-gmultiply.vala              |   26 +
 gcalc/gcalc-gparser.vala                |  503 +++++++++++
 gcalc/gcalc-gplus.vala                  |   26 +
 gcalc/gcalc-gpolynomial.vala            |   33 +
 gcalc/gcalc-gpow.vala                   |   26 +
 gcalc/gcalc-gresult.vala                |   32 +
 gcalc/gcalc-group.vala                  |   45 +
 gcalc/gcalc-gsolver.vala                |   47 ++
 gcalc/gcalc-gterm.vala                  |   33 +
 gcalc/gcalc-gvariable.vala              |   42 +
 gcalc/gcalc-hashable.vala               |   24 +
 gcalc/gcalc-math-equation-manager.vala  |   40 +
 gcalc/gcalc-math-equation.vala          |   24 +
 gcalc/gcalc-minus.vala                  |   22 +
 gcalc/gcalc-multiply.vala               |   22 +
 gcalc/gcalc-operator.vala               |   22 +
 gcalc/gcalc-plus.vala                   |   22 +
 gcalc/gcalc-polynomial.vala             |   61 ++
 gcalc/gcalc-pow.vala                    |   22 +
 gcalc/gcalc-result.vala                 |   25 +
 gcalc/gcalc-solver.vala                 |   28 +
 gcalc/gcalc-term.vala                   |  127 +++
 gcalc/gcalc-variable.vala               |   56 ++
 gcalc/gcalc.deps.in                     |    3 +
 gcalc/gcalc.pc.in                       |   13 +
 gcalc/meson.build                       |  187 +++++
 gcalc/mpfr-glue.vala                    |   28 +
 gcalc/namespace-info.vala.in            |   24 +
 lib/meson.build                         |    3 +-
 lib/mpfr-glue.vala                      |    2 +-
 meson.build                             |   25 +-
 meson_options.txt                       |    3 +
 org.gnome.Calculator.json               |  117 ++-
 search-provider/meson.build             |    5 +-
 src/meson.build                         |    6 +-
 tests/gcalc-parsing.vala                | 1076 ++++++++++++++++++++++++
 tests/gcalc-solving-basic.vala          | 1401 +++++++++++++++++++++++++++++++
 tests/meson.build                       |   48 +-
 vapi/mpc.vapi                           |   20 +-
 74 files changed, 5863 insertions(+), 64 deletions(-)
---
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 4a423b8b..b3a691a5 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -2,12 +2,12 @@
   image: ubuntu:rolling
   before_script:
     - apt-get update
-    - apt-get install -q -y --no-install-recommends meson valac gcc gettext itstool libgtk-3-dev 
libgtksourceview-4-dev libmpc-dev libmpfr-dev libsoup2.4-dev libxml2-dev
+    - apt-get install -q -y --no-install-recommends meson valac gcc gettext itstool libgtk-3-dev 
libgtksourceview-4-dev libmpc-dev libmpfr-dev libsoup2.4-dev libxml2-dev libgee-0.8-dev libvala-0.42
 
 .before_script_template: &fedora_before_script
   image: fedora:latest
   before_script:
-    - dnf install -y meson vala itstool gtk3-devel gtksourceview4-devel libmpc-devel mpfr-devel 
libsoup-devel libxml2-devel
+    - dnf install -y meson vala itstool gtk3-devel gtksourceview4-devel libmpc-devel mpfr-devel 
libsoup-devel libxml2-devel libgee-devel vala-devel
 
 .build_template: &meson_build
   stage: build
@@ -55,4 +55,4 @@ test:fedora:
   dependencies:
     - build:fedora
   <<: *fedora_before_script
-  <<: *meson_test
+  <<: *meson_test
\ No newline at end of file
diff --git a/gcalc/gcalc-assign.vala b/gcalc/gcalc-assign.vala
new file mode 100644
index 00000000..11d9dba3
--- /dev/null
+++ b/gcalc/gcalc-assign.vala
@@ -0,0 +1,46 @@
+/* gcalc-assign.vala
+ *
+ * Copyright (C) 2018  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 interface GCalc.Assign : Object, Expression, Operator, BinaryOperator {
+  public Expression evaluate () throws GLib.Error {
+    if (expressions.get_n_items () != 2) {
+      throw new AssigError.INVALID_STRUCTURE_ERROR ("Invalid number of expressions in assign");
+    }
+    var v = expressions.get_item (0) as Variable;
+    if (v == null) {
+      throw new AssigError.INVALID_STRUCTURE_ERROR ("Invalid variable object in assign");
+    }
+    var p = expressions.get_item (1) as Polynomial;
+    if (p == null) {
+      throw new AssigError.INVALID_STRUCTURE_ERROR ("Invalid polynomial object in assign");
+    }
+    var ca = p.evaluate () as Constant;
+    if (ca == null) {
+      throw new AssigError.INVALID_STRUCTURE_ERROR ("Invalid polynomial evaluation in assign; should a 
constant no Variable update was done");
+    }
+    v.@value = ca;
+    return v.@value;
+  }
+}
+
+public errordomain GCalc.AssigError {
+  INVALID_STRUCTURE_ERROR
+}
+
diff --git a/gcalc/gcalc-binary-operator.vala b/gcalc/gcalc-binary-operator.vala
new file mode 100644
index 00000000..4541fac6
--- /dev/null
+++ b/gcalc/gcalc-binary-operator.vala
@@ -0,0 +1,22 @@
+/* gcalc-binary-operator.vala
+ *
+ * Copyright (C) 2018  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 interface GCalc.BinaryOperator : Object, Expression, Operator {}
+
diff --git a/gcalc/gcalc-constant.vala b/gcalc/gcalc-constant.vala
new file mode 100644
index 00000000..15d1c644
--- /dev/null
+++ b/gcalc/gcalc-constant.vala
@@ -0,0 +1,31 @@
+/* gcalc-constant.vala
+ *
+ * Copyright (C) 2018  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 interface GCalc.Constant : Object, Expression {
+  public abstract double real ();
+  public abstract double imag ();
+  public abstract void zero ();
+  public abstract Constant add (Constant c);
+  public abstract Constant multiply (Constant c);
+  public abstract Constant divide (Constant c);
+  public abstract Constant neg ();
+  public abstract Constant pow (Constant c);
+}
+
diff --git a/gcalc/gcalc-division.vala b/gcalc/gcalc-division.vala
new file mode 100644
index 00000000..68d29bee
--- /dev/null
+++ b/gcalc/gcalc-division.vala
@@ -0,0 +1,22 @@
+/* gcalc-division.vala
+ *
+ * Copyright (C) 2018  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 interface GCalc.Division : Object, Expression, Operator, BinaryOperator {}
+
diff --git a/gcalc/gcalc-error-result.vala b/gcalc/gcalc-error-result.vala
new file mode 100644
index 00000000..365c3d54
--- /dev/null
+++ b/gcalc/gcalc-error-result.vala
@@ -0,0 +1,24 @@
+/* gcalc-error-result.vala
+ *
+ * Copyright (C) 2018  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 interface GCalc.ErrorResult : Object, Result {
+  public abstract string message { get; }
+}
+
diff --git a/gcalc/gcalc-expression-container.vala b/gcalc/gcalc-expression-container.vala
new file mode 100644
index 00000000..2521b389
--- /dev/null
+++ b/gcalc/gcalc-expression-container.vala
@@ -0,0 +1,77 @@
+/* gcalc-expression-container.vala
+ *
+ * Copyright (C) 2018  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.ExpressionContainer : Gee.ArrayList<Expression>, GLib.ListModel {
+  public weak Expression parent { get; set; }
+  public new void add (Expression exp) {
+    (this as Gee.ArrayList<Expression>).add (exp);
+    exp.parent = parent;
+  }
+  public new Expression remove_at (int index) {
+    var r = (this as Gee.ArrayList<Expression>).remove_at (index);
+    if (r != null) {
+      r.parent = null;
+    }
+    return r;
+  }
+  public new Expression remove (Expression exp) {
+    var i = (this as Gee.ArrayList<Expression>).index_of (exp);
+    return remove_at (i);
+  }
+  // GLib.ListModel
+  public Object? get_item (uint position) {
+    return (this as Gee.ArrayList<Expression>).@get ((int) position) as Object;
+  }
+  public Type get_item_type () {
+    return typeof (Expression);
+  }
+  public uint get_n_items () {
+    return (this as Gee.ArrayList<Expression>).size;
+  }
+  public Object? get_object (uint position) {
+    return get_item (position);
+  }
+  public Expression? find (Expression exp) {
+    foreach (Expression e in this) {
+      if (exp is Variable && e is Variable) {
+        if ((exp as Variable).name == (e as Variable).name) {
+          return e;
+        }
+      }
+    }
+    return null;
+  }
+  public Expression? find_named (string name) {
+    foreach (Expression e in this) {
+      if (e is Variable) {
+        if ((e as Variable).name == name) {
+          return e;
+        }
+      }
+      if (e is Function) {
+        if ((e as Function).name == name) {
+          return e;
+        }
+      }
+    }
+    return null;
+  }
+}
+
diff --git a/gcalc/gcalc-expression-hash-map.vala b/gcalc/gcalc-expression-hash-map.vala
new file mode 100644
index 00000000..06e8a793
--- /dev/null
+++ b/gcalc/gcalc-expression-hash-map.vala
@@ -0,0 +1,36 @@
+/* gcalc-expression-hash-table.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.ExpressionHashMap : Gee.HashMap<uint,Expression> {
+  public weak Expression parent { get; set; }
+  public void add (Expression exp)
+    requires (exp is Hashable)
+  {
+    (this as Gee.HashMap<uint,Expression>).set (((Hashable) exp).hash (), exp);
+    exp.parent = parent;
+  }
+  public void remove (Expression exp) {
+    (this as Gee.HashMap<uint,Expression>).unset (((Hashable) exp).hash ());
+  }
+  public Expression find_named (string name) {
+    return (this as Gee.HashMap<uint,Expression>).@get (name.hash ());
+  }
+}
+
diff --git a/gcalc/gcalc-expression.vala b/gcalc/gcalc-expression.vala
new file mode 100644
index 00000000..6b83c5d5
--- /dev/null
+++ b/gcalc/gcalc-expression.vala
@@ -0,0 +1,30 @@
+/* gcalc-expresion.vala
+ *
+ * Copyright (C) 2018  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 interface GCalc.Expression : Object {
+  public abstract weak Expression parent { get; set; }
+  public abstract ExpressionContainer expressions { get; }
+  public abstract string to_string ();
+  public abstract Result solve ();
+}
+
+public interface GCalc.ErrorExpression : Object, Expression {
+}
+
diff --git a/gcalc/gcalc-function-acos.vala b/gcalc/gcalc-function-acos.vala
new file mode 100644
index 00000000..4cdeac66
--- /dev/null
+++ b/gcalc/gcalc-function-acos.vala
@@ -0,0 +1,55 @@
+/* gcalc-function-acos.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.GFunctionAcos : GFunction {
+
+  construct {
+    name = "acos";
+    n_params = 1;
+    param_types.add (new GConstant ());
+  }
+
+  public override Expression evaluate () throws GLib.Error
+  {
+    verify_params ();
+    GConstant c = null;
+    var exp = expressions.get_item (0) as Expression;
+    if (exp == null) {
+      throw new FunctionError.INVOCATION_ERROR ("Invalid parameter type. Expected %s", 
typeof(Expression).name ());
+    }
+    var ev = exp.solve ();
+    if (ev is ErrorResult) {
+       throw new FunctionError.INVOCATION_ERROR ("Invalid expression: %s", ((ErrorResult) ev).message);
+    }
+    if (ev is Result) {
+      c = ((Result) ev).expression as GConstant;
+    }
+    if (c == null) {
+       throw new FunctionError.INVOCATION_ERROR ("Invalid expression in result");
+    }
+    var p1 = MPC.Complex (1000);
+    p1.set (c.get_complex ());
+    var res = MPC.Complex (1000);
+    res.acos (p1);
+    var nc = new GConstant.internal_complex (res);
+    return nc as Expression;
+  }
+}
+
diff --git a/gcalc/gcalc-function-acosh.vala b/gcalc/gcalc-function-acosh.vala
new file mode 100644
index 00000000..00d39d0d
--- /dev/null
+++ b/gcalc/gcalc-function-acosh.vala
@@ -0,0 +1,55 @@
+/* gcalc-function-acosh.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.GFunctionAcosh : GFunction {
+
+  construct {
+    name = "acosh";
+    n_params = 1;
+    param_types.add (new GConstant ());
+  }
+
+  public override Expression evaluate () throws GLib.Error
+  {
+    verify_params ();
+    GConstant c = null;
+    var exp = expressions.get_item (0) as Expression;
+    if (exp == null) {
+      throw new FunctionError.INVOCATION_ERROR ("Invalid parameter type. Expected %s", 
typeof(Expression).name ());
+    }
+    var ev = exp.solve ();
+    if (ev is ErrorResult) {
+       throw new FunctionError.INVOCATION_ERROR ("Invalid expression: %s", ((ErrorResult) ev).message);
+    }
+    if (ev is Result) {
+      c = ((Result) ev).expression as GConstant;
+    }
+    if (c == null) {
+       throw new FunctionError.INVOCATION_ERROR ("Invalid expression in result");
+    }
+    var p1 = MPC.Complex (1000);
+    p1.set (c.get_complex ());
+    var res = MPC.Complex (1000);
+    res.acosh (p1);
+    var nc = new GConstant.internal_complex (res);
+    return nc as Expression;
+  }
+}
+
diff --git a/gcalc/gcalc-function-asin.vala b/gcalc/gcalc-function-asin.vala
new file mode 100644
index 00000000..a8d9ce27
--- /dev/null
+++ b/gcalc/gcalc-function-asin.vala
@@ -0,0 +1,55 @@
+/* gcalc-function-asin.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.GFunctionAsin : GFunction {
+
+  construct {
+    name = "asin";
+    n_params = 1;
+    param_types.add (new GConstant ());
+  }
+
+  public override Expression evaluate () throws GLib.Error
+  {
+    verify_params ();
+    GConstant c = null;
+    var exp = expressions.get_item (0) as Expression;
+    if (exp == null) {
+      throw new FunctionError.INVOCATION_ERROR ("Invalid parameter type. Expected %s", 
typeof(Expression).name ());
+    }
+    var ev = exp.solve ();
+    if (ev is ErrorResult) {
+       throw new FunctionError.INVOCATION_ERROR ("Invalid expression: %s", ((ErrorResult) ev).message);
+    }
+    if (ev is Result) {
+      c = ((Result) ev).expression as GConstant;
+    }
+    if (c == null) {
+       throw new FunctionError.INVOCATION_ERROR ("Invalid expression in result");
+    }
+    var p1 = MPC.Complex (1000);
+    p1.set (c.get_complex ());
+    var res = MPC.Complex (1000);
+    res.asin (p1);
+    var nc = new GConstant.internal_complex (res);
+    return nc as Expression;
+  }
+}
+
diff --git a/gcalc/gcalc-function-asinh.vala b/gcalc/gcalc-function-asinh.vala
new file mode 100644
index 00000000..4bcbf877
--- /dev/null
+++ b/gcalc/gcalc-function-asinh.vala
@@ -0,0 +1,55 @@
+/* gcalc-function-asinh.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.GFunctionAsinh : GFunction {
+
+  construct {
+    name = "asinh";
+    n_params = 1;
+    param_types.add (new GConstant ());
+  }
+
+  public override Expression evaluate () throws GLib.Error
+  {
+    verify_params ();
+    GConstant c = null;
+    var exp = expressions.get_item (0) as Expression;
+    if (exp == null) {
+      throw new FunctionError.INVOCATION_ERROR ("Invalid parameter type. Expected %s", 
typeof(Expression).name ());
+    }
+    var ev = exp.solve ();
+    if (ev is ErrorResult) {
+       throw new FunctionError.INVOCATION_ERROR ("Invalid expression: %s", ((ErrorResult) ev).message);
+    }
+    if (ev is Result) {
+      c = ((Result) ev).expression as GConstant;
+    }
+    if (c == null) {
+       throw new FunctionError.INVOCATION_ERROR ("Invalid expression in result");
+    }
+    var p1 = MPC.Complex (1000);
+    p1.set (c.get_complex ());
+    var res = MPC.Complex (1000);
+    res.asinh (p1);
+    var nc = new GConstant.internal_complex (res);
+    return nc as Expression;
+  }
+}
+
diff --git a/gcalc/gcalc-function-atan.vala b/gcalc/gcalc-function-atan.vala
new file mode 100644
index 00000000..5af108b5
--- /dev/null
+++ b/gcalc/gcalc-function-atan.vala
@@ -0,0 +1,55 @@
+/* gcalc-function-atan.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.GFunctionAtan : GFunction {
+
+  construct {
+    name = "atan";
+    n_params = 1;
+    param_types.add (new GConstant ());
+  }
+
+  public override Expression evaluate () throws GLib.Error
+  {
+    verify_params ();
+    GConstant c = null;
+    var exp = expressions.get_item (0) as Expression;
+    if (exp == null) {
+      throw new FunctionError.INVOCATION_ERROR ("Invalid parameter type. Expected %s", 
typeof(Expression).name ());
+    }
+    var ev = exp.solve ();
+    if (ev is ErrorResult) {
+       throw new FunctionError.INVOCATION_ERROR ("Invalid expression: %s", ((ErrorResult) ev).message);
+    }
+    if (ev is Result) {
+      c = ((Result) ev).expression as GConstant;
+    }
+    if (c == null) {
+       throw new FunctionError.INVOCATION_ERROR ("Invalid expression in result");
+    }
+    var p1 = MPC.Complex (1000);
+    p1.set (c.get_complex ());
+    var res = MPC.Complex (1000);
+    res.atan (p1);
+    var nc = new GConstant.internal_complex (res);
+    return nc as Expression;
+  }
+}
+
diff --git a/gcalc/gcalc-function-atanh.vala b/gcalc/gcalc-function-atanh.vala
new file mode 100644
index 00000000..2bc32229
--- /dev/null
+++ b/gcalc/gcalc-function-atanh.vala
@@ -0,0 +1,55 @@
+/* gcalc-function-atanh.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.GFunctionAtanh : GFunction {
+
+  construct {
+    name = "atanh";
+    n_params = 1;
+    param_types.add (new GConstant ());
+  }
+
+  public override Expression evaluate () throws GLib.Error
+  {
+    verify_params ();
+    GConstant c = null;
+    var exp = expressions.get_item (0) as Expression;
+    if (exp == null) {
+      throw new FunctionError.INVOCATION_ERROR ("Invalid parameter type. Expected %s", 
typeof(Expression).name ());
+    }
+    var ev = exp.solve ();
+    if (ev is ErrorResult) {
+       throw new FunctionError.INVOCATION_ERROR ("Invalid expression: %s", ((ErrorResult) ev).message);
+    }
+    if (ev is Result) {
+      c = ((Result) ev).expression as GConstant;
+    }
+    if (c == null) {
+       throw new FunctionError.INVOCATION_ERROR ("Invalid expression in result");
+    }
+    var p1 = MPC.Complex (1000);
+    p1.set (c.get_complex ());
+    var res = MPC.Complex (1000);
+    res.atanh (p1);
+    var nc = new GConstant.internal_complex (res);
+    return nc as Expression;
+  }
+}
+
diff --git a/gcalc/gcalc-function-cos.vala b/gcalc/gcalc-function-cos.vala
new file mode 100644
index 00000000..ab5828e1
--- /dev/null
+++ b/gcalc/gcalc-function-cos.vala
@@ -0,0 +1,55 @@
+/* gcalc-function-cos.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.GFunctionCos : GFunction {
+
+  construct {
+    name = "cos";
+    n_params = 1;
+    param_types.add (new GConstant ());
+  }
+
+  public override Expression evaluate () throws GLib.Error
+  {
+    verify_params ();
+    GConstant c = null;
+    var exp = expressions.get_item (0) as Expression;
+    if (exp == null) {
+      throw new FunctionError.INVOCATION_ERROR ("Invalid parameter type. Expected %s", 
typeof(Expression).name ());
+    }
+    var ev = exp.solve ();
+    if (ev is ErrorResult) {
+       throw new FunctionError.INVOCATION_ERROR ("Invalid expression: %s", ((ErrorResult) ev).message);
+    }
+    if (ev is Result) {
+      c = ((Result) ev).expression as GConstant;
+    }
+    if (c == null) {
+       throw new FunctionError.INVOCATION_ERROR ("Invalid expression in result");
+    }
+    var p1 = MPC.Complex (1000);
+    p1.set (c.get_complex ());
+    var res = MPC.Complex (1000);
+    res.cos (p1);
+    var nc = new GConstant.internal_complex (res);
+    return nc as Expression;
+  }
+}
+
diff --git a/gcalc/gcalc-function-cosh.vala b/gcalc/gcalc-function-cosh.vala
new file mode 100644
index 00000000..e051ce82
--- /dev/null
+++ b/gcalc/gcalc-function-cosh.vala
@@ -0,0 +1,55 @@
+/* gcalc-function-cosh.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.GFunctionCosh : GFunction {
+
+  construct {
+    name = "cosh";
+    n_params = 1;
+    param_types.add (new GConstant ());
+  }
+
+  public override Expression evaluate () throws GLib.Error
+  {
+    verify_params ();
+    GConstant c = null;
+    var exp = expressions.get_item (0) as Expression;
+    if (exp == null) {
+      throw new FunctionError.INVOCATION_ERROR ("Invalid parameter type. Expected %s", 
typeof(Expression).name ());
+    }
+    var ev = exp.solve ();
+    if (ev is ErrorResult) {
+       throw new FunctionError.INVOCATION_ERROR ("Invalid expression: %s", ((ErrorResult) ev).message);
+    }
+    if (ev is Result) {
+      c = ((Result) ev).expression as GConstant;
+    }
+    if (c == null) {
+       throw new FunctionError.INVOCATION_ERROR ("Invalid expression in result");
+    }
+    var p1 = MPC.Complex (1000);
+    p1.set (c.get_complex ());
+    var res = MPC.Complex (1000);
+    res.cosh (p1);
+    var nc = new GConstant.internal_complex (res);
+    return nc as Expression;
+  }
+}
+
diff --git a/gcalc/gcalc-function-exp.vala b/gcalc/gcalc-function-exp.vala
new file mode 100644
index 00000000..1cf135b1
--- /dev/null
+++ b/gcalc/gcalc-function-exp.vala
@@ -0,0 +1,55 @@
+/* gcalc-function-exp.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.GFunctionExp : GFunction {
+
+  construct {
+    name = "exp";
+    n_params = 1;
+    param_types.add (new GConstant ());
+  }
+
+  public override Expression evaluate () throws GLib.Error
+  {
+    verify_params ();
+    GConstant c = null;
+    var exp = expressions.get_item (0) as Expression;
+    if (exp == null) {
+      throw new FunctionError.INVOCATION_ERROR ("Invalid parameter type. Expected %s", 
typeof(Expression).name ());
+    }
+    var ev = exp.solve ();
+    if (ev is ErrorResult) {
+       throw new FunctionError.INVOCATION_ERROR ("Invalid expression: %s", ((ErrorResult) ev).message);
+    }
+    if (ev is Result) {
+      c = ((Result) ev).expression as GConstant;
+    }
+    if (c == null) {
+       throw new FunctionError.INVOCATION_ERROR ("Invalid expression in result");
+    }
+    var p1 = MPC.Complex (1000);
+    p1.set (c.get_complex ());
+    var res = MPC.Complex (1000);
+    res.exp (p1);
+    var nc = new GConstant.internal_complex (res);
+    return nc as Expression;
+  }
+}
+
diff --git a/gcalc/gcalc-function-log.vala b/gcalc/gcalc-function-log.vala
new file mode 100644
index 00000000..de57efe8
--- /dev/null
+++ b/gcalc/gcalc-function-log.vala
@@ -0,0 +1,55 @@
+/* gcalc-function-log.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.GFunctionLog : GFunction {
+
+  construct {
+    name = "log";
+    n_params = 1;
+    param_types.add (new GConstant ());
+  }
+
+  public override Expression evaluate () throws GLib.Error
+  {
+    verify_params ();
+    GConstant c = null;
+    var exp = expressions.get_item (0) as Expression;
+    if (exp == null) {
+      throw new FunctionError.INVOCATION_ERROR ("Invalid parameter type. Expected %s", 
typeof(Expression).name ());
+    }
+    var ev = exp.solve ();
+    if (ev is ErrorResult) {
+       throw new FunctionError.INVOCATION_ERROR ("Invalid expression: %s", ((ErrorResult) ev).message);
+    }
+    if (ev is Result) {
+      c = ((Result) ev).expression as GConstant;
+    }
+    if (c == null) {
+       throw new FunctionError.INVOCATION_ERROR ("Invalid expression in result");
+    }
+    var p1 = MPC.Complex (1000);
+    p1.set (c.get_complex ());
+    var res = MPC.Complex (1000);
+    res.log (p1);
+    var nc = new GConstant.internal_complex (res);
+    return nc as Expression;
+  }
+}
+
diff --git a/gcalc/gcalc-function-sin.vala b/gcalc/gcalc-function-sin.vala
new file mode 100644
index 00000000..5a288a0b
--- /dev/null
+++ b/gcalc/gcalc-function-sin.vala
@@ -0,0 +1,55 @@
+/* gcalc-function-sin.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.GFunctionSin : GFunction {
+
+  construct {
+    name = "sin";
+    n_params = 1;
+    param_types.add (new GConstant ());
+  }
+
+  public override Expression evaluate () throws GLib.Error
+  {
+    verify_params ();
+    GConstant c = null;
+    var exp = expressions.get_item (0) as Expression;
+    if (exp == null) {
+      throw new FunctionError.INVOCATION_ERROR ("Invalid parameter type. Expected %s", 
typeof(Expression).name ());
+    }
+    var ev = exp.solve ();
+    if (ev is ErrorResult) {
+       throw new FunctionError.INVOCATION_ERROR ("Invalid expression: %s", ((ErrorResult) ev).message);
+    }
+    if (ev is Result) {
+      c = ((Result) ev).expression as GConstant;
+    }
+    if (c == null) {
+       throw new FunctionError.INVOCATION_ERROR ("Invalid expression in result");
+    }
+    var p1 = MPC.Complex (1000);
+    p1.set (c.get_complex ());
+    var res = MPC.Complex (1000);
+    res.sin (p1);
+    var nc = new GConstant.internal_complex (res);
+    return nc as Expression;
+  }
+}
+
diff --git a/gcalc/gcalc-function-sinh.vala b/gcalc/gcalc-function-sinh.vala
new file mode 100644
index 00000000..92c796ef
--- /dev/null
+++ b/gcalc/gcalc-function-sinh.vala
@@ -0,0 +1,55 @@
+/* gcalc-function-sinh.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.GFunctionSinh : GFunction {
+
+  construct {
+    name = "sinh";
+    n_params = 1;
+    param_types.add (new GConstant ());
+  }
+
+  public override Expression evaluate () throws GLib.Error
+  {
+    verify_params ();
+    GConstant c = null;
+    var exp = expressions.get_item (0) as Expression;
+    if (exp == null) {
+      throw new FunctionError.INVOCATION_ERROR ("Invalid parameter type. Expected %s", 
typeof(Expression).name ());
+    }
+    var ev = exp.solve ();
+    if (ev is ErrorResult) {
+       throw new FunctionError.INVOCATION_ERROR ("Invalid expression: %s", ((ErrorResult) ev).message);
+    }
+    if (ev is Result) {
+      c = ((Result) ev).expression as GConstant;
+    }
+    if (c == null) {
+       throw new FunctionError.INVOCATION_ERROR ("Invalid expression in result");
+    }
+    var p1 = MPC.Complex (1000);
+    p1.set (c.get_complex ());
+    var res = MPC.Complex (1000);
+    res.sinh (p1);
+    var nc = new GConstant.internal_complex (res);
+    return nc as Expression;
+  }
+}
+
diff --git a/gcalc/gcalc-function-sqrt.vala b/gcalc/gcalc-function-sqrt.vala
new file mode 100644
index 00000000..0291cd8f
--- /dev/null
+++ b/gcalc/gcalc-function-sqrt.vala
@@ -0,0 +1,55 @@
+/* gcalc-function-sqrt.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.GFunctionSqrt : GFunction {
+
+  construct {
+    name = "sqrt";
+    n_params = 1;
+    param_types.add (new GConstant ());
+  }
+
+  public override Expression evaluate () throws GLib.Error
+  {
+    verify_params ();
+    GConstant c = null;
+    var exp = expressions.get_item (0) as Expression;
+    if (exp == null) {
+      throw new FunctionError.INVOCATION_ERROR ("Invalid parameter type. Expected %s", 
typeof(Expression).name ());
+    }
+    var ev = exp.solve ();
+    if (ev is ErrorResult) {
+       throw new FunctionError.INVOCATION_ERROR ("Invalid expression: %s", ((ErrorResult) ev).message);
+    }
+    if (ev is Result) {
+      c = ((Result) ev).expression as GConstant;
+    }
+    if (c == null) {
+       throw new FunctionError.INVOCATION_ERROR ("Invalid expression in result");
+    }
+    var p1 = MPC.Complex (1000);
+    p1.set (c.get_complex ());
+    var res = MPC.Complex (1000);
+    res.sqrt (p1);
+    var nc = new GConstant.internal_complex (res);
+    return nc as Expression;
+  }
+}
+
diff --git a/gcalc/gcalc-function-tan.vala b/gcalc/gcalc-function-tan.vala
new file mode 100644
index 00000000..3793076b
--- /dev/null
+++ b/gcalc/gcalc-function-tan.vala
@@ -0,0 +1,55 @@
+/* gcalc-function-tan.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.GFunctionTan : GFunction {
+
+  construct {
+    name = "tan";
+    n_params = 1;
+    param_types.add (new GConstant ());
+  }
+
+  public override Expression evaluate () throws GLib.Error
+  {
+    verify_params ();
+    GConstant c = null;
+    var exp = expressions.get_item (0) as Expression;
+    if (exp == null) {
+      throw new FunctionError.INVOCATION_ERROR ("Invalid parameter type. Expected %s", 
typeof(Expression).name ());
+    }
+    var ev = exp.solve ();
+    if (ev is ErrorResult) {
+       throw new FunctionError.INVOCATION_ERROR ("Invalid expression: %s", ((ErrorResult) ev).message);
+    }
+    if (ev is Result) {
+      c = ((Result) ev).expression as GConstant;
+    }
+    if (c == null) {
+       throw new FunctionError.INVOCATION_ERROR ("Invalid expression in result");
+    }
+    var p1 = MPC.Complex (1000);
+    p1.set (c.get_complex ());
+    var res = MPC.Complex (1000);
+    res.tan (p1);
+    var nc = new GConstant.internal_complex (res);
+    return nc as Expression;
+  }
+}
+
diff --git a/gcalc/gcalc-function-tanh.vala b/gcalc/gcalc-function-tanh.vala
new file mode 100644
index 00000000..831157ba
--- /dev/null
+++ b/gcalc/gcalc-function-tanh.vala
@@ -0,0 +1,55 @@
+/* gcalc-function-tanh.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.GFunctionTanh : GFunction {
+
+  construct {
+    name = "tanh";
+    n_params = 1;
+    param_types.add (new GConstant ());
+  }
+
+  public override Expression evaluate () throws GLib.Error
+  {
+    verify_params ();
+    GConstant c = null;
+    var exp = expressions.get_item (0) as Expression;
+    if (exp == null) {
+      throw new FunctionError.INVOCATION_ERROR ("Invalid parameter type. Expected %s", 
typeof(Expression).name ());
+    }
+    var ev = exp.solve ();
+    if (ev is ErrorResult) {
+       throw new FunctionError.INVOCATION_ERROR ("Invalid expression: %s", ((ErrorResult) ev).message);
+    }
+    if (ev is Result) {
+      c = ((Result) ev).expression as GConstant;
+    }
+    if (c == null) {
+       throw new FunctionError.INVOCATION_ERROR ("Invalid expression in result");
+    }
+    var p1 = MPC.Complex (1000);
+    p1.set (c.get_complex ());
+    var res = MPC.Complex (1000);
+    res.tanh (p1);
+    var nc = new GConstant.internal_complex (res);
+    return nc as Expression;
+  }
+}
+
diff --git a/gcalc/gcalc-function.vala b/gcalc/gcalc-function.vala
new file mode 100644
index 00000000..9c6f9f8a
--- /dev/null
+++ b/gcalc/gcalc-function.vala
@@ -0,0 +1,40 @@
+/* gcalc-function.vala
+ *
+ * Copyright (C) 2018  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 interface GCalc.Function : Object, Expression {
+  public abstract ExpressionContainer param_types { get; }
+  public abstract string name { get; construct set; }
+  public abstract uint n_params { get; construct set; }
+  public abstract bool closed { get; set; }
+  public abstract Expression evaluate () throws GLib.Error;
+  public virtual bool verify_params () throws GLib.Error {
+    if (expressions.get_n_items () != n_params) {
+      throw new FunctionError.INVALID_PARAMETERS_ERROR ("Invalid number of parameters. Required %u, 
provided: %u",
+                                                  n_params, expressions.get_n_items ());
+    }
+    return true;
+  }
+}
+
+public errordomain GCalc.FunctionError {
+  INVALID_PARAMETERS_ERROR,
+  INVOCATION_ERROR
+}
+
diff --git a/gcalc/gcalc-gassign.vala b/gcalc/gcalc-gassign.vala
new file mode 100644
index 00000000..91bf4bd9
--- /dev/null
+++ b/gcalc/gcalc-gassign.vala
@@ -0,0 +1,46 @@
+/* gcalc-gassign.vala
+ *
+ * Copyright (C) 2018  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.GAssign : GExpression, Operator, BinaryOperator, Assign {
+  public override string to_string () {
+    if (expressions.get_n_items () != 2) {
+      return "Invalid Assigment structure";
+    }
+    var v = expressions.get_item (0) as Variable;
+    if (v == null) {
+      return "Invalid Assigment structure. No variable is set";
+    }
+    var e = expressions.get_item (1) as Expression;
+    if (e == null) {
+      return "Invalid Assigment structure. No variable's definition is set";
+    }
+    return v.to_string ()+"="+e.to_string ();
+  }
+  public override Result solve () {
+    Result res = null;
+    try {
+      res = new GResult (evaluate ());
+    } catch (GLib.Error e) {
+      res = new GErrorResult ("Invalid expression in Assignment: %s".printf (e.message));
+    }
+    return res;
+  }
+}
+
diff --git a/gcalc/gcalc-gconstant.vala b/gcalc/gcalc-gconstant.vala
new file mode 100644
index 00000000..88ea0bc3
--- /dev/null
+++ b/gcalc/gcalc-gconstant.vala
@@ -0,0 +1,125 @@
+/* gcalc-gconstant.vala
+ *
+ * Copyright (C) 2018  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.GConstant : GExpression, Constant {
+  private MPC.Complex _complex = MPC.Complex (1000);
+
+  internal unowned MPC.Complex get_complex () { return _complex; }
+
+  construct {
+    _complex.set_double (0.0);
+  }
+  internal GConstant.internal_complex (MPC.Complex complex) {
+    _complex.set (complex);
+  }
+  public GConstant.integer (int val) {
+    _complex.set_double (val);
+  }
+  public GConstant.unsigned_integer (uint val) {
+    _complex.set_double (val);
+  }
+  public GConstant.@double (double val) {
+    _complex.set_double (val);
+  }
+  public GConstant.complex (double real, double imag) {
+    _complex.set_double (real, imag);
+  }
+
+  // Constant Interface
+  public double real () {
+    return _complex.get_real_double ();
+  }
+  public double imag () {
+    return _complex.get_imag_double ();
+  }
+  public void zero () {
+    MPFR.Real r = MPFR.Real (1000);
+    r.set_zero ();
+    _complex.set_mpreal (r);
+  }
+  public Constant add (Constant c)
+    requires (c is GConstant)
+  {
+    var res = MPC.Complex (1000);
+    var p1 = MPC.Complex (1000);
+    p1.set ((c as GConstant).get_complex ());
+    res.add (_complex, p1);
+    var nc = new GConstant.internal_complex (res);
+    return nc as Constant;
+  }
+  public Constant subtract (Constant c)
+    requires (c is GConstant)
+  {
+    var res = MPC.Complex (1000);
+    var p1 = MPC.Complex (1000);
+    p1.set ((c as GConstant).get_complex ());
+    res.subtract (_complex, p1);
+    var nc = new GConstant.internal_complex (res);
+    return nc as Constant;
+  }
+  public Constant multiply (Constant c)
+    requires (c is GConstant)
+  {
+    var res = MPC.Complex (1000);
+    var p1 = MPC.Complex (1000);
+    p1.set ((c as GConstant).get_complex ());
+    res.multiply (_complex, p1);
+    var nc = new GConstant.internal_complex (res);
+    return nc as Constant;
+  }
+  public Constant divide (Constant c)
+    requires (c is GConstant)
+  {
+    var res = MPC.Complex (1000);
+    var p1 = MPC.Complex (1000);
+    p1.set ((c as GConstant).get_complex ());
+    res.divide (_complex, p1);
+    var nc = new GConstant.internal_complex (res);
+    return nc as Constant;
+  }
+  public Constant neg ()
+  {
+    var res = MPC.Complex (1000);
+    res.neg (_complex);
+    var nc = new GConstant.internal_complex (res);
+    return nc as Constant;
+  }
+  public Constant pow (Constant c)
+    requires (c is GConstant)
+  {
+    var res = MPC.Complex (1000);
+    var p1 = MPC.Complex (1000);
+    p1.set ((c as GConstant).get_complex ());
+    res.power (_complex, p1);
+    var nc = new GConstant.internal_complex (res);
+    return nc as Constant;
+  }
+  // Expression interface
+  public override string to_string () {
+    if (imag () != 0.0) {
+      return MPC.Complex.to_string (10, 10, _complex);
+    }
+    return "%g".printf (real ());
+  }
+  public override Result solve () {
+    return new GResult (this) as Result;
+  }
+}
+
diff --git a/gcalc/gcalc-gdivision.vala b/gcalc/gcalc-gdivision.vala
new file mode 100644
index 00000000..9832cd0b
--- /dev/null
+++ b/gcalc/gcalc-gdivision.vala
@@ -0,0 +1,26 @@
+/* gcalc-gplus.vala
+ *
+ * Copyright (C) 2018  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.GDivision : GExpression, Operator, BinaryOperator, Division {
+  public override string to_string () {
+    return "/";
+  }
+}
+
diff --git a/gcalc/gcalc-gerror-result.vala b/gcalc/gcalc-gerror-result.vala
new file mode 100644
index 00000000..9cb43886
--- /dev/null
+++ b/gcalc/gcalc-gerror-result.vala
@@ -0,0 +1,35 @@
+/* gcalc-gerror-result.vala
+ *
+ * Copyright (C) 2018  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.GErrorResult : Object, Result, ErrorResult {
+  private string msg = "";
+  private Expression _expression;
+
+  public GErrorResult (string msg) {
+    this.msg = msg;
+    _expression = new GErrorExpression ();
+  }
+  // Result
+  public Expression expression { get { return _expression; } }
+  public string to_string () { return msg; }
+  // ErrorResult
+  public string message { get { return msg; } }
+}
+
diff --git a/gcalc/gcalc-gexpression.vala b/gcalc/gcalc-gexpression.vala
new file mode 100644
index 00000000..ea35587f
--- /dev/null
+++ b/gcalc/gcalc-gexpression.vala
@@ -0,0 +1,43 @@
+/* gcalc-gexpresion.vala
+ *
+ * Copyright (C) 2018  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.GExpression : Object, Expression {
+  ExpressionContainer exps = new ExpressionContainer ();
+  construct {
+    exps.parent = this;
+  }
+  // Expression
+  public weak Expression parent { get; set; }
+  public ExpressionContainer expressions { get { return exps; } }
+  public new virtual string to_string () {
+    string s = "";
+    foreach (Expression e in expressions) {
+      s += e.to_string ();
+    }
+    return s;
+  }
+  public new virtual Result solve () {
+    return new GErrorResult ("Invalid expression");
+  }
+}
+
+
+public class GCalc.GErrorExpression : GExpression, ErrorExpression {}
+
diff --git a/gcalc/gcalc-gfunction.vala b/gcalc/gcalc-gfunction.vala
new file mode 100644
index 00000000..bfb29479
--- /dev/null
+++ b/gcalc/gcalc-gfunction.vala
@@ -0,0 +1,60 @@
+/* gcalc-gfunction.vala
+ *
+ * Copyright (C) 2018  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.GFunction : GExpression, Function, Hashable {
+  ExpressionContainer _param_types = new ExpressionContainer ();
+
+  public ExpressionContainer param_types { get { return _param_types; } }
+  public uint n_params { get; construct set; }
+  public string name { get; construct set; }
+  public bool closed { get; set; }
+
+  construct {
+    name = "NoName";
+  }
+  public GFunction.with_name (string name, int nparams) {
+    this.name = name;
+    n_params = nparams;
+  }
+  public override string to_string () {
+    string s = name + "(";
+    for (uint i = 0; i < expressions.get_n_items (); i++) {
+      var e = expressions.get_item (i) as Expression;
+      if (e == null) {
+        continue;
+      }
+      s += e.to_string ();
+      if (i + 1 < expressions.get_n_items ()) {
+        s += ",";
+      }
+    }
+    s += ")";
+    return s;
+  }
+
+  public new virtual Expression evaluate () throws GLib.Error {
+    return new GErrorExpression ();
+  }
+  // Hashable
+  public uint hash () {
+    return name.hash ();
+  }
+}
+
diff --git a/gcalc/gcalc-ggroup.vala b/gcalc/gcalc-ggroup.vala
new file mode 100644
index 00000000..b9e7b074
--- /dev/null
+++ b/gcalc/gcalc-ggroup.vala
@@ -0,0 +1,54 @@
+/* gcalc-ggroup.vala
+ *
+ * Copyright (C) 2018  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.GGroup : GExpression, Group {
+  public Group.Level level { get; set; }
+  public bool closed { get; set; }
+  public override string to_string () {
+    string s = "";
+    switch (level) {
+      case ONE:
+        s = "(";
+        break;
+      case TWO:
+        s = "[";
+        break;
+      case THREE:
+        s = "{";
+        break;
+    }
+    foreach (Expression e in expressions) {
+      s += e.to_string ();
+    }
+    switch (level) {
+      case ONE:
+        s += ")";
+        break;
+      case TWO:
+        s += "]";
+        break;
+      case THREE:
+        s += "}";
+        break;
+    }
+    return s;
+  }
+}
+
diff --git a/gcalc/gcalc-gmath-equation-manager.vala b/gcalc/gcalc-gmath-equation-manager.vala
new file mode 100644
index 00000000..c0733d35
--- /dev/null
+++ b/gcalc/gcalc-gmath-equation-manager.vala
@@ -0,0 +1,46 @@
+/* gcalc-gmath-equation-manager.vala
+ *
+ * Copyright (C) 2018  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.GMathEquationManager : Object, MathEquationManager {
+  ExpressionContainer _equations = new ExpressionContainer ();
+  ExpressionContainer _functions = new ExpressionContainer ();
+  public ExpressionContainer equations { get { return _equations; } }
+  public ExpressionContainer functions { get { return _functions; } }
+
+  construct {
+    // Initialize default Functions
+    functions.add (new GFunctionSqrt ());
+    functions.add (new GFunctionExp ());
+    functions.add (new GFunctionLog ());
+    functions.add (new GFunctionSin ());
+    functions.add (new GFunctionCos ());
+    functions.add (new GFunctionTan ());
+    functions.add (new GFunctionAsin ());
+    functions.add (new GFunctionAcos ());
+    functions.add (new GFunctionAtan ());
+    functions.add (new GFunctionSinh ());
+    functions.add (new GFunctionCosh ());
+    functions.add (new GFunctionTanh ());
+    functions.add (new GFunctionAsinh ());
+    functions.add (new GFunctionAcosh ());
+    functions.add (new GFunctionAtanh ());
+  }
+}
+
diff --git a/gcalc/gcalc-gmath-equation.vala b/gcalc/gcalc-gmath-equation.vala
new file mode 100644
index 00000000..50d1157f
--- /dev/null
+++ b/gcalc/gcalc-gmath-equation.vala
@@ -0,0 +1,38 @@
+/* gcalc-gmath-equation.vala
+ *
+ * Copyright (C) 2018  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.GMathEquation : GExpression, MathEquation {
+  ExpressionHashMap _variables = new ExpressionHashMap ();
+  public ExpressionHashMap variables { get { return _variables; } }
+  public override Result solve () {
+    Result res = null;
+    if (expressions.get_n_items () == 0) {
+      return new GErrorResult ("No expressions found in equation");
+    }
+    var e = expressions.get_item (0) as Expression;
+    if (e == null) {
+      res = new GErrorResult ("Invalid expression in equation");
+    } else {
+      res = e.solve ();
+    }
+    return res;
+  }
+}
+
diff --git a/gcalc/gcalc-gminus.vala b/gcalc/gcalc-gminus.vala
new file mode 100644
index 00000000..0cc90ea3
--- /dev/null
+++ b/gcalc/gcalc-gminus.vala
@@ -0,0 +1,26 @@
+/* gcalc-gminus.vala
+ *
+ * Copyright (C) 2018  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.GMinus : GExpression, Operator, BinaryOperator, Minus {
+  public override string to_string () {
+    return "-";
+  }
+}
+
diff --git a/gcalc/gcalc-gmultiply.vala b/gcalc/gcalc-gmultiply.vala
new file mode 100644
index 00000000..384b092c
--- /dev/null
+++ b/gcalc/gcalc-gmultiply.vala
@@ -0,0 +1,26 @@
+/* gcalc-gmultiply.vala
+ *
+ * Copyright (C) 2018  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.GMultiply : GExpression, Operator, BinaryOperator, Multiply {
+  public override string to_string () {
+    return "*";
+  }
+}
+
diff --git a/gcalc/gcalc-gparser.vala b/gcalc/gcalc-gparser.vala
new file mode 100644
index 00000000..e6918870
--- /dev/null
+++ b/gcalc/gcalc-gparser.vala
@@ -0,0 +1,503 @@
+/* gcalc-gexpresion.vala
+ *
+ * Copyright (C) 2018  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>
+ */
+using Vala;
+
+public class GCalc.GParser : Object {
+  Expression current = null;
+  Expression current_parent = null;
+  Expression top_parent = null;
+  Gee.ArrayList<Vala.TokenType> expected = new Gee.ArrayList<Vala.TokenType> ();
+
+  public void parse (string str, MathEquationManager eqman) throws GLib.Error {
+    var context = new CodeContext ();
+    CodeContext.push (context);
+    SourceFileType type = SourceFileType.NONE;
+    var sf = new SourceFile (context, type, "gcalc://", str);
+    var scanner = new Vala.Scanner (sf);
+    string[] lines;
+    if ("\n" in str) {
+      lines = str.split ("\n");
+    } else {
+      lines = new string [0];
+      lines[0] = str;
+    }
+    Vala.TokenType token = Vala.TokenType.NONE;
+    GMathEquation eq = new GMathEquation ();
+    current = null;
+    current_parent = null;
+    top_parent = null;
+    while (token != Vala.TokenType.EOF) {
+      Vala.SourceLocation begin, end;
+      token = scanner.read_token (out begin, out end);
+      if (token == Vala.TokenType.EOF) {
+        break;
+      }
+      string n = token.to_string ();
+      n = n.replace ("`", "");
+      n = n.replace ("'", "");
+      string l = lines[begin.line - 1];
+      message ("Token: '%s' : Line: %d Column begin: %d Column end: %d Text: '%s'", n, begin.line, 
begin.column, end.column, l);
+      n = l.substring (begin.column - 1, end.column - begin.column + 1);
+      message ("Token text: '%s'", n);
+      if (expected.size != 0 && !expected.contains (token)) {
+        throw new ParserError.INVALID_TOKEN_ERROR ("Found an unexpected expression");
+      }
+      switch (token) {
+        case Vala.TokenType.ABSTRACT:
+        case Vala.TokenType.AS:
+        case Vala.TokenType.ASYNC:
+        case Vala.TokenType.BASE:
+        case Vala.TokenType.BREAK:
+        case Vala.TokenType.CASE:
+        case Vala.TokenType.CATCH:
+        case Vala.TokenType.CLASS:
+        case Vala.TokenType.CONST:
+        case Vala.TokenType.CONSTRUCT:
+        case Vala.TokenType.CONTINUE:
+        case Vala.TokenType.DEFAULT:
+        case Vala.TokenType.DELEGATE:
+        case Vala.TokenType.DELETE:
+        case Vala.TokenType.DO:
+        case Vala.TokenType.DYNAMIC:
+        case Vala.TokenType.ELSE:
+        case Vala.TokenType.ENUM:
+        case Vala.TokenType.ENSURES:
+        case Vala.TokenType.ERRORDOMAIN:
+        case Vala.TokenType.EXTERN:
+        case Vala.TokenType.FALSE:
+        case Vala.TokenType.FINALLY:
+        case Vala.TokenType.FOR:
+        case Vala.TokenType.FOREACH:
+        case Vala.TokenType.GET:
+        case Vala.TokenType.IF:
+        case Vala.TokenType.IN:
+        case Vala.TokenType.INLINE:
+        case Vala.TokenType.INTERFACE:
+        case Vala.TokenType.INTERNAL:
+        case Vala.TokenType.IS:
+        case Vala.TokenType.LOCK:
+        case Vala.TokenType.NAMESPACE:
+        case Vala.TokenType.NEW:
+        case Vala.TokenType.NULL:
+        case Vala.TokenType.OUT:
+        case Vala.TokenType.OVERRIDE:
+        case Vala.TokenType.OWNED:
+        case Vala.TokenType.PARAMS:
+        case Vala.TokenType.PRIVATE:
+        case Vala.TokenType.PROTECTED:
+        case Vala.TokenType.PUBLIC:
+        case Vala.TokenType.REF:
+        case Vala.TokenType.REQUIRES:
+        case Vala.TokenType.RETURN:
+        case Vala.TokenType.SEALED:
+        case Vala.TokenType.SET:
+        case Vala.TokenType.SIGNAL:
+        case Vala.TokenType.SIZEOF:
+        case Vala.TokenType.STATIC:
+        case Vala.TokenType.STRUCT:
+        case Vala.TokenType.SWITCH:
+        case Vala.TokenType.THIS:
+        case Vala.TokenType.THROW:
+        case Vala.TokenType.THROWS:
+        case Vala.TokenType.TRUE:
+        case Vala.TokenType.TRY:
+        case Vala.TokenType.TYPEOF:
+        case Vala.TokenType.UNOWNED:
+        case Vala.TokenType.USING:
+        case Vala.TokenType.VAR:
+        case Vala.TokenType.VIRTUAL:
+        case Vala.TokenType.VOID:
+        case Vala.TokenType.VOLATILE:
+        case Vala.TokenType.WEAK:
+        case Vala.TokenType.WHILE:
+        case Vala.TokenType.YIELD:
+        case Vala.TokenType.IDENTIFIER:
+          Expression sfunc = eqman.functions.find_named (n);
+          if (sfunc != null) {
+            sfunc = Object.new (sfunc.get_type ()) as Expression;
+            if (current == null) {
+              var exp = new GPolynomial ();
+              eq.expressions.add (exp);
+              var t = new GTerm ();
+              exp.expressions.add (t);
+              t.expressions.add (sfunc);
+              current = sfunc;
+              current_parent = t;
+              top_parent = exp;
+              expected.clear ();
+              expected.add(Vala.TokenType.OPEN_PARENS);
+            } else if (current is Operator && current_parent is Term && top_parent is Polynomial) {
+                current_parent.expressions.add (sfunc);
+                current = sfunc;
+                expected.clear ();
+            } else if (current is Term && current_parent is Polynomial) {
+                current.expressions.add (sfunc);
+                current_parent = current;
+                current = sfunc;
+                top_parent = current_parent.parent;
+                expected.clear ();
+            }
+          } else if (n.down () == "def" && current == null) {
+            // FIXME: implement function definition
+          } else if (n.down () == "def" && current is Function) {
+            throw new ParserError.INVALID_TOKEN_ERROR ("Found an unexpected function definition expression");
+          } else {
+            var v = new GVariable (n) as Expression;
+            var sv = eqman.find_variable (n) as Variable;
+            if (sv == null) {
+              sv = eq.variables.find_named (n) as Variable;
+              if (sv == null) {
+                eq.variables.add (v);
+              } else {
+                ((Variable) v).bind = sv;
+              }
+            } else {
+              ((Variable) v).bind = sv;
+            }
+            if (current == null) {
+              var exp = new GPolynomial ();
+              eq.expressions.add (exp);
+              var t = new GTerm ();
+              exp.expressions.add (t);
+              t.expressions.add (v);
+              current = v;
+              current_parent = v.parent;
+              top_parent = current_parent.parent;
+              expected.clear ();
+            } else if (current is Operator && current_parent is Term && top_parent is Polynomial) {
+                current_parent.expressions.add (v);
+                current = v;
+                expected.clear ();
+            } else if (current is Term) {
+                current.expressions.add (v);
+                current = v;
+                current_parent = v.parent;
+                top_parent = current_parent.parent;
+                message (current.get_type ().name ());
+                message (current_parent.get_type ().name ());
+                message (top_parent.get_type ().name ());
+                expected.clear ();
+            }
+          }
+          break;
+        case Vala.TokenType.INTEGER_LITERAL:
+        case Vala.TokenType.REAL_LITERAL:
+          double res = 0;
+          if (!double.try_parse (n, out res)) {
+            throw new ParserError.INVALID_TOKEN_ERROR ("Found an unexpected expression for a constant");
+          }
+          var cexp = new GConstant.@double (double.parse (n));
+          if (current == null) {
+            var exp = new GPolynomial ();
+            eq.expressions.add (exp);
+            var t = new GTerm ();
+            exp.expressions.add (t);
+            t.expressions.add (cexp);
+            current = cexp;
+            current_parent = t;
+            top_parent = exp;
+          } else if ((current is Operator || current is Term) && current_parent is Term && top_parent is 
Polynomial) {
+            current_parent.expressions.add (cexp);
+            expected.clear ();
+            current = cexp;
+          } else if (current is Term && current_parent is Polynomial && (top_parent is Group || top_parent 
is Function)) {
+            current.expressions.add (cexp);
+            top_parent = current_parent;
+            current_parent = current;
+            current = cexp;
+            expected.clear ();
+          }
+          break;
+        case Vala.TokenType.PERCENT:
+        case Vala.TokenType.CHARACTER_LITERAL:
+          break;
+        case Vala.TokenType.STAR:
+          var op = new GMultiply ();
+          process_term_operator (op, eq);
+          break;
+        case Vala.TokenType.PLUS:
+          var opp = new GPlus ();
+          process_operator (opp, eq);
+          break;
+        case Vala.TokenType.DIV:
+          var op = new GDivision ();
+          process_term_operator (op, eq);
+          break;
+        case Vala.TokenType.MINUS:
+          var opp = new GMinus ();
+          process_operator (opp, eq);
+          break;
+        case Vala.TokenType.ASSIGN:
+          if (current == null) {
+            throw new ParserError.INVALID_TOKEN_ERROR ("Found an unexpected expression for an assignment");
+          } else if (current is Polynomial) {
+            throw new ParserError.INVALID_TOKEN_ERROR ("Found an unexpected expression: can't set a value to 
a polynomial");
+          } else if (current is Variable) {
+            bool removed = false;
+            if (current.parent != null) {
+              if (current.parent is Term) {
+                var t = current.parent;
+                if (t.parent != null) {
+                  if (t.parent is Polynomial) {
+                    var p = t.parent;
+                    if (p.parent != null) {
+                      if (p.parent is MathEquation) {
+                        eq.expressions.remove (p);
+                        p.expressions.remove (t);
+                        removed = true;
+                      }
+                    }
+                  }
+                }
+              }
+            }
+            if (!removed) {
+              throw new ParserError.INVALID_EXPRESSION_ERROR ("Found an unexpected expression for an 
assignment. Assignment should be done on variables");
+            }
+            var expa = new GAssign ();
+            eq.expressions.add (expa);
+            expa.expressions.add (current);
+            var exp = new GPolynomial ();
+            expa.expressions.add (exp);
+            var t = new GTerm ();
+            exp.expressions.add (t);
+            current = t;
+            current_parent = t;
+            top_parent = exp;
+            expected.clear ();
+          }
+          break;
+        case Vala.TokenType.OPEN_PARENS:
+          if (current == null) {
+            var exp = new GPolynomial ();
+            eq.expressions.add (exp);
+            var t = new GTerm ();
+            exp.expressions.add (t);
+            var g = new GGroup ();
+            t.expressions.add (g);
+            var exp2 = new GPolynomial ();
+            var t2 = new GTerm ();
+            exp2.expressions.add (t2);
+            g.expressions.add (exp2);
+            current = t2;
+            current_parent = exp2;
+            top_parent = g;
+          } else if (current is Function) {
+            message ("Function Open parens");
+            var fexp = new GPolynomial ();
+            var t = new GTerm ();
+            fexp.expressions.add (t);
+            current.expressions.add (fexp);
+            top_parent = current;
+            current = t;
+            current_parent = fexp;
+            expected.clear ();
+          } else if (current is Operator && current_parent is Term && top_parent is Polynomial) {
+            var g = new GGroup ();
+            current_parent.expressions.add (g);
+            var exp = new GPolynomial ();
+            g.expressions.add (exp);
+            var t = new GTerm ();
+            exp.expressions.add (t);
+            current = t;
+            current_parent = exp;
+            top_parent = g;
+          }
+          break;
+        case Vala.TokenType.CLOSE_PARENS:
+          if (current == null) {
+            throw new ParserError.INVALID_TOKEN_ERROR ("Found an unexpected expression while closing 
parenthesis");
+          }
+          bool foundp = false;
+          var par = current;
+          while (par != null) {
+            if (par is Group) {
+              if (!((Group) par).closed) {
+                foundp = true;
+                ((Group) par).closed = true;
+                break;
+              }
+            }
+            if (par is Function) {
+              if (!((Function) par).closed) {
+                foundp = true;
+                ((Function) par).closed = true;
+                break;
+              }
+            }
+            par = par.parent;
+          }
+          if (foundp) {
+            current = par;
+            current_parent = par.parent; // Term
+            top_parent = current_parent.parent;
+          }
+          break;
+        case Vala.TokenType.CARRET:
+          var op = new GPow ();
+          if (current == null) {
+            throw new ParserError.INVALID_TOKEN_ERROR ("Found an unexpected expression trying power 
expression");
+          } else {
+            process_term_operator (op, eq);
+          }
+          break;
+        // braces
+        case Vala.TokenType.CLOSE_BRACE:
+        case Vala.TokenType.CLOSE_BRACKET:
+        case Vala.TokenType.OPEN_BRACE:
+        case Vala.TokenType.OPEN_BRACKET:
+          break;
+        case Vala.TokenType.STRING_LITERAL:
+          message ("Found string literal");
+          break;
+        case Vala.TokenType.REGEX_LITERAL:
+        case Vala.TokenType.TEMPLATE_STRING_LITERAL:
+        case Vala.TokenType.VERBATIM_STRING_LITERAL:
+        case Vala.TokenType.ASSIGN_ADD:
+        case Vala.TokenType.ASSIGN_BITWISE_AND:
+        case Vala.TokenType.ASSIGN_BITWISE_OR:
+        case Vala.TokenType.ASSIGN_BITWISE_XOR:
+        case Vala.TokenType.ASSIGN_DIV:
+        case Vala.TokenType.ASSIGN_MUL:
+        case Vala.TokenType.ASSIGN_PERCENT:
+        case Vala.TokenType.ASSIGN_SHIFT_LEFT:
+        case Vala.TokenType.ASSIGN_SUB:
+        case Vala.TokenType.BITWISE_AND:
+        case Vala.TokenType.BITWISE_OR:
+        case Vala.TokenType.OP_AND:
+        case Vala.TokenType.OP_COALESCING:
+        case Vala.TokenType.OP_DEC:
+        case Vala.TokenType.OP_EQ:
+        case Vala.TokenType.OP_GE:
+        case Vala.TokenType.OP_GT:
+        case Vala.TokenType.OP_INC:
+        case Vala.TokenType.OP_LE:
+        case Vala.TokenType.OP_LT:
+        case Vala.TokenType.OP_NE:
+        case Vala.TokenType.OP_NEG:
+        case Vala.TokenType.OP_OR:
+        case Vala.TokenType.OP_PTR:
+        case Vala.TokenType.OP_SHIFT_LEFT:
+        // templates and regex
+        case Vala.TokenType.CLOSE_REGEX_LITERAL:
+        case Vala.TokenType.CLOSE_TEMPLATE:
+        case Vala.TokenType.OPEN_REGEX_LITERAL:
+        case Vala.TokenType.OPEN_TEMPLATE:
+        //
+        case Vala.TokenType.SEMICOLON:
+        case Vala.TokenType.TILDE:
+        case Vala.TokenType.COLON:
+        case Vala.TokenType.COMMA:
+        case Vala.TokenType.DOUBLE_COLON:
+        case Vala.TokenType.DOT:
+        case Vala.TokenType.ELLIPSIS:
+        case Vala.TokenType.INTERR:
+        // Hash
+        case Vala.TokenType.HASH:
+          throw new ParserError.INVALID_TOKEN_ERROR ("Found an unexpected expression");
+      }
+    }
+    eqman.equations.add (eq);
+  }
+  private void process_operator (Operator opp, GMathEquation eq) throws GLib.Error {
+    if (current is BinaryOperator) {
+      throw new ParserError.INVALID_TOKEN_ERROR ("Found an unexpected expression for a plus operator");
+    }
+    if (current == null) {
+      var exp = new GPolynomial ();
+      var t = new GTerm ();
+      t.expressions.add (opp);
+      exp.expressions.add (t);
+      current = opp;
+      current_parent = t;
+      top_parent = exp;
+      eq.expressions.add (exp);
+      expected.clear ();
+    } else if (current_parent is Polynomial && current is Term) {
+      current.expressions.add (opp);
+      top_parent = current_parent;
+      current_parent = current;
+      current = opp;
+      expected.clear ();
+    } else if ((current is Constant || current is Variable)
+               && current_parent is Term && top_parent is Polynomial) {
+      // New term
+      var t = new GTerm ();
+      t.expressions.add (opp);
+      top_parent.expressions.add (t);
+      current = opp;
+      current_parent = t;
+      expected.clear ();
+    } else if ((current is Group || current is Function) && current_parent is Term && top_parent is 
Polynomial) {
+      // New term
+      var t = new GTerm ();
+      t.expressions.add (opp);
+      top_parent.expressions.add (t);
+      current = opp;
+      current_parent = t;
+      top_parent = current_parent.parent;
+      expected.clear ();
+    } else if (current is Variable && current_parent == null) {
+      // New Polynomial
+      var exp = new GPolynomial ();
+      eq.expressions.add (exp);
+      var t = new GTerm ();
+      exp.expressions.add (t);
+      t.expressions.add (current);
+      var t2 = new GTerm ();
+      exp.expressions.add (t2);
+      t2.expressions.add (opp);
+      current = opp;
+      current_parent = t2;
+      top_parent = exp;
+      expected.clear ();
+    }
+  }
+  private void process_term_operator (Operator op, GMathEquation eq) throws GLib.Error {
+    if (current is Operator) {
+      throw new ParserError.INVALID_TOKEN_ERROR ("Found an unexpected expression for a multiply operator");
+    }
+    if ((current is Constant || current is Variable || current is Group || current is Function)
+        && current_parent is Term && top_parent is Polynomial) {
+        current_parent.expressions.add (op);
+        current = op;
+        expected.clear ();
+    } else if (current is Variable && current_parent == null) {
+      // New Polynomial
+      var exp = new GPolynomial ();
+      eq.expressions.add (exp);
+      var t = new GTerm ();
+      exp.expressions.add (t);
+      t.expressions.add (current);
+      t.expressions.add (op);
+      current = op;
+      current_parent = t;
+      top_parent = exp;
+      expected.clear ();
+    }
+  }
+}
+
+public errordomain GCalc.ParserError {
+  INVALID_TOKEN_ERROR,
+  INVALID_EXPRESSION_ERROR
+}
+
diff --git a/gcalc/gcalc-gplus.vala b/gcalc/gcalc-gplus.vala
new file mode 100644
index 00000000..86ba9443
--- /dev/null
+++ b/gcalc/gcalc-gplus.vala
@@ -0,0 +1,26 @@
+/* gcalc-gplus.vala
+ *
+ * Copyright (C) 2018  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.GPlus : GExpression, Operator, BinaryOperator, Plus {
+  public override string to_string () {
+    return "+";
+  }
+}
+
diff --git a/gcalc/gcalc-gpolynomial.vala b/gcalc/gcalc-gpolynomial.vala
new file mode 100644
index 00000000..aa232263
--- /dev/null
+++ b/gcalc/gcalc-gpolynomial.vala
@@ -0,0 +1,33 @@
+/* gcalc-gpolynomial.vala
+ *
+ * Copyright (C) 2018  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.GPolynomial : GExpression, Polynomial {
+  public override Result solve () {
+    Result res = null;
+    try {
+      var e = evaluate ();
+      res = new GResult (e) as Result;
+    } catch (GLib.Error err) {
+      res = new GErrorResult ("Polynomial solving fails: %s".printf (err.message));
+    }
+    return res;
+  }
+}
+
diff --git a/gcalc/gcalc-gpow.vala b/gcalc/gcalc-gpow.vala
new file mode 100644
index 00000000..c21cb561
--- /dev/null
+++ b/gcalc/gcalc-gpow.vala
@@ -0,0 +1,26 @@
+/* gcalc-gpow.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.GPow : GExpression, Operator, Pow {
+  public override string to_string () {
+    return "^";
+  }
+}
+
diff --git a/gcalc/gcalc-gresult.vala b/gcalc/gcalc-gresult.vala
new file mode 100644
index 00000000..20bd8369
--- /dev/null
+++ b/gcalc/gcalc-gresult.vala
@@ -0,0 +1,32 @@
+/* gcalc-gresult.vala
+ *
+ * Copyright (C) 2018  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.GResult : Object, Result {
+  private Expression _expression;
+  public GResult (Expression exp) {
+    _expression = exp;
+  }
+  // Result
+  public string to_string () {
+    return expression.to_string ();
+  }
+  public Expression expression { get { return _expression; } }
+}
+
diff --git a/gcalc/gcalc-group.vala b/gcalc/gcalc-group.vala
new file mode 100644
index 00000000..cfe4c994
--- /dev/null
+++ b/gcalc/gcalc-group.vala
@@ -0,0 +1,45 @@
+/* gcalc-group.vala
+ *
+ * Copyright (C) 2018  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 interface GCalc.Group : Object, Expression {
+  public enum Level {
+    ONE,
+    TWO,
+    THREE
+  }
+  public abstract Level level { get; set; }
+  public abstract bool closed { get; set; }
+  public virtual Expression evaluate () throws GLib.Error {
+    if (expressions.get_n_items () == 0) {
+      throw new GroupError.INVALID_POLYNOMIAL ("No internal polynomial in group");
+    }
+    var e = expressions.get_item (0) as Polynomial;
+    if (e == null) {
+      throw new GroupError.INVALID_POLYNOMIAL ("Invalid internal polynomial in group");
+    }
+    return e.evaluate ();
+  }
+}
+
+public errordomain GCalc.GroupError {
+  INVALID_POLYNOMIAL,
+  INVALID_INTERNAL_TERM,
+}
+
diff --git a/gcalc/gcalc-gsolver.vala b/gcalc/gcalc-gsolver.vala
new file mode 100644
index 00000000..6694b8f5
--- /dev/null
+++ b/gcalc/gcalc-gsolver.vala
@@ -0,0 +1,47 @@
+/* gcalc-solver.vala
+ *
+ * Copyright (C) 2018  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>
+ */
+using GCalc;
+
+public class GCalc.GSolver : Object, Solver {
+  construct {
+    equation_manager = new GMathEquationManager ();
+  }
+  // Sover
+  public MathEquationManager equation_manager { get; set; }
+  public Result solve (string str) throws GLib.Error {
+    var p = new GParser ();
+    Result res;
+    try {
+      p.parse (str, equation_manager);
+      if (equation_manager.equations.get_n_items () == 0) {
+        return new GErrorResult ("No equations found after parsing");
+      }
+      var eq = equation_manager.equations.get_item (0) as MathEquation;
+      if (eq == null) {
+        return new GErrorResult ("No equations found after parsing");
+      }
+      res = eq.solve ();
+    } catch (GLib.Error e) {
+      res = new GErrorResult ("Solving fails: %s".printf (e.message));
+    }
+    return res;
+  }
+}
diff --git a/gcalc/gcalc-gterm.vala b/gcalc/gcalc-gterm.vala
new file mode 100644
index 00000000..1402273c
--- /dev/null
+++ b/gcalc/gcalc-gterm.vala
@@ -0,0 +1,33 @@
+/* gcalc-gterm.vala
+ *
+ * Copyright (C) 2018  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.GTerm : GExpression, Term {
+  public override Result solve () {
+    Result res = null;
+    try {
+      var e = evaluate ();
+      res = new GResult (e) as Result;
+    } catch (GLib.Error err) {
+      res = new GErrorResult ("Term evaluation fails: %s".printf (err.message));
+    }
+    return res;
+  }
+}
+
diff --git a/gcalc/gcalc-gvariable.vala b/gcalc/gcalc-gvariable.vala
new file mode 100644
index 00000000..bd9b3a3d
--- /dev/null
+++ b/gcalc/gcalc-gvariable.vala
@@ -0,0 +1,42 @@
+/* gcalc-gvariable.vala
+ *
+ * Copyright (C) 2018  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.GVariable : GExpression, Variable, Hashable {
+
+  public string name { get; construct set; }
+  public Constant value { get; set; }
+  public Variable bind { get; set; }
+
+  construct {
+    _value = new GConstant.@double (0.0);
+  }
+  public GVariable (string name) {
+    this.name = name;
+  }
+  // Expression
+  public override string to_string () {
+    return name;
+  }
+  // Hashable
+  public uint hash () {
+    return name.hash ();
+  }
+}
+
diff --git a/gcalc/gcalc-hashable.vala b/gcalc/gcalc-hashable.vala
new file mode 100644
index 00000000..9d147607
--- /dev/null
+++ b/gcalc/gcalc-hashable.vala
@@ -0,0 +1,24 @@
+/* gcalc-hashable.vala
+ *
+ * Copyright (C) 2018  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 interface GCalc.Hashable : Object {
+  public abstract uint hash ();
+}
+
diff --git a/gcalc/gcalc-math-equation-manager.vala b/gcalc/gcalc-math-equation-manager.vala
new file mode 100644
index 00000000..5bc076cd
--- /dev/null
+++ b/gcalc/gcalc-math-equation-manager.vala
@@ -0,0 +1,40 @@
+/* gcalc-math-equation-manager.vala
+ *
+ * Copyright (C) 2018  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 interface GCalc.MathEquationManager : Object {
+  public abstract ExpressionContainer equations { get; }
+  public abstract ExpressionContainer functions { get; }
+  public virtual Variable find_variable (string name) {
+    Variable res = null;
+    foreach (Expression e in equations) {
+      var eq = e as MathEquation;
+      if (e == null) {
+        continue;
+      }
+      var v = eq.variables.find_named (name) as Variable;
+      if (v != null) {
+        res = v;
+        break;
+      }
+    }
+    return res;
+  }
+}
+
diff --git a/gcalc/gcalc-math-equation.vala b/gcalc/gcalc-math-equation.vala
new file mode 100644
index 00000000..f76a3032
--- /dev/null
+++ b/gcalc/gcalc-math-equation.vala
@@ -0,0 +1,24 @@
+/* gcalc-math-equation.vala
+ *
+ * Copyright (C) 2018  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 interface GCalc.MathEquation : Object, Expression {
+  public abstract ExpressionHashMap variables { get; }
+}
+
diff --git a/gcalc/gcalc-minus.vala b/gcalc/gcalc-minus.vala
new file mode 100644
index 00000000..0722fd80
--- /dev/null
+++ b/gcalc/gcalc-minus.vala
@@ -0,0 +1,22 @@
+/* gcalc-minus.vala
+ *
+ * Copyright (C) 2018  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 interface GCalc.Minus : Object, Expression, Operator, BinaryOperator {}
+
diff --git a/gcalc/gcalc-multiply.vala b/gcalc/gcalc-multiply.vala
new file mode 100644
index 00000000..bde0f5be
--- /dev/null
+++ b/gcalc/gcalc-multiply.vala
@@ -0,0 +1,22 @@
+/* gcalc-multiply.vala
+ *
+ * Copyright (C) 2018  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 interface GCalc.Multiply : Object, Expression, Operator, BinaryOperator {}
+
diff --git a/gcalc/gcalc-operator.vala b/gcalc/gcalc-operator.vala
new file mode 100644
index 00000000..a41b8d88
--- /dev/null
+++ b/gcalc/gcalc-operator.vala
@@ -0,0 +1,22 @@
+/* gcalc-operator.vala
+ *
+ * Copyright (C) 2018  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 interface GCalc.Operator : Object, Expression {}
+
diff --git a/gcalc/gcalc-plus.vala b/gcalc/gcalc-plus.vala
new file mode 100644
index 00000000..f52c0acc
--- /dev/null
+++ b/gcalc/gcalc-plus.vala
@@ -0,0 +1,22 @@
+/* gcalc-plus.vala
+ *
+ * Copyright (C) 2018  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 interface GCalc.Plus : Object, Expression, Operator, BinaryOperator {}
+
diff --git a/gcalc/gcalc-polynomial.vala b/gcalc/gcalc-polynomial.vala
new file mode 100644
index 00000000..dd52e225
--- /dev/null
+++ b/gcalc/gcalc-polynomial.vala
@@ -0,0 +1,61 @@
+/* gcalc-polynomial.vala
+ *
+ * Copyright (C) 2018  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 interface GCalc.Polynomial : Object, Expression {
+  public virtual Expression evaluate () throws GLib.Error {
+    Term current = null;
+    Expression res = null;
+    for (uint i = 0; i < expressions.get_n_items (); i++) {
+      var e = expressions.get_item (i) as Term;
+      if (e == null) {
+        continue;
+      }
+      if (current == null) {
+        current = (Term) e;
+        if (i+1 < expressions.get_n_items ()) {
+          continue;
+        }
+        var er = ((Term) e).evaluate ();
+        if (res == null) {
+          res = er;
+          break;
+        }
+        if (res is Constant && er is Constant) {
+          res = ((Constant) res).add ((Constant) er);
+          break;
+        }
+      }
+      var re = current.add ((Term) e);
+      current = null;
+      if (res == null) {
+        res = re;
+      } else if (res is Constant && re is Constant) {
+        res = ((Constant) res).add ((Constant) re);
+      }
+      if (res != null) {
+      }
+    }
+    if (res == null) {
+      return new GErrorExpression ();
+    }
+    return res;
+  }
+}
+
diff --git a/gcalc/gcalc-pow.vala b/gcalc/gcalc-pow.vala
new file mode 100644
index 00000000..39e2d84b
--- /dev/null
+++ b/gcalc/gcalc-pow.vala
@@ -0,0 +1,22 @@
+/* gcalc-pow.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 interface GCalc.Pow : Object, Expression, Operator {}
+
diff --git a/gcalc/gcalc-result.vala b/gcalc/gcalc-result.vala
new file mode 100644
index 00000000..a1bfcb7a
--- /dev/null
+++ b/gcalc/gcalc-result.vala
@@ -0,0 +1,25 @@
+/* gcalc-result.vala
+ *
+ * Copyright (C) 2018  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 interface GCalc.Result : Object {
+  public abstract string to_string ();
+  public abstract Expression expression { get; }
+}
+
diff --git a/gcalc/gcalc-solver.vala b/gcalc/gcalc-solver.vala
new file mode 100644
index 00000000..49d7bff6
--- /dev/null
+++ b/gcalc/gcalc-solver.vala
@@ -0,0 +1,28 @@
+/* gcalc-solver.vala
+ *
+ * Copyright (C) 2018  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 interface GCalc.Solver : Object {
+  public abstract MathEquationManager equation_manager { get; set; }
+  public abstract Result solve (string str) throws GLib.Error;
+}
+
+public errordomain GCalc.SolverError {
+  EXPRESSION_ERROR
+}
diff --git a/gcalc/gcalc-term.vala b/gcalc/gcalc-term.vala
new file mode 100644
index 00000000..db69629b
--- /dev/null
+++ b/gcalc/gcalc-term.vala
@@ -0,0 +1,127 @@
+/* gcalc-term.vala
+ *
+ * Copyright (C) 2018  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 interface GCalc.Term : Object, Expression {
+  public virtual Expression add (Term t) throws GLib.Error {
+    if (t.expressions.get_n_items () == 0) {
+      return new GConstant.@double (1.0);
+    }
+    Expression res = new GErrorExpression ();
+    var e = evaluate ();
+    var e2 = t.evaluate ();
+    if (e is Constant && e2 is Constant) {
+      res = ((Constant) e).add ((Constant) e2);
+    }
+    return res;
+  }
+  public virtual Expression evaluate () throws GLib.Error {
+    message ("Evaluating term: %s", this.to_string ());
+    Expression current = null;
+    Operator current_operator = null;
+    bool first = true;
+    foreach (Expression e in expressions) {
+      message ("Evaluating Expression in term: %s", e.to_string ());
+      if (e is Operator) {
+        if (!(e is Minus || e is Plus) && first) {
+          throw new TermError.INVALID_OPERATOR ("Incorrect position for operator in expression");
+        }
+        if (e is Minus && first) {
+          var c = new GConstant.@double (-1.0);
+          current = c;
+          first = false;
+        }
+        message ("Setting current operator to: %s", e.get_type ().name());
+        current_operator = e as Operator;
+        continue;
+      } else if (e is Constant) {
+        if (current == null) {
+          current = e;
+          first = false;
+        } else if (current is Constant) {
+          if (current_operator != null) {
+            current = evaluate_constants ((Constant) current, (Constant) e, current_operator);
+          }
+        }
+      } else if (e is Group) {
+        var ev = ((Group) e).evaluate ();
+        if (current == null) {
+          current = ev;
+          first = false;
+        } else if (current is Constant && ev is Constant) {
+          if (current_operator != null) {
+            current = evaluate_constants ((Constant) current, (Constant) ev, current_operator);
+          }
+        }
+      } else if (e is Function) {
+        var ev = ((Function) e).evaluate ();
+        if (current == null) {
+          current = ev;
+          first = false;
+        } else if (current is Constant && ev is Constant) {
+          if (current_operator != null) {
+            current = evaluate_constants ((Constant) current, (Constant) ev, current_operator);
+          }
+        }
+      } else if (e is Variable) {
+        message ("Evaluating Variable '%s'", (e as Variable).name);
+        var ev = (e as Variable).evaluate ();
+        if (current == null) {
+          current = ev;
+          first = false;
+        } else if (current is Constant && ev is Constant) {
+          if (current_operator != null) {
+            current = evaluate_constants ((Constant) current, (Constant) ev, current_operator);
+          }
+        }
+      }
+    }
+    if (current == null) {
+      throw new TermError.EVALUATION_FAIL ("Evaluation fail on Term");
+    }
+    return current;
+  }
+  public static Expression evaluate_constants (Constant c1, Constant c2, Operator op)
+    throws GLib.Error
+  {
+    Expression res = null;
+    if (op is Minus) {
+      res = (c1 as Constant).multiply (c2 as Constant);
+    }
+    if (op is Multiply) {
+      res = (c1 as Constant).multiply (c2 as Constant);
+    }
+    if (op is Division) {
+      res = (c1 as Constant).divide (c2 as Constant);
+    }
+    if (op is Pow) {
+      res = (c1 as Constant).pow (c2 as Constant);
+    }
+    if (res == null) {
+      throw new TermError.INVALID_OPERATOR ("Unsupported operator in term's expression");
+    }
+    return res;
+  }
+}
+
+public errordomain GCalc.TermError {
+  INVALID_OPERATOR,
+  EVALUATION_FAIL,
+}
+
diff --git a/gcalc/gcalc-variable.vala b/gcalc/gcalc-variable.vala
new file mode 100644
index 00000000..7f1f62da
--- /dev/null
+++ b/gcalc/gcalc-variable.vala
@@ -0,0 +1,56 @@
+/* gcalc-variable.vala
+ *
+ * Copyright (C) 2018  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 interface GCalc.Variable : Object, Expression {
+  public abstract string name { get; construct set; }
+  public abstract Constant @value { get; set; }
+  public abstract Variable bind { get; set; }
+  public virtual bool binded { get { return bind != null; } }
+
+  public virtual Expression evaluate () throws GLib.Error {
+    if (bind != null) {
+      return bind.evaluate ();
+    }
+    if (parent == null) {
+      throw new VariableError.INVALID_PARENT ("Can't access to Variable's expression definition. Invalid 
parent. Expected Assign operator");
+    }
+    if (parent.expressions.get_n_items () != 2) {
+      throw new VariableError.INVALID_EXPRESSION_DEFINITION ("Can't access to Variable's expression 
definition. Expression not found");
+    }
+    var e = parent.expressions.get_item (1) as Polynomial;
+    if (e == null) {
+      throw new VariableError.INVALID_EXPRESSION_DEFINITION ("Can't access to Variable's expression 
definition. Unexpected object type");
+    }
+    var exp = e.evaluate () as Constant;
+    if (exp == null) {
+      throw new VariableError.EVALUATION_FAIL ("Variable evaluation fail. Variable's value not updated");
+    }
+    @value = exp;
+    message ("Variable '%s' evaluated to: %s", name, @value.to_string ());
+    return exp;
+  }
+}
+
+public errordomain GCalc.VariableError {
+  INVALID_PARENT,
+  INVALID_EXPRESSION_DEFINITION,
+  EVALUATION_FAIL
+}
+
diff --git a/gcalc/gcalc.deps.in b/gcalc/gcalc.deps.in
new file mode 100644
index 00000000..23d423ce
--- /dev/null
+++ b/gcalc/gcalc.deps.in
@@ -0,0 +1,3 @@
+gio-2.0
+gee-0.8
+libvala-@VALA_API_VERSION@
diff --git a/gcalc/gcalc.pc.in b/gcalc/gcalc.pc.in
new file mode 100644
index 00000000..faaae0bb
--- /dev/null
+++ b/gcalc/gcalc.pc.in
@@ -0,0 +1,13 @@
+prefix=@prefix@
+exec_prefix=${prefix}
+libdir=@libdir@
+datadir=@prefix@/share
+includedir=@prefix@/include
+
+Name: libgcalc
+Description: GNOME Calculator Libray
+URL: http://live.gnome.org/
+Version: @PROJECT_VERSION@
+Requires: gio-2.0 >= 2.50
+Libs: -L${libdir} -lgcalc-@API_VERSION@
+Cflags: -I${includedir}/gcalc-@API_VERSION@
diff --git a/gcalc/meson.build b/gcalc/meson.build
new file mode 100644
index 00000000..06517e27
--- /dev/null
+++ b/gcalc/meson.build
@@ -0,0 +1,187 @@
+PROJECT_NAME='gcalc'
+API_VERSION='1'
+VERSIONED_PROJECT_NAME=PROJECT_NAME+'-'+API_VERSION
+CAMEL_CASE_NAME='GCalc'
+VERSIONED_CAMEL_CASE_NAME=CAMEL_CASE_NAME+'-'+API_VERSION
+vapidir = join_paths (get_option('datadir'),'vala','vapi')
+GIR_NAME= VERSIONED_CAMEL_CASE_NAME+'.gir'
+TYPELIB_NAME= VERSIONED_CAMEL_CASE_NAME+'.typelib'
+VAPI_NAME = VERSIONED_PROJECT_NAME+'.vapi'
+
+conf = configuration_data()
+conf.set('prefix', get_option('prefix'))
+conf.set('libdir', '${exec_prefix}/'+get_option ('libdir'))
+conf.set('PROJECT_NAME', PROJECT_NAME)
+conf.set('PROJECT_VERSION', meson.project_version ())
+conf.set('API_VERSION', API_VERSION)
+conf.set('VALA_API_VERSION', vala_version)
+
+configure_file(input : 'gcalc.pc.in',
+       output : 'gcalc-@0@.pc'.format(API_VERSION),
+       configuration : conf,
+       install : true,
+       install_dir : join_paths(get_option('libdir'), 'pkgconfig'))
+
+configure_file(input : 'gcalc.deps.in',
+       output : 'gcalc-@0@.deps'.format(API_VERSION),
+       configuration : conf,
+       install : true,
+       install_dir : vapidir)
+
+nsinfo = configure_file(input : 'namespace-info.vala.in',
+       output : 'namespace-info.vala',
+       configuration : conf)
+namespaceinfo_dep = declare_dependency (sources : nsinfo)
+
+confh = configuration_data ()
+confh.set_quoted('PACKAGE_LOCALE_DIR', join_paths(get_option('prefix'), get_option('datadir'), 'locale'))
+confh.set_quoted('GETTEXT_PACKAGE', 'GCalc')
+configure_file(output : 'config.h',
+       configuration : confh)
+
+
+lib_mpfrg_sources = files([
+  'mpfr-glue.vala'
+])
+
+lib_mpfrg = static_library ('mpfrg',
+       lib_mpfrg_sources,
+       vala_header: 'mpfrg.h',
+       vala_vapi: 'mpfrg.vapi',
+       dependencies: [
+               gio,
+               mpc,
+               mpfr,
+       ],
+       install: false,
+)
+
+sources = files([
+       'gcalc-assign.vala',
+       'gcalc-binary-operator.vala',
+       'gcalc-constant.vala',
+       'gcalc-division.vala',
+       'gcalc-expression.vala',
+       'gcalc-expression-container.vala',
+       'gcalc-expression-hash-map.vala',
+       'gcalc-function.vala',
+       'gcalc-function-acos.vala',
+       'gcalc-function-acosh.vala',
+       'gcalc-function-asin.vala',
+       'gcalc-function-asinh.vala',
+       'gcalc-function-atan.vala',
+       'gcalc-function-atanh.vala',
+       'gcalc-function-cos.vala',
+       'gcalc-function-cosh.vala',
+       'gcalc-function-exp.vala',
+       'gcalc-function-log.vala',
+       'gcalc-function-sin.vala',
+       'gcalc-function-sinh.vala',
+       'gcalc-function-sqrt.vala',
+       'gcalc-function-tan.vala',
+       'gcalc-function-tanh.vala',
+       'gcalc-error-result.vala',
+       'gcalc-gexpression.vala',
+       'gcalc-gassign.vala',
+       'gcalc-gconstant.vala',
+       'gcalc-gdivision.vala',
+       'gcalc-gerror-result.vala',
+       'gcalc-gfunction.vala',
+       'gcalc-gmath-equation.vala',
+       'gcalc-gmath-equation-manager.vala',
+       'gcalc-gminus.vala',
+       'gcalc-gmultiply.vala',
+       'gcalc-gparser.vala',
+       'gcalc-gplus.vala',
+       'gcalc-gpolynomial.vala',
+       'gcalc-gpow.vala',
+       'gcalc-gresult.vala',
+       'gcalc-group.vala',
+       'gcalc-ggroup.vala',
+       'gcalc-gsolver.vala',
+       'gcalc-gterm.vala',
+       'gcalc-gvariable.vala',
+       'gcalc-hashable.vala',
+       'gcalc-math-equation.vala',
+       'gcalc-math-equation-manager.vala',
+       'gcalc-minus.vala',
+       'gcalc-multiply.vala',
+       'gcalc-operator.vala',
+       'gcalc-plus.vala',
+       'gcalc-polynomial.vala',
+       'gcalc-pow.vala',
+       'gcalc-result.vala',
+       'gcalc-solver.vala',
+       'gcalc-term.vala',
+       'gcalc-variable.vala',
+])
+
+
+inc_libh = include_directories ('.')
+inc_libh_dep = declare_dependency (include_directories : inc_libh)
+
+deps = [
+       gio,
+       namespaceinfo_dep,
+       inc_libh_dep,
+       inc_rooth_dep,
+       posix,
+       libxml,
+       libsoup,
+       vala_dep,
+       libmath,
+       gee
+]
+
+# LT_VERSION for ABI related changes
+# From: https://autotools.io/libtool/version.html
+# This rules applies to Meson 0.43
+# Increase the current value whenever an interface has been added, removed or changed.
+# Always increase revision value whenever an interface has been added, removed or changed.
+# Increase the age value only if the changes made to the ABI are backward compatible.
+# Set version to the value of subtract age from current
+# Reset current and version to 1 and, age and version to 0 if library's name is changed
+LT_CURRENT='0'
+LT_REVISION='0'
+LT_AGE='0'
+LT_VERSION='0'
+lib = library(VERSIONED_PROJECT_NAME,
+       sources,
+       version : LT_VERSION,
+       soversion : LT_VERSION+'.'+LT_AGE+'.'+LT_REVISION,
+       vala_header : PROJECT_NAME+'.h',
+       vala_vapi : VAPI_NAME,
+       vala_gir : GIR_NAME,
+       dependencies : deps,
+       vala_args: [
+               '--vapidir='+vapi_dir,
+               '--pkg=mpc',
+               '--pkg=mpfr'
+       ],
+       c_args : [
+               '-include',
+               meson.current_build_dir() + '/config.h',
+       ],
+       link_with: [ lib_mpfrg ],
+       install : true,
+       install_dir : [
+               true,
+               join_paths (get_option('includedir'), 'gcalc-@0@'.format (API_VERSION), 'gcalc'),
+               vapidir,
+               true
+       ])
+
+g_ir_compiler = find_program('g-ir-compiler', required: false)
+if g_ir_compiler.found() and not get_option('disable-introspection')
+custom_target('typelib',
+       command: [
+               g_ir_compiler,
+               '--shared-library', 'lib'+PROJECT_NAME+'-@0@.so'.format (API_VERSION),
+               '--output', '@OUTPUT@',
+               join_paths(meson.current_build_dir(), GIR_NAME)
+       ],
+       output: TYPELIB_NAME,
+       depends: lib,
+       install: true,
+       install_dir: join_paths(get_option('libdir'), 'girepository-1.0'))
+endif
\ No newline at end of file
diff --git a/gcalc/mpfr-glue.vala b/gcalc/mpfr-glue.vala
new file mode 100644
index 00000000..9e801748
--- /dev/null
+++ b/gcalc/mpfr-glue.vala
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2016 Phillip Wood <phillip wood dunelm org uk>
+ *
+ * GNOME Calculator - mpfr-glue.vala
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Phillip Wood <phillip wood dunelm org uk>
+ */
+
+namespace MPFRG
+{
+    [Compact]
+    public class RealRef {
+        public MPFR.Real val;
+    }
+}
diff --git a/gcalc/namespace-info.vala.in b/gcalc/namespace-info.vala.in
new file mode 100644
index 00000000..01b7b864
--- /dev/null
+++ b/gcalc/namespace-info.vala.in
@@ -0,0 +1,24 @@
+/* -*- Mode: vala; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
+/* Attr.vala
+ *
+ * Copyright (C) 2018 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Authors:
+ *      Daniel Espinosa <esodan gmail com>
+ */
+[CCode (gir_namespace = "GCalc", gir_version = "@API_VERSION@", cheader_filename = "gcalc/@PROJECT_NAME@.h")]
+namespace GCalc {}
diff --git a/lib/meson.build b/lib/meson.build
index bc1b9792..7cc854f6 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -1,5 +1,4 @@
 libcalculator_sources = [
-  'mpfr-glue.vala',
   'currency.vala',
   'equation.vala',
   'equation-lexer.vala',
@@ -33,6 +32,7 @@ libcalculator_deps = [
   mpc,
   mpfr,
   posix,
+  inc_libh_dep
 ]
 
 libcalculator = static_library('calculator', libcalculator_sources,
@@ -40,5 +40,6 @@ libcalculator = static_library('calculator', libcalculator_sources,
   c_args: libcalculator_c_flags,
   vala_args: libcalculator_vala_flags,
   include_directories: config_h_dir,
+  link_with: [ lib_mpfrg ],
   install: false,
 )
diff --git a/lib/mpfr-glue.vala b/lib/mpfr-glue.vala
index e52c0f6f..9e801748 100644
--- a/lib/mpfr-glue.vala
+++ b/lib/mpfr-glue.vala
@@ -19,7 +19,7 @@
  * Authors: Phillip Wood <phillip wood dunelm org uk>
  */
 
-namespace MPFR
+namespace MPFRG
 {
     [Compact]
     public class RealRef {
diff --git a/meson.build b/meson.build
index 8ef67da7..4cda199d 100644
--- a/meson.build
+++ b/meson.build
@@ -4,6 +4,9 @@ project('gnome-calculator', ['c', 'vala'],
   license: 'GPLv3+',
 )
 
+inc_rooth = include_directories ('.')
+inc_rooth_dep = declare_dependency (include_directories : inc_rooth)
+
 gnome = import('gnome')
 i18n = import('i18n')
 
@@ -25,10 +28,19 @@ gio = dependency('gio-2.0', version: '>= ' + glib_min_version)
 glib = dependency('glib-2.0', version: '>= ' + glib_min_version)
 gmodule_export = dependency('gmodule-export-2.0')
 gobject = dependency('gobject-2.0', version: '>= ' + glib_min_version)
-gtk = dependency('gtk+-3.0', version: '>= 3.19.3')
-gtksourceview = dependency('gtksourceview-4', version: '>= 4.0.2')
-libsoup = dependency('libsoup-2.4', version: '>= 2.42')
 libxml = dependency('libxml-2.0')
+libsoup = dependency('libsoup-2.4', version: '>= 2.42')
+gee = dependency('gee-0.8', version: '>= 0.20.0')
+
+# Vala compiler as expression parser
+vala_version = get_option ('vala-version')
+if vala_version == ''
+       vc = find_program('valac')
+       r = run_command(vc, '--api-version')
+       vala_version = r.stdout().strip()
+endif
+vala_dep_str = 'libvala-@0@'.format (vala_version)
+vala_dep = dependency(vala_dep_str)
 
 # Libraries
 cc = meson.get_compiler('c')
@@ -63,10 +75,15 @@ config_h_dir = include_directories('.')
 meson.add_install_script('meson_post_install.py')
 
 # Subdirs
+subdir('gcalc')
+if not get_option ('disable-ui')
+gtk = dependency('gtk+-3.0', version: '>= 3.19.3')
+gtksourceview = dependency('gtksourceview-4', version: '>= 4.0.2')
 subdir('data')
 subdir('lib')
 subdir('src')
 subdir('search-provider')
-subdir('tests')
 subdir('help')
 subdir('po')
+endif
+subdir('tests')
diff --git a/meson_options.txt b/meson_options.txt
new file mode 100644
index 00000000..96472bb7
--- /dev/null
+++ b/meson_options.txt
@@ -0,0 +1,3 @@
+option('disable-ui', type : 'boolean', value : false, description : 'Disable GTK+ program')
+option('vala-version', type: 'string', value : '', description : 'Use another version of Vala (only the 
latest is officially supported)')
+option('disable-introspection', type : 'boolean', value : false, description : 'Disable GObject 
Introspection Typelib generation')
\ No newline at end of file
diff --git a/org.gnome.Calculator.json b/org.gnome.Calculator.json
index b5826475..7ffbafd7 100644
--- a/org.gnome.Calculator.json
+++ b/org.gnome.Calculator.json
@@ -1,74 +1,103 @@
 {
-    "app-id": "org.gnome.Calculator",
-    "runtime": "org.gnome.Platform",
-    "runtime-version": "master",
-    "sdk": "org.gnome.Sdk",
-    "command": "gnome-calculator",
-    "tags": ["nightly"],
-    "desktop-file-name-prefix": "(Nightly) ",
-    "finish-args": [
-        /* X11 + XShm access */
-        "--share=ipc", "--socket=x11",
-        /* Wayland access */
+    "app-id" : "org.gnome.Calculator",
+    "runtime" : "org.gnome.Sdk",
+    "runtime-version" : "master",
+    "sdk" : "org.gnome.Sdk",
+    "command" : "gnome-calculator",
+    "tags" : [
+        "nightly"
+    ],
+    "desktop-file-name-prefix" : "(Nightly) ",
+    "finish-args" : [
+        "--share=ipc",
+        "--socket=x11",
         "--socket=wayland",
-        /* Needs to talk to the network to get currency data */
         "--share=network",
-        /* Needed for dconf to work */
-        "--filesystem=xdg-run/dconf", "--filesystem=~/.config/dconf:ro",
-        "--talk-name=ca.desrt.dconf", "--env=DCONF_USER_CONFIG_DIR=.config/dconf"
+        "--filesystem=xdg-run/dconf",
+        "--filesystem=~/.config/dconf:ro",
+        "--talk-name=ca.desrt.dconf",
+        "--env=DCONF_USER_CONFIG_DIR=.config/dconf"
     ],
     "build-options" : {
-        "cflags": "-O2 -g -w",
-        "cxxflags": "-O2 -g -w"
+        "cflags" : "-O2 -g -w",
+        "cxxflags" : "-O2 -g -w",
+        "env" : {
+        }
     },
-    "cleanup": ["/include", "/lib/pkgconfig",
-                "/share/pkgconfig", "/share/aclocal",
-                "/man", "/share/man", "/share/gtk-doc",
-                "/share/vala", "*.la", "*.a",
-                "/bin/gcalccmd",
-                "/lib/girepository-1.0", "/share/info", "/share/gtksourceview-4",
-                "/share/doc", "/share/gir-1.0"
+    "cleanup" : [
+        "/include",
+        "/lib/pkgconfig",
+        "/share/pkgconfig",
+        "/share/aclocal",
+        "/man",
+        "/share/man",
+        "/share/gtk-doc",
+        "/share/vala",
+        "*.la",
+        "*.a",
+        "/bin/gcalccmd",
+        "/lib/girepository-1.0",
+        "/share/info",
+        "/share/gtksourceview-4",
+        "/share/doc",
+        "/share/gir-1.0"
     ],
-    "modules": [
+    "modules" : [
         {
-            "name": "mpfr",
-            "sources": [
+            "name" : "mpfr",
+            "sources" : [
                 {
-                    "type": "archive",
-                    "url": "http://www.mpfr.org/mpfr-4.0.1/mpfr-4.0.1.tar.xz";,
-                    "sha256": "67874a60826303ee2fb6affc6dc0ddd3e749e9bfcb4c8655e3953d0458a6e16e"
+                    "type" : "archive",
+                    "url" : "http://www.mpfr.org/mpfr-4.0.1/mpfr-4.0.1.tar.xz";,
+                    "sha256" : "67874a60826303ee2fb6affc6dc0ddd3e749e9bfcb4c8655e3953d0458a6e16e"
                 }
             ]
         },
         {
-            "name": "mpc",
+            "name" : "mpc",
             "config-opts" : [
                 "--with-mpfr=/app"
             ],
-            "sources": [
+            "sources" : [
                 {
-                    "type": "archive",
-                    "url": "https://ftp.gnu.org/gnu/mpc/mpc-1.1.0.tar.gz";,
-                    "sha256": "6985c538143c1208dcb1ac42cedad6ff52e267b47e5f970183a3e75125b43c2e"
+                    "type" : "archive",
+                    "url" : "https://ftp.gnu.org/gnu/mpc/mpc-1.1.0.tar.gz";,
+                    "sha256" : "6985c538143c1208dcb1ac42cedad6ff52e267b47e5f970183a3e75125b43c2e"
                 }
             ]
         },
         {
-            "name": "gtksourceview",
-            "sources": [
+            "name" : "gtksourceview",
+            "sources" : [
                 {
-                    "type": "git",
-                    "url": "https://gitlab.gnome.org/GNOME/gtksourceview.git";
+                    "type" : "git",
+                    "url" : "https://gitlab.gnome.org/GNOME/gtksourceview.git";
                 }
             ]
         },
         {
-            "name": "gnome-calculator",
-            "buildsystem": "meson",
-            "sources": [
+            "name" : "gee",
+            "config-opts" : [
+                "--disable-introspection"
+            ],
+            "sources" : [
+                {
+                    "type" : "archive",
+                    "url" : "https://download.gnome.org/sources/libgee/0.20/libgee-0.20.1.tar.xz";,
+                    "sha256" : "bb2802d29a518e8c6d2992884691f06ccfcc25792a5686178575c7111fea4630"
+                }
+            ]
+        },
+        {
+            "name" : "gnome-calculator",
+            "buildsystem" : "meson",
+            "config-opts" : [
+                "-Ddisable-introspection=true"
+            ],
+            "sources" : [
                 {
-                    "type": "git",
-                    "url": "https://gitlab.gnome.org/GNOME/gnome-calculator.git";
+                    "type" : "git",
+                    "url" : "https://gitlab.gnome.org/GNOME/gnome-calculator.git";
                 }
             ]
         }
diff --git a/search-provider/meson.build b/search-provider/meson.build
index dbcade0a..58b5cead 100644
--- a/search-provider/meson.build
+++ b/search-provider/meson.build
@@ -11,6 +11,7 @@ search_provider_deps = [
   mpc,
   mpfr,
   posix,
+  inc_libh_dep
 ]
 
 search_provider_vala_flags = [
@@ -30,7 +31,7 @@ search_provider_includes = [
 # The executable
 executable('gnome-calculator-search-provider', search_provider_sources,
   dependencies: search_provider_deps,
-  link_with: libcalculator,
+  link_with: [libcalculator, lib_mpfrg],
   install_dir: get_option('libexecdir'),
   include_directories: search_provider_includes,
   vala_args: search_provider_vala_flags,
@@ -55,4 +56,4 @@ configuration_file = configure_file(
 
 install_data(configuration_file,
   install_dir: join_paths(get_option('datadir'), 'dbus-1', 'services'),
-)
\ No newline at end of file
+)
diff --git a/src/meson.build b/src/meson.build
index 5f374d85..7172149b 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -27,6 +27,7 @@ gnome_calculator_deps = [
   mpc,
   mpfr,
   posix,
+  inc_libh_dep
 ]
 
 gnome_calculator_vala_flags = [
@@ -47,10 +48,10 @@ gnome_calculator_includes = [
 
 executable('gnome-calculator', gnome_calculator_sources,
   dependencies: gnome_calculator_deps,
-  link_with: libcalculator,
   include_directories: gnome_calculator_includes,
   vala_args: gnome_calculator_vala_flags,
   c_args: gnome_calculator_c_flags,
+  link_with: [libcalculator, lib_mpfrg],
   install: true,
 )
 
@@ -69,6 +70,7 @@ gcalccmd_deps = [
   mpc,
   mpfr,
   posix,
+  inc_libh_dep
 ]
 
 gcalccmd_vala_flags = [
@@ -83,7 +85,7 @@ gcalccmd_includes = [
 
 executable('gcalccmd', gcalccmd_sources,
   dependencies: gcalccmd_deps,
-  link_with: libcalculator,
+  link_with: [libcalculator, lib_mpfrg],
   include_directories: gcalccmd_includes,
   vala_args: gcalccmd_vala_flags,
   install: true,
diff --git a/tests/gcalc-parsing.vala b/tests/gcalc-parsing.vala
new file mode 100644
index 00000000..e71e8380
--- /dev/null
+++ b/tests/gcalc-parsing.vala
@@ -0,0 +1,1076 @@
+/* -*- Mode: Vala; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
+/*
+ * GCalc Unit Tests
+ * Copyright (C) Daniel Espinosa Ortiz 2018 <esodan gmail com>
+ *
+ * libgda 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * libgda 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+using GCalc;
+
+class Tests {
+  static int main (string[] args)
+  {
+    GLib.Intl.setlocale (GLib.LocaleCategory.ALL, "");
+    Test.init (ref args);
+    Test.add_func ("/gcalc/parser/constant/integer",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("1", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        assert (eq.expressions.get_n_items () == 1);
+        var p = eq.expressions.get_item (0) as Polynomial;
+        assert (p != null);
+        assert (p.expressions.get_n_items () == 1);
+        var t = p.expressions.get_item (0) as Term;
+        assert (t != null);
+        assert (t.expressions.get_n_items () == 1);
+        var c = t.expressions.get_item (0) as Constant;
+        assert (c != null);
+      } catch (GLib.Error error) {
+        warning ("Error: %s", error.message);
+      }
+    });
+    Test.add_func ("/gcalc/parser/constant/double",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("10.3", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        assert (eq.expressions.get_n_items () == 1);
+        var p = eq.expressions.get_item (0) as Polynomial;
+        assert (p != null);
+        assert (p.expressions.get_n_items () == 1);
+        var t = p.expressions.get_item (0) as Term;
+        assert (t != null);
+        assert (t.expressions.get_n_items () == 1);
+        var c = t.expressions.get_item (0) as Constant;
+        assert (c != null);
+      } catch (GLib.Error error) {
+        warning ("Error: %s", error.message);
+      }
+    });
+    Test.add_func ("/gcalc/parser/assign/error",
+    ()=>{
+      var parser = new GParser ();
+      var eqman = new GMathEquationManager ();
+      try {
+        parser.parse ("=", eqman);
+        assert_not_reached ();
+      } catch (GLib.Error error) {
+        message ("Error catched correctly: %s", error.message);
+      }
+    });
+    Test.add_func ("/gcalc/parser/assign/variable/constant",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("var=1", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        assert (eq.expressions.get_n_items () == 1);
+        var assign = eq.expressions.get_item (0) as Assign;
+        assert (assign != null);
+        assert (assign.expressions.get_n_items () == 2);
+        var v = assign.expressions.get_item (0) as Variable;
+        assert (v != null);
+        assert (v.name == "var");
+        var p = assign.expressions.get_item (1) as Polynomial;
+        assert (p != null);
+        assert (p.expressions.get_n_items () == 1);
+        var t = p.expressions.get_item (0) as Term;
+        assert (t != null);
+        assert (t.expressions.get_n_items () == 1);
+        var c = t.expressions.get_item (0) as Constant;
+        assert (c != null);
+      } catch (GLib.Error error) {
+        warning ("Error: %s", error.message);
+      }
+    });
+    Test.add_func ("/gcalc/parser/term/plus/constant",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("1+1", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        assert (eq.expressions.get_n_items () == 1);
+        var p = eq.expressions.get_item (0) as Polynomial;
+        assert (p != null);
+        assert (p.expressions.get_n_items () == 2);
+        var t1 = p.expressions.get_item (0) as Term;
+        assert (t1 != null);
+        assert (t1.expressions.get_n_items () == 1);
+        var c1 = t1.expressions.get_item (0) as Constant;
+        assert (c1 != null);
+        var t2 = p.expressions.get_item (1) as Term;
+        assert (t2 != null);
+        assert (t2.expressions.get_n_items () == 2);
+        var plus = t2.expressions.get_item (0) as Plus;
+        assert (plus != null);
+        var c2 = t2.expressions.get_item (1) as Constant;
+        assert (c2 != null);
+      } catch (GLib.Error error) {
+        warning ("Error: %s", error.message);
+      }
+    });
+    Test.add_func ("/gcalc/parser/term/plus/variables",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("A+B", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        assert (eq.expressions.get_n_items () == 1);
+        var p = eq.expressions.get_item (0) as Polynomial;
+        assert (p != null);
+        assert (p.expressions.get_n_items () == 2);
+        var t1 = p.expressions.get_item (0) as Term;
+        assert (t1 != null);
+        assert (t1.expressions.get_n_items () == 1);
+        var c1 = t1.expressions.get_item (0) as Variable;
+        assert (c1 != null);
+        var t2 = p.expressions.get_item (1) as Term;
+        assert (t2 != null);
+        assert (t2.expressions.get_n_items () == 2);
+        var plus = t2.expressions.get_item (0) as Plus;
+        assert (plus != null);
+        var c2 = t2.expressions.get_item (1) as Variable;
+        assert (c2 != null);
+      } catch (GLib.Error error) {
+        warning ("Error: %s", error.message);
+      }
+    });
+    Test.add_func ("/gcalc/parser/term/plus/variables+constant",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("A+1", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        assert (eq.expressions.get_n_items () == 1);
+        var p = eq.expressions.get_item (0) as Polynomial;
+        assert (p != null);
+        assert (p.expressions.get_n_items () == 2);
+        var t1 = p.expressions.get_item (0) as Term;
+        assert (t1 != null);
+        assert (t1.expressions.get_n_items () == 1);
+        var c1 = t1.expressions.get_item (0) as Variable;
+        assert (c1 != null);
+        var t2 = p.expressions.get_item (1) as Term;
+        assert (t2 != null);
+        assert (t2.expressions.get_n_items () == 2);
+        var plus = t2.expressions.get_item (0) as Plus;
+        assert (plus != null);
+        var c2 = t2.expressions.get_item (1) as Constant;
+        assert (c2 != null);
+      } catch (GLib.Error error) {
+        warning ("Error: %s", error.message);
+      }
+    });
+    Test.add_func ("/gcalc/parser/term/plus/constant+variable",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("1+B", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        assert (eq.expressions.get_n_items () == 1);
+        var p = eq.expressions.get_item (0) as Polynomial;
+        assert (p != null);
+        assert (p.expressions.get_n_items () == 2);
+        var t1 = p.expressions.get_item (0) as Term;
+        assert (t1 != null);
+        assert (t1.expressions.get_n_items () == 1);
+        var c1 = t1.expressions.get_item (0) as Constant;
+        assert (c1 != null);
+        var t2 = p.expressions.get_item (1) as Term;
+        assert (t2 != null);
+        assert (t2.expressions.get_n_items () == 2);
+        var plus = t2.expressions.get_item (0) as Plus;
+        assert (plus != null);
+        var c2 = t2.expressions.get_item (1) as Variable;
+        assert (c2 != null);
+      } catch (GLib.Error error) {
+        warning ("Error: %s", error.message);
+      }
+    });
+    Test.add_func ("/gcalc/parser/term/complex/constant+variable",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("-1+B+3+A", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        assert (eq.expressions.get_n_items () == 1);
+        var p = eq.expressions.get_item (0) as Polynomial;
+        assert (p != null);
+        message ("Terms: %u", p.expressions.get_n_items ());
+        assert (p.expressions.get_n_items () == 4);
+        var t1 = p.expressions.get_item (0) as Term;
+        assert (t1 != null);
+        assert (t1.expressions.get_n_items () == 2);
+        var minus = t1.expressions.get_item (0) as Minus;
+        assert (minus != null);
+        var c1 = t1.expressions.get_item (1) as Constant;
+        assert (c1 != null);
+        var t2 = p.expressions.get_item (1) as Term;
+        assert (t2 != null);
+        assert (t2.expressions.get_n_items () == 2);
+        var plus = t2.expressions.get_item (0) as Plus;
+        assert (plus != null);
+        var c2 = t2.expressions.get_item (1) as Variable;
+        assert (c2 != null);
+        var t3 = p.expressions.get_item (2) as Term;
+        assert (t3 != null);
+        assert (t3.expressions.get_n_items () == 2);
+        var plus2 = t3.expressions.get_item (0) as Plus;
+        assert (plus2 != null);
+        var c3 = t3.expressions.get_item (1) as Constant;
+        assert (c3 != null);
+        var t4 = p.expressions.get_item (3) as Term;
+        assert (t4 != null);
+        assert (t4.expressions.get_n_items () == 2);
+        var plus3 = t4.expressions.get_item (0) as Plus;
+        assert (plus3 != null);
+        var c4 = t4.expressions.get_item (1) as Variable;
+        assert (c4 != null);
+      } catch (GLib.Error error) {
+        warning ("Error: %s", error.message);
+      }
+    });
+    Test.add_func ("/gcalc/parser/term/complex/constant+variable/combined-operators",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("-1+B+3-A", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        assert (eq.expressions.get_n_items () == 1);
+        var p = eq.expressions.get_item (0) as Polynomial;
+        assert (p != null);
+        message ("Terms: %u", p.expressions.get_n_items ());
+        assert (p.expressions.get_n_items () == 4);
+        var t1 = p.expressions.get_item (0) as Term;
+        assert (t1 != null);
+        assert (t1.expressions.get_n_items () == 2);
+        var minus = t1.expressions.get_item (0) as Minus;
+        assert (minus != null);
+        var c1 = t1.expressions.get_item (1) as Constant;
+        assert (c1 != null);
+        var t2 = p.expressions.get_item (1) as Term;
+        assert (t2 != null);
+        assert (t2.expressions.get_n_items () == 2);
+        var plus = t2.expressions.get_item (0) as Plus;
+        assert (plus != null);
+        var c2 = t2.expressions.get_item (1) as Variable;
+        assert (c2 != null);
+        var t3 = p.expressions.get_item (2) as Term;
+        assert (t3 != null);
+        assert (t3.expressions.get_n_items () == 2);
+        var plus2 = t3.expressions.get_item (0) as Plus;
+        assert (plus2 != null);
+        var c3 = t3.expressions.get_item (1) as Constant;
+        assert (c3 != null);
+        var t4 = p.expressions.get_item (3) as Term;
+        assert (t4 != null);
+        assert (t4.expressions.get_n_items () == 2);
+        var minus2 = t4.expressions.get_item (0) as Minus;
+        assert (minus2 != null);
+        var c4 = t4.expressions.get_item (1) as Variable;
+        assert (c4 != null);
+      } catch (GLib.Error error) {
+        warning ("Error: %s", error.message);
+      }
+    });
+    Test.add_func ("/gcalc/parser/term/multiply/constant",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("1*1", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        assert (eq.expressions.get_n_items () == 1);
+        var p = eq.expressions.get_item (0) as Polynomial;
+        assert (p != null);
+        assert (p.expressions.get_n_items () == 1);
+        var t1 = p.expressions.get_item (0) as Term;
+        assert (t1 != null);
+        assert (t1.expressions.get_n_items () == 3);
+        var c1 = t1.expressions.get_item (0) as Constant;
+        assert (c1 != null);
+        var m = t1.expressions.get_item (1) as Multiply;
+        assert (m != null);
+        var c2 = t1.expressions.get_item (2) as Constant;
+        assert (c2 != null);
+      } catch (GLib.Error error) {
+        warning ("Error: %s", error.message);
+      }
+    });
+    Test.add_func ("/gcalc/parser/term/multiply/variable",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("A*B", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        assert (eq.expressions.get_n_items () == 1);
+        var p = eq.expressions.get_item (0) as Polynomial;
+        assert (p != null);
+        message ("Terms: %u", p.expressions.get_n_items ());
+        assert (p.expressions.get_n_items () == 1);
+        var t1 = p.expressions.get_item (0) as Term;
+        assert (t1 != null);
+        assert (t1.expressions.get_n_items () == 3);
+        var c1 = t1.expressions.get_item (0) as Variable;
+        assert (c1 != null);
+        var m = t1.expressions.get_item (1) as Multiply;
+        assert (m != null);
+        var c2 = t1.expressions.get_item (2) as Variable;
+        assert (c2 != null);
+      } catch (GLib.Error error) {
+        warning ("Error: %s", error.message);
+      }
+    });
+    Test.add_func ("/gcalc/parser/term/complex/constant*variable",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("-1*B+3*A", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        assert (eq.expressions.get_n_items () == 1);
+        var p = eq.expressions.get_item (0) as Polynomial;
+        assert (p != null);
+        message ("Terms: %u", p.expressions.get_n_items ());
+        assert (p.expressions.get_n_items () == 2);
+        var t1 = p.expressions.get_item (0) as Term;
+        assert (t1 != null);
+        assert (t1.expressions.get_n_items () == 4);
+        var minus = t1.expressions.get_item (0) as Minus;
+        assert (minus != null);
+        var c1 = t1.expressions.get_item (1) as Constant;
+        assert (c1 != null);
+        var m1 = t1.expressions.get_item (2) as Multiply;
+        assert (m1 != null);
+        var c2 = t1.expressions.get_item (3) as Variable;
+        assert (c2 != null);
+        var t2 = p.expressions.get_item (1) as Term;
+        assert (t2 != null);
+        assert (t2.expressions.get_n_items () == 4);
+        var plus = t2.expressions.get_item (0) as Plus;
+        assert (plus != null);
+        var c3 = t2.expressions.get_item (1) as Constant;
+        assert (c3 != null);
+        var m2 = t2.expressions.get_item (2) as Multiply;
+        assert (m2 != null);
+        var c4 = t2.expressions.get_item (3) as Variable;
+        assert (c4 != null);
+      } catch (GLib.Error error) {
+        warning ("Error: %s", error.message);
+      }
+    });
+    Test.add_func ("/gcalc/parser/term/division/constant",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("1/1", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        assert (eq.expressions.get_n_items () == 1);
+        var p = eq.expressions.get_item (0) as Polynomial;
+        assert (p != null);
+        assert (p.expressions.get_n_items () == 1);
+        var t1 = p.expressions.get_item (0) as Term;
+        assert (t1 != null);
+        assert (t1.expressions.get_n_items () == 3);
+        var c1 = t1.expressions.get_item (0) as Constant;
+        assert (c1 != null);
+        var m = t1.expressions.get_item (1) as Division;
+        assert (m != null);
+        var c2 = t1.expressions.get_item (2) as Constant;
+        assert (c2 != null);
+      } catch (GLib.Error error) {
+        warning ("Error: %s", error.message);
+      }
+    });
+    Test.add_func ("/gcalc/parser/term/division/variable",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("A/B", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        assert (eq.expressions.get_n_items () == 1);
+        var p = eq.expressions.get_item (0) as Polynomial;
+        assert (p != null);
+        message ("Terms: %u", p.expressions.get_n_items ());
+        assert (p.expressions.get_n_items () == 1);
+        var t1 = p.expressions.get_item (0) as Term;
+        assert (t1 != null);
+        assert (t1.expressions.get_n_items () == 3);
+        var c1 = t1.expressions.get_item (0) as Variable;
+        assert (c1 != null);
+        var m = t1.expressions.get_item (1) as Division;
+        assert (m != null);
+        var c2 = t1.expressions.get_item (2) as Variable;
+        assert (c2 != null);
+      } catch (GLib.Error error) {
+        warning ("Error: %s", error.message);
+      }
+    });
+    Test.add_func ("/gcalc/parser/term/complex/multiply-division/constant-variable",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("-1/B+3*A/5", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        assert (eq.expressions.get_n_items () == 1);
+        var p = eq.expressions.get_item (0) as Polynomial;
+        assert (p != null);
+        message ("Terms: %u", p.expressions.get_n_items ());
+        assert (p.expressions.get_n_items () == 2);
+        var t1 = p.expressions.get_item (0) as Term;
+        assert (t1 != null);
+        assert (t1.expressions.get_n_items () == 4);
+        var minus = t1.expressions.get_item (0) as Minus;
+        assert (minus != null);
+        var c1 = t1.expressions.get_item (1) as Constant;
+        assert (c1 != null);
+        var m1 = t1.expressions.get_item (2) as Division;
+        assert (m1 != null);
+        var c2 = t1.expressions.get_item (3) as Variable;
+        assert (c2 != null);
+        var t2 = p.expressions.get_item (1) as Term;
+        assert (t2 != null);
+        assert (t2.expressions.get_n_items () == 6);
+        var plus = t2.expressions.get_item (0) as Plus;
+        assert (plus != null);
+        var c3 = t2.expressions.get_item (1) as Constant;
+        assert (c3 != null);
+        var m2 = t2.expressions.get_item (2) as Multiply;
+        assert (m2 != null);
+        var c4 = t2.expressions.get_item (3) as Variable;
+        assert (c4 != null);
+        var m3 = t2.expressions.get_item (4) as Division;
+        assert (m3 != null);
+        var c5 = t2.expressions.get_item (5) as Constant;
+        assert (c5 != null);
+      } catch (GLib.Error error) {
+        warning ("Error: %s", error.message);
+      }
+    });
+    Test.add_func ("/gcalc/parser/constant/to_string",
+    ()=>{
+      Constant c = new GConstant.@double (-1.0) as Constant;
+      assert ("-1" in c.to_string ());
+    });
+    Test.add_func ("/gcalc/parser/term/parenthesis",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("(1)", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        assert (eq.expressions.get_n_items () == 1);
+        var p = eq.expressions.get_item (0) as Polynomial;
+        assert (p != null);
+        assert (p.expressions.get_n_items () == 1);
+        var t = p.expressions.get_item (0) as Term;
+        assert (t != null);
+        assert (t.expressions.get_n_items () == 1);
+        var g = t.expressions.get_item (0) as Group;
+        assert (g != null);
+        assert (g.closed);
+        assert (g.expressions.get_n_items () == 1);
+        var p1 = g.expressions.get_item (0) as Polynomial;
+        assert (p1 != null);
+        assert (p1.expressions.get_n_items () == 1);
+        var t1 = p1.expressions.get_item (0) as Term;
+        assert (t1 != null);
+        assert (t1.expressions.get_n_items () == 1);
+        var c = t1.expressions.get_item (0) as Constant;
+        assert (c != null);
+      } catch (GLib.Error error) {
+        warning ("Error: %s", error.message);
+      }
+    });
+    Test.add_func ("/gcalc/parser/term/parenthesis/errors",
+    ()=>{
+      var parser = new GParser ();
+      var eqman1 = new GMathEquationManager ();
+      try {
+        parser.parse ("(", eqman1);
+      } catch (GLib.Error error) {
+        message ("Correctly catched grouping error: %s", error.message);
+      }
+      var eqman2 = new GMathEquationManager ();
+      try {
+        parser.parse ("1)", eqman2);
+      } catch (GLib.Error error) {
+        message ("Correctly catched grouping error: %s", error.message);
+      }
+      var eqman3 = new GMathEquationManager ();
+      try {
+        parser.parse ("(1))", eqman3);
+      } catch (GLib.Error error) {
+        message ("Correctly catched grouping error: %s", error.message);
+      }
+      var eqman4 = new GMathEquationManager ();
+      try {
+        parser.parse ("(((1))))", eqman4);
+      } catch (GLib.Error error) {
+        message ("Correctly catched grouping error: %s", error.message);
+      }
+    });
+    Test.add_func ("/gcalc/parser/term/parenthesis/grouping",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("(1)+(1)", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        assert (eq.expressions.get_n_items () == 1);
+        var p = eq.expressions.get_item (0) as Polynomial;
+        assert (p != null);
+        assert (p.expressions.get_n_items () == 2);
+        var t1 = p.expressions.get_item (0) as Term;
+        assert (t1 != null);
+        assert (t1.expressions.get_n_items () == 1);
+        var g1 = t1.expressions.get_item (0) as Group;
+        assert (g1 != null);
+        assert (g1.closed);
+        assert (g1.expressions.get_n_items () == 1);
+        var p1 = g1.expressions.get_item (0) as Polynomial;
+        assert (p1 != null);
+        assert (p1.expressions.get_n_items () == 1);
+        var t11 = p1.expressions.get_item (0) as Term;
+        assert (t11 != null);
+        assert (t11.expressions.get_n_items () == 1);
+        var c1 = t11.expressions.get_item (0) as Constant;
+        assert (c1 != null);
+        var t2 = p.expressions.get_item (1) as Term;
+        assert (t2 != null);
+        assert (t2.expressions.get_n_items () == 2);
+        var plus = t2.expressions.get_item (0) as Plus;
+        assert (plus != null);
+        var g2 = t2.expressions.get_item (1) as Group;
+        assert (g2 != null);
+        assert (g2.closed);
+        assert (g2.expressions.get_n_items () == 1);
+        var p2 = g2.expressions.get_item (0) as Polynomial;
+        assert (p2 != null);
+        assert (p2.expressions.get_n_items () == 1);
+        var t21 = p1.expressions.get_item (0) as Term;
+        assert (t21 != null);
+        assert (t21.expressions.get_n_items () == 1);
+        var c2 = t21.expressions.get_item (0) as Constant;
+        assert (c2 != null);
+      } catch (GLib.Error error) {
+        warning ("Error: %s", error.message);
+      }
+    });
+    Test.add_func ("/gcalc/parser/term/parenthesis/grouping/multiply",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("5*(3+2)", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        assert (eq.expressions.get_n_items () == 1);
+        var p = eq.expressions.get_item (0) as Polynomial;
+        assert (p != null);
+        assert (p.expressions.get_n_items () == 1);
+        var t1 = p.expressions.get_item (0) as Term;
+        assert (t1 != null);
+        assert (t1.expressions.get_n_items () == 3);
+        var c1 = t1.expressions.get_item (0) as Constant;
+        assert (c1 != null);
+        var m1 = t1.expressions.get_item (1) as Multiply;
+        assert (m1 != null);
+        var g = t1.expressions.get_item (2) as Group;
+        assert (g != null);
+        assert (g.closed);
+        assert (g.expressions.get_n_items () == 1);
+        var pg = g.expressions.get_item (0) as Polynomial;
+        assert (pg != null);
+        assert (pg.expressions.get_n_items () == 2);
+        var tg1 = pg.expressions.get_item (0) as Term;
+        assert (tg1 != null);
+        assert (tg1.expressions.get_n_items () == 1);
+        var c2 = tg1.expressions.get_item (0) as Constant;
+        assert (c2 != null);
+        var tg2 = pg.expressions.get_item (1) as Term;
+        assert (tg2 != null);
+        assert (tg2.expressions.get_n_items () == 2);
+        message (tg2.to_string ());
+        var plus = tg2.expressions.get_item (0) as Plus;
+        assert (plus != null);
+        var c3 = tg2.expressions.get_item (1) as Constant;
+        assert (c3 != null);
+      } catch (GLib.Error error) {
+        warning ("Error: %s", error.message);
+      }
+    });
+    Test.add_func ("/gcalc/parser/term/parenthesis/grouping/multiply-inv",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("(3+2)*5", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        assert (eq.expressions.get_n_items () == 1);
+        var p = eq.expressions.get_item (0) as Polynomial;
+        assert (p != null);
+        assert (p.expressions.get_n_items () == 1);
+        var t1 = p.expressions.get_item (0) as Term;
+        assert (t1 != null);
+        assert (t1.expressions.get_n_items () == 3);
+        var g = t1.expressions.get_item (0) as Group;
+        assert (g != null);
+        assert (g.closed);
+        assert (g.expressions.get_n_items () == 1);
+        var pg = g.expressions.get_item (0) as Polynomial;
+        assert (pg != null);
+        assert (pg.expressions.get_n_items () == 2);
+        var tg1 = pg.expressions.get_item (0) as Term;
+        assert (tg1 != null);
+        assert (tg1.expressions.get_n_items () == 1);
+        var c2 = tg1.expressions.get_item (0) as Constant;
+        assert (c2 != null);
+        var tg2 = pg.expressions.get_item (1) as Term;
+        assert (tg2 != null);
+        assert (tg2.expressions.get_n_items () == 2);
+        message (tg2.to_string ());
+        var plus = tg2.expressions.get_item (0) as Plus;
+        assert (plus != null);
+        var c3 = tg2.expressions.get_item (1) as Constant;
+        assert (c3 != null);
+        var m1 = t1.expressions.get_item (1) as Multiply;
+        assert (m1 != null);
+        var c1 = t1.expressions.get_item (2) as Constant;
+        assert (c1 != null);
+      } catch (GLib.Error error) {
+        warning ("Error: %s", error.message);
+      }
+    });
+    Test.add_func ("/gcalc/parser/function/defaults",
+    ()=>{
+      var eqman = new GMathEquationManager ();
+      assert (eqman.functions.get_n_items () > 0);
+      assert (eqman.functions.find_named ("sin") != null);
+      assert (eqman.functions.find_named ("cos") != null);
+      assert (eqman.functions.find_named ("tan") != null);
+      assert (eqman.functions.find_named ("asin") != null);
+      assert (eqman.functions.find_named ("acos") != null);
+      assert (eqman.functions.find_named ("atan") != null);
+      assert (eqman.functions.find_named ("sinh") != null);
+      assert (eqman.functions.find_named ("cosh") != null);
+      assert (eqman.functions.find_named ("tanh") != null);
+      assert (eqman.functions.find_named ("asinh") != null);
+      assert (eqman.functions.find_named ("acosh") != null);
+      assert (eqman.functions.find_named ("atanh") != null);
+      assert (eqman.functions.find_named ("exp") != null);
+      assert (eqman.functions.find_named ("log") != null);
+      assert (eqman.functions.find_named ("sqrt") != null);
+    });
+    Test.add_func ("/gcalc/parser/function/unique",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("sin(0)", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        assert (eq.expressions.get_n_items () == 1);
+        var p = eq.expressions.get_item (0) as Polynomial;
+        assert (p != null);
+        assert (p.expressions.get_n_items () == 1);
+        var t = p.expressions.get_item (0) as Term;
+        assert (t != null);
+        assert (t.expressions.get_n_items () == 1);
+        var f = t.expressions.get_item (0) as Function;
+        assert (f != null);
+        assert (f.expressions.get_n_items () == 1);
+        var p1 = f.expressions.get_item (0) as Polynomial;
+        assert (p1 != null);
+        var t1 =p1.expressions.get_item (0) as Term;
+        assert (t1 != null);
+        message ("Terms: %u", t1.expressions.get_n_items ());
+        assert (t1.expressions.get_n_items () == 1);
+        var c = t1.expressions.get_item (0) as Constant;
+        assert (c != null);
+      } catch (GLib.Error error) {
+        warning ("Error: %s", error.message);
+      }
+    });
+    Test.add_func ("/gcalc/parser/pow/unique",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("3^3", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        assert (eq.expressions.get_n_items () == 1);
+        var p = eq.expressions.get_item (0) as Polynomial;
+        assert (p != null);
+        assert (p.expressions.get_n_items () == 1);
+        var t = p.expressions.get_item (0) as Term;
+        assert (t != null);
+        assert (t.expressions.get_n_items () == 3);
+        var c1 = t.expressions.get_item (0) as Constant;
+        assert (c1 != null);
+        var pw = t.expressions.get_item (1) as Pow;
+        assert (pw != null);
+        var c2 = t.expressions.get_item (2) as Constant;
+        assert (c2 != null);
+      } catch (GLib.Error error) {
+        warning ("Error: %s", error.message);
+      }
+    });
+    Test.add_func ("/gcalc/parser/pow/polynomial",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("3^(3+5*3)", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        assert (eq.expressions.get_n_items () == 1);
+        var p = eq.expressions.get_item (0) as Polynomial;
+        assert (p != null);
+        assert (p.expressions.get_n_items () == 1);
+        var t = p.expressions.get_item (0) as Term;
+        assert (t != null);
+        assert (t.expressions.get_n_items () == 3);
+        var c1 = t.expressions.get_item (0) as Constant;
+        assert (c1 != null);
+        var pw = t.expressions.get_item (1) as Pow;
+        assert (pw != null);
+        var g = t.expressions.get_item (2) as Group;
+        assert (g != null);
+        assert (g.expressions.get_n_items () == 1);
+        var p1 = g.expressions.get_item (0) as Polynomial;
+        assert (p1 != null);
+      } catch (GLib.Error error) {
+        warning ("Error: %s", error.message);
+      }
+    });
+    Test.add_func ("/gcalc/parser/variable/constant",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("x=3", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        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);
+        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);
+        assert (t.expressions.get_n_items () == 1);
+        var c = t.expressions.get_item (0) as Constant;
+        assert (c != null);
+      } catch (GLib.Error error) {
+        warning ("Error: %s", error.message);
+      }
+    });
+    Test.add_func ("/gcalc/parser/variable/polynomial",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("x=3*4*cos(0)+1", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        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);
+        var e = a.expressions.get_item (1) as Polynomial;
+        assert (e != null);
+        assert (e.expressions.get_n_items () == 2);
+        var t1 = e.expressions.get_item (0) as Term;
+        assert (t1 != null);
+        assert (t1.expressions.get_n_items () == 5);
+        var c1 = t1.expressions.get_item (0) as Constant;
+        assert (c1 != null);
+        var m1 = t1.expressions.get_item (1) as Multiply;
+        assert (m1 != null);
+        var c2 = t1.expressions.get_item (2) as Constant;
+        assert (c2 != null);
+        var m2 = t1.expressions.get_item (3) as Multiply;
+        assert (m2 != null);
+        var f1 = t1.expressions.get_item (4) as Function;
+        assert (f1 != null);
+        var t2 = e.expressions.get_item (1) as Term;
+        assert (t2 != null);
+        assert (t2.expressions.get_n_items () == 2);
+        var pl = t2.expressions.get_item (0) as Plus;
+        assert (pl != null);
+        var c3 = t2.expressions.get_item (1) as Constant;
+        assert (c3 != null);
+      } catch (GLib.Error error) {
+        warning ("Error: %s", error.message);
+      }
+    });
+    Test.add_func ("/gcalc/parser/variable/lookup/equation",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("x=3", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        var v = eq.variables.find_named ("x");
+        assert (v != null);
+      } catch (GLib.Error error) {
+        warning ("Error: %s", error.message);
+      }
+    });
+    Test.add_func ("/gcalc/parser/variables/lookup/equation",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("x=3", eqman);
+        parser.parse ("y=x", eqman);
+        assert (eqman.equations.get_n_items () == 2);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        var v = eq.variables.find_named ("x");
+        assert (v != null);
+        var eq2 = eqman.equations.get_item (1) as MathEquation;
+        assert (eq2 != null);
+        var v2 = eq2.variables.find_named ("y");
+        assert (v2 != null);
+        var v3 = eq2.variables.find_named ("x");
+        assert (v3 == null);
+        assert (eqman.find_variable ("x") != null);
+        assert (eqman.find_variable ("y") != null);
+      } catch (GLib.Error error) {
+        warning ("Error: %s", error.message);
+      }
+    });
+    Test.add_func ("/gcalc/parser/variable/equations",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("x=3", 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);
+        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 c = t.expressions.get_item (0) as Constant;
+        assert (c != null);
+        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/variable/equations/asigments",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("x=3", eqman);
+        parser.parse ("y=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);
+        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 c = t.expressions.get_item (0) as Constant;
+        assert (c != null);
+        var eq2 = eqman.equations.get_item (1) as MathEquation;
+        assert (eq2 != null);
+        message (eq2.to_string ());
+        assert (eq2.expressions.get_n_items () == 1);
+        var a2 = eq2.expressions.get_item (0) as Assign;
+        assert (a2 != null);
+        assert (a2.expressions.get_n_items () == 2);
+        var v2 = a2.expressions.get_item (0) as Variable;
+        assert (v2 != null);
+        var e2 = a2.expressions.get_item (1) 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 v3 = t2.expressions.get_item (0) as Variable;
+        assert (v3 != null);
+      } catch (GLib.Error error) {
+        warning ("Error: %s", error.message);
+      }
+    });
+    Test.add_func ("/gcalc/parser/variable/equations/asigments/polynomial/variables",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("x=3", eqman);
+        parser.parse ("y=x", eqman);
+        parser.parse ("z=x+y", eqman);
+        assert (eqman.equations.get_n_items () == 3);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        message ("Eq1: %s", eq.to_string ());
+        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);
+        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 c = t.expressions.get_item (0) as Constant;
+        assert (c != null);
+        var eq2 = eqman.equations.get_item (1) as MathEquation;
+        assert (eq2 != null);
+        message ("Eq2: %s", eq2.to_string ());
+        assert (eq2.expressions.get_n_items () == 1);
+        var a2 = eq2.expressions.get_item (0) as Assign;
+        assert (a2 != null);
+        assert (a2.expressions.get_n_items () == 2);
+        var v2 = a2.expressions.get_item (0) as Variable;
+        assert (v2 != null);
+        var e2 = a2.expressions.get_item (1) 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 v3 = t2.expressions.get_item (0) as Variable;
+        assert (v3 != null);
+        var eq3 = eqman.equations.get_item (2) as MathEquation;
+        assert (eq3 != null);
+        message ("Eq3: %s", eq3.to_string ());
+        assert (eq3.expressions.get_n_items () == 1);
+        var a3 = eq3.expressions.get_item (0) as Assign;
+        assert (a3 != null);
+        assert (a3.expressions.get_n_items () == 2);
+        var v4 = a3.expressions.get_item (0) as Variable;
+        assert (v4 != null);
+        var e3 = a3.expressions.get_item (1) as Polynomial;
+        assert (e3 != null);
+        message ("Termns in Polynomial3: %u", e3.expressions.get_n_items ());
+        assert (e3.expressions.get_n_items () == 2);
+        var t3 = e3.expressions.get_item (0) as Term;
+        assert (t3 != null);
+        assert (t3.expressions.get_n_items () == 1);
+        var v5 = t3.expressions.get_item (0) as Variable;
+        assert (v5 != null);
+        var t4 = e3.expressions.get_item (1) as Term;
+        assert (t4 != null);
+        assert (t4.expressions.get_n_items () == 2);
+        var plus = t4.expressions.get_item (0) as Plus;
+        assert (plus != null);
+        var v6 = t4.expressions.get_item (1) as Variable;
+        assert (v6 != null);
+      } catch (GLib.Error error) {
+        warning ("Error: %s", error.message);
+      }
+    });
+    return Test.run ();
+  }
+}
diff --git a/tests/gcalc-solving-basic.vala b/tests/gcalc-solving-basic.vala
new file mode 100644
index 00000000..bb64f9ee
--- /dev/null
+++ b/tests/gcalc-solving-basic.vala
@@ -0,0 +1,1401 @@
+/* -*- Mode: Vala; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
+/*
+ * GCalc Unit Tests
+ * Copyright (C) Daniel Espinosa Ortiz 2018 <esodan gmail com>
+ *
+ * libgda 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * libgda 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+using GCalc;
+
+class Tests {
+  static int main (string[] args)
+  {
+    GLib.Intl.setlocale (GLib.LocaleCategory.ALL, "");
+    Test.init (ref args);
+    Test.add_func ("/gcalc/solve/constant/add",
+    ()=>{
+      var c1 = new GConstant.@double (3.0);
+      var c2 = new GConstant.@double (3.0);
+      var c3 = c1.add (c2);
+      assert (c3 != null);
+      message (c3.to_string ());
+      assert (c3.real () == 6.0);
+    });
+    Test.add_func ("/gcalc/solve/constant/subtract",
+    ()=>{
+      var c1 = new GConstant.@double (9.0);
+      var c2 = new GConstant.@double (3.0);
+      var c3 = c1.subtract (c2);
+      assert (c3 != null);
+      message (c3.to_string ());
+      assert (c3.real () == 6.0);
+    });
+    Test.add_func ("/gcalc/solve/constant/multiply",
+    ()=>{
+      var c1 = new GConstant.@double (3.0);
+      var c2 = new GConstant.@double (3.0);
+      var c3 = c1.multiply (c2);
+      assert (c3 != null);
+      message (c3.to_string ());
+      assert (c3.real () == 9.0);
+    });
+    Test.add_func ("/gcalc/solve/constant/devide",
+    ()=>{
+      var c1 = new GConstant.@double (9.0);
+      var c2 = new GConstant.@double (3.0);
+      var c3 = c1.divide (c2);
+      assert (c3 != null);
+      message (c3.to_string ());
+      assert (c3.real () == 3.0);
+    });
+    Test.add_func ("/gcalc/solve/constant/negation",
+    ()=>{
+      var c1 = new GConstant.@double (9.0);
+      var c3 = c1.neg ();
+      assert (c3 != null);
+      message (c3.to_string ());
+      assert (c3.real () == -9.0);
+    });
+    Test.add_func ("/gcalc/solve/constant/complex",
+    ()=>{
+      var c1 = new GConstant.complex (10.0, 15.0);
+      var c3 = c1.neg ();
+      assert (c3 != null);
+      message (c3.to_string ());
+      assert (c3.real () == -10.0);
+      assert (c3.imag () == -15.0);
+    });
+    Test.add_func ("/gcalc/solve/constant",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("1", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        var e = eq.expressions.get_item (0) as Polynomial;
+        assert (e != null);
+        var t = e.expressions.get_item (0) as Term;
+        assert (t != null);
+        var c = t.expressions.get_item (0) as Constant;
+        assert (c != null);
+        var res = c.solve ();
+        assert (res != null);
+        assert (res.expression != null);
+        var rc = res.expression as Constant;
+        assert (rc != null);
+        message ("Constant Result: %s", rc.to_string ());
+        assert (rc.real () == 1.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/term/constant",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("1", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        var e = eq.expressions.get_item (0) as Polynomial;
+        assert (e != null);
+        var t = e.expressions.get_item (0) as Term;
+        var res = t.solve ();
+        assert (res != null);
+        assert (res.expression != null);
+        message ("Result type: %s", res.expression.get_type ().name ());
+        assert (!(res is ErrorResult));
+        var rc = res.expression as Constant;
+        assert (rc != null);
+        message ("Constant Result: %s", rc.to_string ());
+        assert (rc.real () == 1.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/term/constant/multiply",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("3*5", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        var e = eq.expressions.get_item (0) as Polynomial;
+        assert (e != null);
+        var t = e.expressions.get_item (0) as Term;
+        var res = t.solve ();
+        assert (res != null);
+        assert (res.expression != null);
+        message ("Result type: %s", res.expression.get_type ().name ());
+        assert (!(res is ErrorResult));
+        var rc = res.expression as Constant;
+        assert (rc != null);
+        message ("Constant Result: %s", rc.to_string ());
+        assert (rc.real () == 15.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/term/constant/division",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("15/3-", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        var e = eq.expressions.get_item (0) as Polynomial;
+        assert (e != null);
+        var t = e.expressions.get_item (0) as Term;
+        var res = t.solve ();
+        assert (res != null);
+        assert (res.expression != null);
+        message ("Result type: %s", res.expression.get_type ().name ());
+        assert (!(res is ErrorResult));
+        var rc = res.expression as Constant;
+        assert (rc != null);
+        message ("Constant Result: %s", rc.to_string ());
+        assert (rc.real () == 5.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/term/add/constant",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("1+1", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        var e = eq.expressions.get_item (0) as Polynomial;
+        assert (e != null);
+        var t1 = e.expressions.get_item (0) as Term;
+        var t2 = e.expressions.get_item (1) as Term;
+        var res = t1.add (t2);
+        assert (res != null);
+        message (res.get_type ().name ());
+        var c = res as Constant;
+        assert (c != null);
+        message (c.to_string ());
+        assert (c.real () == 2.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/term/add/constant-multiple",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("1+1-9+8-3", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        var e = eq.expressions.get_item (0) as Polynomial;
+        assert (e != null);
+        var res = e.evaluate ();
+        assert (res != null);
+        message (res.get_type ().name ());
+        var c = res as Constant;
+        assert (c != null);
+        message (c.to_string ());
+        assert (c.real () == -2.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/term/add-mult-div/constant-multiple",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("15/3+18/6-27/9+4*2-3*2", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        var e = eq.expressions.get_item (0) as Polynomial;
+        assert (e != null);
+        var res = e.evaluate ();
+        assert (res != null);
+        message (res.get_type ().name ());
+        var c = res as Constant;
+        assert (c != null);
+        message (c.to_string ());
+        assert (c.real () == 7.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/group/constant",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("(1)", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        var e = eq.expressions.get_item (0) as Polynomial;
+        assert (e != null);
+        var t = e.expressions.get_item (0) as Term;
+        assert (t != null);
+        var g = t.expressions.get_item (0) as Group;
+        assert (g != null);
+        var res = g.evaluate () as Constant;
+        assert (res != null);
+        message ("Constant Result: %s", res.to_string ());
+        assert (res.real () == 1.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/group/multiple-levels/1",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("(((1)))", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        var e = eq.expressions.get_item (0) as Polynomial;
+        assert (e != null);
+        var res = e.evaluate () as Constant;
+        assert (res != null);
+        message ("Constant Result: %s", res.to_string ());
+        assert (res.real () == 1.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/group/multiple-levels/multiply",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("(((1)))*((((5))))", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        var e = eq.expressions.get_item (0) as Polynomial;
+        assert (e != null);
+        var res = e.evaluate () as Constant;
+        assert (res != null);
+        message ("Constant Result: %s", res.to_string ());
+        assert (res.real () == 5.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/group/multiple-levels/add",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("(((1)))+((((5))))", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        var e = eq.expressions.get_item (0) as Polynomial;
+        assert (e != null);
+        var res = e.evaluate () as Constant;
+        assert (res != null);
+        message ("Constant Result: %s", res.to_string ());
+        assert (res.real () == 6.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/group/constant/basic-polynomial",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("(1+2)", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        var e = eq.expressions.get_item (0) as Polynomial;
+        assert (e != null);
+        var t = e.expressions.get_item (0) as Term;
+        assert (t != null);
+        var g = t.expressions.get_item (0) as Group;
+        assert (g != null);
+        var res = g.evaluate () as Constant;
+        assert (res != null);
+        message ("Constant Result: %s", res.to_string ());
+        assert (res.real () == 3.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/group/constant/polynomial",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("(2*8-10/5)", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        var e = eq.expressions.get_item (0) as Polynomial;
+        assert (e != null);
+        var t = e.expressions.get_item (0) as Term;
+        assert (t != null);
+        var g = t.expressions.get_item (0) as Group;
+        assert (g != null);
+        var res = g.evaluate () as Constant;
+        assert (res != null);
+        message ("Constant Result: %s", res.to_string ());
+        assert (res.real () == 14.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/group/multiple/2",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("(2)+(3)", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        var e = eq.expressions.get_item (0) as Polynomial;
+        assert (e != null);
+        var res = e.evaluate () as Constant;
+        assert (res != null);
+        message ("Constant Result: %s", res.to_string ());
+        assert (res.real () == 5.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/group/multiply-term",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("5*(3+2)", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        var e = eq.expressions.get_item (0) as Polynomial;
+        assert (e != null);
+        var res = e.evaluate () as Constant;
+        assert (res != null);
+        message ("Constant Result: %s", res.to_string ());
+        assert (res.real () == 25.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/group/multiply-term/plug-constant",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("5*(3+2)+1", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        var e = eq.expressions.get_item (0) as Polynomial;
+        assert (e != null);
+        var res = e.evaluate () as Constant;
+        assert (res != null);
+        message ("Constant Result: %s", res.to_string ());
+        assert (res.real () == 26.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/group/multiply-term-inv",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("(3+2)*5", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        var e = eq.expressions.get_item (0) as Polynomial;
+        assert (e != null);
+        var res = e.evaluate () as Constant;
+        assert (res != null);
+        message ("Constant Result: %s", res.to_string ());
+        assert (res.real () == 25.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/group/complex",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("(3+2)*5+1-3*(8-2)*7-(3)", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        var e = eq.expressions.get_item (0) as Polynomial;
+        assert (e != null);
+        var res = e.evaluate () as Constant;
+        assert (res != null);
+        message ("Constant Result: %s", res.to_string ());
+        assert (res.real () == -103.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/function/sqrt",
+    ()=>{
+      try {
+        var c1 = new GConstant.@double (9.0);
+        var f = new GFunctionSqrt ();
+        f.expressions.add (c1);
+        var c2 = f.evaluate () as Constant;
+        assert (c2 != null);
+        message (c2.to_string ());
+        assert (c2.real () == 3.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/function/exp",
+    ()=>{
+      try {
+        var c1 = new GConstant.@double (0.0);
+        var f = new GFunctionExp ();
+        f.expressions.add (c1);
+        var c2 = f.evaluate () as Constant;
+        assert (c2 != null);
+        message (c2.to_string ());
+        assert (c2.real () == 1.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/function/log",
+    ()=>{
+      try {
+        var c1 = new GConstant.@double (1.0);
+        var f = new GFunctionLog ();
+        f.expressions.add (c1);
+        var c2 = f.evaluate () as Constant;
+        assert (c2 != null);
+        message (c2.to_string ());
+        assert (c2.real () == 0.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/function/sin",
+    ()=>{
+      try {
+        var c1 = new GConstant.@double (0.0);
+        var f = new GFunctionSin ();
+        f.expressions.add (c1);
+        var c2 = f.evaluate () as Constant;
+        assert (c2 != null);
+        message (c2.to_string ());
+        assert (c2.real () == 0.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/function/cos",
+    ()=>{
+      try {
+        var c1 = new GConstant.@double (0.0);
+        var f = new GFunctionCos ();
+        f.expressions.add (c1);
+        var c2 = f.evaluate () as Constant;
+        assert (c2 != null);
+        message (c2.to_string ());
+        assert (c2.real () == 1.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/function/tan",
+    ()=>{
+      try {
+        var c1 = new GConstant.@double (0.0);
+        var f = new GFunctionTan ();
+        f.expressions.add (c1);
+        var c2 = f.evaluate () as Constant;
+        assert (c2 != null);
+        message (c2.to_string ());
+        assert (c2.real () == 0.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/function/asin",
+    ()=>{
+      try {
+        var c1 = new GConstant.@double (0.0);
+        var f = new GFunctionAsin ();
+        f.expressions.add (c1);
+        var c2 = f.evaluate () as Constant;
+        assert (c2 != null);
+        message (c2.to_string ());
+        assert (c2.real () == 0.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/function/acos",
+    ()=>{
+      try {
+        var c1 = new GConstant.@double (1.0);
+        var f = new GFunctionAcos ();
+        f.expressions.add (c1);
+        var c2 = f.evaluate () as Constant;
+        assert (c2 != null);
+        message (c2.to_string ());
+        assert (c2.real () == 0.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/function/atan",
+    ()=>{
+      try {
+        var c1 = new GConstant.@double (0.0);
+        var f = new GFunctionAtan ();
+        f.expressions.add (c1);
+        var c2 = f.evaluate () as Constant;
+        assert (c2 != null);
+        message (c2.to_string ());
+        assert (c2.real () == 0.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/function/sinh",
+    ()=>{
+      try {
+        var c1 = new GConstant.@double (0.0);
+        var f = new GFunctionSinh ();
+        f.expressions.add (c1);
+        var c2 = f.evaluate () as Constant;
+        assert (c2 != null);
+        message (c2.to_string ());
+        assert (c2.real () == 0.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/function/cosh",
+    ()=>{
+      try {
+        var c1 = new GConstant.@double (0.0);
+        var f = new GFunctionCosh ();
+        f.expressions.add (c1);
+        var c2 = f.evaluate () as Constant;
+        assert (c2 != null);
+        message (c2.to_string ());
+        assert (c2.real () == 1.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/function/tanh",
+    ()=>{
+      try {
+        var c1 = new GConstant.@double (0.0);
+        var f = new GFunctionTanh ();
+        f.expressions.add (c1);
+        var c2 = f.evaluate () as Constant;
+        assert (c2 != null);
+        message (c2.to_string ());
+        assert (c2.real () == 0.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/function/asinh",
+    ()=>{
+      try {
+        var c1 = new GConstant.@double (0.0);
+        var f = new GFunctionAsinh ();
+        f.expressions.add (c1);
+        var c2 = f.evaluate () as Constant;
+        assert (c2 != null);
+        message (c2.to_string ());
+        assert (c2.real () == 0.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/function/acosh",
+    ()=>{
+      try {
+        var c1 = new GConstant.@double (1.0);
+        var f = new GFunctionAcosh ();
+        f.expressions.add (c1);
+        var c2 = f.evaluate () as Constant;
+        assert (c2 != null);
+        message (c2.to_string ());
+        assert (c2.real () == 0.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/function/atanh",
+    ()=>{
+      try {
+        var c1 = new GConstant.@double (0.0);
+        var f = new GFunctionAtanh ();
+        f.expressions.add (c1);
+        var c2 = f.evaluate () as Constant;
+        assert (c2 != null);
+        message (c2.to_string ());
+        assert (c2.real () == 0.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/function/unique",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("sin(0)", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        var e = eq.expressions.get_item (0) as Polynomial;
+        assert (e != null);
+        var t = e.expressions.get_item (0) as Term;
+        assert (t != null);
+        var f = t.expressions.get_item (0) as Function;
+        assert (f != null);
+        assert (f.closed);
+        var res = f.evaluate () as Constant;
+        assert (res != null);
+        message ("Constant Result: %s", res.to_string ());
+        assert (res.real () == 0.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/function/unique/evaluated-polynomial",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("sin(0)", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        var e = eq.expressions.get_item (0) as Polynomial;
+        assert (e != null);
+        var res = e.evaluate () as Constant;
+        assert (res != null);
+        message ("Constant Result: %s", res.to_string ());
+        assert (res.real () == 0.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/function/term/mul",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("cos(0)*3", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        var e = eq.expressions.get_item (0) as Polynomial;
+        assert (e != null);
+        var res = e.evaluate () as Constant;
+        assert (res != null);
+        message ("Constant Result: %s", res.to_string ());
+        assert (res.real () == 3.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/function/term/mul-inv",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("3*cos(0)", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        var e = eq.expressions.get_item (0) as Polynomial;
+        assert (e != null);
+        var res = e.evaluate () as Constant;
+        assert (res != null);
+        message ("Constant Result: %s", res.to_string ());
+        assert (res.real () == 3.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/function/term/div",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("3/cos(0)", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        var e = eq.expressions.get_item (0) as Polynomial;
+        assert (e != null);
+        var res = e.evaluate () as Constant;
+        assert (res != null);
+        message ("Constant Result: %s", res.to_string ());
+        assert (res.real () == 3.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/function/term/div-inv",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("cos(0)/1", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        var e = eq.expressions.get_item (0) as Polynomial;
+        assert (e != null);
+        var res = e.evaluate () as Constant;
+        assert (res != null);
+        message ("Constant Result: %s", res.to_string ());
+        assert (res.real () == 1.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/function/polynomial",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("cos(0)+4", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        var e = eq.expressions.get_item (0) as Polynomial;
+        assert (e != null);
+        var res = e.evaluate () as Constant;
+        assert (res != null);
+        message ("Constant Result: %s", res.to_string ());
+        assert (res.real () == 5.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/function/polynomial-inv",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("4+cos(0)", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        var e = eq.expressions.get_item (0) as Polynomial;
+        assert (e != null);
+        var res = e.evaluate () as Constant;
+        assert (res != null);
+        message ("Constant Result: %s", res.to_string ());
+        assert (res.real () == 5.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/function/polynomial/functions",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("cos(0)+sin(0)", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        var e = eq.expressions.get_item (0) as Polynomial;
+        assert (e != null);
+        var res = e.evaluate () as Constant;
+        assert (res != null);
+        message ("Constant Result: %s", res.to_string ());
+        assert (res.real () == 1.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/function/polynomial/constan+func",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("1+cos(0)", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        var e = eq.expressions.get_item (0) as Polynomial;
+        assert (e != null);
+        var res = e.evaluate () as Constant;
+        assert (res != null);
+        message ("Constant Result: %s", res.to_string ());
+        assert (res.real () == 2.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/function/polynomial/constan-func",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("4-cos(0)", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        var e = eq.expressions.get_item (0) as Polynomial;
+        assert (e != null);
+        var res = e.evaluate () as Constant;
+        assert (res != null);
+        message ("Constant Result: %s", res.to_string ());
+        assert (res.real () == 3.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/function/polynomial/complex1",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("2*cos(0)-9/cos(0)", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        message ("Equation: %s", eq.to_string ());
+        var e = eq.expressions.get_item (0) as Polynomial;
+        assert (e != null);
+        var res = e.evaluate () as Constant;
+        assert (res != null);
+        message ("Constant Result: %s", res.to_string ());
+        assert (res.real () == -7.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/function/polynomial/group",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("(cos(0))", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        message ("Equation: %s", eq.to_string ());
+        var e = eq.expressions.get_item (0) as Polynomial;
+        assert (e != null);
+        var res = e.evaluate () as Constant;
+        assert (res != null);
+        message ("Constant Result: %s", res.to_string ());
+        assert (res.real () == 1.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/function/polynomial/complex2",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("5*6+tan(0)+tan(0)/2*8+2*cos(0)-9/cos(0)+(1/(cos(0)+cos(0))", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        message ("Equation: %s", eq.to_string ());
+        var e = eq.expressions.get_item (0) as Polynomial;
+        assert (e != null);
+        var res = e.evaluate () as Constant;
+        assert (res != null);
+        message ("Constant Result: %s", res.to_string ());
+        assert (res.real () == 23.5);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/pow",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("3^3", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        message ("Equation: %s", eq.to_string ());
+        var e = eq.expressions.get_item (0) as Polynomial;
+        assert (e != null);
+        var res = e.evaluate () as Constant;
+        assert (res != null);
+        message ("Constant Result: %s", res.to_string ());
+        assert (res.real () == 27.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/pow/polynomial/constants",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("2^(3+5)", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        message ("Equation: %s", eq.to_string ());
+        var e = eq.expressions.get_item (0) as Polynomial;
+        assert (e != null);
+        var res = e.evaluate () as Constant;
+        assert (res != null);
+        message ("Constant Result: %s", res.to_string ());
+        assert (res.real () == 256.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/pow/polynomial/function",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("2^(3+5*cos(0))", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        message ("Equation: %s", eq.to_string ());
+        var e = eq.expressions.get_item (0) as Polynomial;
+        assert (e != null);
+        var res = e.evaluate () as Constant;
+        assert (res != null);
+        message ("Constant Result: %s", res.to_string ());
+        assert (res.real () == 256.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/pow/polynomial/terms",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("2^(3+5*cos(0))+5*3-3^(sin(0)+5/cos(0))", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        message ("Equation: %s", eq.to_string ());
+        var e = eq.expressions.get_item (0) as Polynomial;
+        assert (e != null);
+        var res = e.evaluate () as Constant;
+        assert (res != null);
+        message ("Constant Result: %s", res.to_string ());
+        assert (res.real () == 28.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/variable/constant",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("x=3", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        var a = eq.expressions.get_item (0) as Assign;
+        assert (a != null);
+        var res1 = a.evaluate () as Constant;
+        assert (res1 != null);
+        message ("Constant Result: %s", res1.to_string ());
+        assert (res1.real () == 3.0);
+        assert (a.expressions.get_n_items () == 2);
+        var v = a.expressions.get_item (0) as Variable;
+        assert (v != null);
+        var res2 = v.evaluate () as Constant;
+        assert (res2 != null);
+        message ("Constant Result: %s", res2.to_string ());
+        assert (res2.real () == 3.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/variable/complex/polynomial",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("x=3*4/cos(0)+(4+5)/(1+sin(0))*4", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        var a = eq.expressions.get_item (0) as Assign;
+        assert (a != null);
+        var res1 = a.evaluate () as Constant;
+        assert (res1 != null);
+        message ("Constant Result: %s", res1.to_string ());
+        assert (res1.real () == 48.0);
+        assert (a.expressions.get_n_items () == 2);
+        var v = a.expressions.get_item (0) as Variable;
+        assert (v != null);
+        var res2 = v.evaluate () as Constant;
+        assert (res2 != null);
+        message ("Constant Result: %s", res2.to_string ());
+        assert (res2.real () == 48.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/equation/solve/variable",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("x=3", eqman);
+        assert (eqman.equations.get_n_items () == 1);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        var res = eq.solve ();
+        if (res is ErrorResult) {
+          warning ("Error: %s", (res as ErrorResult).message);
+        }
+        assert (res.expression != null);
+        assert (res.expression is Constant);
+        message ("Result: %s", res.expression.to_string ());
+        var c = res.expression as Constant;
+        assert (c != null);
+        assert (c.real () == 3.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/equations/solve/variable",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("x=3", 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 res = eq.solve ();
+        if (res is ErrorResult) {
+          warning ("Error: %s", (res as ErrorResult).message);
+        }
+        assert (res.expression != null);
+        assert (res.expression is Constant);
+        message ("Result: %s", res.expression.to_string ());
+        var c = res.expression as Constant;
+        assert (c != null);
+        assert (c.real () == 3.0);
+        var eq2 = eqman.equations.get_item (0) as MathEquation;
+        assert (eq2 != null);
+        var res2 = eq2.solve ();
+        if (res2 is ErrorResult) {
+          warning ("Error: %s", (res2 as ErrorResult).message);
+        }
+        assert (res2.expression != null);
+        assert (res2.expression is Constant);
+        message ("Result: %s", res2.expression.to_string ());
+        var c2 = res2.expression as Constant;
+        assert (c2 != null);
+        assert (c2.real () == 3.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/equations/solve/variable/assignment",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("x=3", eqman);
+        parser.parse ("y=x", eqman);
+        assert (eqman.equations.get_n_items () == 2);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        var res = eq.solve ();
+        if (res is ErrorResult) {
+          warning ("Error: %s", (res as ErrorResult).message);
+        }
+        assert (res.expression != null);
+        assert (res.expression is Constant);
+        message ("Result: %s", res.expression.to_string ());
+        var c = res.expression as Constant;
+        assert (c != null);
+        assert (c.real () == 3.0);
+        var eq2 = eqman.equations.get_item (0) as MathEquation;
+        assert (eq2 != null);
+        var res2 = eq2.solve ();
+        if (res2 is ErrorResult) {
+          warning ("Error: %s", (res2 as ErrorResult).message);
+        }
+        assert (res2.expression != null);
+        assert (res2.expression is Constant);
+        message ("Result: %s", res2.expression.to_string ());
+        var c2 = res2.expression as Constant;
+        assert (c2 != null);
+        assert (c2.real () == 3.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/equations/solve/variable/assignment/polynomial",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("x=3", eqman);
+        parser.parse ("y=x", eqman);
+        parser.parse ("z=y+x", eqman);
+        assert (eqman.equations.get_n_items () == 3);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        var res = eq.solve ();
+        if (res is ErrorResult) {
+          warning ("Error: %s", (res as ErrorResult).message);
+        }
+        assert (res.expression != null);
+        assert (res.expression is Constant);
+        message ("Result: %s", res.expression.to_string ());
+        var c = res.expression as Constant;
+        assert (c != null);
+        assert (c.real () == 3.0);
+        var eq2 = eqman.equations.get_item (0) as MathEquation;
+        assert (eq2 != null);
+        var res2 = eq2.solve ();
+        if (res2 is ErrorResult) {
+          warning ("Error: %s", (res2 as ErrorResult).message);
+        }
+        assert (res2.expression != null);
+        assert (res2.expression is Constant);
+        message ("Result: %s", res2.expression.to_string ());
+        var c2 = res2.expression as Constant;
+        assert (c2 != null);
+        assert (c2.real () == 3.0);
+        var eq3 = eqman.equations.get_item (2) as MathEquation;
+        assert (eq3 != null);
+        message ("Evaluating Eq3...");
+        var res3 = eq3.solve ();
+        if (res3 is ErrorResult) {
+          warning ("Error: %s", (res3 as ErrorResult).message);
+        }
+        assert (res3.expression != null);
+        message ("Result Type: %s", res3.expression.get_type ().name ());
+        assert (res3.expression is Constant);
+        message ("Result: %s", res3.expression.to_string ());
+        var c3 = res3.expression as Constant;
+        assert (c3 != null);
+        assert (c3.real () == 6.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/equations/solve/variable/assignment/polynomial/complex1",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("x=3", eqman);
+        parser.parse ("y=x", eqman);
+        parser.parse ("z=y+x*3+9/y*2*x", eqman);
+        assert (eqman.equations.get_n_items () == 3);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        var res = eq.solve ();
+        if (res is ErrorResult) {
+          warning ("Error: %s", (res as ErrorResult).message);
+        }
+        assert (res.expression != null);
+        assert (res.expression is Constant);
+        message ("Result: %s", res.expression.to_string ());
+        var c = res.expression as Constant;
+        assert (c != null);
+        assert (c.real () == 3.0);
+        var eq2 = eqman.equations.get_item (0) as MathEquation;
+        assert (eq2 != null);
+        var res2 = eq2.solve ();
+        if (res2 is ErrorResult) {
+          warning ("Error: %s", (res2 as ErrorResult).message);
+        }
+        assert (res2.expression != null);
+        assert (res2.expression is Constant);
+        message ("Result: %s", res2.expression.to_string ());
+        var c2 = res2.expression as Constant;
+        assert (c2 != null);
+        assert (c2.real () == 3.0);
+        var eq3 = eqman.equations.get_item (2) as MathEquation;
+        assert (eq3 != null);
+        message ("Evaluating Eq3...");
+        var res3 = eq3.solve ();
+        if (res3 is ErrorResult) {
+          warning ("Error: %s", (res3 as ErrorResult).message);
+        }
+        assert (res3.expression != null);
+        message ("Result Type: %s", res3.expression.get_type ().name ());
+        assert (res3.expression is Constant);
+        message ("Result: %s", res3.expression.to_string ());
+        var c3 = res3.expression as Constant;
+        assert (c3 != null);
+        assert (c3.real () == 30.0);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/equations/solve/variable/assignment/polynomial/complex2",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("x=3", eqman);
+        parser.parse ("y=x", eqman);
+        parser.parse ("z=y+x*3+9/y*2*x-((x-2*y)/(x+2-y))", eqman);
+        assert (eqman.equations.get_n_items () == 3);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        var res = eq.solve ();
+        if (res is ErrorResult) {
+          warning ("Error: %s", (res as ErrorResult).message);
+        }
+        assert (res.expression != null);
+        assert (res.expression is Constant);
+        message ("Result: %s", res.expression.to_string ());
+        var c = res.expression as Constant;
+        assert (c != null);
+        assert (c.real () == 3.0);
+        var eq2 = eqman.equations.get_item (0) as MathEquation;
+        assert (eq2 != null);
+        var res2 = eq2.solve ();
+        if (res2 is ErrorResult) {
+          warning ("Error: %s", (res2 as ErrorResult).message);
+        }
+        assert (res2.expression != null);
+        assert (res2.expression is Constant);
+        message ("Result: %s", res2.expression.to_string ());
+        var c2 = res2.expression as Constant;
+        assert (c2 != null);
+        assert (c2.real () == 3.0);
+        var eq3 = eqman.equations.get_item (2) as MathEquation;
+        assert (eq3 != null);
+        message ("Evaluating Eq3...");
+        var res3 = eq3.solve ();
+        if (res3 is ErrorResult) {
+          warning ("Error: %s", (res3 as ErrorResult).message);
+        }
+        assert (res3.expression != null);
+        message ("Result Type: %s", res3.expression.get_type ().name ());
+        assert (res3.expression is Constant);
+        message ("Result: %s", res3.expression.to_string ());
+        var c3 = res3.expression as Constant;
+        assert (c3 != null);
+        assert (c3.real () == 31.5);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    Test.add_func ("/gcalc/solve/equations/solve/variables/polynomial/complex",
+    ()=>{
+      try {
+        var parser = new GParser ();
+        var eqman = new GMathEquationManager ();
+        parser.parse ("x=3", eqman);
+        parser.parse ("y=x", eqman);
+        parser.parse ("z=y+x*3+9/y*2*x-((x-2*y)/(x+2-y))", eqman);
+        parser.parse ("x+2*y-z/(z+2*y)", eqman);
+        assert (eqman.equations.get_n_items () == 4);
+        var eq = eqman.equations.get_item (0) as MathEquation;
+        assert (eq != null);
+        var res = eq.solve ();
+        if (res is ErrorResult) {
+          warning ("Error: %s", (res as ErrorResult).message);
+        }
+        assert (res.expression != null);
+        assert (res.expression is Constant);
+        message ("Result: %s", res.expression.to_string ());
+        var c = res.expression as Constant;
+        assert (c != null);
+        assert (c.real () == 3.0);
+        var eq2 = eqman.equations.get_item (0) as MathEquation;
+        assert (eq2 != null);
+        var res2 = eq2.solve ();
+        if (res2 is ErrorResult) {
+          warning ("Error: %s", (res2 as ErrorResult).message);
+        }
+        assert (res2.expression != null);
+        assert (res2.expression is Constant);
+        message ("Result: %s", res2.expression.to_string ());
+        var c2 = res2.expression as Constant;
+        assert (c2 != null);
+        assert (c2.real () == 3.0);
+        var eq3 = eqman.equations.get_item (2) as MathEquation;
+        assert (eq3 != null);
+        message ("Evaluating Eq3...");
+        var res3 = eq3.solve ();
+        if (res3 is ErrorResult) {
+          warning ("Error: %s", (res3 as ErrorResult).message);
+        }
+        assert (res3.expression != null);
+        message ("Result Type: %s", res3.expression.get_type ().name ());
+        assert (res3.expression is Constant);
+        message ("Result: %s", res3.expression.to_string ());
+        var c3 = res3.expression as Constant;
+        assert (c3 != null);
+        assert (c3.real () == 31.5);
+        var eq4 = eqman.equations.get_item (3) as MathEquation;
+        assert (eq4 != null);
+        message ("Evaluating Eq4...");
+        var res4 = eq4.solve ();
+        if (res4 is ErrorResult) {
+          warning ("Error: %s", (res4 as ErrorResult).message);
+        }
+        assert (res4.expression != null);
+        message ("Result Type: %s", res4.expression.get_type ().name ());
+        assert (res4.expression is Constant);
+        message ("Result: %s", res4.expression.to_string ());
+        var c4 = res4.expression as Constant;
+        assert (c4 != null);
+        assert (c4.real () == 8.16);
+      } catch (GLib.Error e) {
+        warning ("Error: %s", e.message);
+      }
+    });
+    return Test.run ();
+  }
+}
diff --git a/tests/meson.build b/tests/meson.build
index 808c85e3..eb459673 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -1,14 +1,17 @@
+if not get_option ('disable-ui')
+
 # Common
 gnome_calculator_tests_deps = [
+  gtk,
+  gtksourceview,
   gio,
   glib,
   gobject,
-  gtk,
-  gtksourceview,
   libmath,
   mpc,
   mpfr,
   posix,
+  inc_rooth_dep
 ]
 
 gnome_calculator_tests_includes = [
@@ -16,12 +19,13 @@ gnome_calculator_tests_includes = [
 ]
 
 # Tests
+
 test_equation_sources = [
   'test-equation.vala',
 ]
 test_equation = executable('test-equation', test_equation_sources,
   dependencies: gnome_calculator_tests_deps,
-  link_with: libcalculator,
+  link_with: [libcalculator, lib_mpfrg],
   include_directories: gnome_calculator_tests_includes,
 )
 test('Equation test', test_equation)
@@ -31,7 +35,7 @@ test_number_sources = [
 ]
 test_number = executable('test-number', test_number_sources,
   dependencies: gnome_calculator_tests_deps,
-  link_with: libcalculator,
+  link_with: [libcalculator, lib_mpfrg],
   include_directories: gnome_calculator_tests_includes,
 )
 test('Number test', test_number)
@@ -41,7 +45,41 @@ test_serializer_sources = [
 ]
 test_serializer = executable('test-serializer', test_serializer_sources,
   dependencies: gnome_calculator_tests_deps,
-  link_with: libcalculator,
+  link_with: [libcalculator, lib_mpfrg],
   include_directories: gnome_calculator_tests_includes,
 )
 test('Serializer test', test_serializer)
+endif
+
+tests_deps = [
+  gio,
+  glib,
+  gobject,
+  libmath,
+  mpc,
+  mpfr,
+  posix,
+  gee,
+  inc_rooth_dep
+]
+
+test_parsing_sources = [
+  'gcalc-parsing.vala',
+]
+
+test_parsing = executable('gcalc-parsing', test_parsing_sources,
+  dependencies:tests_deps,
+  link_with: [lib, lib_mpfrg],
+)
+test('gcalc-parsing', test_parsing)
+
+
+test_solve_basic_sources = [
+  'gcalc-solving-basic.vala',
+]
+
+test_solve_basic = executable('gcalc-solve-basic', test_solve_basic_sources,
+  dependencies:tests_deps,
+  link_with: [lib, lib_mpfrg],
+)
+test('gcalc-solve-basic', test_solve_basic)
diff --git a/vapi/mpc.vapi b/vapi/mpc.vapi
index d34521bb..bc818344 100644
--- a/vapi/mpc.vapi
+++ b/vapi/mpc.vapi
@@ -49,6 +49,8 @@ namespace MPC {
     public struct Complex {
         [CCode (cname="mpc_init2")]
         public Complex (MPFR.Precision prec);
+        [CCode (cname="mpc_set_prec")]
+        public void set_prec (MPFR.Precision prec);
         public int @set (Complex op, Round rnd = Round.NEAREST);
         [CCode (cname="mpc_set_ui_ui")]
         public int set_unsigned_integer (ulong re, ulong im = 0, Round rnd = Round.NEAREST);
@@ -66,9 +68,9 @@ namespace MPC {
         [CCode (cname="mpc_set_d_d")]
         public int set_double (double re, double im = 0, Round rnd = Round.NEAREST);
         [CCode (cname="mpc_realref")]
-        public unowned MPFR.RealRef get_real ();
+        public unowned MPFRG.RealRef get_real ();
         [CCode (cname="mpc_imagref")]
-        public unowned MPFR.RealRef get_imag ();
+        public unowned MPFRG.RealRef get_imag ();
         public bool is_zero () { var res = cmp_si_si (0, 0); return inex_re (res) == 0 && inex_im (res) == 
0; }
         public bool is_equal (Complex c) { var res = cmp (c); return inex_re (res) == 0 && inex_im (res) == 
0; }
         public int cmp (Complex op2);
@@ -119,5 +121,19 @@ namespace MPC {
         public int asinh (Complex op, Round rnd = Round.NEAREST);
         public int acosh (Complex op, Round rnd = Round.NEAREST);
         public int atanh (Complex op, Round rnd = Round.NEAREST);
+
+        public double get_real_double () {
+          var r = MPFR.Real (1000);
+          r.set (get_real ().val);
+          return r.get_double ();
+        }
+        public double get_imag_double () {
+          var i = MPFR.Real (1000);
+          i.set (get_imag ().val);
+          return i.get_double ();
+        }
+
+        [CCode (cname="mpc_get_str")]
+        public static string to_string (int @base, size_t digits, Complex op, Round rnd = Round.NEAREST);
     }
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]