[template-glib] expr-parser.y: allow calling anonymous functions
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [template-glib] expr-parser.y: allow calling anonymous functions
- Date: Thu, 5 May 2022 00:51:50 +0000 (UTC)
commit 8993d1594c2963c6c184a3ef578541b61918e3d5
Author: Christian Hergert <chergert redhat com>
Date: Wed May 4 17:47:38 2022 -0700
expr-parser.y: allow calling anonymous functions
src/tmpl-expr-eval.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++
src/tmpl-expr-parser.y | 6 ++++
src/tmpl-expr-private.h | 9 +++++
src/tmpl-expr-types.h | 1 +
src/tmpl-expr.c | 21 ++++++++++++
src/tmpl-expr.h | 3 ++
tests/test1.script | 4 +++
7 files changed, 134 insertions(+)
---
diff --git a/src/tmpl-expr-eval.c b/src/tmpl-expr-eval.c
index 98081ab..e5ea6f4 100644
--- a/src/tmpl-expr-eval.c
+++ b/src/tmpl-expr-eval.c
@@ -1089,6 +1089,93 @@ cleanup:
return ret;
}
+static gboolean
+tmpl_expr_anon_fn_call_eval (TmplExprAnonFnCall *node,
+ TmplScope *scope,
+ GValue *return_value,
+ GError **error)
+{
+ char **args;
+ TmplExpr *params = NULL;
+ TmplScope *local_scope = NULL;
+ gboolean ret = FALSE;
+ gint n_args = 0;
+
+ g_assert (node != NULL);
+ g_assert (scope != NULL);
+ g_assert (return_value != NULL);
+
+ if (node->anon->any.type != TMPL_EXPR_FUNC)
+ {
+ g_set_error_literal (error,
+ TMPL_ERROR,
+ TMPL_ERROR_NOT_A_FUNCTION,
+ "Not a function to evaluate");
+ return FALSE;
+ }
+
+ args = node->anon->func.symlist;
+ n_args = args ? g_strv_length (args) : 0;
+ local_scope = tmpl_scope_new_with_parent (scope);
+ params = node->params;
+
+ for (guint i = 0; i < n_args; i++)
+ {
+ const gchar *arg = args[i];
+ GValue value = G_VALUE_INIT;
+
+ if (params == NULL)
+ {
+ g_set_error (error,
+ TMPL_ERROR,
+ TMPL_ERROR_SYNTAX_ERROR,
+ "Function takes %d arguments, got %d",
+ n_args, i);
+ return FALSE;
+ }
+
+ if (params->any.type == TMPL_EXPR_ARGS)
+ {
+ TmplExprSimple *simple = (TmplExprSimple *)params;
+
+ if (!tmpl_expr_eval_internal (simple->left, local_scope, &value, error))
+ goto cleanup;
+
+ params = simple->right;
+ }
+ else
+ {
+ if (!tmpl_expr_eval_internal (params, local_scope, &value, error))
+ goto cleanup;
+
+ params = NULL;
+ }
+
+ tmpl_scope_set_value (local_scope, arg, &value);
+ TMPL_CLEAR_VALUE (&value);
+ }
+
+ if (params != NULL)
+ {
+ g_set_error (error,
+ TMPL_ERROR,
+ TMPL_ERROR_SYNTAX_ERROR,
+ "Function takes %d params",
+ n_args);
+ goto cleanup;
+ }
+
+ if (!tmpl_expr_eval_internal (node->anon, local_scope, return_value, error))
+ goto cleanup;
+
+ ret = TRUE;
+
+cleanup:
+ g_clear_pointer (&local_scope, tmpl_scope_unref);
+
+ return ret;
+}
+
static gboolean
tmpl_expr_user_fn_call_eval (TmplExprUserFnCall *node,
TmplScope *scope,
@@ -1325,6 +1412,9 @@ tmpl_expr_eval_internal (TmplExpr *node,
case TMPL_EXPR_FN_CALL:
return tmpl_expr_fn_call_eval ((TmplExprFnCall *)node, scope, return_value, error);
+ case TMPL_EXPR_ANON_FN_CALL:
+ return tmpl_expr_anon_fn_call_eval ((TmplExprAnonFnCall *)node, scope, return_value, error);
+
case TMPL_EXPR_USER_FN_CALL:
return tmpl_expr_user_fn_call_eval ((TmplExprUserFnCall *)node, scope, return_value, error);
diff --git a/src/tmpl-expr-parser.y b/src/tmpl-expr-parser.y
index d8f47af..a10ebf7 100644
--- a/src/tmpl-expr-parser.y
+++ b/src/tmpl-expr-parser.y
@@ -285,6 +285,12 @@ exp: exp CMP exp {
$$ = tmpl_expr_new_user_fn_call ($1, NULL);
g_free ($1);
}
+ | exp '(' ')' {
+ $$ = tmpl_expr_new_anon_call ($1, NULL);
+ }
+ | exp '(' explist ')' {
+ $$ = tmpl_expr_new_anon_call ($1, $3);
+ }
| '!' exp {
$$ = tmpl_expr_new_invert_boolean ($2);
}
diff --git a/src/tmpl-expr-private.h b/src/tmpl-expr-private.h
index 4d7a19a..d9d733e 100644
--- a/src/tmpl-expr-private.h
+++ b/src/tmpl-expr-private.h
@@ -60,6 +60,14 @@ typedef struct
TmplExpr *params;
} TmplExprUserFnCall;
+typedef struct
+{
+ TmplExprType type;
+ volatile gint ref_count;
+ TmplExpr *anon;
+ TmplExpr *params;
+} TmplExprAnonFnCall;
+
typedef struct
{
TmplExprType type;
@@ -158,6 +166,7 @@ union _TmplExpr
TmplExprSimple simple;
TmplExprGiCall gi_call;
TmplExprFnCall fn_call;
+ TmplExprAnonFnCall anon_fn_call;
TmplExprUserFnCall user_fn_call;
TmplExprFlow flow;
TmplExprNumber number;
diff --git a/src/tmpl-expr-types.h b/src/tmpl-expr-types.h
index 6862ff2..4e4ad97 100644
--- a/src/tmpl-expr-types.h
+++ b/src/tmpl-expr-types.h
@@ -67,6 +67,7 @@ typedef enum
TMPL_EXPR_SYMBOL_REF,
TMPL_EXPR_SYMBOL_ASSIGN,
TMPL_EXPR_FN_CALL,
+ TMPL_EXPR_ANON_FN_CALL,
TMPL_EXPR_USER_FN_CALL,
TMPL_EXPR_GETATTR,
TMPL_EXPR_SETATTR,
diff --git a/src/tmpl-expr.c b/src/tmpl-expr.c
index d5a1422..d040f81 100644
--- a/src/tmpl-expr.c
+++ b/src/tmpl-expr.c
@@ -92,6 +92,11 @@ tmpl_expr_destroy (TmplExpr *self)
g_clear_pointer (&self->user_fn_call.params, tmpl_expr_unref);
break;
+ case TMPL_EXPR_ANON_FN_CALL:
+ g_clear_pointer (&self->anon_fn_call.anon, tmpl_expr_unref);
+ g_clear_pointer (&self->user_fn_call.params, tmpl_expr_unref);
+ break;
+
case TMPL_EXPR_GETATTR:
g_clear_pointer (&self->getattr.attr, g_free);
g_clear_pointer (&self->getattr.left, tmpl_expr_unref);
@@ -412,6 +417,22 @@ tmpl_expr_new_func (char *name,
return (TmplExpr *)ret;
}
+TmplExpr *
+tmpl_expr_new_anon_call (TmplExpr *func,
+ TmplExpr *params)
+{
+ TmplExprAnonFnCall *ret;
+
+ g_return_val_if_fail (func != NULL, NULL);
+ g_return_val_if_fail (func->any.type == TMPL_EXPR_FUNC, NULL);
+
+ ret = tmpl_expr_new (TMPL_EXPR_ANON_FN_CALL);
+ ret->anon = func;
+ ret->params = params;
+
+ return (TmplExpr *)ret;
+}
+
TmplExpr *
tmpl_expr_new_nop (void)
{
diff --git a/src/tmpl-expr.h b/src/tmpl-expr.h
index a57b0b4..b9951e6 100644
--- a/src/tmpl-expr.h
+++ b/src/tmpl-expr.h
@@ -91,6 +91,9 @@ TmplExpr *tmpl_expr_new_func (char *name,
char **symlist,
TmplExpr *list);
TMPL_AVAILABLE_IN_3_36
+TmplExpr *tmpl_expr_new_anon_call (TmplExpr *func,
+ TmplExpr *params);
+TMPL_AVAILABLE_IN_3_36
TmplExpr *tmpl_expr_new_nop (void);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (TmplExpr, tmpl_expr_unref)
diff --git a/tests/test1.script b/tests/test1.script
index a8f256f..7ceab69 100644
--- a/tests/test1.script
+++ b/tests/test1.script
@@ -49,4 +49,8 @@ order3(1,2,3)
def weird1(a) assert(a==1)
end
+# anonymous functions can have a single statement
+(func() 123)()
+(func(a,b) assert((a==1)&&(b==2)))(1,2)
+
1234;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]