texinfo-commits
[Top][All Lists]
Advanced

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

branch master updated: linemacro implementation for the XS Parser


From: Patrice Dumas
Subject: branch master updated: linemacro implementation for the XS Parser
Date: Sun, 26 Mar 2023 19:26:09 -0400

This is an automated email from the git hooks/post-receive script.

pertusus pushed a commit to branch master
in repository texinfo.

The following commit(s) were added to refs/heads/master by this push:
     new 81f4e13d33 linemacro implementation for the XS Parser
81f4e13d33 is described below

commit 81f4e13d33abeb15a50d0ba98031025f54cb0bdd
Author: Patrice Dumas <pertusus@free.fr>
AuthorDate: Mon Mar 27 01:26:00 2023 +0200

    linemacro implementation for the XS Parser
    
    * tp/Texinfo/XS/parsetexi/api.c (linemacro_expansion),
    tp/Texinfo/XS/parsetexi/context_stack.h (no_paragraph_context),
    tp/Texinfo/XS/parsetexi/def.c (parse_def),
    tp/Texinfo/XS/parsetexi/element_types.txt,
    tp/Texinfo/XS/parsetexi/end_line.c (end_line_def_line)
    (end_line_misc_line, end_line),
    tp/Texinfo/XS/parsetexi/handle_commands.c (handle_block_command),
    tp/Texinfo/XS/parsetexi/macro.c (handle_macro),
    tp/Texinfo/XS/parsetexi/parser.c (process_remaining_on_line)
    (parse_texi), tp/Texinfo/XS/parsetexi/separator.c (handle_open_brace),
    tp/Texinfo/XS/parsetexi/source_marks.c (register_source_mark)
    (source_marks_reset_counters): handle @linemacro and linemacro defined
    command calls using the same design as for perl Parser.
    
    * tp/Texinfo/ParserNonXS.pm (%no_paragraph_contexts): set
    ct_linecommand to be no paragraph context.
    
    * tp/Texinfo/ParserNonXS.pm (_process_remaining_on_line):
    change code opening arguments_container line_arg for linemacro command
    call to be more like XS parser.
---
 ChangeLog                                 |  25 +++++
 tp/Texinfo/ParserNonXS.pm                 |  12 +-
 tp/Texinfo/XS/parsetexi/api.c             |   1 +
 tp/Texinfo/XS/parsetexi/context_stack.h   |   6 +-
 tp/Texinfo/XS/parsetexi/def.c             | 141 +++++++++++++++++++-----
 tp/Texinfo/XS/parsetexi/element_types.c   |   1 +
 tp/Texinfo/XS/parsetexi/element_types.h   |   1 +
 tp/Texinfo/XS/parsetexi/element_types.txt |   1 +
 tp/Texinfo/XS/parsetexi/end_line.c        | 175 ++++++++++++++++++++++++++++--
 tp/Texinfo/XS/parsetexi/handle_commands.c |   2 +-
 tp/Texinfo/XS/parsetexi/macro.c           | 155 +++++++++++++-------------
 tp/Texinfo/XS/parsetexi/macro.h           |   2 +
 tp/Texinfo/XS/parsetexi/parser.c          |  64 ++++++++---
 tp/Texinfo/XS/parsetexi/separator.c       |   6 +-
 tp/Texinfo/XS/parsetexi/source_marks.c    |   7 ++
 tp/Texinfo/XS/parsetexi/tree_types.h      |   1 +
 16 files changed, 468 insertions(+), 132 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index cbc3cb0e1b..16f533479a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,28 @@
+2023-03-26  Patrice Dumas  <pertusus@free.fr>
+
+       linemacro implementation for the XS Parser
+
+       * tp/Texinfo/XS/parsetexi/api.c (linemacro_expansion),
+       tp/Texinfo/XS/parsetexi/context_stack.h (no_paragraph_context),
+       tp/Texinfo/XS/parsetexi/def.c (parse_def),
+       tp/Texinfo/XS/parsetexi/element_types.txt,
+       tp/Texinfo/XS/parsetexi/end_line.c (end_line_def_line)
+       (end_line_misc_line, end_line),
+       tp/Texinfo/XS/parsetexi/handle_commands.c (handle_block_command),
+       tp/Texinfo/XS/parsetexi/macro.c (handle_macro),
+       tp/Texinfo/XS/parsetexi/parser.c (process_remaining_on_line)
+       (parse_texi), tp/Texinfo/XS/parsetexi/separator.c (handle_open_brace),
+       tp/Texinfo/XS/parsetexi/source_marks.c (register_source_mark)
+       (source_marks_reset_counters): handle @linemacro and linemacro defined
+       command calls using the same design as for perl Parser.
+
+       * tp/Texinfo/ParserNonXS.pm (%no_paragraph_contexts): set
+       ct_linecommand to be no paragraph context.
+
+       * tp/Texinfo/ParserNonXS.pm (_process_remaining_on_line):
+       change code opening arguments_container line_arg for linemacro command
+       call to be more like XS parser.
+
 2023-03-26  Gavin Smith <gavinsmith0123@gmail.com>
 
        * NEWS: add 7.0.3 news.
