#include #include #include #include #include "apl9.h" Datum *getquotequad(void); void setquotequad(Datum *); Datum *getquad(void); void setquad(Datum *); Datum *getquadrawio(void); void setquadrawio(Datum *); Datum *getio(void); void setio(Datum *); Datum *getpp(void); void setpp(Datum *); Datum *getdiv(void); void setdiv(Datum *); Datum *geta(void); Datum *getd(void); Datum *geten(void); Datum *getself(void); Datum *getsession(void); void setsession(Datum *); /* Array *runfile(Array *); in apl9.h */ Array *quadem(Array *); Array *quadsignal1(Array *); Array *quadsignal2(Array *, Array *); Array *quadinfo(Array *); Array *quadproto(Array *); Array *quaducs(Array *); Array *quaddl(Array *); Array *quadthreads1(Array *); Array *quadthreads2(Array *, Array *); static Rune *quadquotebuf = nil; static Array *session = nil; QuadnameDef quadnames[] = { {L"⍞", NameTag, getquotequad, setquotequad, nil, nil}, {L"⎕", NameTag, getquad, setquad, nil, nil}, {L"⎕RAWIO", NameTag, getquadrawio, setquadrawio, nil, nil}, {L"⎕IO", NameTag, getio, setio, nil, nil}, {L"⎕PP", NameTag, getpp, setpp, nil, nil}, {L"⎕DIV", NameTag, getdiv, setdiv, nil, nil}, {L"⎕A", NameTag, geta, nil, nil, nil}, {L"⎕D", NameTag, getd, nil, nil, nil}, {L"⎕EN", NameTag, geten, nil, nil, nil}, {L"⎕SELF", NameTag, getself, nil, nil, nil}, {L"⎕SESSION", NameTag, getsession, setsession, nil, nil}, {L"⎕RUN", FunctionTag, nil, nil, runfile, nil}, {L"⎕EM", FunctionTag, nil, nil, quadem, nil}, {L"⎕SIGNAL", FunctionTag, nil, nil, quadsignal1, quadsignal2}, {L"⎕INFO", FunctionTag, nil, nil, quadinfo, nil}, {L"⎕PROTO", FunctionTag, nil, nil, quadproto, nil}, {L"⎕UCS", FunctionTag, nil, nil, quaducs, nil}, {L"⎕DL", FunctionTag, nil, nil, quaddl, nil}, {L"⎕THREADS", FunctionTag, nil, nil, quadthreads1, quadthreads2}, {nil, 0, nil, nil, nil, nil} /* MUST BE LAST */ }; void initquadnames(void) { Symbol *s; QuadnameDef q; int i; for(i = 0; quadnames[i].name != nil; i++){ q = quadnames[i]; if(q.tag == NameTag){ s = getsym(q.name, 1); s->getfn = q.get; s->setfn = q.set; } } } Datum * quadnamedatum(QuadnameDef q) { Datum *d = allocdatum(q.tag, 0); switch(q.tag){ case NameTag: d->name = runestrdup(q.name); break; case FunctionTag: d->func.type = FunctypeQuad; d->func.quad = emalloc(sizeof(QuadnameDef)); *d->func.quad = q; d->func.left = nil; break; case MonadicOpTag: case DyadicOpTag: default: print("Can't use quad names with type=%d\n", q.tag); threadexitsall(nil); } return d; } /* ⍞ */ Datum * getquotequad(void) { int sizemax = 512; int size; Rune *input; if(quadquotebuf != nil){ input = quadquotebuf; size = runestrlen(input); sizemax = size+1; quadquotebuf = nil; }else{ input = emalloc(sizeof(Rune) * sizemax); size = 0; } do{ if(size == sizemax-1){ sizemax += 512; input = erealloc(input, sizeof(Rune) * sizemax); } input[size] = Bgetrune(stdin); size++; }while(input[size-1] != '\n'); input[size-1] = 0; Datum *result = allocdatum(ArrayTag, 0); result->array = mkrunearray(input); free(input); return result; } void setquotequad(Datum *d) { Rune *str = ppdatum(d); Array *strarray = mkrunearray(str); if(session) rundfn(L"0::⎕RAWIO←⍶ ⋄ ('⍞' ⍺) ⍈ ⍵", d, nil, strarray, session); else setquadrawio(d); free(str); freearray(strarray); } /* ⎕ */ Datum * getquad(void) { return getquadrawio(); } void setquad(Datum *d) { Rune *str = ppdatum(d); Array *strarray = mkrunearray(str); if(session) rundfn(L"0::⎕RAWIO←⍶ ⋄ ('⎕' ⍺) ⍈ ⍵", d, nil, strarray, session); else setquadrawio(d); free(str); } /* for output from main loop */ void outputmain(Datum *d) { Rune *str = ppdatum(d); Array *data = allocarray(AtypeArray, 1, 2); data->shape[0] = 2; data->arraydata[0] = mkscalarint(d->shy); data->arraydata[1] = mkrunearray(str); if(session) rundfn(L"0::⎕RAWIO←⍶ ⋄ ('→' (⍺)) ⍈ ⍵", d, nil, data, session); else setquadrawio(d); free(str); freearray(data); } /* ⎕RAWIO */ Datum * getquadrawio(void) { print("⎕:\n\t"); Datum *result = evalline(nil, nil, 1); /* TODO check that the expression doesn't fail */ return result; } void setquadrawio(Datum *new) { if(new->tag == ArrayTag && GetType(new->array) == AtypeRune){ for(int i = 0; i < GetSize(new->array); i++) print("%C", new->array->runedata[i]); return; } Rune *str = ppdatum(new); print("%S", str); free(str); } /* ⎕IO */ Datum * getio(void) { Datum *d = allocdatum(ArrayTag, 0); d->array = mkscalarint(globalIO()); return d; } void setio(Datum *new) { if(new->tag != ArrayTag || GetRank(new->array) != 0 || GetType(new->array) != AtypeInt || (new->array->intdata[0] != 0 && new->array->intdata[0] != 1)) throwerror(nil, EDomain); else globalIOset(new->array->intdata[0]); } /* ⎕PP */ Datum * getpp(void) { Datum *d = allocdatum(ArrayTag, 0); d->array = mkscalarint(printprecision); return d; } void setpp(Datum *new) { if(new->tag != ArrayTag || GetRank(new->array) != 0 || GetType(new->array) != AtypeInt || new->array->intdata[0] < 0) throwerror(nil, EDomain); else printprecision = new->array->intdata[0]; } /* ⎕DIV */ Datum * getdiv(void) { Datum *d = allocdatum(ArrayTag, 0); d->array = mkscalarint(globalDIV()); return d; } void setdiv(Datum *new) { if(new->tag != ArrayTag || GetRank(new->array) != 0 || GetType(new->array) != AtypeInt || (new->array->intdata[0] != 0 && new->array->intdata[0] != 1)) throwerror(nil, EDomain); else globalDIVset(new->array->intdata[0]); } /* ⎕A */ Datum * geta(void) { Datum *d = allocdatum(ArrayTag, 0); d->array = mkrunearray(L"ABCDEFGHIJKLMNOPQRSTUVWXYZ"); return d; } /* ⎕D */ Datum * getd(void) { Datum *d = allocdatum(ArrayTag, 0); d->array = mkrunearray(L"0123456789"); return d; } /* ⎕EN */ Datum * geten(void) { Datum *d = allocdatum(ArrayTag, 0); ThreadData *td = getthreaddata(); d->array = mkscalarint(td->lasterror); return d; } /* ⎕SELF */ Datum * getself(void) { Datum *d = allocdatum(ArrayTag, 0); d->array = mkscalarint(threadid()); return d; } /* ⎕SELF */ Datum * getsession(void) { Datum *d = allocdatum(ArrayTag, 0); d->array = fnSame(session); return d; } void setsession(Datum *new) { if(new->tag != ArrayTag || GetRank(new->array) != 0 || GetType(new->array) != AtypeInt) throwerror(nil, EDomain); session = fnSame(new->array); } /* ⎕RUN */ Array * runfile(Array *a) { if(GetType(a) != AtypeRune || GetRank(a) > 1){ return mkscalarint(0); } char *filename = smprint("%S", pparray(a)); Biobuf *bio = Bopen(filename, OREAD); if(bio == nil) return mkscalarint(0); while(1){ Rune r = Bgetrune(bio); Bungetrune(bio); if(r == Beof) break; else evalline(nil, bio, 1); } Bterm(bio); return mkscalarint(1); } /* ⎕EM */ Array * quadem(Array *codes) { if(GetType(codes) != AtypeInt) throwerror(nil, EDomain); Array *res; if(GetSize(codes) == 1){ Rune *msg = errorstr(codes->intdata[0]); if(runestrlen(msg) == 0){ msg = runesmprint("ERROR NUMBER %lld", codes->intdata[0]); res = mkrunearray(msg); free(msg); }else res = mkrunearray(msg); }else{ res = duparrayshape(codes, AtypeArray); for(int i = 0; i < GetSize(codes); i++){ Array *code = arrayitem(codes, i); res->arraydata[i] = quadem(code); freearray(code); } } return res; } /* ⎕SIGNAL */ Array * quadsignal1(Array *code) { if(GetType(code) != AtypeInt) throwerror(nil, EDomain); if(GetSize(code) != 1) throwerror(nil, ELength); throwerror(nil, code->intdata[0]); return nil; } Array * quadsignal2(Array *msg, Array *code) { if(GetType(code) != AtypeInt || GetType(msg) != AtypeRune) throwerror(nil, EDomain); if(GetSize(code) != 1) throwerror(nil, ELength); if(GetRank(msg) > 1) throwerror(nil, ERank); throwerror(pparray(msg), code->intdata[0]); return nil; } /* ⎕INFO */ Array * quadinfo(Array *a) { if(GetType(a) != AtypeRune) throwerror(nil, EDomain); Rune *code = pparray(a); Datum *res = evalline(code, nil, 0); Rune *info; switch(res->tag){ case ArrayTag:{ char *typestring = "?"; switch(GetType(res->array)){ case AtypeInt: typestring = "int"; break; case AtypeFloat: typestring = "float"; break; case AtypeRune: typestring = "rune"; break; case AtypeMixed: typestring = "mixed"; break; case AtypeArray: typestring = "array"; break; } uvlong size = arrayspaceused(res->array); info = runesmprint("Type = %s, size in bytes = %ulld", typestring, size); break; } default: info = runesmprint("Can't show info for datum tag %d", res->tag); } Array *infoarr = mkrunearray(info); free(code); free(res); free(info); return infoarr; } /* ⎕PROTO */ Array * quadproto(Array *a) { return fillelement(a); } /* ⎕UCS */ Array * quaducs(Array *a) { Array *res = nil; if(GetType(a) == AtypeInt){ res = duparrayshape(a, AtypeRune); for(int i = 0; i < GetSize(res); i++) res->runedata[i] = a->intdata[i]; }else if(GetType(a) == AtypeRune){ res = duparrayshape(a, AtypeInt); for(int i = 0; i < GetSize(res); i++) res->intdata[i] = a->runedata[i]; }else throwerror(nil, EDomain); return res; } /* ⎕DL */ Array * quaddl(Array *a) { /* TODO: return amount of seconds slept */ if(GetSize(a) != 1) throwerror(nil, ELength); if(GetType(a) != AtypeInt && GetType(a) != AtypeFloat) throwerror(nil, EDomain); if(GetType(a) == AtypeInt && a->intdata[0] >= 0) sleep(a->intdata[0] * 1000); else if(GetType(a) == AtypeFloat && a->floatdata[0] >= 0) sleep(a->floatdata[0] * 1000); else throwerror(nil, EDomain); return fnSame(a); } /* ⎕THREADS */ Array * quadthreads1(Array *properties) { Array *threadids = runningthreads(); Array *res = quadthreads2(threadids, properties); freearray(threadids); return res; } Array * quadthreads2(Array *thread, Array *property) { if(GetType(thread) != AtypeInt || GetType(property) != AtypeInt) throwerror(nil, EDomain); if(GetRank(thread) > 1 || GetRank(property) > 1) throwerror(nil, ERank); if(GetRank(thread) > 0 || GetRank(property) > 0) return rundfn(L"⍺ ⎕THREADS⌾ ⍵", nil, nil, thread, property); /* Get thread with ID thread, and property based on number in property */ return threadproperty(thread->intdata[0], property->intdata[0]); }