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)