[gimp] libgimpwidgets: add exponentiation support to eevl



commit 8d35299410442411872dd693c4a96ab47416552d
Author: Ell <ell_se yahoo com>
Date:   Fri Jun 1 10:37:47 2018 -0400

    libgimpwidgets: add exponentiation support to eevl
    
    Add support for exponentiation (using the ^ operator) to eevl.
    This is occasionally useful, e.g., in geometrically-derived
    quantities involving square roots.

 libgimpwidgets/gimpeevl.c  | 63 +++++++++++++++++++++++++++++++++++++++-------
 libgimpwidgets/test-eevl.c | 35 ++++++++++++++------------
 2 files changed, 73 insertions(+), 25 deletions(-)
---
diff --git a/libgimpwidgets/gimpeevl.c b/libgimpwidgets/gimpeevl.c
index fe0281e30f..27658b0abe 100644
--- a/libgimpwidgets/gimpeevl.c
+++ b/libgimpwidgets/gimpeevl.c
@@ -46,13 +46,15 @@
  *
  *   signed factor ::= ( '+' | '-' )? factor ;
  *
- *   unit factor   ::= factor unit? ;
+ *   factor        ::= quantity ( '^' signed factor )? ;
  *
- *   factor        ::= number | '(' expression ')' ;
+ *   quantity      ::= number unit? | '(' expression ')' ;
  *
  *   number        ::= ? what g_strtod() consumes ? ;
  *
- *   unit          ::= ? what not g_strtod() consumes and not whitespace ? ;
+ *   unit          ::= simple unit ( '^' signed factor )? ;
+ *
+ *   simple unit   ::= ? what not g_strtod() consumes and not whitespace ? ;
  *
  * The code should match the EBNF rather closely (except for the
  * non-terminal unit factor, which is inlined into factor) for
@@ -70,6 +72,8 @@
 
 #include <glib-object.h>
 
+#include "libgimpmath/gimpmath.h"
+
 #include "gimpeevl.h"
 #include "gimpwidgets-error.h"
 
@@ -128,6 +132,7 @@ static GimpEevlQuantity gimp_eevl_term                     (GimpEevl
 static GimpEevlQuantity gimp_eevl_ratio                    (GimpEevl              *eva);
 static GimpEevlQuantity gimp_eevl_signed_factor            (GimpEevl              *eva);
 static GimpEevlQuantity gimp_eevl_factor                   (GimpEevl              *eva);
+static GimpEevlQuantity gimp_eevl_quantity                 (GimpEevl              *eva);
 static gboolean         gimp_eevl_accept                   (GimpEevl              *eva,
                                                             GimpEevlTokenType      token_type,
                                                             GimpEevlToken         *consumed_token);
@@ -387,18 +392,42 @@ gimp_eevl_signed_factor (GimpEevl *eva)
 static GimpEevlQuantity
 gimp_eevl_factor (GimpEevl *eva)
 {
-  GimpEevlQuantity evaluated_factor = { 0, 0 };
+  GimpEevlQuantity evaluated_factor;
+
+  evaluated_factor = gimp_eevl_quantity (eva);
+
+  if (gimp_eevl_accept (eva, '^', NULL))
+    {
+      GimpEevlQuantity evaluated_exponent;
+
+      evaluated_exponent = gimp_eevl_signed_factor (eva);
+
+      if (evaluated_exponent.dimension != 0)
+        gimp_eevl_error (eva, "Exponent is not a dimensionless quantity");
+
+      evaluated_factor.value      = pow (evaluated_factor.value,
+                                         evaluated_exponent.value);
+      evaluated_factor.dimension *= evaluated_exponent.value;
+    }
+
+  return evaluated_factor;
+}
+
+static GimpEevlQuantity
+gimp_eevl_quantity (GimpEevl *eva)
+{
+  GimpEevlQuantity evaluated_quantity = { 0, 0 };
   GimpEevlToken    consumed_token;
 
   if (gimp_eevl_accept (eva,
                         GIMP_EEVL_TOKEN_NUM,
                         &consumed_token))
     {
-      evaluated_factor.value = consumed_token.value.fl;
+      evaluated_quantity.value = consumed_token.value.fl;
     }
   else if (gimp_eevl_accept (eva, '(', NULL))
     {
-      evaluated_factor = gimp_eevl_expression (eva);
+      evaluated_quantity = gimp_eevl_expression (eva);
       gimp_eevl_expect (eva, ')', 0);
     }
   else
@@ -424,8 +453,24 @@ gimp_eevl_factor (GimpEevl *eva)
                                            &result,
                                            eva->options.data))
         {
-          evaluated_factor.value      /= result.value;
-          evaluated_factor.dimension  += result.dimension;
+          if (gimp_eevl_accept (eva, '^', NULL))
+            {
+              GimpEevlQuantity evaluated_exponent;
+
+              evaluated_exponent = gimp_eevl_signed_factor (eva);
+
+              if (evaluated_exponent.dimension != 0)
+                {
+                  gimp_eevl_error (eva,
+                                   "Exponent is not a dimensionless quantity");
+                }
+
+              result.value      = pow (result.value, evaluated_exponent.value);
+              result.dimension *= evaluated_exponent.value;
+            }
+
+          evaluated_quantity.value     /= result.value;
+          evaluated_quantity.dimension += result.dimension;
         }
       else
         {
@@ -433,7 +478,7 @@ gimp_eevl_factor (GimpEevl *eva)
         }
     }
 
