shithub: mc

Download patch

ref: b05bd318302a3b5043a56479d20261d81bc27012
parent: d17587d89ed49739392eb6d768d583c7f5955d2c
author: Ori Bernstein <[email protected]>
date: Sun Jun 28 10:26:16 EDT 2015

Implement '__init__' functions.

--- a/6/asm.h
+++ b/6/asm.h
@@ -236,6 +236,7 @@
 extern int extracheck;
 extern Asmsyntax asmsyntax;
 
+void fillglobls(Stab *st, Htab *globls);
 void simpglobl(Node *dcl, Htab *globls, Func ***fn, size_t *nfn, Node ***blob, size_t *nblob);
 void selfunc(Isel *is, Func *fn, Htab *globls, Htab *strtab);
 void gen(Node *file, char *out);
--- a/6/gen.c
+++ b/6/gen.c
@@ -15,6 +15,29 @@
 #include "asm.h"
 #include "../config.h"
 
+void fillglobls(Stab *st, Htab *globls)
+{
+    void **k;
+    size_t i, nk;
+    Stab *stab;
+    Node *s;
+
+    k = htkeys(st->dcl, &nk);
+    for (i = 0; i < nk; i++) {
+        s = htget(st->dcl, k[i]);
+        htput(globls, s, asmname(s));
+    }
+    free(k);
+
+    k = htkeys(st->ns, &nk);
+    for (i = 0; i < nk; i++) {
+        stab = htget(st->ns, k[i]);
+        fillglobls(stab, globls);
+    }
+
+    free(k);
+}
+
 static int islocal(Node *dcl)
 {
     if (dcl->decl.vis != Visintern)
--- a/6/gengas.c
+++ b/6/gengas.c
@@ -40,28 +40,6 @@
 
 static void locprint(FILE *fd, Loc *l, char spec);
 
-static void fillglobls(Stab *st, Htab *globls)
-{
-    void **k;
-    size_t i, nk;
-    Stab *stab;
-    Node *s;
-
-    k = htkeys(st->dcl, &nk);
-    for (i = 0; i < nk; i++) {
-        s = htget(st->dcl, k[i]);
-        htput(globls, s, asmname(s));
-    }
-    free(k);
-
-    k = htkeys(st->ns, &nk);
-    for (i = 0; i < nk; i++) {
-        stab = htget(st->ns, k[i]);
-        fillglobls(stab, globls);
-    }
-    free(k);
-}
-
 static void initconsts(Htab *globls)
 {
     Type *ty;
--- a/6/genp9.c
+++ b/6/genp9.c
@@ -39,28 +39,6 @@
 
 static void locprint(FILE *fd, Loc *l, char spec);
 
-static void fillglobls(Stab *st, Htab *globls)
-{
-    void **k;
-    size_t i, nk;
-    Stab *stab;
-    Node *s;
-
-    k = htkeys(st->dcl, &nk);
-    for (i = 0; i < nk; i++) {
-        s = htget(st->dcl, k[i]);
-        htput(globls, s, asmname(s));
-    }
-    free(k);
-
-    k = htkeys(st->ns, &nk);
-    for (i = 0; i < nk; i++) {
-        stab = htget(st->ns, k[i]);
-        fillglobls(stab, globls);
-    }
-    free(k);
-}
-
 static void initconsts(Htab *globls)
 {
     Type *ty;
--- a/6/main.c
+++ b/6/main.c
@@ -117,6 +117,20 @@
     return buf;
 }
 
+static int hasmain(Node *file)
+{
+    Node *n, *name;
+
+    name = mknsname(Zloc, "", "main");
+    n = getdcl(file->file.globls, name);
+    if (!n)
+        return 0;
+    n = n->decl.name;
+    if (n->name.ns)
+        return 0;
+    return 1;
+}
+
 static void genuse(char *path)
 {
     FILE *f;
@@ -208,7 +222,9 @@
         if (debugopt['T'])
             dump(file, stdout);
         infer(file);
-        tagexports(file->file.globls, 0);
+        if (hasmain(file))
+            geninit(file);
+        tagexports(file, 0);
         /* after all type inference */
         if (debugopt['t'])
             dump(file, stdout);
--- a/libstd/alloc.myr
+++ b/libstd/alloc.myr
@@ -54,7 +54,6 @@
 const Align	= 16	/* minimum allocation alignment */
 
 var buckets	: bucket[32] /* excessive */
-var initdone	: bool
 
 type slheader = struct
 	cap	: size	/* capacity in bytes */
@@ -80,6 +79,14 @@
 	next	: chunk#	/* the next chunk in the free list */
 ;;
 
+const __init__ = {
+	var i
+
+	for i = 0; i < buckets.len && (Align << i) <= Bktmax; i++
+		bktinit(&buckets[i], Align << i)
+	;;
+}
+
 /* Allocates an object of type @a, returning a pointer to it. */
 generic alloc = {-> @a#
 	-> bytealloc(sizeof(@a)) castto(@a#)
@@ -209,14 +216,7 @@
 
 /* Allocates a blob that is 'sz' bytes long. Dies if the allocation fails */
 const bytealloc = {sz
-	var i, bkt, p
-
-	if !initdone
-		for i = 0; i < buckets.len && (Align << i) <= Bktmax; i++
-			bktinit(&buckets[i], Align << i)
-		;;
-		initdone = true
-	;;
+	var bkt, p
 
 	if (sz <= Bktmax)
 		bkt = &buckets[bktnum(sz)]
--- a/libstd/fmt.myr
+++ b/libstd/fmt.myr
@@ -47,6 +47,10 @@
 	$noret const fatalv	: (fmt : byte[:], ap : valist# -> void)
 ;;
 
+const __init__ = {
+	fmtmap = mkht(strhash, streq)
+}
+
 type fmtdesc = struct
 	fn	: (sb : strbuf#, ap : valist#, opts : (byte[:],byte[:])[:] -> void)
 	optdesc	: (byte[:], bool)[:]
@@ -67,14 +71,9 @@
 	exit(1)
 }
 
-var fmtmapinited : bool = false
 var fmtmap : htab(byte[:], fmtdesc)#
 
 const fmtinstall = {ty, fn, optdesc
-	if !fmtmapinited
-		fmtmapinited = true
-		fmtmap = mkht(strhash, streq)
-	;;
 	htput(fmtmap, ty, [.fn=fn, .optdesc=optdesc])
 }
 
@@ -149,10 +148,6 @@
 	orig = fmt
 	nparams = ap.tc.nelt
 	nfmt = 0
-	if !fmtmapinited
-		fmtmapinited = true
-		fmtmap = mkht(strhash, streq)
-	;;
 	while fmt.len != 0
 		(c, fmt) = striter(fmt)
 		match c
--- a/mbld/deps.myr
+++ b/mbld/deps.myr
@@ -234,7 +234,8 @@
 	| `std.None:	std.fatal("library {}: could not read usefile\n", lib)
 	;;
 	match bio.getbe32(f)
-	| `std.Some 1:	/* nothing: version matches. */
+	| `std.Some 2:	/* nothing: version matches. */
+	| `std.Some 1:	std.fput(1, "library {}: warning: old usefile version\n", lib)
 	| `std.Some 0:	std.fput(1, "library {}: warning: old usefile version\n", lib)
 	| `std.Some _:	std.fatal("library {}: usefile version unknown\n", lib)
 	| `std.None:	std.fatal("library {}: corrutpt or invalid usefile\n", lib)
--- a/mbld/main.myr
+++ b/mbld/main.myr
@@ -38,6 +38,7 @@
 		][:]
 	])
 
+	targname = ""
 	bld.initopts()
 	for opt in cmd.opts
 		match opt
--- a/muse/muse.c
+++ b/muse/muse.c
@@ -92,7 +92,7 @@
     for (i = 0; i < ctx.nargs; i++)
         mergeuse(ctx.args[i]);
     infer(file);
-    tagexports(file->file.globls, 1);
+    tagexports(file, 1);
     f = fopen(outfile, "w");
     if (debugopt['s'] || show)
         dumpstab(file->file.globls, stdout);
--- a/parse/gram.y
+++ b/parse/gram.y
@@ -26,6 +26,7 @@
 static void installucons(Stab *st, Type *t);
 static void addtrait(Type *t, char *str);
 static void setattrs(Node *dcl, char **attrs, size_t nattrs);
+static void setupinit(Node *n);
 
 %}
 
@@ -219,11 +220,15 @@
                 Node *n;
 
                 for (i = 0; i < $1.nn; i++) {
+                    if (!strcmp(declname($1.nl[i]), "__init__"))
+                        setupinit($1.nl[i]);
                     /* putdcl can merge, so we need to getdcl after */
                     putdcl(file->file.globls, $1.nl[i]);
                     n = getdcl(file->file.globls, $1.nl[i]->decl.name);
                     lappend(&file->file.stmts, &file->file.nstmts, n);
                     $1.nl[i]->decl.isglobl = 1;
+                    if ($1.nl[i]->decl.isinit)
+                        file->file.localinit = $1.nl[i];
                 }
             }
         | /* empty */
@@ -915,6 +920,23 @@
         ;
 
 %%
+
+static void setupinit(Node *n)
+{
+    char name[1024];
+    char *p;
+
+    snprintf(name, sizeof name, "%s$__init__", file->file.files[0]);
+    p = name;
+    while (*p) {
+        if (!isalnum(*p) && *p != '_')
+            *p = '$';
+        p++;
+    }
+    n->decl.isinit = 1;
+    n->decl.vis = Vishidden;
+    n->decl.name->name.name = strdup(name);
+}
 
 static void addtrait(Type *t, char *str)
 {
--- a/parse/infer.c
+++ b/parse/infer.c
@@ -2217,14 +2217,16 @@
     }
 }
 
-void tagexports(Stab *st, int hidelocal)
+void tagexports(Node *file, int hidelocal)
 {
+    size_t i, j, n;
+    Trait *tr;
+    Stab *st;
     void **k;
     Node *s;
     Type *t;
-    Trait *tr;
-    size_t i, j, n;
 
+    st = file->file.globls;
     k = htkeys(st->dcl, &n);
     for (i = 0; i < n; i++) {
         s = getdcl(st, k[i]);
@@ -2240,6 +2242,11 @@
             nodetag(st, s, 0, hidelocal);
     }
     free(k);
+
+    for (i = 0; i < file->file.ninit; i++)
+        nodetag(st, file->file.init[i], 0, hidelocal);
+    if (file->file.localinit)
+        nodetag(st, file->file.localinit, 0, hidelocal);
 
     k = htkeys(st->tr, &n);
     for (i = 0; i < n; i++) {
--- a/parse/parse.h
+++ b/parse/parse.h
@@ -4,7 +4,7 @@
 #	define FATAL
 #endif
 
-#define Abiversion 1
+#define Abiversion 2
 
 typedef uint8_t         byte;
 typedef unsigned int    uint;
@@ -219,8 +219,10 @@
             size_t nlibdeps;
             Node **stmts;       /* all top level statements */
             size_t nstmts;
+            Node **init;        /* a list of all __init__ function names of our deps. NB, this is a Nname, not an Ndecl */
+            size_t ninit;
+            Node *localinit;    /* and the local one, if any */
             Stab  *globls;      /* global symtab */
-            int hasinit;        /* did we declare __init__? */
         } file;
 
         struct {
@@ -306,16 +308,19 @@
              impl.
             */
             Trait *trait;
-            char  vis;
-            char  isglobl;
-            char  isconst;
-            char  isgeneric;
-            char  isextern;
-            char  ispkglocal;
-            char  ishidden;
-            char  isimport;
-            char  isnoret;
-            char  isexportinit;
+            char vis;
+
+            /* flags */
+            char isglobl;
+            char isconst;
+            char isgeneric;
+            char isextern;
+            char ispkglocal;
+            char ishidden;
+            char isimport;
+            char isnoret;
+            char isexportinit;
+            char isinit;
         } decl;
 
         struct {
@@ -473,6 +478,7 @@
 void putimpl(Stab *st, Node *impl);
 void updatetype(Stab *st, Node *n, Type *t);
 void putdcl(Stab *st, Node *dcl);
+void putnsdcl(Node *dcl);
 void forcedcl(Stab *st, Node *dcl);
 void putucon(Stab *st, Ucon *uc);
 
@@ -577,12 +583,13 @@
 Node *specializedcl(Node *n, Type *to, Node **name);
 Type *tyspecialize(Type *t, Htab *tymap, Htab *delayed);
 Node *genericname(Node *n, Type *t);
+void geninit(Node *file);
 
 /* usefiles */
 int  loaduse(char *path, FILE *f, Stab *into, Vis vis);
 void readuse(Node *use, Stab *into, Vis vis);
 void writeuse(FILE *fd, Node *file);
-void tagexports(Stab *st, int hidelocal);
+void tagexports(Node *file, int hidelocal);
 
 /* typechecking/inference */
 void infer(Node *file);
--- a/parse/specialize.c
+++ b/parse/specialize.c
@@ -430,3 +430,71 @@
         popstab();
     return d;
 }
+
+/*
+ * Not really specialization, but close enough.
+ *
+ * Generate an init function that's the equivalent of
+ * this code:
+ *
+ * const __init__ {
+ *      file1$myr$__init__
+ *      file2$myr$__init__
+ *      ...
+ * }
+ */
+static Node *initdecl(Node *file, Node *name, Type *tyvoidfn)
+{
+    Node *dcl;
+
+    dcl = getdcl(file->file.globls, name);
+    if (!dcl) {
+        dcl = mkdecl(Zloc, name, tyvoidfn);
+        dcl->decl.isconst = 1;
+        dcl->decl.isinit = 1;
+        putnsdcl(dcl);
+    }
+    return dcl;
+}
+
+static void callinit(Node *block, Node *init, Type *tyvoid, Type *tyvoidfn)
+{
+    Node *call, *var;
+
+    var = mkexpr(Zloc, Ovar, init->decl.name, NULL);
+    call = mkexpr(Zloc, Ocall, var, NULL);
+
+    var->expr.type = tyvoidfn;
+    call->expr.type = tyvoid;
+    var->expr.did = init->decl.did;
+    var->expr.isconst = 1;
+    lappend(&block->block.stmts, &block->block.nstmts, call);
+}
+
+void geninit(Node *file)
+{
+    Node *name, *decl, *func, *block, *init;
+    Type *tyvoid, *tyvoidfn;
+    size_t i;
+
+    name = mkname(Zloc, "__init__");
+    decl = mkdecl(Zloc, name, mktyvar(Zloc));
+    block = mkblock(Zloc, mkstab());
+    block->block.scope->super = file->file.globls;
+    tyvoid = mktype(Zloc, Tyvoid);
+    tyvoidfn = mktyfunc(Zloc, NULL, 0, tyvoid);
+
+    for (i = 0; i < file->file.ninit; i++) {
+        init = initdecl(file, file->file.init[i], tyvoidfn);
+        callinit(block, init, tyvoid, tyvoidfn);
+    }
+    if (file->file.localinit)
+        callinit(block, file->file.localinit, tyvoid, tyvoidfn);
+    func = mkfunc(Zloc, NULL, 0, mktype(Zloc, Tyvoid), block);
+    func->expr.type = tyvoidfn;
+    decl->decl.init = mkexpr(Zloc, Olit, func, NULL);
+    decl->decl.isconst = 1;
+    decl->decl.type = tyvoidfn;
+
+    lappend(&file->file.stmts, &file->file.nstmts, decl);
+}
--- a/parse/stab.c
+++ b/parse/stab.c
@@ -253,6 +253,13 @@
     return 1;
 }
 
+void forcedcl (Stab *st, Node *s) {
+    if (st->name)
+        setns(s->decl.name, st->name);
+    htput(st->dcl, s->decl.name, s);
+    assert(htget(st->dcl, s->decl.name) != NULL);
+}
+
 void putdcl(Stab *st, Node *s)
 {
     Node *old;
@@ -264,11 +271,19 @@
         fatal(old, "%s already declared on %s:%d", namestr(s->decl.name), fname(s->loc), lnum(s->loc));
 }
 
-void forcedcl (Stab *st, Node *s) {
-    if (st->name)
-        setns(s->decl.name, st->name);
-    htput(st->dcl, s->decl.name, s);
-    assert(htget(st->dcl, s->decl.name) != NULL);
+void putnsdcl(Node *dcl)
+{
+    Node *name;
+    Stab *ns;
+
+    name = dcl->decl.name;
+    ns = getns_str(file->file.globls, name->name.ns);
+    if (!ns) {
+        ns = mkstab();
+        updatens(ns, name->name.ns);
+        putns(file->file.globls, ns);
+    }
+    putdcl(ns, dcl);
 }
 
 void updatetype(Stab *st, Node *n, Type *t)
--- a/parse/use.c
+++ b/parse/use.c
@@ -25,6 +25,7 @@
 static Htab *tydedup;   /* map from name -> type, contains all Tynames loaded ever */
 static Htab *tidmap;    /* map from tid -> type */
 static Htab *trmap;     /* map from trait id -> trait */
+static Htab *initmap;   /* map from init name -> int */
 
 #define Builtinmask (1 << 30)
 static Type ***typefixdest;     /* list of types we need to replace */
@@ -161,6 +162,7 @@
     wrbool(fd, val->decl.ispkglocal);
     wrbool(fd, val->decl.isnoret);
     wrbool(fd, val->decl.isexportinit);
+    wrbool(fd, val->decl.isinit);
     if (val->decl.isexportinit) {
         pickle(fd, val->decl.init);
     }
@@ -189,6 +191,7 @@
     n->decl.isnoret = rdbool(fd);
     n->decl.isimport = 1;
     n->decl.isexportinit = rdbool(fd);
+    n->decl.isinit = rdbool(fd);
     if (n->decl.isexportinit)
         n->decl.init = unpickle(fd);
     return n;
@@ -818,7 +821,7 @@
     intptr_t tid;
     size_t i;
     char *pkg;
-    Node *dcl, *impl;
+    Node *dcl, *impl, *init;
     Stab *s;
     Type *ty;
     Trait *tr;
@@ -859,6 +862,8 @@
     }
     tidmap = mkht(ptrhash, ptreq);
     trmap = mkht(ptrhash, ptreq);
+    if (!initmap)
+        initmap = mkht(namehash, nameeq);
     /* builtin traits */
     for (i = 0; i < Ntraits; i++)
         htput(trmap, itop(i), traittab[i]);
@@ -882,6 +887,13 @@
                 dcl->decl.vis = vis;
                 putdcl(s, dcl);
                 break;
+            case 'S':
+                init = unpickle(f);
+                if (!hthas(initmap, init)) {
+                    htput(initmap, init, init);
+                    lappend(&file->file.init, &file->file.ninit, init);
+                }
+                break;
             case 'R':
                 tr = traitunpickle(f);
                 tr->vis = vis;
@@ -1038,13 +1050,21 @@
         if (s->decl.vis == Visintern || s->decl.vis == Visbuiltin)
             continue;
         /* trait functions get written out with their traits */
-        if (s->decl.trait)
+        if (s->decl.trait || s->decl.isinit)
             continue;
-        if (s->decl.isgeneric)
+        else if (s->decl.isgeneric)
             wrbyte(f, 'G');
         else
             wrbyte(f, 'D');
         wrsym(f, s);
+    }
+    for (i = 0; i < file->file.ninit; i++) {
+        wrbyte(f, 'S');
+        pickle(f, file->file.init[i]);
+    }
+    if (file->file.localinit) {
+        wrbyte(f, 'S');
+        pickle(f, file->file.localinit->decl.name);
     }
     free(k);
 }
--- a/rt/_myrrt-plan9.s
+++ b/rt/_myrrt-plan9.s
@@ -57,6 +57,7 @@
 	PUSHQ	R13
 	PUSHQ	DX
 
+	CALL	__init__(SB)
 	CALL	main(SB)
 	POPQ	DX
 	POPQ	R13
--- a/rt/start-linux.s
+++ b/rt/start-linux.s
@@ -67,6 +67,8 @@
 	pushq %rdx
 
 	/* enter the main program */
+	call	__init__
+	/* enter the main program */
 	call	main
 	/* exit(0) */
         xorq	%rdi,%rdi
--- a/support/vim/indent/myr.vim
+++ b/support/vim/indent/myr.vim
@@ -66,9 +66,9 @@
                 \    '\<while\>','\<for\>', '\<match\>',
                 \    '\<struct\>', '\<union\>',
                 \    '{', '\[', '(', '^\s*|.*:', '=\s*$']
-        let outpat = ['}', ']', ')', ';;']
+        let outpat = ['}', ']', ')']
         let outalone = ['\<else\>', '\<elif\>.*', ';;', '|.*',
-                    \ '].*', ').*', '}.*']
+                    \ '].*', '}.*']
         let width = &tabstop
 
         let n_in = s:CountMatches(prevln, ln - i, inpat)
@@ -84,9 +84,10 @@
             let n_out = n_out + 1
         endif
 
-        " we already outdented if we had an outalone
-        if s:LineMatch(prevln, outalone) != 0
-            let n_out = 0
+        " we already outdented if we had an outalone, but since all
+        " outpats are also outalones, we don't want to double count.
+        if s:LineMatch(prevln, outalone) != 0 && n_out > 0
+            let n_out = n_out - 1
         endif
         let n_out = n_out + s:LineMatch(curln, outalone)