[template-glib] expr: implement user function definitions



commit acab44aaffabe91779f61a9fc74366be46ccf5a7
Author: Christian Hergert <chergert redhat com>
Date:   Wed May 4 13:06:23 2022 -0700

    expr: implement user function definitions
    
    We always had this in the syntax, but we never actually finished the
    implementation of defining functions so that the user can call them.
    
    I'd still like to change the syntax somewhat, but this at least gets
    things working so we can define those functions and use them from the
    test script.

 src/tmpl-expr-eval.c    | 35 ++++++++++++++++++++++++++++++++
 src/tmpl-expr-parser.y  | 54 ++++++++++++++++++++++++++-----------------------
 src/tmpl-expr-private.h | 10 +++++++++
 src/tmpl-expr-types.h   |  1 +
 src/tmpl-expr.c         | 24 ++++++++++++++++++++++
 src/tmpl-expr.h         |  4 ++++
 tests/test1.script      |  5 +++--
 7 files changed, 106 insertions(+), 27 deletions(-)
---
diff --git a/src/tmpl-expr-eval.c b/src/tmpl-expr-eval.c
index a5ee4b1..79de672 100644
--- a/src/tmpl-expr-eval.c
+++ b/src/tmpl-expr-eval.c
@@ -1210,6 +1210,38 @@ tmpl_expr_require_eval (TmplExprRequire  *node,
   return TRUE;
 }
 
+static gboolean
+tmpl_expr_func_eval (TmplExprFunc  *node,
+                     TmplScope     *scope,
+                     GValue        *return_value,
+                     GError       **error)
+{
+  GPtrArray *args = NULL;
+  TmplSymbol *symbol;
+
+  g_assert (node != NULL);
+  g_assert (scope != NULL);
+  g_assert (return_value != NULL);
+
+  /* We just need to insert a symbol into @scope that includes
+   * the function defined here. If the symbol already exists,
+   * it will be replaced with this function.
+   */
+
+  if (node->symlist != NULL)
+    {
+      args = g_ptr_array_new_with_free_func (g_free);
+      for (guint i = 0; node->symlist[i]; i++)
+        g_ptr_array_add (args, g_strdup (node->symlist[i]));
+    }
+
+  symbol = tmpl_scope_get (scope, node->name);
+  tmpl_symbol_assign_expr (symbol, node->list, args);
+  g_clear_pointer (&args, g_ptr_array_unref);
+
+  return TRUE;
+}
+
 static gboolean
 tmpl_expr_eval_internal (TmplExpr   *node,
                          TmplScope  *scope,
@@ -1308,6 +1340,9 @@ tmpl_expr_eval_internal (TmplExpr   *node,
         return ret;
       }
 
+    case TMPL_EXPR_FUNC:
+      return tmpl_expr_func_eval ((TmplExprFunc *)node, scope, return_value, error);
+
     default:
       break;
     }
diff --git a/src/tmpl-expr-parser.y b/src/tmpl-expr-parser.y
index f2da6fd..6055847 100644
--- a/src/tmpl-expr-parser.y
+++ b/src/tmpl-expr-parser.y
@@ -44,6 +44,27 @@ tmpl_expr_parser_error (TmplExprParser *parser,
   parser->error_str = g_strdup (message);
 }
 
+static void
+add_expr_to_parser (TmplExprParser *parser,
+                    TmplExpr       *node)
+{
+  if (parser->ast != NULL)
+    {
+      if (parser->ast->any.type != TMPL_EXPR_STMT_LIST)
+        {
+          GPtrArray *ar = g_ptr_array_new_with_free_func ((GDestroyNotify)tmpl_expr_unref);
+          g_ptr_array_add (ar, parser->ast);
+          parser->ast = tmpl_expr_new_stmt_list (ar);
+        }
+
+      g_ptr_array_add (parser->ast->stmt_list.stmts, node);
+    }
+  else
+    {
+      parser->ast = node;
+    }
+}
+
 # define scanner parser->scanner
 %}
 
