DISPLAY MACROS: New command.
authorBen Pfaff <blp@cs.stanford.edu>
Tue, 21 Feb 2023 19:05:16 +0000 (11:05 -0800)
committerBen Pfaff <blp@cs.stanford.edu>
Tue, 21 Feb 2023 19:05:16 +0000 (11:05 -0800)
NEWS
src/language/command.def
src/language/commands/sys-file-info.c
src/language/lexer/lexer.c
src/language/lexer/lexer.h
tests/language/commands/define.at

diff --git a/NEWS b/NEWS
index 46973b48cf283268b6c1855011303797c0cd937c..79c0f000bf738fbaccdb01ba435bc655e9b990b1 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -17,6 +17,8 @@ Changes after 1.6.2:
 
    - Break variables are now optional.
 
+ * DISPLAY MACROS is now implemented.
+
  * Removed the MODIFY VARS command, which is not in SPSS.
 
  * Building from a Git repository, which previously required GIMP, now
index 5d642d693af867b1d56f97cefb90caf827574698..0131b5dc7deda04becd989e945e00503239e1fb6 100644 (file)
@@ -19,6 +19,7 @@ DEF_CMD (S_ANY, F_ENHANCED, "CLOSE FILE HANDLE", cmd_close_file_handle)
 DEF_CMD (S_ANY, 0, "CACHE", cmd_cache)
 DEF_CMD (S_ANY, 0, "CD", cmd_cd)
 DEF_CMD (S_ANY, 0, "DEFINE", cmd_define)
+DEF_CMD (S_ANY, 0, "DISPLAY MACROS", cmd_display_macros)
 DEF_CMD (S_ANY, 0, "DO REPEAT", cmd_do_repeat)
 DEF_CMD (S_ANY, 0, "END REPEAT", cmd_end_repeat)
 DEF_CMD (S_ANY, 0, "ECHO", cmd_echo)
index c3ceefb6992b68dbcabdda3f2a9fb8a11e69489f..1b2b6784042807bc724e8a330f3c1bfd2c889e28 100644 (file)
@@ -34,6 +34,7 @@
 #include "language/command.h"
 #include "language/commands/file-handle.h"
 #include "language/lexer/lexer.h"
+#include "language/lexer/macro.h"
 #include "language/lexer/variable-parser.h"
 #include "libpspp/array.h"
 #include "libpspp/hash-functions.h"
@@ -271,23 +272,17 @@ error:
 \f
 /* DISPLAY utility. */
 
