bug-gawk
[Top][All Lists]
Advanced

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

Re: Inconsistency in Namespace Internal Name Management, Ver 5.1.1


From: arnold
Subject: Re: Inconsistency in Namespace Internal Name Management, Ver 5.1.1
Date: Wed, 05 Jan 2022 12:12:29 -0700
User-agent: Heirloom mailx 12.5 7/5/10

Hi.

Thanks for the report.

J Naman <jnaman2@gmail.com> wrote:

> Ref: 15.6 Internal Name Management (in Namespaces)
> "For backwards compatibility, all identifiers in the awk namespace are
> stored internally as
> unadorned identifiers (that is, without a leading ‘awk::’). This is mainly
> relevant when
> using such identifiers as indices for SYMTAB, FUNCTAB, and
> PROCINFO["identifiers"]"
>
> The above is True for user-defined functions (UDFs)
> defined with a namespace qualified name, i.e. ns::foo()
> @namespace "ns"
> ns::foo is YES in FUNCTAB
> ns::foo is YES in PROCINFO["identifiers"];
>
> *NOT True* for UDFs defined with awk namespace qualified name, i.e.
> awk::foo()

Thanks for this report and for the test case sent privately.
Below is the fix.  Your test case uncovered a nasty bug that was
due to how LALR(1) parsing works, no less!

I will be pushing to Git shortly.

Thanks,

Arnold
--------------------------
diff --git a/awkgram.y b/awkgram.y
index 0729d353..07de872f 100644
--- a/awkgram.y
+++ b/awkgram.y
@@ -57,6 +57,7 @@ static void dumpintlstr2(const char *str1, size_t len1, const 
char *str2, size_t
 static bool include_source(INSTRUCTION *file, void **srcfile_p);
 static bool load_library(INSTRUCTION *file, void **srcfile_p);
 static void set_namespace(INSTRUCTION *ns, INSTRUCTION *comment);
+static void change_namespace(const char *new_namespace);
 static void next_sourcefile(void);
 static char *tokexpand(void);
 static NODE *set_profile_text(NODE *n, const char *str, size_t len);
@@ -112,6 +113,7 @@ static void add_sign_to_num(NODE *n, char sign);
 
 static bool at_seen = false;
 static bool want_source = false;
+static bool want_namespace = false;
 static bool want_regexp = false;       /* lexical scanning kludge */
 static enum {
        FUNC_HEADER,
@@ -317,7 +319,20 @@ rule
          }
        | '@' LEX_NAMESPACE namespace statement_term
          {
+               /*
+                * 1/2022:
+                * We have an interesting isssue here.  This production isn't
+                * reduced until after the token following the statement_term
+                * is seen. As a result, the change in namespace doesn't take
+                * effect until then. That's fine if the first token is 
'function'
+                * or BEGIN or some such, but it's a disaster if it's an 
identifer;
+                * that identifier will be in the previous namespace.
+                * Therefore, the actual setting of the namespace is done 
immediately
+                * down in the scanner.
+                */
+
                want_source = false;
+               want_namespace = false;
                at_seen = false;
 
                // this frees $3 storage in all cases
@@ -4078,6 +4093,8 @@ retry:
                yylval = GET_INSTRUCTION(Op_token);
                if (want_source) {
                        yylval->lextok = estrdup(tokstart, tok - tokstart);
+                       if (want_namespace)
+                               change_namespace(yylval->lextok);
                        return lasttok = FILENAME;
                }
 
@@ -4418,6 +4435,8 @@ retry:
 
                switch (class) {
                case LEX_NAMESPACE:
+                       want_namespace = true;
+                       // fall through
                case LEX_INCLUDE:
                case LEX_LOAD:
                        want_source = true;
@@ -6818,7 +6837,7 @@ done:
        return i;
 }
 
-/* set_namespace --- change the current namespace */
+/* set_namespace --- update namespace data structures */
 
 static void
 set_namespace(INSTRUCTION *ns, INSTRUCTION *comment)
@@ -6849,13 +6868,9 @@ set_namespace(INSTRUCTION *ns, INSTRUCTION *comment)
                return;
        }
 
-       if (strcmp(ns->lextok, current_namespace) == 0)
-               ;       // nothing to do
-       else if (strcmp(ns->lextok, awk_namespace) == 0) {
-               set_current_namespace(awk_namespace);
-       } else {
-               set_current_namespace(estrdup(ns->lextok, strlen(ns->lextok)));
-       }
+       // Actual changing of namespace is done earlier.
+       // See comments in the production and in yylex().
+
        efree(ns->lextok);
 
        // save info and push on front of list of namespaces seen
@@ -6868,11 +6883,35 @@ set_namespace(INSTRUCTION *ns, INSTRUCTION *comment)
        ns->lextok = NULL;
        bcfree(ns);
 
-       namespace_changed = true;
-
        return;
 }
 
+/* change_namespace --- change the current namespace */
+
+static void
+change_namespace(const char *new_namespace)
+{
+       /* error messages will come from set_namespace(), above */
+
+       if (! is_valid_identifier(new_namespace))
+               return;
+
+       int mid = check_special(new_namespace);
+
+       if (mid >= 0)
+               return;
+
+       if (strcmp(new_namespace, current_namespace) == 0)
+               ;       // nothing to do
+       else if (strcmp(new_namespace, awk_namespace) == 0) {
+               set_current_namespace(awk_namespace);
+       } else {
+               set_current_namespace(estrdup(new_namespace, 
strlen(new_namespace)));
+       }
+
+       namespace_changed = true;
+}
+
 /* qualify_name --- put name into namespace */
 
 static char *
diff --git a/symbol.c b/symbol.c
index be01369c..300fa871 100644
--- a/symbol.c
+++ b/symbol.c
@@ -604,7 +604,10 @@ load_symbols()
                            || r->type == Node_var
                            || r->type == Node_var_array
                            || r->type == Node_var_new) {
-                               tmp = make_string(r->vname, strlen(r->vname));
+                               if (strncmp(r->vname, "awk::", 5) == 0)
+                                       tmp = make_string(r->vname + 5, 
strlen(r->vname) - 5);
+                               else
+                                       tmp = make_string(r->vname, 
strlen(r->vname));
                                aptr = assoc_lookup(sym_array, tmp);
                                unref(tmp);
                                unref(*aptr);



reply via email to

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