diff --git a/tp/Texinfo/ParserNonXS.pm b/tp/Texinfo/ParserNonXS.pm
index 5274d555bd..e8b401dfe1 100644
--- a/tp/Texinfo/ParserNonXS.pm
+++ b/tp/Texinfo/ParserNonXS.pm
@@ -543,7 +543,7 @@ foreach my $canonical_encoding ('us-ascii', 'utf-8', 
'iso-8859-1',
 # a paragraph
 my %no_paragraph_contexts;
 foreach my $no_paragraph_context ('math', 'preformatted', 'rawpreformatted',
-                                  'def', 'inlineraw') {
+                                  'def', 'inlineraw', 'linecommand') {
   $no_paragraph_contexts{'ct_'.$no_paragraph_context} = 1;
 };
 
@@ -6867,10 +6867,12 @@ sub _process_remaining_on_line($$$$)
       # FIXME needed? Correct?
       $arguments_container->{'source_info'} = $source_info;
       $self->_push_context('ct_linecommand', $command);
-      $current = $current->{'contents'}->[-1];
-      $current->{'args'} = [{ 'type' => 'line_arg',
-                          'parent' => $current }];
-      $current = $current->{'args'}->[-1];
+      $current = $arguments_container;
+      $current->{'args'} = [];
+      my $line_arg = { 'type' => 'line_arg',
+                        'parent' => $current };
+      push @{$current->{'args'}}, $line_arg;
+      $current = $line_arg;
       $line = _start_empty_line_after_command($line, $current,
                                               $arguments_container);
       return ($current, $line, $source_info, $retval);
diff --git a/tp/Texinfo/XS/parsetexi/api.c b/tp/Texinfo/XS/parsetexi/api.c
index 83c9d83443..a96b7ceda4 100644
--- a/tp/Texinfo/XS/parsetexi/api.c
+++ b/tp/Texinfo/XS/parsetexi/api.c
@@ -471,6 +471,7 @@ store_source_mark_list (ELEMENT *e)
               SAVE_S_M_TYPE (delcomment)
               SAVE_S_M_TYPE (defline_continuation)
               SAVE_S_M_TYPE (macro_expansion)
+              SAVE_S_M_TYPE (linemacro_expansion)
               SAVE_S_M_TYPE (value_expansion)
               SAVE_S_M_TYPE (ignored_conditional_block)
               SAVE_S_M_TYPE (expanded_conditional_command)
diff --git a/tp/Texinfo/XS/parsetexi/context_stack.h 
b/tp/Texinfo/XS/parsetexi/context_stack.h
index b2ed4f7706..e218483b5e 100644
--- a/tp/Texinfo/XS/parsetexi/context_stack.h
+++ b/tp/Texinfo/XS/parsetexi/context_stack.h
@@ -26,7 +26,8 @@ enum context {
     ct_rawpreformatted,
     ct_math,
     ct_brace_command,
-    ct_inlineraw
+    ct_inlineraw,
+    ct_linecommand
 };
 
 /* Contexts where an empty line doesn't start a new paragraph. */
@@ -35,7 +36,8 @@ enum context {
    || (c) == ct_def \
    || (c) == ct_preformatted \
    || (c) == ct_rawpreformatted \
-   || (c) == ct_inlineraw)
+   || (c) == ct_inlineraw \
+   || (c) == ct_linecommand)
 
 void push_context (enum context c, enum command_id cmd);
 enum context pop_context (void);
diff --git a/tp/Texinfo/XS/parsetexi/def.c b/tp/Texinfo/XS/parsetexi/def.c
index 2a4d5de8c4..2085dca435 100644
--- a/tp/Texinfo/XS/parsetexi/def.c
+++ b/tp/Texinfo/XS/parsetexi/def.c
@@ -22,6 +22,7 @@
 #include "parser.h"
 #include "text.h"
 #include "source_marks.h"
+#include "debug.h"
 
 void
 gather_def_item (ELEMENT *current, enum command_id next_command)
@@ -329,8 +330,9 @@ parse_def (enum command_id command, ELEMENT *current)
   int type, next_type;
   int i, i_def;
   int arg_types_nr;
-  ELEMENT *e, *e1; 
+  ELEMENT *e, *e1;
   DEF_ARG **result;
+  char **arguments_list;
 
   split_def_args (current, contents_idx);
 
@@ -371,43 +373,128 @@ parse_def (enum command_id command, ELEMENT *current)
       insert_into_contents (current, e, contents_idx + 1);
     }
 
-  /* Read arguments as CATEGORY [CLASS] [TYPE] NAME [ARGUMENTS]. */
-  
+  /* prepare the arguments numbers and list */
+  if (command_data(command).flags & CF_MACRO)
+    {
+      int args_number;
+      MACRO *macro_record = lookup_macro (command);
+      ELEMENT *macro;
+      if (!macro_record)
+        fatal ("no linemacro record for arguments parsing");
+      macro = macro_record->element;
+      args_number = macro->args.number - 1;
+      arguments_list = malloc ((args_number + 1) * sizeof (char *));
+      arguments_list[args_number] = 0;
+      arg_types_nr = args_number;
+      if (args_number > 0)
+        {
+          int arg_index;
+          ELEMENT **args = macro->args.list;
+          for (arg_index = 1; arg_index <= args_number; arg_index++)
+            {
+              if (args[arg_index]->type == ET_macro_arg)
+                arguments_list[arg_index -1] = args[arg_index]->text.text;
+              else
+                arguments_list[arg_index -1] = 0;
+            }
+          /* remove one for the rest of the line argument */
+          arg_types_nr--;
 
-  for (i_def = 0; i_def < sizeof (def_maps) / sizeof (*def_maps); i_def++)
+          result = malloc ((args_number+1) * sizeof (DEF_ARG *));
+        }
+    }
+  else
     {
-      if (def_maps[i_def].command == command)
-        goto def_found;
+     /* Read arguments as CATEGORY [CLASS] [TYPE] NAME [ARGUMENTS]. */
+
+      for (i_def = 0; i_def < sizeof (def_maps) / sizeof (*def_maps); i_def++)
+        {
+          if (def_maps[i_def].command == command)
+            goto def_found;
+        }
+      fatal ("no arguments for def command");
+     def_found:
+
+      /* determine non arg/argtype number of arguments */
+      arg_types_nr = 0;
+      arguments_list = def_maps[i_def].arguments;
+      while (arguments_list[arg_types_nr])
+        {
+          char *arg_type_name = arguments_list[arg_types_nr];
+
+          /* FIXME keep information about arg/argtype? */
+          if (!strcmp (arg_type_name, "arg")
+              || !strcmp (arg_type_name, "argtype"))
+            break;
+          arg_types_nr++;
+        }
+      result = malloc ((arg_types_nr+1) * sizeof (DEF_ARG *));
     }
