poke-devel
[Top][All Lists]
Advanced

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

[COMMITTED] libpoke,testsuite,doc: support for lambda expressions


From: Jose E. Marchesi
Subject: [COMMITTED] libpoke,testsuite,doc: support for lambda expressions
Date: Sun, 08 Nov 2020 13:11:45 +0100
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux)

This commit adds support for lambda expressions to Poke.  Lambda
expressions use the following simple syntax:

  lambda FUNCTION_SPECIFIER

Where a FUNCTION_SPECIFIER is the same notation that one would use
when defining a function in a `fun' construction.  Examples:

 (poke) lambda void: {}
 #<closure>
 (poke) lambda (int i) int: { return i + 2; }
 #<closure>

Lambdas can be invoked like any other function value:

 (poke) lambda void: {} ()
 (poke) lambda (int i) int: { return i + 2; } (10)
 12

Lambdas can also be stored in variables:

 (poke) var la = lambda (int i) int: { return i + 2; }
 (poke) la (10)
 12

2020-11-08  Jose E. Marchesi  <jemarch@gnu.org>

        * libpoke/pkl-lex.l: Support `lambda'.
        * libpoke/pkl-tab.y (LABMDA): New token.
        (primary): Support lambdas as primaries in expressions.
        * libpoke/pkl-ast.h (enum pkl_ast_code): New value PKL_AST_LAMBDA.
        (PKL_AST_LAMBDA_FUNCTION): Define.
        (struct pkl_ast_lambda): Likewise.
        (union pkl_ast_node): New field `lambda'.
        (pkl_ast_make_lambda): New prototype.
        * libpoke/pkl-ast.c (pkl_ast_make_lambda): New function.
        (pkl_ast_node_free): Handle lambda AST nodes.
        (pkl_ast_print_1): Likewise.
        * libpoke/pkl-pass.c (pkl_do_pass_1): Likewise.
        * libpoke/pkl-typify.c (pkl_typify1_ps_lambda): New handler.
        (pkl_phase_typify1): Register handler.
        * libpoke/pkl-gen.c (pkl_gen_pr_lambda): New handler.
        (pkl_gen_ps_lambda): Likewise.
        (pkl_phase_gen): Register handlers.
        * testsuite/poke.pkl/lambda-1.pk: New test.
        * testsuite/poke.pkl/lambda-2.pk: Likewise.
        * testsuite/poke.pkl/lambda-3.pk: Likewise.
        * testsuite/poke.pkl/lambda-diag-1.pk: Likewise.
        * testsuite/Makefile.am (EXTRA_DIST): Add new tests.
        * doc/poke.texi (Lambdas): New section.
---
 ChangeLog                           | 26 ++++++++++++++++++
 doc/poke.texi                       | 28 ++++++++++++++++++++
 libpoke/pkl-ast.c                   | 25 ++++++++++++++++++
 libpoke/pkl-ast.h                   | 18 +++++++++++++
 libpoke/pkl-gen.c                   | 41 +++++++++++++++++++++++++++++
 libpoke/pkl-lex.l                   |  1 +
 libpoke/pkl-pass.c                  |  3 +++
 libpoke/pkl-tab.y                   | 16 +++++++++++
 libpoke/pkl-typify.c                | 12 +++++++++
 testsuite/Makefile.am               |  4 +++
 testsuite/poke.pkl/lambda-1.pk      |  6 +++++
 testsuite/poke.pkl/lambda-2.pk      |  6 +++++
 testsuite/poke.pkl/lambda-3.pk      |  5 ++++
 testsuite/poke.pkl/lambda-diag-1.pk |  3 +++
 14 files changed, 194 insertions(+)
 create mode 100644 testsuite/poke.pkl/lambda-1.pk
 create mode 100644 testsuite/poke.pkl/lambda-2.pk
 create mode 100644 testsuite/poke.pkl/lambda-3.pk
 create mode 100644 testsuite/poke.pkl/lambda-diag-1.pk

diff --git a/ChangeLog b/ChangeLog
index fa4b5137..ef1cf618 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,29 @@
+2020-11-08  Jose E. Marchesi  <jemarch@gnu.org>
+
+       * libpoke/pkl-lex.l: Support `lambda'.
+       * libpoke/pkl-tab.y (LABMDA): New token.
+       (primary): Support lambdas as primaries in expressions.
+       * libpoke/pkl-ast.h (enum pkl_ast_code): New value PKL_AST_LAMBDA.
+       (PKL_AST_LAMBDA_FUNCTION): Define.
+       (struct pkl_ast_lambda): Likewise.
+       (union pkl_ast_node): New field `lambda'.
+       (pkl_ast_make_lambda): New prototype.
+       * libpoke/pkl-ast.c (pkl_ast_make_lambda): New function.
+       (pkl_ast_node_free): Handle lambda AST nodes.
+       (pkl_ast_print_1): Likewise.
+       * libpoke/pkl-pass.c (pkl_do_pass_1): Likewise.
+       * libpoke/pkl-typify.c (pkl_typify1_ps_lambda): New handler.
+       (pkl_phase_typify1): Register handler.
+       * libpoke/pkl-gen.c (pkl_gen_pr_lambda): New handler.
+       (pkl_gen_ps_lambda): Likewise.
+       (pkl_phase_gen): Register handlers.
+       * testsuite/poke.pkl/lambda-1.pk: New test.
+       * testsuite/poke.pkl/lambda-2.pk: Likewise.
+       * testsuite/poke.pkl/lambda-3.pk: Likewise.
+       * testsuite/poke.pkl/lambda-diag-1.pk: Likewise.
+       * testsuite/Makefile.am (EXTRA_DIST): Add new tests.
+       * doc/poke.texi (Lambdas): New section.
+
 2020-11-08  Jose E. Marchesi  <jemarch@gnu.org>
 
        * etc/poke-mode.el (poke-font-lock-keywords): Remove unneeded
diff --git a/doc/poke.texi b/doc/poke.texi
index ac0b0ac1..fd5b42e7 100644
--- a/doc/poke.texi
+++ b/doc/poke.texi
@@ -7678,6 +7678,7 @@ The value computed by the expression will be discarded.
 * Variadic Functions::         Functions taking any number of arguments.
 * Calling Functions::          Invoking functions.
 * Function Types::             Useful for defining interfaces.
+* Lambdas::                     Functions in expressions.
 @end menu
 
 @node Function Declarations
@@ -7862,6 +7863,33 @@ fun printf (string fmt, args@dots{}) void: @{ @dots{} @}
 @noindent
 is @code{(string,@dots{})void:}.
 
+@node Lambdas
+@subsection Lambdas
+
+Poke support @dfn{lambda expressions} using the following syntax:
+
+@example
+lambda @var{function_specifier}
+@end example
+
+@noindent
+Where @var{function_specifier} is any function specifier.  Examples:
+
+@example
+lambda void: @{@}
+lambda (int i) int: @{ return i * 2; @}
+@end example
+
+@noindent
+Lambdas can be manipulated exactly like any other Poke value, and can
+be stored in variables.  Therefore, this is an alternative way of
+defining a named function (which can't be recursive for obvious
+reasons):
+
+@example
+var double = lambda (int i) int: @{ return i * 2 @};
+@end example
+
 @node Endianness
 @section Endianness
 @cindex endianness
diff --git a/libpoke/pkl-ast.c b/libpoke/pkl-ast.c
index 9b210b22..9615adcc 100644
--- a/libpoke/pkl-ast.c
+++ b/libpoke/pkl-ast.c
@@ -1538,6 +1538,19 @@ pkl_ast_make_var (pkl_ast ast, pkl_ast_node name,
   return var;
 }
 
+/* Build and return an AST node for a lambda expression.  */
+
+pkl_ast_node
+pkl_ast_make_lambda (pkl_ast ast, pkl_ast_node function)
+{
+  pkl_ast_node lambda = pkl_ast_make_node (ast, PKL_AST_LAMBDA);
+
+  assert (function);
+
+  PKL_AST_LAMBDA_FUNCTION (lambda) = ASTREF (function);
+  return lambda;
+}
+
 /* Build and return an AST node for a compound statement.  */
 
 pkl_ast_node
@@ -2067,6 +2080,11 @@ pkl_ast_node_free (pkl_ast_node ast)
         pkl_ast_node_free (PKL_AST_VAR_DECL (ast));
       break;
 
+    case PKL_AST_LAMBDA:
+
+      pkl_ast_node_free (PKL_AST_LAMBDA_FUNCTION (ast));
+      break;
+
     case PKL_AST_COMP_STMT:
 
       for (t = PKL_AST_COMP_STMT_STMTS (ast); t; t = n)
@@ -2842,6 +2860,13 @@ pkl_ast_print_1 (FILE *fp, pkl_ast_node ast, int indent)
       PRINT_AST_IMM (over, VAR_OVER, "%d");
       break;
 
+    case PKL_AST_LAMBDA:
+      IPRINTF ("LAMBDA::\n");
+
+      PRINT_COMMON_FIELDS;
+      PRINT_AST_SUBAST (function, LAMBDA_FUNCTION);
+      break;
+
     case PKL_AST_COMP_STMT:
       IPRINTF ("COMP_STMT::\n");
 
diff --git a/libpoke/pkl-ast.h b/libpoke/pkl-ast.h
index d56d80b3..6a44cfb7 100644
--- a/libpoke/pkl-ast.h
+++ b/libpoke/pkl-ast.h
@@ -55,6 +55,7 @@ enum pkl_ast_code
   PKL_AST_FUNCALL,
   PKL_AST_FUNCALL_ARG,
   PKL_AST_VAR,
+  PKL_AST_LAMBDA,
   PKL_AST_GCD,
   PKL_AST_LAST_EXP = PKL_AST_GCD,
   /* Types.  */
@@ -1283,6 +1284,22 @@ pkl_ast_node pkl_ast_make_var (pkl_ast ast,
                                pkl_ast_node initial,
                                int back, int over);
 
+/* PKL_AST_LAMBDA nodes represent lambda expressions, which evaluate
+   to a function.
+
+   FUNCTION is a node of type PKL_AST_FUNC.  */
+
+#define PKL_AST_LAMBDA_FUNCTION(AST) ((AST)->lambda.function)
+
+struct pkl_ast_lambda
+{
+  struct pkl_ast_common common;
+
+  union pkl_ast_node *function;
+};
+
+pkl_ast_node pkl_ast_make_lambda (pkl_ast ast, pkl_ast_node function);
+
 /* PKL_AST_COMPOUND_STMT nodes represent compound statements in the
    language.
 
@@ -1715,6 +1732,7 @@ union pkl_ast_node
   struct pkl_ast_funcall funcall;
   struct pkl_ast_funcall_arg funcall_arg;
   struct pkl_ast_var var;
+  struct pkl_ast_lambda lambda;
   /* Types.  */
   struct pkl_ast_type type;
   struct pkl_ast_struct_type_field sct_type_elem;
diff --git a/libpoke/pkl-gen.c b/libpoke/pkl-gen.c
index 65ea7735..87762621 100644
--- a/libpoke/pkl-gen.c
+++ b/libpoke/pkl-gen.c
@@ -444,6 +444,45 @@ PKL_PHASE_BEGIN_HANDLER (pkl_gen_ps_var)
 }
 PKL_PHASE_END_HANDLER
 
+/*
+ * LAMBDA
+ * | FUNCTION
+ */
+
+PKL_PHASE_BEGIN_HANDLER (pkl_gen_pr_lambda)
+{
+  /* FUNCTION is a PKL_AST_FUNC, that will compile into a program
+     containing the function code.  Push a new assembler.  */
+  PKL_GEN_PUSH_ASM (pkl_asm_new (PKL_PASS_AST,
+                                 PKL_GEN_PAYLOAD->compiler,
+                                 0 /* prologue */));
+}
+PKL_PHASE_END_HANDLER
+
+/*
+ * | FUNCTION
+ * LAMBDA
+ */
+
+PKL_PHASE_BEGIN_HANDLER (pkl_gen_ps_lambda)
+{
+  /* At this point the code for FUNCTION has been assembled in the
+     current macroassembler.  Finalize the program and put it in a PVM
+     closure, along with the current environment.  */
+
+  pvm_program program = pkl_asm_finish (PKL_GEN_ASM,
+                                        0 /* epilogue */);
+  pvm_val closure;
+
+  PKL_GEN_POP_ASM;
+  pvm_program_make_executable (program);
+  closure = pvm_make_cls (program);
+
+  pkl_asm_insn (PKL_GEN_ASM, PKL_INSN_PUSH, closure);
+  pkl_asm_insn (PKL_GEN_ASM, PKL_INSN_PEC);
+}
+PKL_PHASE_END_HANDLER
+
 /*
  * NULL_STMT
  */
@@ -3433,6 +3472,8 @@ struct pkl_phase pkl_phase_gen
    PKL_PHASE_PR_HANDLER (PKL_AST_DECL, pkl_gen_pr_decl),
    PKL_PHASE_PS_HANDLER (PKL_AST_DECL, pkl_gen_ps_decl),
    PKL_PHASE_PS_HANDLER (PKL_AST_VAR, pkl_gen_ps_var),
+   PKL_PHASE_PR_HANDLER (PKL_AST_LAMBDA, pkl_gen_pr_lambda),
+   PKL_PHASE_PS_HANDLER (PKL_AST_LAMBDA, pkl_gen_ps_lambda),
    PKL_PHASE_PR_HANDLER (PKL_AST_COND_EXP, pkl_gen_pr_cond_exp),
    PKL_PHASE_PR_HANDLER (PKL_AST_COMP_STMT, pkl_gen_pr_comp_stmt),
    PKL_PHASE_PS_HANDLER (PKL_AST_COMP_STMT, pkl_gen_ps_comp_stmt),
diff --git a/libpoke/pkl-lex.l b/libpoke/pkl-lex.l
index 00f2b38c..92ba1468 100644
--- a/libpoke/pkl-lex.l
+++ b/libpoke/pkl-lex.l
@@ -224,6 +224,7 @@ S ::
 "big"           { return BIG; }
 "little"        { return LITTLE; }
 "load"          { return LOAD; }
+"lambda"        { return LAMBDA; }
 "__PKL_BUILTIN_RAND__" {
    if (yyextra->bootstrapped) REJECT; return BUILTIN_RAND; }
 "__PKL_BUILTIN_GET_ENDIAN__" {
diff --git a/libpoke/pkl-pass.c b/libpoke/pkl-pass.c
index ac85f095..e464fe2e 100644
--- a/libpoke/pkl-pass.c
+++ b/libpoke/pkl-pass.c
@@ -567,6 +567,9 @@ pkl_do_pass_1 (pkl_compiler compiler,
       if (PKL_AST_PRINT_STMT_ARGS (node))
         PKL_PASS_CHAIN (PKL_AST_PRINT_STMT_ARGS (node));
       break;
+    case PKL_AST_LAMBDA:
+      PKL_PASS (PKL_AST_LAMBDA_FUNCTION (node));
+      break;
     case PKL_AST_NULL_STMT:
     case PKL_AST_INTEGER:
     case PKL_AST_STRING:
diff --git a/libpoke/pkl-tab.y b/libpoke/pkl-tab.y
index 131134ec..c4a5ea8c 100644
--- a/libpoke/pkl-tab.y
+++ b/libpoke/pkl-tab.y
@@ -335,6 +335,7 @@ token <integer> UNION    _("keyword `union'")
 %token PRINT             _("keyword `print'")
 %token PRINTF            _("keyword `printf'")
 %token LOAD              _("keyword `load'")