-static void display_macros (void);
 static void display_documents (const struct dictionary *dict);
 static void display_vectors (const struct dictionary *dict, int sorted);
 
 int
 cmd_display (struct lexer *lexer, struct dataset *ds)
 {
-  /* Whether to sort the list of variables alphabetically. */
-  int sorted;
-
   /* Variables to display. */
   size_t n;
   const struct variable **vl;
 
-  if (lex_match_id (lexer, "MACROS"))
-    display_macros ();
-  else if (lex_match_id (lexer, "DOCUMENTS"))
+  if (lex_match_id (lexer, "DOCUMENTS"))
     display_documents (dataset_dict (ds));
   else if (lex_match_id (lexer, "FILE"))
     {
@@ -308,7 +303,7 @@ cmd_display (struct lexer *lexer, struct dataset *ds)
     {
       int flags;
 
-      sorted = lex_match_id (lexer, "SORTED");
+      bool sorted = lex_match_id (lexer, "SORTED");
 
       if (lex_match_id (lexer, "VECTORS"))
        {
@@ -397,10 +392,67 @@ cmd_display (struct lexer *lexer, struct dataset *ds)
   return CMD_SUCCESS;
 }
 
-static void
-display_macros (void)
+static int
+compare_macros_by_name (const void *a_, const void *b_, const void *aux UNUSED)
 {
-  msg (SW, _("Macros not supported."));
+  const struct macro *const *ap = a_;
+  const struct macro *const *bp = b_;
+  const struct macro *a = *ap;
+  const struct macro *b = *bp;
+
+  return utf8_strcasecmp (a->name, b->name);
+}
+
+int
+cmd_display_macros (struct lexer *lexer, struct dataset *ds UNUSED)
+{
+  const struct macro_set *set = lex_get_macros (lexer);
+
+  if (hmap_is_empty (&set->macros))
+    {
+      msg (SN, _("No macros to display."));
+      return CMD_SUCCESS;
+    }
+
+  const struct macro **macros = xnmalloc (hmap_count (&set->macros),
+                                          sizeof *macros);
+  size_t n = 0;
+  const struct macro *m;
+  HMAP_FOR_EACH (m, struct macro, hmap_node, &set->macros)
+    macros[n++] = m;
+  assert (n == hmap_count (&set->macros));
+  sort (macros, n, sizeof *macros, compare_macros_by_name, NULL);
+
+  struct pivot_table *table = pivot_table_create (N_("Macros"));
+
+  struct pivot_dimension *attributes = pivot_dimension_create (
+    table, PIVOT_AXIS_COLUMN, N_("Attributes"));
+  pivot_category_create_leaf (attributes->root,
+                              pivot_value_new_text (N_("Source Location")));
+
+  struct pivot_dimension *names = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Name"));
+  names->root->show_label = true;
+
+  for (size_t i = 0; i < n; i++)
+    {
+      const struct macro *m = macros[i];
+
+      pivot_category_create_leaf (names->root,
+                                  pivot_value_new_user_text (m->name, -1));
+
+      struct string location = DS_EMPTY_INITIALIZER;
+      msg_location_format (m->location, &location);
+      pivot_table_put2 (
+        table, 0, i,
+        pivot_value_new_user_text_nocopy (ds_steal_cstr (&location)));
+    }
+
+  pivot_table_submit (table);
+
+  free (macros);
+
+  return CMD_SUCCESS;
 }
 
 static char *
index 35a9afa381f038968fafb27c05a87d57e408b176..d22985c7e5350f7e374d1b78f5613890eedd957d 100644 (file)
@@ -362,6 +362,13 @@ lex_define_macro (struct lexer *lexer, struct macro *m)
   macro_set_add (lexer->macros, m);
 }
 
+/* Returns LEXER's macro set.  The caller should not modify it. */
+const struct macro_set *
+lex_get_macros (const struct lexer *lexer)
+{
+  return lexer->macros;
+}
+
 /* Inserts READER into LEXER so that the next token read by LEXER comes from
    READER.  Before the caller, LEXER must either be empty or at a T_ENDCMD
    token. */
index ae40a87a04253894669fb6e274d6307ea507a4c7..ccb8d73a80cd534a7e5fadba96baf4b069818d06 100644 (file)
@@ -97,6 +97,7 @@ void lex_destroy (struct lexer *);
 
 /* Macros. */
 void lex_define_macro (struct lexer *, struct macro *);
+const struct macro_set *lex_get_macros (const struct lexer *);
 
 /* Files. */
 void lex_include (struct lexer *, struct lex_reader *);
index fb66b01378429a2984e717d945d1b5e07ab18513..2e1a7eebad2fe4678d620290d25f403984c0316d 100644 (file)
@@ -2453,4 +2453,29 @@ AT_CHECK([pspp --testing-mode define.sps], [0], [dnl
 
 [[ < y > ]]
 ])
-AT_CLEANUP
\ No newline at end of file
+AT_CLEANUP
+
+AT_SETUP([DISPLAY MACROS])
+AT_DATA([define.sps], [dnl
+DEFINE !b() 0 !ENDDEFINE.
+DEFINE !macro()
+a b c d
+e f g h.
+i j k l
+1,2,3,4.
+5+6+7.
+m(n,o).
+"a" "b" "c" 'a' 'b' 'c'.
+"x "" y".
+!ENDDEFINE.
+DEFINE !a() 1 !ENDDEFINE.
+DISPLAY MACROS.
+])
+AT_CHECK([pspp -O format=csv define.sps], [0], [dnl
+Table: Macros
+Name,Source Location
+!a,define.sps:12
+!b,define.sps:1
+!macro,define.sps:2-11
+])
+AT_CLEANUP