-  fatal ("no arguments for def command");
- def_found:
 
-  /* determine non arg/argtype number of arguments */
-  arg_types_nr = 0;
-  while (def_maps[i_def].arguments[arg_types_nr])
+  for (i = 0; i < arg_types_nr; i++)
     {
-      char *arg_type_name = def_maps[i_def].arguments[arg_types_nr];
+      ELEMENT *e = next_bracketed_or_word_agg (current, &contents_idx);
 
-      /* FIXME keep information about arg/argtype? */
-      if (!strcmp (arg_type_name, "arg")
-          || !strcmp (arg_type_name, "argtype"))
-        break;
-      arg_types_nr++;
+      if (e)
+        {
+          char *arg_type_name = arguments_list[i];
+          DEF_ARG *def_arg = malloc (sizeof (DEF_ARG));
+
+          result[i] = def_arg;
+          def_arg->arg_type = strdup(arg_type_name);
+          def_arg->element = e;
+        }
+      else
+        {
+          i++;
+          break;
+        }
+    }
+
+  result[i] = 0;
+  if (command_data(command).flags & CF_MACRO)
+    {
+      /* FIXME do not add leading space to def_arg */
+      /* note that element at contents_idx is not collected at that point */
+      if (contents_idx < current->contents.number)
+        {
+          DEF_ARG *def_arg = malloc (sizeof (DEF_ARG));
+          int contents_nr = current->contents.number - contents_idx;
+
+          result[i] = def_arg;
+          result[i+1] = 0;
+
+          def_arg->arg_type = strdup (arguments_list[i]);
+          if (contents_nr == 1)
+            def_arg->element = current->contents.list[contents_idx];
+          else
+            {
+              ELEMENT *new = new_element (ET_def_aggregate);
+              int j;
+              for (j = 0; j < contents_nr; j++)
+                {
+                  add_to_element_contents (new,
+                                           remove_from_contents (current,
+                                                                 
contents_idx));
+                }
+              add_to_element_contents (current, new);
+              def_arg->element = new;
+            }
+        }
+      return result;
     }
-  result = malloc ((arg_types_nr+1) * sizeof (DEF_ARG *));
 
   for (i = 0; i < arg_types_nr; i++)
     {
-      char *arg_type_name = def_maps[i_def].arguments[i];
-      DEF_ARG *def_arg = malloc (sizeof (DEF_ARG));
-
-      result[i] = def_arg;
-      def_arg->arg_type = strdup(arg_type_name);
-      def_arg->element = next_bracketed_or_word_agg (current, &contents_idx);
-      if (def_arg->element)
-        add_extra_string_dup (def_arg->element, "def_role", arg_type_name);
+      if (result[i])
+        {
+          DEF_ARG *def_arg = result[i];
+          if (def_arg->element)
+            add_extra_string_dup (def_arg->element, "def_role", 
def_arg->arg_type);
+        }
+      else
+        break;
     }
-  result[i] = 0;
 
   /* Process args */
   split_delimiters (current, contents_idx);
diff --git a/tp/Texinfo/XS/parsetexi/element_types.c 
b/tp/Texinfo/XS/parsetexi/element_types.c
index b04de39add..dc1cfb4e32 100644
--- a/tp/Texinfo/XS/parsetexi/element_types.c
+++ b/tp/Texinfo/XS/parsetexi/element_types.c
@@ -68,5 +68,6 @@ char *element_type_names[] = {
 "untranslated",
 "macro_call",
 "rmacro_call",
+"linemacro_call",
 
 };
diff --git a/tp/Texinfo/XS/parsetexi/element_types.h 
b/tp/Texinfo/XS/parsetexi/element_types.h
index adb67235ef..7ff8d35e60 100644
--- a/tp/Texinfo/XS/parsetexi/element_types.h
+++ b/tp/Texinfo/XS/parsetexi/element_types.h
@@ -71,6 +71,7 @@ ET_spaces,
 ET_untranslated,
 ET_macro_call,
 ET_rmacro_call,
+ET_linemacro_call,
 };
 
 extern char *element_type_names[];
diff --git a/tp/Texinfo/XS/parsetexi/element_types.txt 
b/tp/Texinfo/XS/parsetexi/element_types.txt
index 84a6c912ad..d82fe6fe5a 100644
--- a/tp/Texinfo/XS/parsetexi/element_types.txt
+++ b/tp/Texinfo/XS/parsetexi/element_types.txt
@@ -99,4 +99,5 @@ untranslated
 # for macro expansion source marks
 macro_call
 rmacro_call