+%token LAMBDA            _("keyword lambda")
 %token BUILTIN_RAND BUILTIN_GET_ENDIAN BUILTIN_SET_ENDIAN
 %token BUILTIN_GET_IOS BUILTIN_SET_IOS BUILTIN_OPEN BUILTIN_CLOSE
 %token BUILTIN_IOSIZE BUILTIN_GETENV BUILTIN_FORGET
@@ -971,6 +972,21 @@ primary:
                 {
                   $$ = $2;
                 }
+        | LAMBDA
+                {
+                  /* function_specifier needs to know whether we are
+                     in a function declaration or a method
+                     declaration.  */
+                  pkl_parser->in_method_decl_p = 0;
+                }
+          function_specifier
+                {
+                  /* Annotate the contained RETURN statements with
+                     their function and their lexical nest level
+                     within the function.  */
+                  pkl_ast_finish_returns ($3);
+                  $$ = pkl_ast_make_lambda (pkl_parser->ast, $3);
+                }
         ;
 
 funcall:
diff --git a/libpoke/pkl-typify.c b/libpoke/pkl-typify.c
index 493abddc..5e190f72 100644
--- a/libpoke/pkl-typify.c
+++ b/libpoke/pkl-typify.c
@@ -2021,6 +2021,17 @@ PKL_PHASE_BEGIN_HANDLER (pkl_typify1_ps_var)
 }
 PKL_PHASE_END_HANDLER
 
