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->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.isexportinit = rdbool(fd); n->decl.isinit = rdbool(fd); if (n->decl.isexportinit) n->decl.init = unpickle(fd); return n; }
void LoopScheduler() { // The heartbeat timer controls how often the green LED blinks if(rdint(I_LSC_HEARTBEAT) <= 0) { wrint(I_LSC_HEARTBEAT, rdint(I_LSD_HEARTBEAT)); HeliosSetLED1(!HeliosReadLED1()); } // the state data timer controls how often the state register data is // sent to the GUI. if(rdint(I_LSC_STATE_DATA) <= 0) { wrint(I_LSC_STATE_DATA, rdint(I_LSD_STATE_DATA)); wrchar(C_REQ_STATE_DATA,TRUE); } // The read button timer controls how often we read the button. // This is done to "de-bounce" the button if(rdint(I_LSC_READ_BUTTON) <= 0) { wrint(I_LSC_READ_BUTTON, 100); // Hard code to the button to be read every 100ms if(HeliosReadBTN()) { xil_printf("BUTTON!"); // Do something in response to button push Game_Shoot(GAME_KILL_SHOT); wrint(I_LSC_READ_BUTTON, 750); // if the button was pushed then we want to wait longer before reading it again to avoid double pushing } } int stat = CameraStatus(XPAR_PLB_VISION_0_BASEADDR); if(stat == 0xD1) //capture done but FIFO not empty { stallTimes++; if(stallTimes > 1000) { //xil_printf("Reboot"); ResetCameraCore(); FT_StartCapture(g_capture_fte->next); //StartFrameCapture(XPAR_PLB_VISION_0_BASEADDR); stallTimes = 0; } } //These should also be calculated every so many ms // but i don't need them right now so i am not implementing them //calculateSpeed(); //TruckControlInterruptRoutine(); }
Trait *traitunpickle(FILE *fd) { Trait *tr; size_t i, n; intptr_t uid; /* create an empty trait */ tr = mktrait(Zloc, NULL, NULL, NULL, 0, NULL, 0, 0); uid = rdint(fd); tr->ishidden = rdbool(fd); tr->name = unpickle(fd); tr->param = tyunpickle(fd); n = rdint(fd); for (i = 0; i < n; i++) lappend(&tr->memb, &tr->nmemb, rdsym(fd, tr)); n = rdint(fd); for (i = 0; i < n; i++) lappend(&tr->funcs, &tr->nfuncs, rdsym(fd, tr)); htput(trmap, itop(uid), tr); return tr; }
static void rdtype(FILE *fd, Type **dest) { uintptr_t tid; tid = rdint(fd); if (tid & Builtinmask) { *dest = mktype(Zloc, tid & ~Builtinmask); } else { lappend(&typefixdest, &ntypefixdest, dest); lappend(&typefixid, &ntypefixid, itop(tid)); } }
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->file.nfiles - 1; if (rdbool(fd)) rdtype(fd, &uc->etype); uc->id = id; uc->synth = synth; return uc; }
/* 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 void rdtrait(FILE *fd, Trait **dest, Type *ty) { uintptr_t tid; tid = rdint(fd); if (tid & Builtinmask) { if (dest) *dest = traittab[tid & ~Builtinmask]; if (ty) settrait(ty, traittab[tid & ~Builtinmask]); } else { lappend(&traitfixdest, &ntraitfixdest, dest); lappend(&traitfixtype, &ntraitfixtype, ty); lappend(&traitfixid, &ntraitfixid, itop(tid)); } }
void patchpatch( VMRef pv, int ptype ) { Patch * p; switch( ptype ) { default: error("patchpatch: Illegal patch subtype: %x",ptype); break; case OBJMODSIZE: trace("PATCH MODSIZE"); break; case OBJMODNUM: trace("PATCH MODNUM"); break; case OBJCODESYMB: if (!smtopt) error("CODESYMB directive encountered without split module table mode set"); case OBJDATASYMB: case OBJDATAMODULE: case OBJLABELREF: #ifdef NEW_STUBS case OBJCODESTUB: case OBJADDRSTUB: #endif { VMRef v = rdsymb(); Symbol * s; s = VMAddr( Symbol, v ); if (ptype == OBJDATAMODULE) { movesym( v ); /* implicit GLOBAL declaration */ if (s->referenced) refsymbol_def( v ); } else { refsymbol_nondef( v ); } trace("PatchPatch %s %s %#x", ptype == OBJDATASYMB ? "DATASYMB" : ptype == OBJDATAMODULE ? "DATAMODULE" : ptype == OBJCODESYMB ? "CODESYMB" : #ifdef NEW_STUBS ptype == OBJCODESTUB ? "CODESTUB" : ptype == OBJADDRSTUB ? "ADDRSTUB" : #endif "LABELREF" , s->name, v ); p = VMAddr( Patch, pv ); p->value.v = v; VMDirty( pv ); break; } case OBJPATCH: case OBJPATCH + 1: case OBJPATCH + 2: case OBJPATCH + 3: case OBJPATCH + 4: case OBJPATCH + 5: case OBJPATCH + 6: case OBJPATCH + 7: case OBJPATCH + 8: case OBJPATCH + 9: case OBJPATCH + 10: case OBJPATCH + 11: case OBJPATCH + 12: /* recursive patch */ { Patch *p2; word pword = 0; /* patch data */ int type; /* patch type */ VMRef pv2 = VMNew(sizeof(Patch)); if (ptype != PATCHSWAP) /* no patch data for swap patch */ pword = rdint(); /* patch data */ type = (int)rdint(); /* patch type */ p = VMAddr(Patch,pv); p->value.v = pv2; /* chain patches */ p2 = VMAddr(Patch,pv2); p2->word = pword; p2->type = type; VMDirty(pv2); VMDirty(pv); patchpatch(pv2, type); /* set value of ptype, or another patch */ } } return; } /* patchpatch */
void genpatch( word op ) { word type = rdint(); int size = (int)op & 0x7; copycode(); trace("Read PATCH"); switch( type ) { default: error("genpatch: Illegal patch type: %x",type); return; case OBJMODSIZE: trace("MODSIZE"); (void)newcode(op,size,type,curloc,0L); break; case OBJMODNUM: trace("MODNUM"); (void)newcode(op,size,type,curloc,0L); break; case OBJCODESYMB: if (!smtopt) error("CODESYMB directive encountered without split module table mode set"); case OBJLABELREF: case OBJDATASYMB: case OBJDATAMODULE: #ifdef NEW_STUBS case OBJCODESTUB: case OBJADDRSTUB: #endif { VMRef v = rdsymb(); Symbol * s; if (type == OBJDATAMODULE) { movesym( v ); /* implicit GLOBAL declaration */ } s = VMAddr( Symbol, v ); trace( "Single level %s %s %#x", #ifdef NEW_STUBS type == OBJCODESTUB ? "CODESTUB" : type == OBJADDRSTUB ? "ADDRSTUB" : #endif type == OBJDATASYMB ? "DATASYMB" : type == OBJDATAMODULE ? "DATAMODULE" : type == OBJCODESYMB ? "CODESYMB" : "LABELREF" , s->name, v ); refsymbol_nondef( v ); (void)newcode( op, size, type, curloc, v ); break; } case OBJPATCH: case OBJPATCH + 1: case OBJPATCH + 2: case OBJPATCH + 3: case OBJPATCH + 4: case OBJPATCH + 5: case OBJPATCH + 6: case OBJPATCH + 7: case OBJPATCH + 8: case OBJPATCH + 9: case OBJPATCH + 10: case OBJPATCH + 11: case OBJPATCH + 12: { Patch *p; word pword = 0; /* patch data */ int ptype; /* patch type */ VMRef pv = VMNew(sizeof(Patch)); if (type != PATCHSWAP) /* no patch data for swap patch */ pword = rdint(); /* patch data */ p = VMAddr(Patch,pv); p->word = pword; p->type = ptype = (int)rdint(); /* patch type */ patchpatch(pv, ptype); /* patch in value of type, or another patch */ (void)newcode(op,size,type,curloc,pv); break; } } curloc += size; return; } /* genpatch */
void readfile( void ) { VMRef v; Symbol * s; word op = 0; /* * Quick Test. * Determine if the first byte in the input file is a GHOF * directive. If not then do not bother to parse the rest * of the file. */ op = getc( infd ); if (op >= 0x40) { #if defined __ARM && (defined RS6000 || defined __SUN4) /* only support AOF -> GHOF conversion when cross linking */ if (op == 0xC3 || op == 0xC5) { s_aof * pAOF; uword iCodeSize; char * pTempFileName; trace( "Assuming file is in AOF format" ); pTempFileName = malloc( strlen( infile_duplicate ) + 5 /* strlen( ".ghof" ) */ + 1 ); if (pTempFileName == NULL) { error( "Out of memory allocating temporary file name" ); return; } strcpy( pTempFileName, infile_duplicate ); strcat( pTempFileName, ".ghof" ); file_trace( "creating GHOF copy of AOF file '%s'", infile_duplicate ); pAOF = open_aof( infile_duplicate ); if (pAOF == NULL) { error( "Failed to reopen file in AOF mode" ); return; } (void)convert_aof( pAOF, pTempFileName, bSharedLib, bTinyModel, bDeviceDriver ); /* Open the temporary file again */ file_trace( "opening GHOF copy '%s'", pTempFileName ); infd = freopen( pTempFileName, "rb", infd ); if (infd == NULL) { error( "Unable to reopen temporary file %s", pTempFileName ); return; } else file_trace( "copy opened" ); free( pTempFileName ); /* drop throiugh into normal readfile() code */ } else #endif /* __ARM and (RS6000 or __SUN4) */ { error( "Input file is not in GHOF format" ); return; } } else { ungetc( (char)op, infd ); } do { op = rdint(); trace("OP = %x, curloc = %x, codepos = %x",op,curloc, codepos); switch( op ) { default: error( "Illegal linker directive '%x'", op ); break; case EOF: return; case OBJCODE: { word size = rdint(); if (size < 0) error( "Negative sized code directive encountered (%x)", size ); trace("CODE %d",size); while( size-- ) genbyte(rdch()); break; } case OBJBSS: { word size = rdint(); if (size < 0) error("Negative sized bss defined"); trace("BSS %d",size); while( size-- ) genbyte(0L); break; } case OBJWORD: genpatch( OBJWORD ); break; case OBJSHORT: genpatch( OBJSHORT ); break; case OBJBYTE: genpatch( OBJBYTE ); break; case OBJINIT: geninit(); break; case OBJMODULE: genmodule(rdint()); break; case OBJBYTESEX: if( bytesex != 0 ) error("bytesex already set"); bytesex = rdint(); trace("BYTESEX %d",bytesex); break; case OBJREF: v = rdsymb(); movesym(v); /* XXX - all REF symbols are implicitly global */ refsymbol_nondef(v); break; case OBJGLOBAL: v = rdsymb(); s = VMAddr(Symbol,v); movesym(v); if (s->referenced) { refsymbol_def(v); } break; case OBJLABEL: v = rdsymb(); s = VMAddr(Symbol,v); trace("LABEL %s",s->name); if( s->type != S_UNBOUND ) { if (!inlib) warn( "Duplicate definition of symbol '%s' defined in file '%s'", s->name, s->file_name ); } else { if (s->AOFassumedData) { error( "(AOF) Symbol '%s' has been assumed to be data in file '%s'", s->name, s->file_name ); s->AOFassumedData = FALSE; } copycode(); s->type = S_CODESYMB; s->value.v = codeptr(); s->module = curmod; s->file_name = infile_duplicate; if (s->referenced) refsymbol_def(v); { int len = strlen( s->name ); /* hack to insert correct name for resident libraries */ VMlock( v ); if (len > 8 && strcmp( s->name + len - 8, ".library" ) == 0 && VMAddr( asm_Module, curmod )->id != -1 ) { VMAddr( asm_Module, curmod )->file_name = s->name; } VMunlock( v ); } } break; case OBJDATA: case OBJCOMMON: { word size = rdint(); if (size < 0) error("Negative sized data/common directive encountered"); v = rdsymb(); s = VMAddr(Symbol,v); trace("%s %d %s",op== OBJDATA ? "DATA" : "COMMON",size,s->name); if( s->type != S_UNBOUND ) { if( s->type != S_COMMSYMB) { if (!inlib) warn("Duplicate data definition of symbol '%s' defined in file '%s'",s->name, s->file_name); } else { if( s->value.w < size ) s->value.w = size; } } else { s->type = op== OBJDATA ? S_DATASYMB : S_COMMSYMB; s->value.w = size; s->module = curmod; s->file_name = infile_duplicate; if(s->referenced) refsymbol_def(v); } (void)newcode(op,0,0,curloc,v); break; } case OBJCODETABLE: { if (!smtopt) error("CODETABLE directive encountered without split module table mode set"); v = rdsymb(); s = VMAddr(Symbol,v); #if 0 /* problems for .MaxCodeP */ movesym(v); /* implicit global directive */ #endif trace("%s %s","CODETABLE",s->name); if ( s->type != S_UNBOUND ) { if (!inlib) warn("Duplicate definition of symbol '%s' defined in file '%s'", s->name, s->file_name); } else { if (s->AOFassumedData) { error( "(AOF) Symbol '%s' has been assumed to be data in file '%s'", s->name, s->file_name ); s->AOFassumedData = FALSE; } s->type = S_FUNCSYMB; s->value.w = 4; s->module = curmod; s->file_name = infile_duplicate; if(s->referenced) refsymbol_def(v); } (void)newcode(op,0,0,curloc,v); break; } } } while( op != EOF ); return; }
/* Usefile format: * U<pkgname> * T<pickled-type> * R<picled-trait> * I<pickled-impl> * D<picled-decl> * G<pickled-decl><pickled-initializer> */ int loaduse(char *path, FILE *f, Stab *st, Vis vis) { intptr_t tid; size_t i; int v; char *pkg; Node *dcl, *impl, *init; Stab *s; Type *ty; Trait *tr; char *lib; int c; pushstab(file->file.globls); if (!tydedup) tydedup = mkht(tyhash, tyeq); if (fgetc(f) != 'U') return 0; v = rdint(f); if (v != Abiversion) { fprintf(stderr, "%s: abi version %d, expected %d\n", path, v, Abiversion); return 0; } pkg = rdstr(f); /* if the package names match up, or the usefile has no declared * package, then we simply add to the current stab. Otherwise, * we add a new stab under the current one */ if (st->name) { if (pkg && !strcmp(pkg, st->name)) { s = st; } else { s = findstab(st, pkg); } } else { if (pkg) { s = findstab(st, pkg); } else { s = st; } } if (!streq(st->name, pkg)) vis = Visintern; if (!s) { printf("could not find matching package for merge: %s in %s\n", st->name, path); exit(1); } 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]); while ((c = fgetc(f)) != EOF) { switch(c) { case 'L': lib = rdstr(f); for (i = 0; i < file->file.nlibdeps; i++) if (!strcmp(file->file.libdeps[i], lib)) /* break out of both loop and switch */ goto foundlib; lappend(&file->file.libdeps, &file->file.nlibdeps, lib); foundlib: break; case 'X': lib = rdstr(f); for (i = 0; i < file->file.nextlibs; i++) if (!strcmp(file->file.extlibs[i], lib)) /* break out of both loop and switch */ goto foundextlib; lappend(&file->file.extlibs, &file->file.nextlibs, lib); foundextlib: break; case 'F': lappend(&file->file.files, &file->file.nfiles, rdstr(f)); break; case 'G': case 'D': dcl = rdsym(f, NULL); dcl->decl.vis = vis; dcl->decl.isglobl = 1; 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; puttrait(s, tr->name, tr); for (i = 0; i < tr->nfuncs; i++) putdcl(s, tr->funcs[i]); break; case 'T': tid = rdint(f); ty = tyunpickle(f); if(!ty->ishidden) ty->vis = vis; htput(tidmap, itop(tid), ty); /* fix up types */ if (ty->type == Tyname || ty->type == Tygeneric) { if (ty->issynth) break; if (!streq(s->name, ty->name->name.ns)) ty->ishidden = 1; if (!gettype(s, ty->name) && !ty->ishidden) puttype(s, ty->name, ty); } else if (ty->type == Tyunion) { for (i = 0; i < ty->nmemb; i++) if (!getucon(s, ty->udecls[i]->name) && !ty->udecls[i]->synth) putucon(s, ty->udecls[i]); } break; case 'I': impl = unpickle(f); putimpl(s, impl); /* specialized declarations always go into the global stab */ for (i = 0; i < impl->impl.ndecls; i++) putdcl(file->file.globls, impl->impl.decls[i]); break; case EOF: break; } } fixtypemappings(s); fixtraitmappings(s); htfree(tidmap); popstab(); return 1; }
/* Unpickles a node from a file. Minimal checking * is done. Specifically, no checks are done for * sane arities, a bad file can crash the compiler */ static Node *unpickle(FILE *fd) { size_t i; Ntype type; Node *n; type = rdbyte(fd); if (type == Nnone) return NULL; n = mknode(Zloc, type); n->loc.line = rdint(fd); n->loc.file = file->file.nfiles - 1; switch (n->type) { case Nfile: lappend(&n->file.files, &n->file.nfiles, rdstr(fd)); n->file.nuses = rdint(fd); n->file.uses = zalloc(sizeof(Node*)*n->file.nuses); for (i = 0; i < n->file.nuses; i++) n->file.uses[i] = unpickle(fd); n->file.nstmts = rdint(fd); n->file.stmts = zalloc(sizeof(Node*)*n->file.nstmts); for (i = 0; i < n->file.nstmts; i++) n->file.stmts[i] = unpickle(fd); n->file.globls = rdstab(fd, 0); break; case Nexpr: n->expr.op = rdbyte(fd); rdtype(fd, &n->expr.type); n->expr.isconst = rdbool(fd); n->expr.idx = unpickle(fd); n->expr.nargs = rdint(fd); n->expr.args = zalloc(sizeof(Node *)*n->expr.nargs); for (i = 0; i < n->expr.nargs; i++) n->expr.args[i] = unpickle(fd); break; case Nname: if (rdbool(fd)) n->name.ns = rdstr(fd); n->name.name = rdstr(fd); break; case Nuse: n->use.islocal = rdbool(fd); n->use.name = rdstr(fd); break; case Nlit: n->lit.littype = rdbyte(fd); rdtype(fd, &n->lit.type); n->lit.nelt = rdint(fd); switch (n->lit.littype) { case Lchr: n->lit.chrval = rdint(fd); break; case Lint: n->lit.intval = rdint(fd); break; case Lflt: n->lit.fltval = rdflt(fd); break; case Lstr: rdlenstr(fd, &n->lit.strval); break; case Llbl: n->lit.lblval = rdstr(fd); break; case Lbool: n->lit.boolval = rdbool(fd); break; case Lfunc: n->lit.fnval = unpickle(fd); break; } break; case Nloopstmt: n->loopstmt.init = unpickle(fd); n->loopstmt.cond = unpickle(fd); n->loopstmt.step = unpickle(fd); n->loopstmt.body = unpickle(fd); break; case Niterstmt: n->iterstmt.elt = unpickle(fd); n->iterstmt.seq = unpickle(fd); n->iterstmt.body = unpickle(fd); break; case Nmatchstmt: n->matchstmt.val = unpickle(fd); n->matchstmt.nmatches = rdint(fd); n->matchstmt.matches = zalloc(sizeof(Node *)*n->matchstmt.nmatches); for (i = 0; i < n->matchstmt.nmatches; i++) n->matchstmt.matches[i] = unpickle(fd); break; case Nmatch: n->match.pat = unpickle(fd); n->match.block = unpickle(fd); break; case Nifstmt: n->ifstmt.cond = unpickle(fd); n->ifstmt.iftrue = unpickle(fd); n->ifstmt.iffalse = unpickle(fd); break; case Nblock: n->block.scope = rdstab(fd, 0); n->block.nstmts = rdint(fd); n->block.stmts = zalloc(sizeof(Node *)*n->block.nstmts); n->block.scope->super = curstab(); pushstab(n->func.scope->super); for (i = 0; i < n->block.nstmts; i++) n->block.stmts[i] = unpickle(fd); popstab(); break; case Ndecl: n->decl.did = ndecls; /* unique within file */ /* sym */ n->decl.name = unpickle(fd); rdtype(fd, &n->decl.type); /* symflags */ n->decl.isconst = rdbool(fd); n->decl.isgeneric = rdbool(fd); n->decl.isextern = rdbool(fd); n->decl.isnoret = rdbool(fd); n->decl.ispkglocal = rdbool(fd); /* init */ n->decl.init = unpickle(fd); lappend(&decls, &ndecls, n); break; case Nfunc: rdtype(fd, &n->func.type); n->func.scope = rdstab(fd, 1); n->func.nargs = rdint(fd); n->func.args = zalloc(sizeof(Node *)*n->func.nargs); n->func.scope->super = curstab(); pushstab(n->func.scope->super); for (i = 0; i < n->func.nargs; i++) n->func.args[i] = unpickle(fd); n->func.body = unpickle(fd); popstab(); break; case Nimpl: n->impl.traitname = unpickle(fd); i = rdint(fd); rdtrait(fd, &n->impl.trait, NULL); rdtype(fd, &n->impl.type); n->impl.ndecls = rdint(fd); n->impl.decls = zalloc(sizeof(Node *)*n->impl.ndecls); for (i = 0; i < n->impl.ndecls; i++) n->impl.decls[i] = rdsym(fd, n->impl.trait); break; case Nnone: die("Nnone should not be seen as node type!"); break; } return n; }
/* Writes types to a file. Errors on * internal only types like Tyvar that * will not be meaningful in another file */ static Type *tyunpickle(FILE *fd) { size_t i, n; Type *ty; Ty t; t = rdbyte(fd); ty = mktype(Zloc, t); ty->isimport = 1; if (rdbyte(fd) == Vishidden) ty->ishidden = 1; /* tid is generated; don't write */ n = rdint(fd); for (i = 0; i < n; i++) rdtrait(fd, NULL, ty); 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: 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->issynth = rdbool(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->issynth = rdbool(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; }