+linemacro_call
 
diff --git a/tp/Texinfo/XS/parsetexi/end_line.c 
b/tp/Texinfo/XS/parsetexi/end_line.c
index 68088201b4..8106a0b014 100644
--- a/tp/Texinfo/XS/parsetexi/end_line.c
+++ b/tp/Texinfo/XS/parsetexi/end_line.c
@@ -643,19 +643,165 @@ end_line_def_line (ELEMENT *current)
   ELEMENT *index_entry = 0; /* Index entry text. */
   ELEMENT *def_info_name = 0;
   ELEMENT *def_info_class = 0;
-  ELEMENT * def_info_category = 0;
+  ELEMENT *def_info_category = 0;
   int i = 0;
+  enum command_id top_cmd = current_context_command ();
+  enum context top_context = pop_context ();
 
-  if (pop_context () != ct_def)
-    fatal ("def context expected");
+  if (top_context != ct_def && top_context != ct_linecommand)
+    fatal ("def or linecommand context expected");
 
-  k = lookup_extra (current->parent, "def_command");
-  def_command = lookup_command ((char *) k->value);
+  if (top_context == ct_def)
+    {
+      k = lookup_extra (current->parent, "def_command");
+      def_command = lookup_command ((char *) k->value);
+    }
+  else
+    {
+      /* The following also works
+      k = lookup_extra (current->parent, "name");
+      def_command = lookup_command ((char *) k->value);
+      */
+      def_command = top_cmd;
+    }
 
   def_info = parse_def (def_command, current);
 
+  /* def_line or linemacro_call */
   current = current->parent;
 
+  if (top_context != ct_def)
+    {
+      /* convert arguments tree elements back to Texinfo text and substitute */
+      int args_number;
+      MACRO *macro_record = lookup_macro (def_command);
+      ELEMENT *macro;
+      ELEMENT *macro_args = 0;
+      ELEMENT *popped;
+      TEXT expanded;
+      SOURCE_MARK *macro_source_mark;
+      char *expanded_macro_text;
+
+      if (!macro_record)
+        fatal ("no linemacro record for expansion");
+
+      text_init (&expanded);
+
+      macro = macro_record->element;
+      args_number = macro->args.number - 1;
+
+      if (args_number > 0)
+        {
+          int def_info_index;
+          macro_args = new_element (ET_NONE);
+          for (def_info_index = 0; def_info_index < args_number; 
def_info_index++)
+            {
+              char *argument_text;
+              ELEMENT *macro_arg_text;
+              ELEMENT *macro_arg_element;
+
+              if (!def_info[def_info_index])
+                break;
+              /* convert the argument to a Texinfo string */
+              if (def_info[def_info_index]->element)
+                {
+                  ELEMENT *arg = def_info[def_info_index]->element;
+                  if (arg->type == ET_bracketed_arg)
+                    {
+                      /* we also duplicate leading and trailing spaces */
+                      KEY_PAIR *kspaces_before
+                        = lookup_info (arg, "spaces_before_argument");
+                      KEY_PAIR *kspaces_after
+                        = lookup_info (arg, "spaces_after_argument");
+
+                      if (arg->contents.number > 0
+                          || kspaces_before || kspaces_after)
+                        {
+                          ELEMENT *tmp_element = new_element (ET_NONE);
+                          tmp_element->contents = arg->contents;
+                          if (kspaces_before)
+                            {
+                              ELEMENT *spaces_element = new_element (ET_NONE);
+                              text_append (&spaces_element->text,
+                                           (char 
*)kspaces_before->value->text.text);
+                              add_info_element_oot (tmp_element,
+                                                    "spaces_before_argument",
+                                                    spaces_element);
+                            }
+                          if (kspaces_after)
+                            {
+                              ELEMENT *spaces_element = new_element (ET_NONE);
+                              text_append (&spaces_element->text,
+                                           (char 
*)kspaces_after->value->text.text);
+                              add_info_element_oot (tmp_element,
+                                                    "spaces_after_argument",
+                                                    spaces_element);
+                            }
+                          argument_text = convert_to_texinfo (tmp_element);
+                          tmp_element->contents.list = 0;
+                          destroy_element (tmp_element);
+                        }
+                      else
+                        argument_text = strdup("");
+                    }
+                  else
+                    {
+                      /* FIXME remove leading spaces but they should probably
+                         not be in the input */
+                      char *converted_string = convert_to_texinfo (arg);
+                      argument_text = strdup(converted_string
+                       + strspn (converted_string, 
whitespace_chars_except_newline));
+                      free (converted_string);
+                    }
+                }
+              else
+                argument_text = strdup("");
+
+              free (def_info[def_info_index]->arg_type);
+              free (def_info[def_info_index]);
+
+              /* setup an argument suitable for expand_macro_body and
+                 add it to macro_args */
+              macro_arg_text = new_element (ET_NONE);
+              text_append (&macro_arg_text->text, argument_text);
+              free (argument_text);
+              macro_arg_element = new_element (ET_NONE);
+              add_to_element_contents (macro_arg_element, macro_arg_text);
+              add_to_element_args (macro_args, macro_arg_element);
+            }
+        }
+      free (def_info);
+
+      expand_macro_body (macro_record, macro_args, &expanded);
+      debug ("LINEMACROBODY: %s||||||", expanded.text);
+
+      if (expanded.text)
+        expanded_macro_text = expanded.text;
+      else
+        /* we want to always have a text for the source mark */
+        expanded_macro_text = strdup ("");
+      input_push_text (expanded_macro_text, current_source_info.line_nr,
+                       command_name(def_command), 0);
+
+      macro_source_mark = new_source_mark (SM_type_linemacro_expansion);
+      macro_source_mark->status = SM_status_start;
+      /* at this point current is the linemacro_call container,
+         associate it to the source mark */
+      macro_source_mark->element = current;
+
+      current = current->parent;
+      /* remove the linemacro_call container from the main tree.
+         The container holds the arguments Texinfo elements tree */
+      popped = pop_element_from_contents (current);
+
+      register_source_mark (current, macro_source_mark);
+      set_input_source_mark (macro_source_mark);
+
+      destroy_element_and_children (macro_args);
+
+      return current;
+    }
+
   /* Record the index entry if def_info is not empty. */
 
   while (def_info[i] != 0 && def_info[i]->element != 0)
