#include #include #include #include "apl9.h" Rune primmonopnames[] = L"¨⍨⌸⌶&⌾∆"; Rune primdyadopnames[] = L"⍣.∘⍤⍥@⍠⌺⍢⍫⍙"; opmonad monadoperatordefs[] = { opEach, /* ¨ */ opSwitch, /* ⍨ */ opKey, /* ⌸ */ 0, /* ⌶ */ 0, /* & */ opOuterProduct, /* ⌾ */ opSelfReference1, /* ∆ */ }; opdyad dyadoperatordefs[] = { opPower, /* ⍣ */ opInnerProduct, /* . */ opBind, /* ∘ */ opAtop, /* ⍤ */ opOver, /* ⍥ */ 0, /* @ */ 0, /* ⍠ */ 0, /* ⌺ */ opUnder, /* ⍢ */ opObverse, /* ⍫ */ opSelfReference2, /* ⍙ */ }; /* Monadic operators */ Array * opEach(Datum *lefto, Array *left, Array *right) { int i; if(lefto->tag != FunctionTag) return nil; Array *leftarr; Array *rightarr; if(left){ int rankok = scalarextend(left, right, &leftarr, &rightarr); if(!rankok) throwerror(nil, ERank); }else{ leftarr = nil; rightarr = fnSame(right); } Array *result = allocarray(AtypeArray, rightarr->rank, rightarr->size); for(i = 0; i < rightarr->rank; i++) result->shape[i] = rightarr->shape[i]; for(i = 0; i < rightarr->size; i++){ Array *elem1 = leftarr ? arrayitem(leftarr, i) : nil; Array *elem2 = arrayitem(rightarr, i); result->arraydata[i] = runfunc(lefto->func, elem1, elem2); freearray(elem1); freearray(elem2); } freearray(leftarr); freearray(rightarr); return result; } Array * opSwitch(Datum *lefto, Array *left, Array *right) { if(lefto->tag == ArrayTag){ incref(lefto->array); return lefto->array; }else if(lefto->tag == FunctionTag){ if(left) return runfunc(lefto->func, right, left); else return runfunc(lefto->func, right, right); }else return nil; } Array * opKey(Datum *lefto, Array *left, Array *right) { if(lefto->tag != FunctionTag) throwerror(nil, EType); if(left) return rundfn(L"↑⍵∘(⍶{⍵⍶⍺⌷⍨⊂⍸⍹≡¨⍵}⍺)¨⊂¨∪⍺", lefto, nil, left, right); else return rundfn(L"⍵⍶⌸⍳≢⍵", lefto, nil, left, right); } Array * opOuterProduct(Datum *lefto, Array *left, Array *right) { if(left == nil) throwerror(L"f⌾ expected a left argument", ESyntax); if(lefto->tag != FunctionTag) throwerror(nil, EType); int i; int rank = left->rank + right->rank; int size = 1; int *shape = malloc(sizeof(int) * rank); for(i = 0; i < left->rank; i++){ shape[i] = left->shape[i]; size *= left->shape[i]; } for(i = 0; i < right->rank; i++){ shape[i+left->rank] = right->shape[i]; size *= right->shape[i]; } Array *result = allocarray(AtypeArray, rank, size); for(i = 0; i < rank; i++) result->shape[i] = shape[i]; for(int leftindex = 0; leftindex < left->size; leftindex++){ for(int rightindex = 0; rightindex < right->size; rightindex++){ i = leftindex * right->size + rightindex; Array *leftitem = arrayitem(left, leftindex); Array *rightitem = arrayitem(right, rightindex); result->arraydata[i] = runfunc(lefto->func, leftitem, rightitem); freearray(leftitem); freearray(rightitem); } } free(shape); return result; } Array * opSelfReference1(Datum *lefto, Array *left, Array *right) { DfnFrame *dfn = getcurrentdfn(); if(dfn) return rundfn(dfn->code, lefto, nil, left, right); else{ throwerror(nil, ESyntax); return nil; } } /* Dyadic operators */ Array * opPower(Datum *lefto, Datum *righto, Array *left, Array *right) { Rune *code = nil; if(lefto->tag != FunctionTag) throwerror(nil, EType); if(righto->tag == FunctionTag){ if(left) code = L"next←⍺⍶⍵ ⋄ next⍹⍵:⍵ ⋄ ⍺∇next"; else code = L"next←⍶⍵ ⋄ next⍹⍵:⍵ ⋄ ∇next"; }else if(righto->tag == ArrayTag){ if(righto->array->type != AtypeInt || righto->array->rank != 0 || righto->array->size != 1) throwerror(L"right operand to ⍣", EDomain); vlong times = righto->array->intdata[0]; if(times < 0){ lefto->func = inverse(lefto->func); times = -times; } righto->array->intdata[0] = times; if(left) code = L"⍹=0:⍵ ⋄ ⍺ ⍶⍙(⍹-1)⊢⍺⍶⍵"; else code = L"⍹=0:⍵ ⋄ ⍶⍙(⍹-1)⊢⍶⍵"; } if(code) return rundfn(code, lefto, righto, left, right); else{ throwerror(nil, EDomain); return nil; } } Array * opInnerProduct(Datum *lefto, Datum *righto, Array *left, Array *right) { if(left == nil) throwerror(L"f.g expected a left argument", ESyntax); if(lefto->tag != FunctionTag || righto->tag != FunctionTag) throwerror(nil, EType); if(left->rank > 0 && right->rank > 0 && left->shape[left->rank-1] != right->shape[0]) throwerror(nil, ELength); return rundfn(L"↑(↓⍺)(⍶/⍹¨)⌾⍉↓⍉⍵", lefto, righto, left, right); } Array * opBind(Datum *lefto, Datum *righto, Array *left, Array *right) { if(lefto->tag == FunctionTag && righto->tag == FunctionTag){ Array *right1 = runfunc(righto->func, nil, right); Array *result = runfunc(lefto->func, left, right1); freearray(right1); return result; }else if(lefto->tag == FunctionTag && righto->tag == ArrayTag){ if(left) throwerror(L"The function doesn't take a left argument", ESyntax); return runfunc(lefto->func, right, righto->array); }else if(lefto->tag == ArrayTag && righto->tag == FunctionTag){ if(left) throwerror(L"The function doesn't take a left argument", ESyntax); return runfunc(righto->func, lefto->array, right); }else return nil; } Array * opAtop(Datum *lefto, Datum *righto, Array *left, Array *right) { if(lefto->tag == FunctionTag && righto->tag == FunctionTag){ Array *right1; if(left) right1 = runfunc(righto->func, left, right); else right1 = runfunc(righto->func, nil, right); Array *result = runfunc(lefto->func, nil, right1); freearray(right1); return result; }else if(lefto->tag == FunctionTag && righto->tag == ArrayTag){ Array *ranks = righto->array; if(ranks->rank > 1) throwerror(nil, ERank); if(ranks->type != AtypeInt) throwerror(nil, EType); if(ranks->size < 1 || ranks->size > 3) throwerror(nil, ELength); int p,q,r; switch(ranks->size){ case 1: p = q = r = ranks->intdata[0]; break; case 2: q = ranks->intdata[0]; p = r = ranks->intdata[1]; break; case 3: p = ranks->intdata[0]; q = ranks->intdata[1]; r = ranks->intdata[2]; break; default: p = q = r = 0; } print("Running %S with ranks %d %d %d\n", ppdatum(*lefto), p, q, r); if(left) throwerror(nil, ENotImplemented); else{ } throwerror(nil, ENotImplemented); return nil; }else return nil; } Array * opUnder(Datum *lefto, Datum *righto, Array *left, Array *right) { if(lefto->tag != FunctionTag || righto->tag != FunctionTag) throwerror(L"⍢ operands must be functions", EDomain); if(left) return rundfn(L"⍹⍣¯1 ⊢ (⍹ ⍺) ⍶ ⍹ ⍵", lefto, righto, left, right); else return rundfn(L"⍹⍣¯1 ⍶ ⍹ ⍵", lefto, righto, left, right); } Array * opObverse(Datum *lefto, Datum *righto, Array *left, Array *right) { if(lefto->tag != FunctionTag || righto->tag != FunctionTag) throwerror(L"⍫ operands must be functions", EDomain); return runfunc(lefto->func, left, right); } Array * opOver(Datum *lefto, Datum *righto, Array *left, Array *right) { if(lefto->tag != FunctionTag || righto->tag != FunctionTag) return nil; if(left){ Array *r = runfunc(righto->func, nil, right); Array *l = runfunc(righto->func, nil, left); Array *res = runfunc(lefto->func, l, r); freearray(r); freearray(l); return res; }else{ Array *tmp = runfunc(righto->func, nil, right); Array *res = runfunc(lefto->func, nil, tmp); freearray(tmp); return res; } } Array * opSelfReference2(Datum *lefto, Datum *righto, Array *left, Array *right) { DfnFrame *dfn = getcurrentdfn(); if(dfn) return rundfn(dfn->code, lefto, righto, left, right); else{ throwerror(nil, ESyntax); return nil; } }