+/* The type of a lambda node is the type of its function.  */
+
+PKL_PHASE_BEGIN_HANDLER (pkl_typify1_ps_lambda)
+{
+  pkl_ast_node lambda = PKL_PASS_NODE;
+  pkl_ast_node function = PKL_AST_LAMBDA_FUNCTION (lambda);
+
+  PKL_AST_TYPE (lambda) = ASTREF (PKL_AST_TYPE (function));
+}
+PKL_PHASE_END_HANDLER
+
 /* The type of the condition of a loop statement should be a boolean.  */
 
 PKL_PHASE_BEGIN_HANDLER (pkl_typify1_ps_loop_stmt)
@@ -2758,6 +2769,7 @@ struct pkl_phase pkl_phase_typify1
   {
    PKL_PHASE_PR_HANDLER (PKL_AST_PROGRAM, pkl_typify_pr_program),
    PKL_PHASE_PS_HANDLER (PKL_AST_VAR, pkl_typify1_ps_var),
+   PKL_PHASE_PS_HANDLER (PKL_AST_LAMBDA, pkl_typify1_ps_lambda),
    PKL_PHASE_PS_HANDLER (PKL_AST_CAST, pkl_typify1_ps_cast),
    PKL_PHASE_PS_HANDLER (PKL_AST_ISA, pkl_typify1_ps_isa),
    PKL_PHASE_PS_HANDLER (PKL_AST_MAP, pkl_typify1_ps_map),
diff --git a/testsuite/Makefile.am b/testsuite/Makefile.am
index cf936d19..1656dbd5 100644
--- a/testsuite/Makefile.am
+++ b/testsuite/Makefile.am
@@ -957,6 +957,10 @@ EXTRA_DIST = \
   poke.pkl/isa-7.pk \
   poke.pkl/isa-8.pk \
   poke.pkl/isa-9.pk \
+  poke.pkl/lambda-1.pk \
+  poke.pkl/lambda-2.pk \
+  poke.pkl/lambda-3.pk \
+  poke.pkl/lambda-diag-1.pk \
   poke.pkl/le-arrays-diag-1.pk \
   poke.pkl/le-integers-1.pk \
   poke.pkl/le-integers-2.pk \
diff --git a/testsuite/poke.pkl/lambda-1.pk b/testsuite/poke.pkl/lambda-1.pk
new file mode 100644
index 00000000..5e33ab2d
--- /dev/null
+++ b/testsuite/poke.pkl/lambda-1.pk
@@ -0,0 +1,6 @@
+/* { dg-do run } */
+
+/* { dg-command "lambda void: {}" } */
+/* { dg-output "#<closure>" } */
+/* { dg-command "lambda void: {} ()" } */
+/* { dg-output "\n" } */
diff --git a/testsuite/poke.pkl/lambda-2.pk b/testsuite/poke.pkl/lambda-2.pk
new file mode 100644
index 00000000..8c9aacfc
--- /dev/null
+++ b/testsuite/poke.pkl/lambda-2.pk
@@ -0,0 +1,6 @@
+/* { dg-do run } */
+
+/* { dg-command "lambda (int i) int: { return i + 2; }" } */
+/* { dg-output "#<closure>" } */
+/* { dg-command "lambda (int i) int: { return i + 2; } (10)" } */
+/* { dg-output "\n12" } */
diff --git a/testsuite/poke.pkl/lambda-3.pk b/testsuite/poke.pkl/lambda-3.pk
new file mode 100644
index 00000000..b505330d
--- /dev/null
+++ b/testsuite/poke.pkl/lambda-3.pk
@@ -0,0 +1,5 @@
+/* { dg-do run } */
+
+/* { dg-command "var la = lambda (int i) int: { return i + 2; }" } */
+/* { dg-command "la (12)" } */
+/* { dg-output "14" } */
diff --git a/testsuite/poke.pkl/lambda-diag-1.pk 
b/testsuite/poke.pkl/lambda-diag-1.pk
new file mode 100644
index 00000000..9d3ce0c5
--- /dev/null
+++ b/testsuite/poke.pkl/lambda-diag-1.pk
@@ -0,0 +1,3 @@
+/* { dg-do compile } */
+
+lambda (int i, string s) void: {} (10, 20); /* { dg-error ".*\n.*expected 
string" } */
-- 
2.25.0.2.g232378479e





reply via email to

[Prev in Thread] Current Thread [Next in Thread]