@@ -1170,21 +1316,23 @@ end_line_misc_line (ELEMENT *current)
   if (cmd == CM_item)
     data_cmd = CM_item_LINE;
 
-  if (!cmd)
+  if (!cmd && !current->parent->type == ET_linemacro_call)
     fatal ("command name unknown for line command end");
 
+  /* FIXME add a condition to avoid linecommands? */
   if (command_data(data_cmd).flags & CF_contain_basic_inline)
     (void) pop_command (&nesting_context.basic_inline_stack_on_line);
   isolate_last_space (current);
 
-  if (current->parent->type == ET_def_line)
+  if (current->parent->type == ET_def_line
+      || current->parent->type == ET_linemacro_call)
     return end_line_def_line (current);
 
   current = current->parent;
   misc_cmd = current;
 
   arg_spec = command_data(data_cmd).data;
-   
+
   debug ("MISC END %s", command_name(cmd));
 
   if (pop_context () != ct_line)
@@ -1828,7 +1976,8 @@ end_line (ELEMENT *current)
 
   /* 'line' or 'def' at top of "context stack" - this happens when
      line commands are nested (always incorrectly?) */
-  if (current_context () == ct_line || current_context () == ct_def)
+  if (current_context () == ct_line || current_context () == ct_def
+       || current_context () == ct_linecommand)
     {
       debug_nonl ("Still opened line command %d:", current_context ());
       debug_print_element (current, 1); debug("");
@@ -1840,6 +1989,14 @@ end_line (ELEMENT *current)
               current = close_current (current, 0, 0);
             }
         }
