1300 lines · 28.7 KB · C
RawDownload
#include <stdlib.h>#include <stdio.h>#include <stdarg.h>#include <inttypes.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" typedef struct Typefix Typefix;struct Typefix {	Type **dest;	intptr_t id;}; typedef struct Traitfix Traitfix;struct Traitfix {	Trait **dest;	Type *type;	intptr_t id;}; static void wrtype(FILE *fd, Type *val);static void rdtype(FILE *fd, Type **dest);static void wrstab(FILE *fd, Stab *val);static Stab *rdstab(FILE *fd, int isfunc);static void wrsym(FILE *fd, Node *val);static Node *rdsym(FILE *fd, Trait *ctx);static void pickle(FILE *fd, Node *n);static Node *unpickle(FILE *fd); /* type fixup list */static Htab *trdeduptab;	/* 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 *autocallmap;	/* map from autocall name -> int */ #define Builtinmask (1 << 30)static Typefix *typefix;	/* list of types we need to replace */static size_t ntypefix;		/* size of replacement list */ static Traitfix *traitfix;	/* list of traits we need to replace */static size_t ntraitfix;	/* size of replacement list */ static Node **implfix;		/* list of impls we need to fix up */static size_t nimplfix;		/* size of replacement list */ voidaddextlibs(char **libs, size_t nlibs){	size_t i, j; 	for (i = 0; i < nlibs; i++) {		for (j = 0; j < file.nextlibs; j++)			if (!strcmp(file.extlibs[j], libs[i]))				continue;		lappend(&file.extlibs, &file.nextlibs, libs[i]);	}} /* Outputs a symbol table to file in a way that can be * read back usefully. Only writes declarations, type * and sub-namespaces. Captured variables are ommitted. */static voidwrstab(FILE *fd, Stab *val){	size_t n, i;	void **keys; 	wrstr(fd, val->name); 	/* write decls */	keys = htkeys(val->dcl, &n);	wrint(fd, n);	for (i = 0; i < n; i++)		wrsym(fd, getdcl(val, keys[i]));	free(keys); 	/* write types */	keys = htkeys(val->ty, &n);	wrint(fd, n);	for (i = 0; i < n; i++) {		pickle(fd, keys[i]);			/* name */		wrtype(fd, gettype(val, keys[i]));	/* type */	}	free(keys);} /* Reads a symbol table from file. The converse * of wrstab. */static Stab *rdstab(FILE *fd, int isfunc){	Stab *st;	Type *ty;	Node *nm;	int n;	int i; 	/* read dcls */	st = mkstab(isfunc);	st->name = rdstr(fd);	n = rdint(fd);	for (i = 0; i < n; i++)		putdcl(st, rdsym(fd, NULL)); 	/* read types */	n = rdint(fd);	for (i = 0; i < n; i++) {		nm = unpickle(fd);		rdtype(fd, &ty);		puttype(st, nm, ty);	}	return st;} static voidwrucon(FILE *fd, Ucon *uc){	wrint(fd, uc->loc.line);	wrint(fd, uc->id);	wrbool(fd, uc->synth);	pickle(fd, uc->name);	wrbool(fd, uc->etype != NULL);	if (uc->etype)		wrtype(fd, uc->etype);} static Ucon *rducon(FILE *fd, Type *ut){	Type *et;	Node *name;	Ucon *uc;	size_t id;	int line;	int synth; 	et = NULL;	line = rdint(fd);	id = rdint(fd);	synth = rdbool(fd);	name = unpickle(fd);	uc = mkucon(Zloc, name, ut, et);	uc->loc.line = line;	uc->loc.file = file.nfiles - 1;	if (rdbool(fd))		rdtype(fd, &uc->etype);	uc->id = id;	uc->synth = synth;	return uc;} /* Writes the name and type of a variable, * but only writes its intializer for thing * we want to inline cross-file (currently, * the only cross-file inline is generics) */static voidwrsym(FILE *fd, Node *val){	/* sym */	wrint(fd, val->loc.line);	pickle(fd, val->decl.name);	wrtype(fd, val->decl.type); 	/* symflags */	wrint(fd, val->decl.vis);	wrbool(fd, val->decl.isconst);	wrbool(fd, val->decl.isgeneric);	wrbool(fd, val->decl.isextern);	wrbool(fd, val->decl.ispkglocal);	wrbool(fd, val->decl.isnoret);	wrbool(fd, val->decl.isexportval);	wrbyte(fd, val->decl.isinit);	wrbyte(fd, val->decl.isfini);	if (val->decl.isexportval)		pickle(fd, val->decl.init);} static Node *rdsym(FILE *fd, Trait *ctx){	int line;	Node *name;	Node *n; 	line = rdint(fd);	name = unpickle(fd);	n = mkdecl(Zloc, name, NULL);	n->loc.line = line;	n->loc.file = file.nfiles - 1;	rdtype(fd, &n->decl.type); 	if (rdint(fd) == Vishidden)		n->decl.ishidden = 1;	n->decl.trait = ctx;	n->decl.isconst = rdbool(fd);	n->decl.isgeneric = rdbool(fd);	n->decl.isextern = rdbool(fd);	n->decl.ispkglocal = rdbool(fd);	n->decl.isnoret = rdbool(fd);	n->decl.isimport = 1;	n->decl.isexportval = rdbool(fd);	n->decl.isinit = rdbool(fd);	n->decl.isfini = rdbool(fd);	if (n->decl.isexportval)		n->decl.init = unpickle(fd);	return n;} /* Writes types to a file. Errors on * internal only types like Tyvar that * will not be meaningful in another file*/static voidtypickle(FILE *fd, Type *ty){	size_t i, j; 	if (!ty) {		die("trying to pickle null type\n");		return;	}	wrbyte(fd, ty->type);	wrbyte(fd, ty->vis);	wrint(fd, ty->nspec);	for (i = 0; i < ty->nspec; i++) {		wrint(fd, ty->spec[i]->ntrait);		for (j = 0; j < ty->spec[i]->ntrait; j++)			pickle(fd, ty->spec[i]->trait[j]);		wrtype(fd, ty->spec[i]->param);		wrbool(fd, ty->spec[i]->aux != NULL);		if (ty->spec[i]->aux)			wrtype(fd, ty->spec[i]->aux);	}	wrtype(fd, ty->seqaux);	wrint(fd, ty->nsub);	switch (ty->type) {	case Tyunres:		pickle(fd, ty->name);		break;	case Typaram:		/* tid is generated; don't write */		if (ty->trneed) {			wrint(fd, bscount(ty->trneed));			for (i = 0; bsiter(ty->trneed, &i); i++) {				if (i < Ntraits)					wrint(fd, i | Builtinmask);				else					wrint(fd, traittab[i]->uid);			}		} else {			wrint(fd, 0);		}		wrstr(fd, ty->pname);	break;	case Tystruct:		wrint(fd, ty->nmemb);		for (i = 0; i < ty->nmemb; i++)			pickle(fd, ty->sdecls[i]);		break;	case Tyunion:		wrint(fd, ty->nmemb);		for (i = 0; i < ty->nmemb; i++)			wrucon(fd, ty->udecls[i]);		break;	case Tyarray:		wrtype(fd, ty->sub[0]);		pickle(fd, ty->asize);		break;	case Tyslice:	wrtype(fd, ty->sub[0]);	break;	case Tyvar:	die("Attempting to pickle %s. This will not work.\n", tystr(ty));	break;	case Tyname:		pickle(fd, ty->name);		wrint(fd, ty->narg);		for (i = 0; i < ty->narg; i++)			wrtype(fd, ty->arg[i]);		wrtype(fd, ty->sub[0]);		break;	case Tygeneric:		pickle(fd, ty->name);		wrint(fd, ty->ngparam);		for (i = 0; i < ty->ngparam; i++)			wrtype(fd, ty->gparam[i]);		wrtype(fd, ty->sub[0]);		break;	default:		for (i = 0; i < ty->nsub; i++)			wrtype(fd, ty->sub[i]);		break;	}} static voidtraitpickle(FILE *fd, Trait *tr){	size_t i; 	wrint(fd, tr->uid);	wrint(fd, tr->vis);	pickle(fd, tr->name);	typickle(fd, tr->param);	wrint(fd, tr->naux);	for (i = 0; i < tr->naux; i++)		wrtype(fd, tr->aux[i]);	wrint(fd, tr->nproto);	for (i = 0; i < tr->nproto; i++)		wrsym(fd, tr->proto[i]);} static voidwrtype(FILE *fd, Type *ty){	if (!ty) {		wrint(fd, 0);		return;	}	if (ty->tid >= Builtinmask)		die("Type id %d for %s too big", ty->tid, tystr(ty));	if (ty->vis == Visbuiltin)		wrint(fd, ty->type | Builtinmask);	else		wrint(fd, ty->tid);} static voidrdtype(FILE *fd, Type **dest){	uintptr_t tid; 	tid = rdint(fd);	if (tid == 0) {		return;	} else if (tid & Builtinmask) {		*dest = mktype(Zloc, tid & ~Builtinmask);	} else {		typefix = xrealloc(typefix, (ntypefix + 1) * sizeof(typefix[0]));		typefix[ntypefix++] = (Typefix){dest, tid};	}} static voidrdtrait(FILE *fd, Trait **dest, Type *ty){	uintptr_t tid; 	tid = rdint(fd);	if (tid & Builtinmask) {		if (dest)			*dest = traittab[tid & ~Builtinmask];		if (ty) {			if (!ty->trneed)				ty->trneed = mkbs();			bsput(ty->trneed, traittab[tid & ~Builtinmask]->uid);		}	} else {		traitfix = xrealloc(traitfix, (ntraitfix + 1) * sizeof(traitfix[0]));		traitfix[ntraitfix++] = (Traitfix){dest, ty, tid};	}} /* Reads types from a file. */static Type *tyunpickle(FILE *fd){	size_t i, j, n;	Type *ty;	Ty t; 	t = rdbyte(fd);	ty = mktype(Zloc, t);	ty->isimport = 1;	if (rdbyte(fd) == Vishidden)		ty->ishidden = 1;	ty->nspec = rdint(fd);	ty->spec = malloc(ty->nspec * sizeof(Traitspec*));	for (i = 0; i < ty->nspec; i++) {		ty->spec[i] = zalloc(sizeof(Traitspec));		n = rdint(fd);		ty->spec[i]->ntrait = n;		ty->spec[i]->trait = malloc(n * sizeof(Node*));		for (j = 0; j < ty->spec[i]->ntrait; j++)			ty->spec[i]->trait[j] = unpickle(fd);		rdtype(fd, &ty->spec[i]->param);		if (rdbool(fd))			rdtype(fd, &ty->spec[i]->aux);	}	rdtype(fd, &ty->seqaux);	ty->nsub = rdint(fd);	if (ty->nsub > 0)		ty->sub = zalloc(ty->nsub * sizeof(Type *));	switch (ty->type) {	case Tyunres:		ty->name = unpickle(fd);		break;	case Typaram:			n = rdint(fd);		for (i = 0; i < n; i++)			rdtrait(fd, NULL, ty);		ty->pname = rdstr(fd);		break;	case Tystruct:		ty->nmemb = rdint(fd);		ty->sdecls = zalloc(ty->nmemb * sizeof(Node *));		for (i = 0; i < ty->nmemb; i++)			ty->sdecls[i] = unpickle(fd);		break;	case Tyunion:		ty->nmemb = rdint(fd);		ty->udecls = zalloc(ty->nmemb * sizeof(Node *));		for (i = 0; i < ty->nmemb; i++)			ty->udecls[i] = rducon(fd, ty);		break;	case Tyarray:		rdtype(fd, &ty->sub[0]);		ty->asize = unpickle(fd);		break;	case Tyslice:		rdtype(fd, &ty->sub[0]);		break;	case Tyname:		ty->name = unpickle(fd);		ty->narg = rdint(fd);		ty->arg = zalloc(ty->narg * sizeof(Type *));		for (i = 0; i < ty->narg; i++)			rdtype(fd, &ty->arg[i]);		rdtype(fd, &ty->sub[0]);		break;	case Tygeneric:		ty->name = unpickle(fd);		ty->ngparam = rdint(fd);		ty->gparam = zalloc(ty->ngparam * sizeof(Type *));		for (i = 0; i < ty->ngparam; i++)			rdtype(fd, &ty->gparam[i]);		rdtype(fd, &ty->sub[0]);		break;	default:		for (i = 0; i < ty->nsub; i++)			rdtype(fd, &ty->sub[i]);		break;	}	return ty;} Trait *traitunpickle(FILE *fd){	Trait *tr;	Node *proto;	size_t i, n;	intptr_t uid; 	/* create an empty trait */	tr = mktrait(Zloc, NULL, NULL,		NULL, 0,		NULL, 0,		0);	uid = rdint(fd);	if (rdint(fd) == Vishidden)		tr->ishidden = 1;	tr->name = unpickle(fd);	tr->param = tyunpickle(fd);	tr->naux = rdint(fd);	tr->aux = zalloc(tr->naux * sizeof(Type*));	tr->isimport = 1;	for (i = 0; i < tr->naux; i++)		rdtype(fd, &tr->aux[i]);	n = rdint(fd);	for (i = 0; i < n; i++) {		proto = rdsym(fd, tr);		proto->decl.impls = mkht(tyhash, tyeq);		lappend(&tr->proto, &tr->nproto, proto);	}	htput(trmap, itop(uid), tr);	return tr;} /* Pickles a node to a file.  The format * is more or less equivalen to to * simplest serialization of the * in-memory representation. Minimal * checking is done, so a bad type can * crash the compiler */static voidpickle(FILE *fd, Node *n){	size_t i; 	if (!n) {		wrbyte(fd, Nnone);		return;	}	wrbyte(fd, n->type);	wrint(fd, n->loc.line);	switch (n->type) {	case Nexpr:

Lines 1–500 of 1300.