#include #include #include #include "apl9.h" void strdims(Rune *, int *, int *); Rune *printborder(Rune *, int *, int, int); Rune * ppdatum(Datum d) { Rune *result; switch(d.tag){ case ArrayTag: result = pparray(d.array); break; case FunctionTag: if(d.func.type == FunctypePrim) result = runesmprint("%C", primfuncnames[d.func.code]); else if(d.func.type == FunctypeDfn) result = runesmprint("{%S}", d.func.dfn); else result = runesmprint("%S", ppoperator(d.func.operator)); break; case HybridTag: result = runesmprint("%C", primhybridnames[d.func.code]); break; case MonadicOpTag: case DyadicOpTag: result = ppoperator(d.operator); break; case BoundFunctionTag: if(d.func.type == FunctypePrim) result = runesmprint("%S∘%C", pparray(d.func.left), primfuncnames[d.func.code]); else if(d.func.type == FunctypeDfn) result = runesmprint("%S∘{%S}", pparray(d.func.left), d.func.dfn); else result = runesmprint("%S∘%S", pparray(d.func.left), ppoperator(d.func.operator)); break; case LParTag: result = runestrdup(L"("); break; case RParTag: result = runestrdup(L")"); break; case LBracketTag: result = runestrdup(L"["); break; case RBracketTag: result = runestrdup(L"]"); break; case ArrowTag: result = runestrdup(L"←"); break; case AssignmentTag: result = runesmprint("%S←", d.symbol->name); break; case NameTag: result = runestrdup(d.symbol->name); break; default: result = runesmprint("", d.tag); } return result; } Rune * ppdatums(Datum *ds, int n) { int i; Rune *res = runesmprint(""); Rune *tmp; for(i = 0; i < n; i++){ tmp = res; res = runesmprint("%S %S", res, ppdatum(ds[i])); free(tmp); } return res; } Rune * pparray(Array *a) { Rune **elemstrs = malloc(sizeof(Rune *) * a->size); int rowcount = 1; if(a->rank > 0){ for(int i = 0; i < a->rank-1; i++) rowcount *= a->shape[i]; } Rune **rowstrs = mallocz(sizeof(Rune *) * rowcount, 1); int boxing = a->type == AtypeArray; char *align = a->type == AtypeArray ? "-" : ""; for(int i = 0; i < a->size; i++){ if(a->type == AtypeArray){ Rune *arrstr = pparray(a->arraydata[i]); elemstrs[i] = runesmprint("%S", arrstr); free(arrstr); }else if(a->type == AtypeInt) elemstrs[i] = runesmprint("%lld", a->intdata[i]); } int lastdim = a->rank ? a->shape[a->rank-1] : 1; int *widths = mallocz(sizeof(int) * lastdim, 1); for(int i = 0; i < a->size; i++){ int w,h; strdims(elemstrs[i], &w, &h); if(w > widths[i%lastdim]) widths[i%lastdim] = w; } /* Should do height padding here as well */ for(int i = 0; i < a->size; i++){ if(i%lastdim == 0) rowstrs[i/lastdim] = runesmprint("%S", boxing ? L"│" : L""); Rune *tmp = rowstrs[i/lastdim]; char *fmt = smprint("%%%s%dS", align, widths[i%lastdim]); Rune *elem = runesmprint(fmt, elemstrs[i]); Rune *spacing; if((i+1)%lastdim == 0) spacing = boxing ? L"│" : L""; else spacing = boxing ? L"│" : L" "; rowstrs[i/lastdim] = runesmprint("%S%S%S", tmp, elem, spacing); free(tmp); free(elem); free(fmt); free(elemstrs[i]); } free(elemstrs); if(rowstrs[0] == nil) rowstrs[0] = runestrdup(L""); if(rowcount == 1 && !boxing) return rowstrs[0]; Rune *res = runesmprint(""); Rune *tmp; for(int i = 0; i < rowcount; i++){ if(i == 0 && boxing) res = printborder(res, widths, lastdim, 0); int j = 1; int blanks = 0; for(int dim = 0; dim < a->rank - 1 && i+1 != a->size; dim++){ j *= a->shape[a->rank-dim-2]; if(i%j == 0) blanks++; } if(i != 0 && blanks == 0 && boxing) res = printborder(res, widths, lastdim, 1); if(i != 0 && blanks > 0 && boxing) res = printborder(res, widths, lastdim, 2); for(int b = 0; i != 0 && b < blanks; b++){ tmp = res; res = runesmprint("%S\n", tmp); free(tmp); } if(blanks > 0 && i != 0 && i < rowcount-1 && boxing) res = printborder(res, widths, lastdim, 0); tmp = res; res = runesmprint("%S%S\n", tmp, rowstrs[i]); free(tmp); if(i == rowcount-1 && boxing) res = printborder(res, widths, lastdim, 2); } res[runestrlen(res)-1] = 0; /* remove trailing newline */ return res; } Rune * ppoperator(Operator op) { Rune *left = op.left ? ppdatum(*op.left) : runestrdup(L""); Rune *right = op.right ? ppdatum(*op.right) : runestrdup(L""); Rune *res; if(op.type == OperatortypeDop) res = runesmprint("(%S{%S}%S)", left, op.dop, right); else{ res = runesmprint("(%S%C%S)", left, op.dyadic ? primdyadopnames[op.code] : primmonopnames[op.code], right); } free(left); free(right); return res; } void strdims(Rune *s, int *width, int *height) { int currentwidth = 0; *width = 0; *height = 1; int len = runestrlen(s); int i; for(i = 0; i < len; i++){ if(s[i] == '\n'){ (*height)++; if(currentwidth > *width) *width = currentwidth; currentwidth = 0; }else currentwidth++; } if(currentwidth > *width) *width = currentwidth; } Rune * printborder(Rune *input, int *widths, int lastdim, int type) { Rune *borderchars = L"????"; switch(type){ case 0: borderchars = L"┌─┬┐"; break; case 1: borderchars = L"├─┼┤"; break; case 2: borderchars = L"└─┴┘"; break; } int width = 1; for(int i = 0; i < lastdim; i++) width += widths[i]+1; Rune *border = malloc(sizeof(Rune) * width + 1); border[width] = 0; border[0] = borderchars[0]; border[width-1] = borderchars[3]; for(int i = 1; i < width-1; i++) border[i] = borderchars[1]; int offset = 1; for(int i = 0; i < lastdim-1; i++){ offset += widths[i]; border[offset] = borderchars[2]; offset++; } Rune *result = runesmprint("%S%S\n", input, border); //free(border); //free(input); return result; }