# New Ticket Created by  Steve Fink 
# Please include the string:  [perl #18856]
# in the subject line of all future correspondence about this issue. 
# <URL: http://rt.perl.org/rt2/Ticket/Display.html?id=18856 >


Here's a patch with a few minor fixes and one new feature. It requires
some discussion (or, more likely, a decision by Leo.) I did not
include the autogenerated files since I expect Leo will modify this
patch.

- The .local directive requires a type. I fixed the documentation.
- The lexer allows an optional dot in front of a parrot op or
  identifier, but then seems to assume that the dot is not there. So I
  took it off.
- A few trivial things: parenthesized a macro arg for safety, fixed a
  typo, added a missing va_end.
- Implemented one idea of namespaces.

The last item is the significant bit. There was an unimplemented
....namespace directive in IMCC that I needed for some regex stuff I'm
working on, but I couldn't tell what the exact intention was behind
it. So I implemented something that gave me what I needed. It may be
totally wrong from other people's perspectives, so let me first
describe what I need:

I want an inline regex like

  if (/a/) ...

to be exactly that: inline. So instead of making every regex into its
own sub, I want that to just immediately look for an 'a' in the
current topic.

In order to do this, and also have a self-contained regex compiler, I
need a separate namespace for all the variables I use. (Okay, so I
don't actually "need" any of this -- I could just use numbered
registers that IMCC would assign to actual registers for me, like $P42
and $I43. But 'rx_pos' looks much nicer to me than $I3112.)

One way to provide a separate namespace would be for me to prefix my
own mangled identifier, like "regex14_rx_pos". But I'd prefer
something like:

#      ...(preceding code)...
#      .namespace __regex14__
#        .local int rx_pos
#        ...(compiled regex code)...
#      .endnamespace __regex14__

so that I can just use 'rx_pos' within my (possibly nested) namespace.

So that's what this patch implements. A .local <type> <varname>
directive now creates a variable named <current-namespace>::<varname>
(or just <varname> at the top level), and any identifier to be looked
up is searched for in all enclosing namespaces. So 'set rx_pos, 0'
within the namespace 'outer' within the namespace 'inner' would look
for:

  1. outer::inner::rx_pos
  2. outer::rx_pos
  3. rx_pos

The implementation isn't beautiful, but I wasn't sure if people would
like these semantics anyway.


-- attachment  1 ------------------------------------------------------
url: http://rt.perl.org/rt2/attach/43866/34880/e45fc8/namespace.patch

Index: README
===================================================================
RCS file: /cvs/public/parrot/languages/imcc/README,v
retrieving revision 1.10
diff -u -r1.10 README
--- README      3 Dec 2002 14:35:29 -0000       1.10
+++ README      4 Dec 2002 04:21:38 -0000
@@ -90,8 +90,8 @@
   You may also define lexicals with the .local directive below
   and use them by name.
 
-   .local i
-   .local j
+   .local int i
+   .local int j
    i = 4
    j = i * i
 
@@ -125,7 +125,7 @@
 
    .end
 
-   .local <IDENTIFIER>
+   .local <type> <IDENTIFIER>
 
    .arg <lval>
 
Index: imcc.l
===================================================================
RCS file: /cvs/public/parrot/languages/imcc/imcc.l,v
retrieving revision 1.16
diff -u -r1.16 imcc.l
--- imcc.l      3 Dec 2002 14:35:29 -0000       1.16
+++ imcc.l      4 Dec 2002 04:21:38 -0000
@@ -92,6 +92,7 @@
 ".class"        return(CLASS);
 ".endclass"     return(ENDCLASS);
 ".namespace"    return(NAMESPACE);
+".endnamespace" return(ENDNAMESPACE);
 ".local"        return(LOCAL);
 ".param"        return(PARAM);
 "end"           return(END);
