#include #include #include #include "apl9.h" int printprecision = 10; void strdims(Rune *, int *, int *); Rune *printborder(Rune *, int *, int, int); Rune *strline(Rune *, int); Rune * ppdatum(Datum *d) { if(d == nil) return runesmprint(""); Rune *result; switch(d->tag){ case ArrayTag: result = pparray(d->array); break; case BoundFunctionTag: case FunctionTag: result = ppfunction(d->func); break; case HybridTag: result = runesmprint("%C", primhybridnames[d->func.code]); break; case MonadicOpTag: case DyadicOpTag: result = ppoperator(d->operator); break; case LParTag: result = runesmprint("(%S", ppdatums(d->stmt.toks, d->stmt.ntoks)); break; case RParTag: result = runestrdup(L")"); break; case ArrowTag: result = runestrdup(L"←"); break; case AssignmentTag: result = runesmprint("(%S)←", ppdatums(d->stmt.toks, d->stmt.ntoks)); break; case NameTag: result = runestrdup(d->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%s", res, ppdatum(ds[i]), (i+1) < n ? " " : ""); free(tmp); } return res; } Rune * pparray(Array *a) { Rune **elemstrs = emalloc(sizeof(Rune *) * GetSize(a)); int rowcount = 1; if(GetRank(a) > 0){ for(int i = 0; i < GetRank(a)-1; i++) rowcount *= a->shape[i]; } Rune **rowstrs = emallocz(sizeof(Rune *) * rowcount, 1); int boxing = !simplearray(a); char *align = GetType(a) == AtypeArray ? "-" : ""; for(int i = 0; i < GetSize(a); i++){ if(GetType(a) == AtypeArray){ Rune *arrstr = pparray(a->arraydata[i]); elemstrs[i] = runesmprint("%S", arrstr); free(arrstr); }else{ Array *e = arrayitem(a, i); /* a scalar */ if(GetType(e) == AtypeInt) elemstrs[i] = runesmprint("%lld", e->intdata[0]); else if(GetType(e) == AtypeRune) elemstrs[i] = runesmprint("%C", e->runedata[0]); else if(GetType(e) == AtypeFloat){ char *fmt = smprint("%%.%df", printprecision); elemstrs[i] = runesmprint(fmt, e->floatdata[0]); free(fmt); Rune *p = &elemstrs[i][runestrlen(elemstrs[i])-1]; int done = 0; while((*p == '0' || *p == '.') && !done){ if(*p == '.') done = 1; *p-- = 0; /* remove trailing 0's */ } } if(elemstrs[i][0] == '-' && (GetType(e) == AtypeInt || GetType(e) == AtypeFloat)) elemstrs[i][0] = L'¯'; freearray(e); } } int lastdim = GetRank(a) ? a->shape[GetRank(a)-1] : 1; int *widths = emallocz(sizeof(int) * lastdim, 1); int *heights = emallocz(sizeof(int) * rowcount, 1); for(int i = 0; i < GetSize(a); i++){ int w,h; strdims(elemstrs[i], &w, &h); if(w > widths[i%lastdim]) widths[i%lastdim] = w; if(h > heights[i/lastdim]) heights[i/lastdim] = h; } Rune *tmp; for(int row = 0; row < rowcount; row++){ rowstrs[row] = runestrdup(L""); for(int y = 0; y < heights[row]; y++){ if(boxing){ tmp = rowstrs[row]; rowstrs[row] = runesmprint("%S│", tmp); free(tmp); } for(int x = 0; x < lastdim; x++){ int i = row * lastdim + x; tmp = rowstrs[row]; char *fmt = smprint("%%%s%dS", align, widths[x]); Rune *line = strline(elemstrs[i], y); Rune *padded = runesmprint(fmt, line); Rune *spacing; if(boxing) spacing = L"│"; else if(x == lastdim - 1 || GetType(a) == AtypeRune) spacing = L""; else spacing = L" "; rowstrs[row] = runesmprint("%S%S%S", tmp, padded, spacing); free(tmp); free(fmt); free(line); free(padded); if(y == heights[row]-1) free(elemstrs[i]); } if(y < heights[row]-1){ tmp = rowstrs[row]; rowstrs[row] = runesmprint("%S\n", tmp); free(tmp); } } } if(rowcount == 1 && !boxing) return rowstrs[0]; Rune *res = runesmprint(""); 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 < GetRank(a) - 1 && i+1 != GetSize(a); dim++){ j *= a->shape[GetRank(a)-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 if(op.type == OperatortypeHybrid){ res = runesmprint("%S%C", left, primhybridnames[op.code]); }else{ res = runesmprint("%S%C%S", left, op.dyadic ? primdyadopnames[op.code] : primmonopnames[op.code], right); } if(op.left || op.right){ Rune *tmp = res; res = runesmprint("(%S)", res); free(tmp); } free(left); free(right); return res; } Rune * ppfunction(Function f) { Rune *result; Rune *left; if(f.left) left = runesmprint("%S∘", pparray(f.left)); else left = runestrdup(L""); switch(f.type){ case FunctypePrim: result = runesmprint("%S%C", left, primfuncnames[f.code]); break; case FunctypeDfn: result = runesmprint("%S{%S}", left, f.dfn); break; case FunctypeOp: result = runesmprint("%S%S", left, ppoperator(f.operator)); break; case FunctypeQuad: result = runesmprint("%S%S", left, f.quad->name); break; case FunctypeTrain: result = runestrdup(left); for(int i = 0; i < f.train.nfuncs; i++){ Rune *tmp = result; Rune *fun = ppfunction(f.train.funcs[i]); result = runesmprint("%S%S", tmp, fun); free(tmp); free(fun); } break; default: result = runesmprint("", f.type); break; } free(left); return result; } 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 = emalloc(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; } Rune * strline(Rune *str, int n) { Rune *start = str; Rune *end = str; int l = 0; while(l