+      else if (current_context () == ct_linecommand)
+        {
+          while (current->parent
+                 && current->parent->type != ET_linemacro_call)
+            {
+              current = close_current (current, 0, 0);
+            }
+        }
       else
         {
           while (current->parent
diff --git a/tp/Texinfo/XS/parsetexi/handle_commands.c 
b/tp/Texinfo/XS/parsetexi/handle_commands.c
index eb4381dbf1..b9a07a026a 100644
--- a/tp/Texinfo/XS/parsetexi/handle_commands.c
+++ b/tp/Texinfo/XS/parsetexi/handle_commands.c
@@ -996,7 +996,7 @@ handle_block_command (ELEMENT *current, char **line_inout,
   ELEMENT *block = 0;
 
   /* New macro being defined. */
-  if (cmd == CM_macro || cmd == CM_rmacro)
+  if (cmd == CM_macro || cmd == CM_rmacro || cmd == CM_linemacro)
     {
       block = parse_macro_command_line (cmd, &line, current);
       add_to_element_contents (current, block);
diff --git a/tp/Texinfo/XS/parsetexi/macro.c b/tp/Texinfo/XS/parsetexi/macro.c
index 17067237d9..3cb30c2b8f 100644
--- a/tp/Texinfo/XS/parsetexi/macro.c
+++ b/tp/Texinfo/XS/parsetexi/macro.c
@@ -421,7 +421,7 @@ funexit:
 
 /* ARGUMENTS element holds the arguments used in the macro invocation.
    EXPANDED gets the result of the expansion. */
-static void
+void
 expand_macro_body (MACRO *macro_record, ELEMENT *arguments, TEXT *expanded)
 {
   int pos; /* Index into arguments. */
@@ -577,91 +577,97 @@ handle_macro (ELEMENT *current, char **line_inout, enum 
command_id cmd)
     arguments_container->type = ET_macro_call;
   else if (macro->cmd == CM_rmacro)
     arguments_container->type = ET_rmacro_call;
-  add_extra_string_dup (arguments_container, "name", command_name(cmd));
+  else if (macro->cmd == CM_linemacro)
+    arguments_container->type = ET_linemacro_call;
 
-  /* Get number of args. - 1 for the macro name. */
-  args_number = macro->args.number - 1;
+  add_extra_string_dup (arguments_container, "name", command_name(cmd));
 
-  p = line + strspn (line, whitespace_chars);
-  if (*p == '{')
-    {
-      p++;
-      line = p;
-      line += strspn (line, whitespace_chars);
-      if (line - p)
-        {
-          ELEMENT *spaces_element = new_element (ET_NONE);
-          text_append_n (&spaces_element->text, p, line - p);
-          add_info_element_oot (arguments_container, "spaces_before_argument",
-                                spaces_element);
-        }
-      expand_macro_arguments (macro, &line, cmd, arguments_container);
-    }
-  /* Warning depending on the number of arguments this macro
-     is supposed to take. */
-  else if (args_number != 1)
+  if (macro->cmd != CM_linemacro)
     {
-      if (args_number > 1)
-        line_warn ("@%s defined with zero or more than one argument should "
-                   "be invoked with {}", command_name(cmd));
-      /* As agreed on the bug-texinfo mailing list, no warn when zero
-         arg and not called with {}. */
-    }
-  else
-    {
-      ELEMENT *arg_elt = new_element (ET_line_arg);
-      add_to_element_args (arguments_container, arg_elt);
+      /* Get number of args. - 1 for the macro name. */
+      args_number = macro->args.number - 1;
 
-      while (1)
+      p = line + strspn (line, whitespace_chars);
+      if (*p == '{')
         {
-          if (*line == '\0')
+          p++;
+          line = p;
+          line += strspn (line, whitespace_chars);
+          if (line - p)
             {
-            /* If it takes a single line of input, and we don't have a
-               full line of input already, call new_line. */
-              line = new_line (arg_elt);
-              if (!line)
-                {
-                  line = "";
-                  break;
-                }
+              ELEMENT *spaces_element = new_element (ET_NONE);
+              text_append_n (&spaces_element->text, p, line - p);
+              add_info_element_oot (arguments_container, 
"spaces_before_argument",
+                                    spaces_element);
             }
-          else
+          expand_macro_arguments (macro, &line, cmd, arguments_container);
+        }
+      /* Warning depending on the number of arguments this macro
+         is supposed to take. */
+      else if (args_number != 1)
+        {
+          if (args_number > 1)
+            line_warn ("@%s defined with zero or more than one argument should 
"
+                       "be invoked with {}", command_name(cmd));
+          /* As agreed on the bug-texinfo mailing list, no warn when zero
+             arg and not called with {}. */
+        }
+      else
+        {
+          ELEMENT *arg_elt = new_element (ET_line_arg);
+          add_to_element_args (arguments_container, arg_elt);
+
+          while (1)
             {
-              int leading_spaces_added = 0;
-              if (arg_elt->contents.number == 0)
+              if (*line == '\0')
                 {
-                  int leading_spaces_nr = strspn (line,
-                                           whitespace_chars_except_newline);
-                  if (leading_spaces_nr)
+                /* If it takes a single line of input, and we don't have a
+                   full line of input already, call new_line. */
+                  line = new_line (arg_elt);
+                  if (!line)
                     {
-                      ELEMENT *internal_space
-                        = new_element (ET_internal_spaces_before_argument);
-                      text_append_n (&internal_space->text, line,
-                                     leading_spaces_nr);
-                      add_extra_element (internal_space,
-                                         "spaces_associated_command",
-                                         arguments_container);
-                      add_to_element_contents (arg_elt, internal_space);
-
-                      line += leading_spaces_nr;
-
-                      leading_spaces_added = 1;
+                      line = "";
+                      break;
                     }
                 }
-              if (! leading_spaces_added)
+              else
                 {
-                  char *p = strchr (line, '\n');
-                  if (!p)
+                  int leading_spaces_added = 0;
+                  if (arg_elt->contents.number == 0)
                     {
-                      arg_elt = merge_text (arg_elt, line, 0);
-                      line += strlen(line);
+                      int leading_spaces_nr = strspn (line,
+                                               
whitespace_chars_except_newline);
+                      if (leading_spaces_nr)
+                        {
+                          ELEMENT *internal_space
+                            = new_element (ET_internal_spaces_before_argument);
+                          text_append_n (&internal_space->text, line,
+                                         leading_spaces_nr);
+                          add_extra_element (internal_space,
+                                             "spaces_associated_command",
+                                             arguments_container);
+                          add_to_element_contents (arg_elt, internal_space);
+
+                          line += leading_spaces_nr;
+
+                          leading_spaces_added = 1;
+                        }
                     }
-                  else
+                  if (! leading_spaces_added)
                     {
-                      *p = '\0';
-                      arg_elt = merge_text (arg_elt, line, 0);
-                      line = "\n";
-                      break;
+                      char *p = strchr (line, '\n');
+                      if (!p)
+                        {
+                          arg_elt = merge_text (arg_elt, line, 0);
+                          line += strlen(line);
+                        }
+                      else
+                        {
+                          *p = '\0';
+                          arg_elt = merge_text (arg_elt, line, 0);
+                          line = "\n";
+                          break;
+                        }
                     }
                 }
             }
@@ -679,7 +685,7 @@ handle_macro (ELEMENT *current, char **line_inout, enum 
command_id cmd)
       goto funexit;
     }
 
-  if (macro->cmd == CM_macro)
+  if (macro->cmd != CM_rmacro)
     {
       if (expanding_macro (command_name(cmd)))
         {
@@ -690,6 +696,11 @@ handle_macro (ELEMENT *current, char **line_inout, enum 
command_id cmd)
         }
     }
 
+  macro_expansion_nr++;
+
+  if (macro->cmd == CM_linemacro)
+    goto funexit;
+
   expand_macro_body (macro_record, arguments_container, &expanded);
   debug ("MACROBODY: %s||||||", expanded.text);
 
@@ -701,8 +712,6 @@ handle_macro (ELEMENT *current, char **line_inout, enum 
command_id cmd)
   macro_source_mark->element = arguments_container;
   register_source_mark (current, macro_source_mark);
 
-  macro_expansion_nr++;
-
   /* Put expansion in front of the current line. */
   input_push_text (strdup (line), current_source_info.line_nr, 0, 0);
   /* not really important as line is ignored by the caller if there
diff --git a/tp/Texinfo/XS/parsetexi/macro.h b/tp/Texinfo/XS/parsetexi/macro.h
index 6f8603d5ce..f6c7311319 100644
--- a/tp/Texinfo/XS/parsetexi/macro.h
+++ b/tp/Texinfo/XS/parsetexi/macro.h
@@ -38,6 +38,8 @@ ELEMENT *handle_macro (ELEMENT *current, char **line_inout,
                        enum command_id cmd_id);
 void delete_macro (char *name);
 void unset_macro_record (MACRO *m);
+void expand_macro_body (MACRO *macro_record, ELEMENT *arguments,
+                        TEXT *expanded);
 MACRO *lookup_macro (enum command_id cmd);
 void wipe_macros (void);
 
diff --git a/tp/Texinfo/XS/parsetexi/parser.c b/tp/Texinfo/XS/parsetexi/parser.c
index 7429b37303..4199ed890d 100644
--- a/tp/Texinfo/XS/parsetexi/parser.c
+++ b/tp/Texinfo/XS/parsetexi/parser.c
@@ -1294,6 +1294,7 @@ int
 process_remaining_on_line (ELEMENT **current_inout, char **line_inout)
 {
   ELEMENT *current = *current_inout;
+  ELEMENT *macro_call_element = 0;
   char *line = *line_inout;
   char *line_after_command;
   int retval = STILL_MORE_TO_PROCESS;
@@ -1312,7 +1313,8 @@ process_remaining_on_line (ELEMENT **current_inout, char 
**line_inout)
       enum command_id cmd = 0;
       int closed_nested_raw = 0;
       /* Check if we are using a macro within a macro. */
-      if (current->cmd == CM_macro || current->cmd == CM_rmacro)
+      if (current->cmd == CM_macro || current->cmd == CM_rmacro
+          || current->cmd == CM_linemacro)
         {
           p += strspn (p, whitespace_chars);
           if (!strncmp (p, "@macro", strlen ("@macro")))
@@ -1325,6 +1327,11 @@ process_remaining_on_line (ELEMENT **current_inout, char 
**line_inout)
               p += strlen ("@rmacro");
               cmd = CM_rmacro;
             }
+          else if (!strncmp (p, "@linemacro", strlen ("@linemacro")))
+            {
+              p += strlen ("@linemacro");
+              cmd = CM_linemacro;
+            }
           if (*p && !strchr (whitespace_chars, *p))
             cmd = 0;
         }
@@ -1374,7 +1381,8 @@ process_remaining_on_line (ELEMENT **current_inout, char 
**line_inout)
                                  "beginning of a line", command_name(end_cmd));
                     }
                   /* For macros, define a new macro. */
-                  if (end_cmd == CM_macro || end_cmd == CM_rmacro)
+                  if (end_cmd == CM_macro || end_cmd == CM_rmacro
+                      || end_cmd == CM_linemacro)
                     {
                       char *name;
                       enum command_id existing;
@@ -1687,7 +1695,6 @@ process_remaining_on_line (ELEMENT **current_inout, char 
**line_inout)
   if (cmd && (command_data(cmd).flags & CF_MACRO))
     {
       static char *allocated_line;
-      ELEMENT *macro_call_element;
 
       line = line_after_command;
       macro_call_element = handle_macro (current, &line, cmd);
@@ -1696,7 +1703,14 @@ process_remaining_on_line (ELEMENT **current_inout, char 
**line_inout)
           if (from_alias != CM_NONE)
             add_info_string_dup (macro_call_element, "alias_of",
                                  command_name (from_alias));
-
+        }
+      if (macro_call_element && macro_call_element->type == ET_linemacro_call)
+       /* do nothing, the linemacro defined command call is done at the
+          end of the line after parsing the line similarly as for @def* */
+        {
+        }
+      else if (macro_call_element)
+        {
           /* directly get the following input (macro expansion text) instead
              of going through the next call of process_remaining_on_line and
              the processing of empty text.  No difference in output, more
@@ -1706,8 +1720,10 @@ process_remaining_on_line (ELEMENT **current_inout, char 
**line_inout)
           free (allocated_line);
           allocated_line = next_text (current);
           line = allocated_line;
+          goto funexit;
         }
-      goto funexit;
+      else
+        goto funexit;
     }
   /* expand value if it actually expands and changes the line.  It is
      considered again together with other commands below for all the other 
cases
@@ -1884,7 +1900,9 @@ process_remaining_on_line (ELEMENT **current_inout, char 
**line_inout)
                    line_warn ("command `@%s' must not be followed by new line",
                               command_name(current->cmd));
                    if (current_context() == ct_def
-                       || current_context() == ct_line)
+                       || current_context() == ct_line
+                     /* FIXME check that it is correct and add a test case */
+                       || current_context() == ct_linecommand)
                      {
                     /* do not consider the end of line to be possibly between
                        the @-command and the argument if at the end of a
@@ -2075,6 +2093,20 @@ process_remaining_on_line (ELEMENT **current_inout, char 
**line_inout)
               goto funexit;
             }
         }
+      else if (macro_call_element)
+        {
+          ELEMENT *line_arg = new_element (ET_line_arg);
+
+          add_to_element_contents (current, macro_call_element);
+          /* FIXME needed? Correct? */
+          macro_call_element->source_info = current_source_info;
+          push_context (ct_linecommand, cmd);
+          current = macro_call_element;
+          add_to_element_args (current, line_arg);
+          current = line_arg;
+          start_empty_line_after_command (current, &line, macro_call_element);
+          goto funexit;
+        }
 
       /* Warn on deprecated command */
       if (command_data(cmd).flags & CF_deprecated)
@@ -2094,6 +2126,16 @@ process_remaining_on_line (ELEMENT **current_inout, char 
**line_inout)
              gettext is implemented */
         }
 
+      /* special case with @ followed by a newline protecting end of lines
+         in linemacro invokations and @def* */
+      if (current_context () == ct_linecommand && cmd == CM_NEWLINE)
+        {
+          ELEMENT *command_e = new_element (ET_NONE);
+          command_e->cmd = cmd;
+          add_to_element_contents (current, command_e);
+          retval = GET_A_NEW_LINE;
+          goto funexit;
+        }
       def_line_continuation = (current_context() == ct_def
                                && cmd == CM_NEWLINE);
       /* warn on not appearing at line beginning.  Need to do before closing
@@ -2410,7 +2452,8 @@ parse_texi (ELEMENT *root_elt, ELEMENT *current_elt)
                  || (command_data(current->cmd).data == BLOCK_format_raw
                      && !format_expanded_p (command_name(current->cmd)))))
             || current->parent && current->parent->cmd == CM_verb)
-          && current_context () != ct_def)
+          && current_context () != ct_def
+          && current_context () != ct_linecommand)
         {
           ELEMENT *e;
           int n;
@@ -2453,7 +2496,7 @@ parse_texi (ELEMENT *root_elt, ELEMENT *current_elt)
             }
         }
     }
-finished_totally:
+ finished_totally:
 
   /* Check for unclosed conditionals */
   while (conditional_number > 0)
@@ -2521,10 +2564,5 @@ finished_totally:
   if (input_number > 0)
     fprintf (stderr, "BUG: at end, input_number > 0: %d", input_number);
 
-  /* to avoid a memory leak if @bye is given */
-  /*
-  input_reset_input_stack ();
-  */
-
   return current;
 }
diff --git a/tp/Texinfo/XS/parsetexi/separator.c 
b/tp/Texinfo/XS/parsetexi/separator.c
index 7fee7e5083..eeb18d4739 100644
--- a/tp/Texinfo/XS/parsetexi/separator.c
+++ b/tp/Texinfo/XS/parsetexi/separator.c
@@ -166,7 +166,8 @@ handle_open_brace (ELEMENT *current, char **line_inout)
       debug ("OPENED");
     }
   else if (current->parent && (current->parent->cmd == CM_multitable
-           || current->parent->type == ET_def_line))
+                               || current->parent->type == ET_def_line
+                               || current->parent->type == ET_linemacro_call))
     {
       ELEMENT *b, *e;
       abort_empty_line (&current, NULL);
@@ -195,7 +196,8 @@ handle_open_brace (ELEMENT *current, char **line_inout)
    */
   else if (current_context() == ct_math
            || current_context() == ct_rawpreformatted
-           || current_context() == ct_inlineraw)
+           || current_context() == ct_inlineraw
+           || current_context() == ct_linecommand)
     {
       ELEMENT *b = new_element (ET_balanced_braces);
       ELEMENT *open_brace = new_element (ET_NONE);
diff --git a/tp/Texinfo/XS/parsetexi/source_marks.c 
b/tp/Texinfo/XS/parsetexi/source_marks.c
index fe7b08b2d0..5a071101fb 100644
--- a/tp/Texinfo/XS/parsetexi/source_marks.c
+++ b/tp/Texinfo/XS/parsetexi/source_marks.c
@@ -26,6 +26,7 @@ int setfilename_counter = 0;
 int delcomment_counter = 0;
 int defline_continuation_counter = 0;
 int macro_expansion_counter = 0;
+int linemacro_expansion_counter = 0;
 int value_expansion_counter = 0;
 int ignored_conditional_block_counter = 0;
 int expanded_conditional_command_counter = 0;
@@ -137,6 +138,11 @@ register_source_mark (ELEMENT *e, SOURCE_MARK *source_mark)
           macro_expansion_counter++;
           source_mark->counter = macro_expansion_counter;
         }