@@ -139,16 +140,17 @@
         return(MACRO);
     }
 <INITIAL>{DOT}?{LETTER}{LETTERDIGIT}* {
-       SymReg *r = get_sym(yytext);
+        char * ident = (yytext[0] == '.') ? yytext+1 : yytext;
+       SymReg *r = find_sym(ident);
        if (r && r->type & VTIDENTIFIER) {
            yylval.sr = r;
            return VAR;
        }
-        yylval.s = str_dup(yytext);
+        yylval.s = str_dup(ident);
         return(is_op(yylval.s) ? PARROT_OP : IDENTIFIER);
     }
 <emit,INITIAL>{LETTER}{LETTERDIGIT}* {
-       SymReg *r = get_sym(yytext);
+       SymReg *r = find_sym(yytext);
        if (r && r->type & VTIDENTIFIER) {
            yylval.sr = r;
            return VAR;
Index: imcc.y
===================================================================
RCS file: /cvs/public/parrot/languages/imcc/imcc.y,v
retrieving revision 1.29
diff -u -r1.29 imcc.y
--- imcc.y      3 Dec 2002 15:54:20 -0000       1.29
+++ imcc.y      4 Dec 2002 04:21:38 -0000
@@ -41,7 +41,7 @@
 static int nargs = 0;
 static SymReg *keys[IMCC_MAX_REGS];
 static int nkeys = 0;
-#define KEY_BIT(argnum) (1 << argnum)
+#define KEY_BIT(argnum) (1 << (argnum))
 
 static SymReg ** RR(int n, ...)
 {
@@ -52,6 +52,7 @@
     while (n--) {
        regs[i++] = va_arg(ap, SymReg *);
     }
+    va_end(ap);
     while (i < IMCC_MAX_REGS)
        regs[i++] = 0;
     return regs;
@@ -425,7 +426,7 @@
                 ins->type |= ITALIAS;
         }
         else if (!strcmp(name, "set_addr")) {
-            /* XXX propably a CATCH block */
+            /* XXX probably a CATCH block */
             ins->type = ITADDR | IF_r1_branch | ITBRANCH;
         }
     } else {
@@ -445,7 +446,8 @@
 }
 
 %token <t> CALL GOTO ARG PRINT IF UNLESS NEW END SAVEALL RESTOREALL
-%token <t> SUB NAMESPACE CLASS ENDCLASS SYM LOCAL PARAM INC DEC
+%token <t> SUB NAMESPACE ENDNAMESPACE CLASS ENDCLASS SYM LOCAL PARAM
+%token <t> INC DEC
 %token <t> SHIFT_LEFT SHIFT_RIGHT INTV FLOATV STRINGV DEFINED LOG_XOR
 %token <t> RELOP_EQ RELOP_NE RELOP_GT RELOP_GTE RELOP_LT RELOP_LTE
 %token <t> GLOBAL ADDR CLONE RESULT RETURN POW SHIFT_RIGHT_U LOG_AND LOG_OR
@@ -550,6 +552,8 @@
        assignment
     |   if_statement
     |   SYM type IDENTIFIER            { mk_ident($3, $2); }
+    |   NAMESPACE IDENTIFIER            { push_namespace($2); }
+    |   ENDNAMESPACE IDENTIFIER         { pop_namespace($2); }
     |   LOCAL type IDENTIFIER          { mk_ident($3, $2); }
     |   LOCAL type VAR                 { $$ = 0;
             warning("parser", "file %s line %d: %s already defined\n",
Index: symreg.c
===================================================================
RCS file: /cvs/public/parrot/languages/imcc/symreg.c,v
retrieving revision 1.6
diff -u -r1.6 symreg.c
--- symreg.c    25 Sep 2002 22:50:57 -0000      1.6
+++ symreg.c    4 Dec 2002 04:21:41 -0000
@@ -7,6 +7,59 @@
 /* Globals: */
 /* Code: */
 
+static void delete_sym(const char * name);
+
+/* namespaces */
+
+typedef struct ident_t Identifier;
+struct ident_t {
+    char * name;
+    Identifier * next;
+};
+
+typedef struct namespace_t Namespace;
+struct namespace_t {
+    Namespace * parent;
+    char * name;
+    Identifier * idents;
+};
+
+static Namespace * namespace = NULL;
+
+void push_namespace(char * name) {
+    Namespace * ns = (Namespace *) malloc(sizeof(*ns));
+    ns->parent = namespace;
+    ns->name = name;
+    ns->idents = NULL;
+    namespace = ns;
+}
+
+void pop_namespace(char * name) {
+    Namespace * ns = namespace;
+    if (ns == NULL) {
+        fprintf(stderr, "pop() on empty namespace stack\n");
+        abort();
+    }
+
+    if (name && strcmp(name, ns->name) != 0) {
+        fprintf(stderr, "tried to pop namespace(%s), "
+                "but top of stack is namespace(%s)\n", name, ns->name);
+        abort();
+    }
+
+    while (ns->idents) {
+        Identifier * ident = ns->idents;
+        delete_sym(ident->name);
+        ns->idents = ident->next;
+        free(ident);
+    }
+
+    namespace = ns->parent;
+    free(ns);
+}
+
+/* symbolic registers */
+
 /* Makes a new SymReg from its varname and type */
 SymReg * _mk_symreg(SymReg*hash[],char * name, char t) {
     SymReg * r;
@@ -45,10 +98,21 @@
             name, r->set, r->color, r->type);
     return r;
 }
+
+static char * _mk_fullname(Namespace * ns, const char * name) {
+    char * result;
+    if (ns == NULL) return strdup(name);
+    result = (char *) malloc(strlen(name) + strlen(ns->name) + 3);
+    sprintf(result, "%s::%s", ns->name, name);
+    return result;
+}
+
 /* Makes a new identifier */
 SymReg * mk_ident(char * name, char t) {
-    SymReg * r = mk_symreg(name, t);
+    char * fullname = _mk_fullname(namespace, name);
+    SymReg * r = mk_symreg(fullname, t);
     r->type = VTIDENTIFIER;
+    if (fullname != name) free(name);
     return r;
 }
 
@@ -229,15 +293,50 @@
     }
     return 0;
 }