@@ -74,37 +95,20 @@ expr: /* nothing */ EOL {
     YYACCEPT;
   }
   | stmt EOL {
-    if (parser->ast != NULL)
-      {
-        if (parser->ast->any.type != TMPL_EXPR_STMT_LIST)
-          {
-            GPtrArray *ar = g_ptr_array_new_with_free_func ((GDestroyNotify)tmpl_expr_unref);
-            g_ptr_array_add (ar, parser->ast);
-            parser->ast = tmpl_expr_new_stmt_list (ar);
-          }
-        g_ptr_array_add (parser->ast->stmt_list.stmts, $1);
-      }
-    else
-      {
-        parser->ast = $1;
-      }
-
+    add_expr_to_parser (parser, $1);
     YYACCEPT;
   }
   | FUNC NAME '(' symlist ')' '=' list EOL {
-    /* todo: add ast node to define the expr on the scope
-     * when evaluated.
-     */
-    //tmpl_scope_add_user_func (parser->scope, $2, $4, $7);
-    parser->ast = NULL;
+    g_ptr_array_add ($4, NULL);
+    add_expr_to_parser (parser,
+                        tmpl_expr_new_func ($2,
+                                            (char **)(gpointer)g_ptr_array_free ($4, FALSE),
+                                            $7));
+    $4 = NULL;
     YYACCEPT;
   }
   | FUNC NAME '(' ')' '=' list EOL {
-    /* todo: add ast node to define the expr on the scope
-     * when evaluated.
-     */
-    //tmpl_scope_add_user_func (parser->scope, $2, NULL, $6);
-    parser->ast = NULL;
+    add_expr_to_parser (parser, tmpl_expr_new_func ($2, NULL, $6));
     YYACCEPT;
   }
 ;
diff --git a/src/tmpl-expr-private.h b/src/tmpl-expr-private.h
index c1ebe2b..4d7a19a 100644
--- a/src/tmpl-expr-private.h
+++ b/src/tmpl-expr-private.h
@@ -143,6 +143,15 @@ typedef struct
   GPtrArray     *stmts;
 } TmplExprStmtList;
 
+typedef struct
+{
+  TmplExprType    type;
+  volatile gint   ref_count;
+  char           *name;
+  char          **symlist;
+  TmplExpr       *list;
+} TmplExprFunc;
+
 union _TmplExpr
 {
   TmplExprAny          any;
@@ -159,6 +168,7 @@ union _TmplExpr
   TmplExprSetattr      setattr;
   TmplExprRequire      require;
   TmplExprStmtList     stmt_list;
+  TmplExprFunc         func;
 };
 
 G_END_DECLS
diff --git a/src/tmpl-expr-types.h b/src/tmpl-expr-types.h
index acedfb9..037d9ec 100644
--- a/src/tmpl-expr-types.h
+++ b/src/tmpl-expr-types.h
@@ -76,6 +76,7 @@ typedef enum
   TMPL_EXPR_OR,
   TMPL_EXPR_INVERT_BOOLEAN,
   TMPL_EXPR_ARGS,
+  TMPL_EXPR_FUNC,
 } TmplExprType;
 
 typedef enum
diff --git a/src/tmpl-expr.c b/src/tmpl-expr.c
index 65099ea..18008b2 100644
--- a/src/tmpl-expr.c
+++ b/src/tmpl-expr.c
@@ -142,6 +142,12 @@ tmpl_expr_destroy (TmplExpr *self)
       g_clear_pointer (&self->require.version, g_free);
       break;
 
+    case TMPL_EXPR_FUNC:
+      g_clear_pointer (&self->func.name, g_free);
+      g_clear_pointer (&self->func.symlist, g_strfreev);
+      g_clear_pointer (&self->func.list, tmpl_expr_unref);
+      break;
+
     default:
       g_assert_not_reached ();
     }
@@ -380,3 +386,21 @@ tmpl_expr_from_string (const gchar  *str,
 
   return ret;
 }
+
+TmplExpr *
+tmpl_expr_new_func (char      *name,
+                    char     **symlist,
+                    TmplExpr  *list)
+{
+  TmplExprFunc *ret;
+
+  g_return_val_if_fail (name != NULL, NULL);
+  g_return_val_if_fail (list != NULL, NULL);
+
+  ret = tmpl_expr_new (TMPL_EXPR_FUNC);
+  ret->name = name;
+  ret->symlist = symlist;
+  ret->list = list;
+
+  return (TmplExpr *)ret;
+}
diff --git a/src/tmpl-expr.h b/src/tmpl-expr.h
index 3c7a733..61bafe0 100644
--- a/src/tmpl-expr.h
+++ b/src/tmpl-expr.h
@@ -86,6 +86,10 @@ TmplExpr *tmpl_expr_new_symbol_assign (const gchar      *symbol,
                                        TmplExpr         *right);
 TMPL_AVAILABLE_IN_3_36
 TmplExpr *tmpl_expr_new_stmt_list     (GPtrArray        *stmts);
+TMPL_AVAILABLE_IN_3_36
+TmplExpr *tmpl_expr_new_func          (char             *name,
+                                       char            **symlist,
+                                       TmplExpr         *list);
 
 G_DEFINE_AUTOPTR_CLEANUP_FUNC (TmplExpr, tmpl_expr_unref)
 
diff --git a/tests/test1.script b/tests/test1.script
index beaa731..147fdc6 100644
--- a/tests/test1.script
+++ b/tests/test1.script
@@ -1,5 +1,6 @@
 require GLib
 require Gio version "2.0"
 
-a = 2
-617 * a
+func multiply(x,y) = x * y;
+
+multiply(617, 2)


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