Ori BernsteinRename traits correctly.6c7c8507 years agoHistory
753 lines · 13.7 KB · C
RawDownload
#include <stdlib.h>#include <stdio.h>#include <inttypes.h>#include <stdarg.h>#include <ctype.h>#include <string.h>#include <assert.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h> #include "util.h"#include "parse.h" /* Allows us to look up types/traits by name nodes */typedef struct Tydefn Tydefn;typedef struct Traitdefn Traitdefn;struct Tydefn {	Srcloc loc;	Node *name;	Type *type;}; struct Traitdefn {	Srcloc loc;	Node *name;	Trait *trait;}; #define Maxstabdepth 128static Stab *stabstk[Maxstabdepth];static size_t stabstkoff; static Tyenv *envstk[Maxstabdepth];static size_t envstkoff;  /* name hashing: we want namespaced lookups to find the * name even if we haven't set the namespace up, since * we can update it after the fact. */ulongnsnamehash(void *n){	return strhash(namestr(n));} intnsnameeq(void *a, void *b){	return a == b || !strcmp(namestr(a), namestr(b));} static ulongimplhash(void *p){	Node *n;	ulong h; 	n = p;	h = nsnamehash(n->impl.traitname);	h *= tyhash(n->impl.type);	return h;} static intimpleq(void *pa, void *pb){	Node *a, *b; 	a = pa;	b = pb;	if (nsnameeq(a->impl.traitname, b->impl.traitname))		return tyeq(a->impl.type, b->impl.type);	return 0;} Stab *mkstab(int isfunc){	Stab *st; 	st = zalloc(sizeof(Stab));	st->dcl = mkht(nsnamehash, nsnameeq);	st->ty = mkht(nsnamehash, nsnameeq);	st->tr = mkht(nsnamehash, nsnameeq);	st->uc = mkht(nsnamehash, nsnameeq);	if (isfunc) {		st->env = mkht(nsnamehash, nsnameeq);		st->lbl = mkht(strhash, streq);	}	st->impl = mkht(implhash, impleq);	st->isfunc = isfunc;	return st;} Stab *curstab(){	assert(stabstkoff > 0);	return stabstk[stabstkoff - 1];} voidpushstab(Stab *st){	assert(stabstkoff < Maxstabdepth);	stabstk[stabstkoff++] = st;} voidpopstab(){	assert(stabstkoff > 0);	stabstkoff--;} ulongparamhash(void *p){	return strhash(((Type*)p)->pname);} intparameq(void *a, void *b){	return streq(((Type*)a)->pname, ((Type*)b)->pname);} Tyenv*mkenv(){	Tyenv *e; 	e = malloc(sizeof(Tyenv));	e->super = NULL;	e->tab = mkht(paramhash, parameq);	return e;} Tyenv*curenv(){	if (!envstkoff)		return NULL;	else		return envstk[envstkoff - 1];} voidpushenv(Tyenv *env){	if (!env)		return;	assert(envstkoff < Maxstabdepth);	envstk[envstkoff++] = env;} voidpopenv(Tyenv *env){	if (!env)		return;	assert(envstkoff > 0);	envstkoff--;} Stab *findstab(Stab *st, Node *n){	Stab *ns; 	if (n->name.ns) {		ns = getns(n->name.ns);		if (!ns) {			ns = mkstab(0);			updatens(ns, n->name.ns);		}		st = ns;	}	return st;} Node *getclosed(Stab *st, Node *n){	while (st && !st->env)		st = st->super;	if (st)		return htget(st->env, n);	return NULL;} Node **getclosure(Stab *st, size_t *n){	size_t nkeys, i;	void **keys;	Node **vals; 	while (st && !st->env)		st = st->super; 	if (!st) {		*n = 0;		return NULL;	} 	vals = NULL;	*n = 0;	keys = htkeys(st->env, &nkeys);	for (i = 0; i < nkeys; i++)		lappend(&vals, n, htget(st->env, keys[i]));	free(keys);	return vals;} static voidenvclose(Stab *start, Stab *found, Stab *fn, Node *s){	Stab *st; 	for (st = start; st != found; st = st->super)		if (st->env && !s->decl.isglobl && !s->decl.isgeneric)			htput(st->env, s->decl.name, s);} /* * Searches for declarations from current * scope, and all enclosing scopes. Doe * not resolve namespaces -- that is the job * of the caller of this function. * * If a resoved name is not global, and i * not in the current scope, it is recorded * in the scope's closure. */Node *getdcl(Stab *start, Node *n){	Stab *st, *fn;	Node *s; 	fn = NULL;	st = start;	do {		s = htget(st->dcl, n);		if (s) {			envclose(start, st, fn, s);			return s;		}		if (!fn && st->env)			fn = st;		st = st->super;	} while (st);	return NULL;} voidputlbl(Stab *st, char *name, Node *lbl){	assert(st && st->isfunc);	if (hthas(st->lbl, name))		fatal(lbl, "duplicate label %s, first defined on line %d\n", name, lbl->loc.line);	htput(st->lbl, name, lbl);} Node *getlbl(Stab *st, Srcloc loc, char *name){	while (st && !st->isfunc)		st = st->super;	if (!st || !hthas(st->lbl, name))		return NULL;	return htget(st->lbl, name);} Type *gettype_l(Stab *st, Node *n){	Tydefn *t; 	if ((t = htget(st->ty, n)))		return t->type;	return NULL;} Type *gettype(Stab *st, Node *n){	Tydefn *t; 	do {		if ((t = htget(st->ty, n)))			return t->type;		st = st->super;	} while (st);	return NULL;} inthastype(Stab *st, Node *n){	do {		if (hthas(st->ty, n))			return 1;		st = st->super;	} while (st);	return 0;} Ucon *getucon(Stab *st, Node *n){	Ucon *uc; 	do {		if ((uc = htget(st->uc, n)))			return uc;		st = st->super;	} while (st);	return NULL;} Trait *gettrait(Stab *st, Node *n){	Traitdefn *c; 	if (n->name.ns)		st = getns(n->name.ns);	do {		if ((c = htget(st->tr, n)))			return c->trait;		st = st->super;	} while (st);	return NULL;} Stab *getns(char *name) {	return htget(file.ns, name);} static intmergedecl(Node *old, Node *new){	Node *e, *g; 	if (old->decl.isimport && new->decl.isimport) {		old->decl.ishidden = old->decl.ishidden && new->decl.ishidden;		return 1;	}	if (old->decl.isextern || new->decl.isextern) {		old->decl.isextern = old->decl.isextern && new->decl.isextern;		return 1;	}	if (old->decl.vis == Visexport && new->decl.vis != Visexport) {		e = old;		g = new;	} else if (new->decl.vis == Visexport && old->decl.vis != Visexport) {		e = new;		g = old;	} else {		return 0;	}	old->decl.vis = Visexport; 	if (e->decl.init && g->decl.init)		fatal(e, "export %s double initialized on %s:%d", declname(e), fname(g->loc),				lnum(g->loc));	if (e->decl.isgeneric != g->decl.isgeneric)		fatal(e, "export %s declared with different genericness on %s:%d", declname(e),				fname(g->loc), lnum(g->loc));	if (e->decl.isconst != g->decl.isconst)		fatal(e, "export %s declared with different constness on %s:%d", declname(e),				fname(g->loc), lnum(g->loc));	if (e->decl.isextern != g->decl.isextern)		fatal(e, "export %s declared with different externness on %s:%d", declname(e),				fname(g->loc), lnum(g->loc)); 	setns(old->decl.name, new->decl.name->name.ns);	if (e->decl.type->type == Tyvar)		e->decl.type = g->decl.type;	else if (g->decl.type->type == Tyvar)		g->decl.type = e->decl.type;	else		fatal(e, "FIXME: types on both prototype and decl not yet allowed\n"); 	if (!e->decl.init)		e->decl.init = g->decl.init;	else if (!g->decl.init)		g->decl.init = e->decl.init;	if (old->decl.env || e->decl.env) {		if (!old->decl.env)			old->decl.env = e->decl.env;		if (!e->decl.env)			e->decl.env = old->decl.env;		bindtype(e->decl.env, old->decl.type);		bindtype(old->decl.env, e->decl.type);	} 	/* FIXME: check compatible typing */	old->decl.ishidden = e->decl.ishidden || g->decl.ishidden;	old->decl.isimport = e->decl.isimport || g->decl.isimport;	old->decl.isnoret = e->decl.isnoret || g->decl.isnoret;	old->decl.isexportval = e->decl.isexportval || g->decl.isexportval;	old->decl.isglobl = e->decl.isglobl || g->decl.isglobl;	old->decl.ispkglocal = e->decl.ispkglocal || g->decl.ispkglocal;	old->decl.isextern = e->decl.isextern || g->decl.isextern;	return 1;} voidforcedcl(Stab *st, Node *s){	setns(s->decl.name, st->name);	htput(st->dcl, s->decl.name, s);	assert(htget(st->dcl, s->decl.name) != NULL);} voidputdcl(Stab *st, Node *s){	Node *old; 	st = findstab(st, s->decl.name);	old = htget(st->dcl, s->decl.name);	if (!old)		forcedcl(st, s);	else if (!mergedecl(old, s))		fatal(old, "%s already declared on %s:%d", namestr(s->decl.name), fname(s->loc),				lnum(s->loc));} voidupdatetype(Stab *st, Node *n, Type *t){	Tydefn *td; 	td = htget(st->ty, n);	if (!td)		die("no type %s to update", namestr(n));	td->type = t;} intmergetype(Type *old, Type *new){	if (!new) {		lfatal(old->loc, "double prototyping of %s", tystr(old));	} else if (old->vis == Visexport && new->vis != Visexport) {		if (!old->sub && new->sub) {			old->sub = new->sub;			old->nsub = new->nsub;			return 1;		}	} else if (new->vis == Visexport && old->vis != Visexport) {		if (!new->sub && old->sub) {			new->sub = old->sub;			new->nsub = old->nsub;			return 1;		}	}	return 0;} voidputtype(Stab *st, Node *n, Type *t){	Tydefn *td;	Type *ty; 	st = findstab(st, n);	setns(n, st->name);	if (st->name && t && t->name)		setns(t->name, st->name); 	ty = gettype(st, n);	if (!ty) {		if (t && hastype(st, n)) {			t->vis = Visexport;			updatetype(st, n, t);		} else {			td = xalloc(sizeof(Tydefn));			td->loc = n->loc;			td->name = n;			td->type = t;			htput(st->ty, td->name, td);		}	} else if (!mergetype(ty, t)) {		fatal(n, "type %s already declared on %s:%d", tystr(ty), fname(ty->loc),				lnum(ty->loc));	}} voidputucon(Stab *st, Ucon *uc){	Ucon *old;

Lines 1–500 of 753.