-  return evaluated_factor;
+  return evaluated_quantity;
 }
 
 static gboolean
diff --git a/libgimpwidgets/test-eevl.c b/libgimpwidgets/test-eevl.c
index aac6e106e5..9656c14d4a 100644
--- a/libgimpwidgets/test-eevl.c
+++ b/libgimpwidgets/test-eevl.c
@@ -28,6 +28,8 @@
 
 #include <glib-object.h>
 
+#include "libgimpmath/gimpmath.h"
+
 #include "gimpeevl.h"
 
 
@@ -41,32 +43,33 @@ typedef struct
 static TestCase cases[] =
 {
   /* "Default" test case */
-  { "2in + 3in",                 { 2 + 3, 1},        TRUE },
+  { "2in + 3in",                 { 2 + 3, 1},               TRUE },
 
   /* Whitespace variations */
-  { "2in+3in",                   { 2 + 3, 1},        TRUE },
-  { "   2in + 3in",              { 2 + 3, 1},        TRUE },
-  { "2in + 3in   ",              { 2 + 3, 1},        TRUE },
-  { "2 in + 3 in",               { 2 + 3, 1},        TRUE },
-  { "   2   in   +   3   in   ", { 2 + 3, 1},        TRUE },
+  { "2in+3in",                   { 2 + 3, 1},               TRUE },
+  { "   2in + 3in",              { 2 + 3, 1},               TRUE },
+  { "2in + 3in   ",              { 2 + 3, 1},               TRUE },
+  { "2 in + 3 in",               { 2 + 3, 1},               TRUE },
+  { "   2   in   +   3   in   ", { 2 + 3, 1},               TRUE },
 
   /* Make sure the default unit is applied as it should */
-  { "2 + 3in",                   { 2 + 3, 1 },       TRUE },
-  { "3",                         { 3, 1 },           TRUE },
+  { "2 + 3in",                   { 2 + 3, 1 },              TRUE },
+  { "3",                         { 3, 1 },                  TRUE },
 
   /* Somewhat complicated input */
-  { "(2 + 3)in",                 { 2 + 3, 1},        TRUE },
-//  { "2 / 3 in",                  { 2 / 3., 1},        TRUE },
-  { "(2 + 2/3)in",               { 2 + 2 / 3., 1},    TRUE },
-  { "1/2 + 1/2",                 { 1, 1},            TRUE },
+  { "(2 + 3)in",                 { 2 + 3, 1},               TRUE },
+//  { "2 / 3 in",                  { 2 / 3., 1},              TRUE },
+  { "(2 + 2/3)in",               { 2 + 2 / 3., 1},          TRUE },
+  { "1/2 + 1/2",                 { 1, 1},                   TRUE },
+  { "2 ^ 3 ^ 4",                 { pow (2, pow (3, 4)), 1}, TRUE },
 
   /* Mixing of units */
-  { "2mm + 3in",                 { 2 / 25.4 + 3, 1}, TRUE },
+  { "2mm + 3in",                 { 2 / 25.4 + 3, 1},        TRUE },
 
   /* 'odd' behavior */
-  { "2 ++ 1",                    { 3, 1},            TRUE },
-  { "2 +- 1",                    { 1, 1},            TRUE },
-  { "2 -- 1",                    { 3, 1},            TRUE },
+  { "2 ++ 1",                    { 3, 1},                   TRUE },
+  { "2 +- 1",                    { 1, 1},                   TRUE },
+  { "2 -- 1",                    { 3, 1},                   TRUE },
 
   /* End of test cases */
   { NULL, { 0, 0 }, TRUE }


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