# 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 */