-
 SymReg * get_sym(const char * name) {
     return _get_sym(hash, name);
 }
 
+SymReg * _find_sym(Namespace * namespace, SymReg * hash[], const char * name) {
+    Namespace * ns;
+    
+    for (ns = namespace; ns; ns = ns->parent) {
+        char * fullname = _mk_fullname(ns, name);
+        SymReg * p = _get_sym(hash, fullname);
+        free(fullname);
+        if (p) return p;
+    }
+
+    return _get_sym(hash, name);
+}
+SymReg * find_sym(const char * name) {
+    return _find_sym(namespace, hash, name);
+}
+
+static void _delete_sym(SymReg * hash[], const char * name) {
+    SymReg ** p;
+    int index = hash_str(name) % HASH_SIZE;
+    for(p = &hash[index]; *p; p = &(*p)->next) {
+        SymReg * deadmeat = *p;
+       if(!strcmp(name, deadmeat->name)) {
+            *p = deadmeat->next;
+            free_sym(deadmeat);
+            return;
+        }
+    }
+
+    fprintf(stderr, "Tried to delete nonexistent symbol '%s'\n", name);
+    abort();
+}
+static void delete_sym(const char * name) {
+    return _delete_sym(hash, name);
+}
+
 /* Deletes all symbols */
 void clear_tables() {
     int i;
     SymReg * p, *next;
+    while (namespace) pop_namespace(NULL);
     for(i = 0; i < HASH_SIZE; i++) {
        for(p = hash[i]; p; ) {
            next = p->next;
@@ -247,7 +346,6 @@
         hash[i] = NULL;
     }
 }
-
 
 /* utility functions: */
 
Index: symreg.h
===================================================================
RCS file: /cvs/public/parrot/languages/imcc/symreg.h,v
retrieving revision 1.6
diff -u -r1.6 symreg.h
--- symreg.h    25 Sep 2002 22:50:57 -0000      1.6
+++ symreg.h    4 Dec 2002 04:21:41 -0000
@@ -76,16 +76,20 @@
 
 void free_sym(SymReg *r);
 void store_symreg(SymReg * r);
+SymReg * find_sym(const char * name);
 SymReg * get_sym(const char * name);
 SymReg * _get_sym(SymReg * hash[], const char * name);
 SymReg * _mk_symreg(SymReg* hash[],char * name, char t);
 SymReg * _mk_const(SymReg *hash[], char * name, char t);
-SymReg * _mk_address(SymReg *hash[], char * name, int uniq);
 void _store_symreg(SymReg *hash[], SymReg * r);
+SymReg * _mk_address(SymReg *hash[], char * name, int uniq);
 SymReg * link_keys(int nargs, SymReg *keys[]);
 void clear_tables();
 unsigned int  hash_str(const char * str);
 void free_life_info(SymReg *r);
+
+void push_namespace(char * name);
+void pop_namespace(char * name);
 
 /* globals */
 

Reply via email to