+      else if (source_mark->type == SM_type_linemacro_expansion)
+        {
+          linemacro_expansion_counter++;
+          source_mark->counter = linemacro_expansion_counter;
+        }
       else if (source_mark->type == SM_type_value_expansion)
         {
           value_expansion_counter++;
@@ -165,6 +171,7 @@ source_marks_reset_counters (void)
   delcomment_counter = 0;
   defline_continuation_counter = 0;
   macro_expansion_counter = 0;
+  linemacro_expansion_counter = 0;
   value_expansion_counter = 0;
   ignored_conditional_block_counter = 0;
   expanded_conditional_command_counter = 0;
diff --git a/tp/Texinfo/XS/parsetexi/tree_types.h 
b/tp/Texinfo/XS/parsetexi/tree_types.h
index e4a742bcf5..9d5e81d005 100644
--- a/tp/Texinfo/XS/parsetexi/tree_types.h
+++ b/tp/Texinfo/XS/parsetexi/tree_types.h
@@ -41,6 +41,7 @@ enum source_mark_type { SM_type_none,
                         SM_type_delcomment,
                         SM_type_defline_continuation,
                         SM_type_macro_expansion,
+                        SM_type_linemacro_expansion,
                         SM_type_value_expansion,
                         SM_type_ignored_conditional_block,
                         SM_type_expanded_conditional_command



reply via email to

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