2008-11-23 02:12:37 -05:00
|
|
|
static htable_t printconses;
|
2008-08-02 12:18:39 -04:00
|
|
|
static u_int32_t printlabel;
|
2008-08-04 21:43:12 -04:00
|
|
|
static int print_pretty;
|
2008-09-10 22:37:38 -04:00
|
|
|
static int SCR_WIDTH = 80;
|
2008-06-30 21:54:22 -04:00
|
|
|
|
|
|
|
static int HPOS, VPOS;
|
2008-08-17 14:16:31 -04:00
|
|
|
static void outc(char c, ios_t *f)
|
2008-06-30 21:54:22 -04:00
|
|
|
{
|
2008-08-17 14:16:31 -04:00
|
|
|
ios_putc(c, f);
|
2008-06-30 21:54:22 -04:00
|
|
|
HPOS++;
|
|
|
|
}
|
2008-08-17 14:16:31 -04:00
|
|
|
static void outs(char *s, ios_t *f)
|
2008-06-30 21:54:22 -04:00
|
|
|
{
|
2008-08-17 14:16:31 -04:00
|
|
|
ios_puts(s, f);
|
2008-06-30 21:54:22 -04:00
|
|
|
HPOS += u8_strwidth(s);
|
|
|
|
}
|
2009-01-03 00:30:22 -05:00
|
|
|
static int outindent(int n, ios_t *f)
|
2008-06-30 21:54:22 -04:00
|
|
|
{
|
2009-01-03 00:30:22 -05:00
|
|
|
// move back to left margin if we get too indented
|
|
|
|
if (n > SCR_WIDTH-12)
|
|
|
|
n = 2;
|
|
|
|
int n0 = n;
|
2008-08-17 14:16:31 -04:00
|
|
|
ios_putc('\n', f);
|
2008-06-30 21:54:22 -04:00
|
|
|
VPOS++;
|
|
|
|
HPOS = n;
|
|
|
|
while (n >= 8) {
|
2008-08-17 14:16:31 -04:00
|
|
|
ios_putc('\t', f);
|
2008-06-30 21:54:22 -04:00
|
|
|
n -= 8;
|
|
|
|
}
|
|
|
|
while (n) {
|
2008-08-17 14:16:31 -04:00
|
|
|
ios_putc(' ', f);
|
2008-06-30 21:54:22 -04:00
|
|
|
n--;
|
|
|
|
}
|
2009-01-03 00:30:22 -05:00
|
|
|
return n0;
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
|
2008-12-20 01:16:00 -05:00
|
|
|
void fl_print_chr(char c, ios_t *f)
|
|
|
|
{
|
|
|
|
outc(c, f);
|
|
|
|
}
|
|
|
|
|
|
|
|
void fl_print_str(char *s, ios_t *f)
|
|
|
|
{
|
|
|
|
outs(s, f);
|
|
|
|
}
|
|
|
|
|
2008-11-28 16:44:59 -05:00
|
|
|
void print_traverse(value_t v)
|
2008-06-30 21:54:22 -04:00
|
|
|
{
|
|
|
|
value_t *bp;
|
|
|
|
while (iscons(v)) {
|
|
|
|
if (ismarked(v)) {
|
|
|
|
bp = (value_t*)ptrhash_bp(&printconses, (void*)v);
|
2008-11-23 02:12:37 -05:00
|
|
|
if (*bp == (value_t)HT_NOTFOUND)
|
2008-06-30 21:54:22 -04:00
|
|
|
*bp = fixnum(printlabel++);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
mark_cons(v);
|
|
|
|
print_traverse(car_(v));
|
|
|
|
v = cdr_(v);
|
|
|
|
}
|
|
|
|
if (!ismanaged(v) || issymbol(v))
|
|
|
|
return;
|
2008-08-04 21:43:12 -04:00
|
|
|
if (ismarked(v)) {
|
|
|
|
bp = (value_t*)ptrhash_bp(&printconses, (void*)v);
|
2008-11-23 02:12:37 -05:00
|
|
|
if (*bp == (value_t)HT_NOTFOUND)
|
2008-08-04 21:43:12 -04:00
|
|
|
*bp = fixnum(printlabel++);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (isvector(v)) {
|
|
|
|
mark_cons(v);
|
|
|
|
unsigned int i;
|
|
|
|
for(i=0; i < vector_size(v); i++)
|
|
|
|
print_traverse(vector_elt(v,i));
|
|
|
|
}
|
2009-01-02 18:00:21 -05:00
|
|
|
else if (iscprim(v)) {
|
|
|
|
mark_cons(v);
|
|
|
|
}
|
2008-08-04 21:43:12 -04:00
|
|
|
else {
|
|
|
|
assert(iscvalue(v));
|
|
|
|
cvalue_t *cv = (cvalue_t*)ptr(v);
|
|
|
|
// don't consider shared references to ""
|
2008-12-10 23:04:17 -05:00
|
|
|
if (!cv_isstr(cv) || cv_len(cv)!=0)
|
2008-06-30 21:54:22 -04:00
|
|
|
mark_cons(v);
|
2008-12-20 01:16:00 -05:00
|
|
|
fltype_t *t = cv_class(cv);
|
|
|
|
if (t->vtable != NULL && t->vtable->print_traverse != NULL)
|
|
|
|
t->vtable->print_traverse(v);
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-08-17 14:16:31 -04:00
|
|
|
static void print_symbol_name(ios_t *f, char *name)
|
2008-06-30 21:54:22 -04:00
|
|
|
{
|
|
|
|
int i, escape=0, charescape=0;
|
|
|
|
|
|
|
|
if ((name[0] == '\0') ||
|
|
|
|
(name[0] == '.' && name[1] == '\0') ||
|
|
|
|
(name[0] == '#') ||
|
|
|
|
isnumtok(name, NULL))
|
|
|
|
escape = 1;
|
|
|
|
i=0;
|
|
|
|
while (name[i]) {
|
|
|
|
if (!symchar(name[i])) {
|
|
|
|
escape = 1;
|
|
|
|
if (name[i]=='|' || name[i]=='\\') {
|
|
|
|
charescape = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
if (escape) {
|
|
|
|
if (charescape) {
|
|
|
|
outc('|', f);
|
|
|
|
i=0;
|
|
|
|
while (name[i]) {
|
|
|
|
if (name[i]=='|' || name[i]=='\\')
|
|
|
|
outc('\\', f);
|
|
|
|
outc(name[i], f);
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
outc('|', f);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
outc('|', f);
|
|
|
|
outs(name, f);
|
|
|
|
outc('|', f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
outs(name, f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
The following implements a simple pretty-printing algorithm. This is
|
|
|
|
an unlimited-width approach that doesn't require an extra pass.
|
|
|
|
It uses some heuristics to guess whether an expression is "small",
|
|
|
|
and avoids wrapping symbols across lines. The result is high
|
|
|
|
performance and nice output for typical code. Quality is poor for
|
|
|
|
pathological or deeply-nested expressions, but those are difficult
|
|
|
|
to print anyway.
|
|
|
|
*/
|
2009-02-23 21:21:16 -05:00
|
|
|
#define SMALL_STR_LEN 20
|
2008-06-30 21:54:22 -04:00
|
|
|
static inline int tinyp(value_t v)
|
|
|
|
{
|
2009-01-03 00:30:22 -05:00
|
|
|
if (issymbol(v))
|
2009-02-23 21:21:16 -05:00
|
|
|
return (u8_strwidth(symbol_name(v)) < SMALL_STR_LEN);
|
|
|
|
if (isstring(v))
|
|
|
|
return (cv_len((cvalue_t*)ptr(v)) < SMALL_STR_LEN);
|
2009-01-03 00:30:22 -05:00
|
|
|
return (isfixnum(v) || isbuiltinish(v));
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int smallp(value_t v)
|
|
|
|
{
|
|
|
|
if (tinyp(v)) return 1;
|
|
|
|
if (isnumber(v)) return 1;
|
|
|
|
if (iscons(v)) {
|
|
|
|
if (tinyp(car_(v)) && (tinyp(cdr_(v)) ||
|
|
|
|
(iscons(cdr_(v)) && tinyp(car_(cdr_(v))) &&
|
|
|
|
cdr_(cdr_(v))==NIL)))
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (isvector(v)) {
|
|
|
|
size_t s = vector_size(v);
|
|
|
|
return (s == 0 || (tinyp(vector_elt(v,0)) &&
|
|
|
|
(s == 1 || (s == 2 &&
|
|
|
|
tinyp(vector_elt(v,1))))));
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-08-04 21:43:12 -04:00
|
|
|
static int specialindent(value_t head)
|
2008-06-30 21:54:22 -04:00
|
|
|
{
|
|
|
|
// indent these forms 2 spaces, not lined up with the first argument
|
switching to scheme #t, #f, and () values
porting code to sort out which NILs are false and which are
empty lists
switching to scheme-style special forms. however you feel about
scheme names vs. CL names, using both is silly.
mostly switching to scheme predicate names, with compatibility
aliases for now. adding set-constant! to make this efficient.
adding null?, eqv?, assq, assv, assoc, memq, memv, member
adding 2-argument form of if
allowing else as final cond condition
looking for init file in same directory as executable, so flisp
can be started from anywhere
renaming T to FL_T, since exporting a 1-character symbol is
not very nice
adding opaque type boilerplate example file
adding correctness checking for the pattern-lambda benchmark
bugfix in int2str
2009-01-28 20:04:23 -05:00
|
|
|
if (head == LAMBDA || head == TRYCATCH || head == definesym ||
|
2008-08-04 21:43:12 -04:00
|
|
|
head == defmacrosym || head == forsym || head == labelsym)
|
2008-06-30 21:54:22 -04:00
|
|
|
return 2;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int lengthestimate(value_t v)
|
|
|
|
{
|
|
|
|
// get the width of an expression if we can do so cheaply
|
|
|
|
if (issymbol(v))
|
|
|
|
return u8_strwidth(symbol_name(v));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int allsmallp(value_t v)
|
|
|
|
{
|
|
|
|
int n = 1;
|
|
|
|
while (iscons(v)) {
|
|
|
|
if (!smallp(car_(v)))
|
|
|
|
return 0;
|
|
|
|
v = cdr_(v);
|
|
|
|
n++;
|
|
|
|
if (n > 25)
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2008-08-04 21:43:12 -04:00
|
|
|
static int indentafter3(value_t head, value_t v)
|
|
|
|
{
|
|
|
|
// for certain X always indent (X a b c) after b
|
switching to scheme #t, #f, and () values
porting code to sort out which NILs are false and which are
empty lists
switching to scheme-style special forms. however you feel about
scheme names vs. CL names, using both is silly.
mostly switching to scheme predicate names, with compatibility
aliases for now. adding set-constant! to make this efficient.
adding null?, eqv?, assq, assv, assoc, memq, memv, member
adding 2-argument form of if
allowing else as final cond condition
looking for init file in same directory as executable, so flisp
can be started from anywhere
renaming T to FL_T, since exporting a 1-character symbol is
not very nice
adding opaque type boilerplate example file
adding correctness checking for the pattern-lambda benchmark
bugfix in int2str
2009-01-28 20:04:23 -05:00
|
|
|
return ((head == forsym) && !allsmallp(cdr_(v)));
|
|
|
|
}
|
|
|
|
|
|
|
|
static int indentafter2(value_t head, value_t v)
|
|
|
|
{
|
|
|
|
// for certain X always indent (X a b) after a
|
|
|
|
return ((head == definesym || head == defmacrosym) &&
|
2008-08-04 21:43:12 -04:00
|
|
|
!allsmallp(cdr_(v)));
|
|
|
|
}
|
|
|
|
|
2008-06-30 21:54:22 -04:00
|
|
|
static int indentevery(value_t v)
|
|
|
|
{
|
|
|
|
// indent before every subform of a special form, unless every
|
|
|
|
// subform is "small"
|
|
|
|
value_t c = car_(v);
|
2009-01-03 00:30:22 -05:00
|
|
|
if (c == LAMBDA || c == labelsym || c == setqsym)
|
2008-06-30 21:54:22 -04:00
|
|
|
return 0;
|
|
|
|
value_t f;
|
|
|
|
if (issymbol(c) && (f=((symbol_t*)ptr(c))->syntax) && isspecial(f))
|
|
|
|
return !allsmallp(cdr_(v));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int blockindent(value_t v)
|
|
|
|
{
|
|
|
|
// in this case we switch to block indent mode, where the head
|
|
|
|
// is no longer considered special:
|
|
|
|
// (a b c d e
|
|
|
|
// f g h i j)
|
|
|
|
return (allsmallp(v) > 9);
|
|
|
|
}
|
|
|
|
|
2008-08-17 14:16:31 -04:00
|
|
|
static void print_pair(ios_t *f, value_t v, int princ)
|
2008-06-30 21:54:22 -04:00
|
|
|
{
|
|
|
|
value_t cd;
|
|
|
|
char *op = NULL;
|
|
|
|
if (iscons(cdr_(v)) && cdr_(cdr_(v)) == NIL &&
|
|
|
|
!ptrhash_has(&printconses, (void*)cdr_(v)) &&
|
|
|
|
(((car_(v) == QUOTE) && (op = "'")) ||
|
|
|
|
((car_(v) == BACKQUOTE) && (op = "`")) ||
|
|
|
|
((car_(v) == COMMA) && (op = ",")) ||
|
|
|
|
((car_(v) == COMMAAT) && (op = ",@")) ||
|
|
|
|
((car_(v) == COMMADOT) && (op = ",.")))) {
|
|
|
|
// special prefix syntax
|
|
|
|
unmark_cons(v);
|
|
|
|
unmark_cons(cdr_(v));
|
|
|
|
outs(op, f);
|
2008-12-20 01:16:00 -05:00
|
|
|
fl_print_child(f, car_(cdr_(v)), princ);
|
2008-06-30 21:54:22 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
int startpos = HPOS;
|
|
|
|
outc('(', f);
|
|
|
|
int newindent=HPOS, blk=blockindent(v);
|
2009-01-03 00:30:22 -05:00
|
|
|
int lastv, n=0, si, ind=0, est, always=0, nextsmall, thistiny;
|
2008-06-30 21:54:22 -04:00
|
|
|
if (!blk) always = indentevery(v);
|
|
|
|
value_t head = car_(v);
|
2008-08-04 21:43:12 -04:00
|
|
|
int after3 = indentafter3(head, v);
|
switching to scheme #t, #f, and () values
porting code to sort out which NILs are false and which are
empty lists
switching to scheme-style special forms. however you feel about
scheme names vs. CL names, using both is silly.
mostly switching to scheme predicate names, with compatibility
aliases for now. adding set-constant! to make this efficient.
adding null?, eqv?, assq, assv, assoc, memq, memv, member
adding 2-argument form of if
allowing else as final cond condition
looking for init file in same directory as executable, so flisp
can be started from anywhere
renaming T to FL_T, since exporting a 1-character symbol is
not very nice
adding opaque type boilerplate example file
adding correctness checking for the pattern-lambda benchmark
bugfix in int2str
2009-01-28 20:04:23 -05:00
|
|
|
int after2 = indentafter2(head, v);
|
2009-01-03 00:30:22 -05:00
|
|
|
int n_unindented = 1;
|
2008-06-30 21:54:22 -04:00
|
|
|
while (1) {
|
|
|
|
lastv = VPOS;
|
|
|
|
unmark_cons(v);
|
2008-12-20 01:16:00 -05:00
|
|
|
fl_print_child(f, car_(v), princ);
|
2008-06-30 21:54:22 -04:00
|
|
|
cd = cdr_(v);
|
|
|
|
if (!iscons(cd) || ptrhash_has(&printconses, (void*)cd)) {
|
|
|
|
if (cd != NIL) {
|
|
|
|
outs(" . ", f);
|
2008-12-20 01:16:00 -05:00
|
|
|
fl_print_child(f, cd, princ);
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
outc(')', f);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-08-04 21:43:12 -04:00
|
|
|
if (princ || !print_pretty ||
|
|
|
|
((head == LAMBDA || head == labelsym) && n == 0)) {
|
2008-06-30 21:54:22 -04:00
|
|
|
// never break line before lambda-list or in princ
|
|
|
|
ind = 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
est = lengthestimate(car_(cd));
|
|
|
|
nextsmall = smallp(car_(cd));
|
2009-01-03 00:30:22 -05:00
|
|
|
thistiny = tinyp(car_(v));
|
|
|
|
ind = (((VPOS > lastv) ||
|
|
|
|
(HPOS>SCR_WIDTH/2 && !nextsmall && !thistiny && n>0)) ||
|
2008-08-04 21:43:12 -04:00
|
|
|
|
2009-01-03 00:30:22 -05:00
|
|
|
(HPOS > SCR_WIDTH-4) ||
|
2008-06-30 21:54:22 -04:00
|
|
|
|
2009-01-03 00:30:22 -05:00
|
|
|
(est!=-1 && (HPOS+est > SCR_WIDTH-2)) ||
|
2008-06-30 21:54:22 -04:00
|
|
|
|
2008-08-04 21:43:12 -04:00
|
|
|
((head == LAMBDA || head == labelsym) && !nextsmall) ||
|
|
|
|
|
|
|
|
(n > 0 && always) ||
|
2008-06-30 21:54:22 -04:00
|
|
|
|
2008-10-30 22:50:00 -04:00
|
|
|
(n == 2 && after3) ||
|
switching to scheme #t, #f, and () values
porting code to sort out which NILs are false and which are
empty lists
switching to scheme-style special forms. however you feel about
scheme names vs. CL names, using both is silly.
mostly switching to scheme predicate names, with compatibility
aliases for now. adding set-constant! to make this efficient.
adding null?, eqv?, assq, assv, assoc, memq, memv, member
adding 2-argument form of if
allowing else as final cond condition
looking for init file in same directory as executable, so flisp
can be started from anywhere
renaming T to FL_T, since exporting a 1-character symbol is
not very nice
adding opaque type boilerplate example file
adding correctness checking for the pattern-lambda benchmark
bugfix in int2str
2009-01-28 20:04:23 -05:00
|
|
|
(n == 1 && after2) ||
|
2008-10-30 22:50:00 -04:00
|
|
|
|
2009-01-03 00:30:22 -05:00
|
|
|
(n_unindented >= 3 && !nextsmall) ||
|
|
|
|
|
2008-10-30 22:50:00 -04:00
|
|
|
(n == 0 && !smallp(head)));
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ind) {
|
2009-01-03 00:30:22 -05:00
|
|
|
newindent = outindent(newindent, f);
|
|
|
|
n_unindented = 1;
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
else {
|
2009-01-03 00:30:22 -05:00
|
|
|
n_unindented++;
|
2008-06-30 21:54:22 -04:00
|
|
|
outc(' ', f);
|
|
|
|
if (n==0) {
|
|
|
|
// set indent level after printing head
|
|
|
|
si = specialindent(head);
|
|
|
|
if (si != -1)
|
|
|
|
newindent = startpos + si;
|
|
|
|
else if (!blk)
|
|
|
|
newindent = HPOS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
n++;
|
|
|
|
v = cd;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-11 15:16:40 -04:00
|
|
|
static void cvalue_print(ios_t *f, value_t v, int princ);
|
2008-06-30 21:54:22 -04:00
|
|
|
|
2008-12-20 01:16:00 -05:00
|
|
|
void fl_print_child(ios_t *f, value_t v, int princ)
|
2008-06-30 21:54:22 -04:00
|
|
|
{
|
|
|
|
value_t label;
|
|
|
|
char *name;
|
|
|
|
|
|
|
|
switch (tag(v)) {
|
2008-08-04 21:43:12 -04:00
|
|
|
case TAG_NUM :
|
2008-08-17 14:16:31 -04:00
|
|
|
case TAG_NUM1: HPOS+=ios_printf(f, "%ld", numval(v)); break;
|
2008-06-30 21:54:22 -04:00
|
|
|
case TAG_SYM:
|
|
|
|
name = symbol_name(v);
|
|
|
|
if (princ)
|
|
|
|
outs(name, f);
|
|
|
|
else if (ismanaged(v)) {
|
|
|
|
outs("#:", f);
|
|
|
|
outs(name, f);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
print_symbol_name(f, name);
|
|
|
|
break;
|
|
|
|
case TAG_BUILTIN:
|
switching to scheme #t, #f, and () values
porting code to sort out which NILs are false and which are
empty lists
switching to scheme-style special forms. however you feel about
scheme names vs. CL names, using both is silly.
mostly switching to scheme predicate names, with compatibility
aliases for now. adding set-constant! to make this efficient.
adding null?, eqv?, assq, assv, assoc, memq, memv, member
adding 2-argument form of if
allowing else as final cond condition
looking for init file in same directory as executable, so flisp
can be started from anywhere
renaming T to FL_T, since exporting a 1-character symbol is
not very nice
adding opaque type boilerplate example file
adding correctness checking for the pattern-lambda benchmark
bugfix in int2str
2009-01-28 20:04:23 -05:00
|
|
|
if (v == FL_T) {
|
|
|
|
outs("#t", f);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (v == FL_F) {
|
|
|
|
outs("#f", f);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (v == NIL) {
|
|
|
|
outs("()", f);
|
|
|
|
break;
|
|
|
|
}
|
2008-06-30 21:54:22 -04:00
|
|
|
if (isbuiltin(v)) {
|
2009-03-10 15:29:30 -04:00
|
|
|
if (!princ)
|
|
|
|
outs("#.", f);
|
2008-06-30 21:54:22 -04:00
|
|
|
outs(builtin_names[uintval(v)], f);
|
|
|
|
break;
|
|
|
|
}
|
2008-12-21 00:55:00 -05:00
|
|
|
label = (value_t)ptrhash_get(&reverse_dlsym_lookup_table, ptr(v));
|
|
|
|
if (label == (value_t)HT_NOTFOUND) {
|
|
|
|
HPOS += ios_printf(f, "#<builtin @0x%08lx>",
|
|
|
|
(unsigned long)(builtin_t)ptr(v));
|
|
|
|
}
|
|
|
|
else {
|
2009-03-10 15:29:30 -04:00
|
|
|
if (princ)
|
|
|
|
outs(symbol_name(label), f);
|
|
|
|
else
|
|
|
|
HPOS += ios_printf(f, "#builtin(%s)", symbol_name(label));
|
2008-12-21 00:55:00 -05:00
|
|
|
}
|
2008-08-04 21:43:12 -04:00
|
|
|
break;
|
|
|
|
case TAG_CVALUE:
|
2009-01-02 18:00:21 -05:00
|
|
|
case TAG_CPRIM:
|
2009-03-11 10:52:37 -04:00
|
|
|
if (v == UNBOUND) { outs("#<undefined>", f); break; }
|
2008-08-04 21:43:12 -04:00
|
|
|
case TAG_VECTOR:
|
2008-06-30 21:54:22 -04:00
|
|
|
case TAG_CONS:
|
|
|
|
if ((label=(value_t)ptrhash_get(&printconses, (void*)v)) !=
|
2008-11-23 02:12:37 -05:00
|
|
|
(value_t)HT_NOTFOUND) {
|
2008-06-30 21:54:22 -04:00
|
|
|
if (!ismarked(v)) {
|
2008-08-17 14:16:31 -04:00
|
|
|
HPOS+=ios_printf(f, "#%ld#", numval(label));
|
2008-06-30 21:54:22 -04:00
|
|
|
return;
|
|
|
|
}
|
2008-08-17 14:16:31 -04:00
|
|
|
HPOS+=ios_printf(f, "#%ld=", numval(label));
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
if (isvector(v)) {
|
|
|
|
outc('[', f);
|
|
|
|
int newindent = HPOS, est;
|
|
|
|
unmark_cons(v);
|
|
|
|
int i, sz = vector_size(v);
|
|
|
|
for(i=0; i < sz; i++) {
|
2008-12-20 01:16:00 -05:00
|
|
|
fl_print_child(f, vector_elt(v,i), princ);
|
2008-06-30 21:54:22 -04:00
|
|
|
if (i < sz-1) {
|
|
|
|
if (princ) {
|
|
|
|
outc(' ', f);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
est = lengthestimate(vector_elt(v,i+1));
|
2009-01-03 00:30:22 -05:00
|
|
|
if (HPOS > SCR_WIDTH-4 ||
|
|
|
|
(est!=-1 && (HPOS+est > SCR_WIDTH-2)) ||
|
|
|
|
(HPOS > SCR_WIDTH/2 &&
|
|
|
|
!smallp(vector_elt(v,i+1)) &&
|
|
|
|
!tinyp(vector_elt(v,i))))
|
|
|
|
newindent = outindent(newindent, f);
|
2008-06-30 21:54:22 -04:00
|
|
|
else
|
|
|
|
outc(' ', f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
outc(']', f);
|
|
|
|
break;
|
|
|
|
}
|
2009-01-02 18:00:21 -05:00
|
|
|
if (iscvalue(v) || iscprim(v)) {
|
2008-06-30 21:54:22 -04:00
|
|
|
unmark_cons(v);
|
|
|
|
cvalue_print(f, v, princ);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
print_pair(f, v, princ);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-11 15:16:40 -04:00
|
|
|
static void print_string(ios_t *f, char *str, size_t sz)
|
2008-06-30 21:54:22 -04:00
|
|
|
{
|
|
|
|
char buf[512];
|
|
|
|
size_t i = 0;
|
|
|
|
|
|
|
|
outc('"', f);
|
|
|
|
while (i < sz) {
|
|
|
|
u8_escape(buf, sizeof(buf), str, &i, sz, 1, 0);
|
|
|
|
outs(buf, f);
|
|
|
|
}
|
|
|
|
outc('"', f);
|
|
|
|
}
|
|
|
|
|
|
|
|
static numerictype_t sym_to_numtype(value_t type);
|
|
|
|
|
|
|
|
// 'weak' means we don't need to accurately reproduce the type, so
|
|
|
|
// for example #int32(0) can be printed as just 0. this is used
|
|
|
|
// printing in a context where a type is already implied, e.g. inside
|
|
|
|
// an array.
|
2008-08-17 14:16:31 -04:00
|
|
|
static void cvalue_printdata(ios_t *f, void *data, size_t len, value_t type,
|
2008-06-30 21:54:22 -04:00
|
|
|
int princ, int weak)
|
|
|
|
{
|
|
|
|
int64_t tmp=0;
|
|
|
|
|
2008-12-23 23:43:36 -05:00
|
|
|
if (type == bytesym) {
|
2008-06-30 21:54:22 -04:00
|
|
|
unsigned char ch = *(unsigned char*)data;
|
|
|
|
if (princ)
|
|
|
|
outc(ch, f);
|
|
|
|
else if (weak)
|
2008-12-23 23:43:36 -05:00
|
|
|
HPOS+=ios_printf(f, "0x%hhx", ch);
|
2008-06-30 21:54:22 -04:00
|
|
|
else
|
2008-12-23 23:43:36 -05:00
|
|
|
HPOS+=ios_printf(f, "#byte(0x%hhx)", ch);
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
else if (type == wcharsym) {
|
|
|
|
uint32_t wc = *(uint32_t*)data;
|
|
|
|
char seq[8];
|
2008-12-23 23:43:36 -05:00
|
|
|
if (princ || iswprint(wc)) {
|
2008-06-30 21:54:22 -04:00
|
|
|
size_t nb = u8_toutf8(seq, sizeof(seq), &wc, 1);
|
|
|
|
seq[nb] = '\0';
|
|
|
|
// TODO: better multibyte handling
|
|
|
|
if (!princ) outs("#\\", f);
|
|
|
|
outs(seq, f);
|
|
|
|
}
|
2008-12-23 23:43:36 -05:00
|
|
|
else if (weak) {
|
|
|
|
HPOS+=ios_printf(f, "%d", (int)wc);
|
|
|
|
}
|
2008-06-30 21:54:22 -04:00
|
|
|
else {
|
2008-08-17 14:16:31 -04:00
|
|
|
HPOS+=ios_printf(f, "#%s(%d)", symbol_name(type), (int)wc);
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (type == int64sym
|
|
|
|
#ifdef BITS64
|
|
|
|
|| type == longsym
|
|
|
|
#endif
|
|
|
|
) {
|
|
|
|
int64_t i64 = *(int64_t*)data;
|
|
|
|
if (fits_fixnum(i64) || princ) {
|
|
|
|
if (weak || princ)
|
2008-08-17 14:16:31 -04:00
|
|
|
HPOS+=ios_printf(f, "%lld", i64);
|
2008-06-30 21:54:22 -04:00
|
|
|
else
|
2008-08-17 14:16:31 -04:00
|
|
|
HPOS+=ios_printf(f, "#%s(%lld)", symbol_name(type), i64);
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
else
|
2008-08-17 14:16:31 -04:00
|
|
|
HPOS+=ios_printf(f, "#%s(0x%08x%08x)", symbol_name(type),
|
|
|
|
(uint32_t)(i64>>32),
|
|
|
|
(uint32_t)(i64));
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
else if (type == uint64sym
|
|
|
|
#ifdef BITS64
|
|
|
|
|| type == ulongsym
|
|
|
|
#endif
|
|
|
|
) {
|
|
|
|
uint64_t ui64 = *(uint64_t*)data;
|
|
|
|
if (fits_fixnum(ui64) || princ) {
|
|
|
|
if (weak || princ)
|
2008-08-17 14:16:31 -04:00
|
|
|
HPOS+=ios_printf(f, "%llu", ui64);
|
2008-06-30 21:54:22 -04:00
|
|
|
else
|
2008-08-17 14:16:31 -04:00
|
|
|
HPOS+=ios_printf(f, "#%s(%llu)", symbol_name(type), ui64);
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
else
|
2008-08-17 14:16:31 -04:00
|
|
|
HPOS+=ios_printf(f, "#%s(0x%08x%08x)", symbol_name(type),
|
|
|
|
(uint32_t)(ui64>>32),
|
|
|
|
(uint32_t)(ui64));
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
else if (type == floatsym || type == doublesym) {
|
|
|
|
char buf[64];
|
|
|
|
double d;
|
2008-08-16 17:15:36 -04:00
|
|
|
int ndec;
|
|
|
|
if (type == floatsym) { d = (double)*(float*)data; ndec = 8; }
|
|
|
|
else { d = *(double*)data; ndec = 16; }
|
2008-11-23 02:12:37 -05:00
|
|
|
if (!DFINITE(d)) {
|
|
|
|
char *rep;
|
|
|
|
if (isnan(d))
|
|
|
|
rep = sign_bit(d) ? "-NaN" : "+NaN";
|
|
|
|
else
|
|
|
|
rep = sign_bit(d) ? "-Inf" : "+Inf";
|
2009-03-11 10:52:37 -04:00
|
|
|
if (type == floatsym && !princ && !weak)
|
2008-11-23 02:12:37 -05:00
|
|
|
HPOS+=ios_printf(f, "#%s(%s)", symbol_name(type), rep);
|
|
|
|
else
|
2009-03-11 10:52:37 -04:00
|
|
|
outs(rep, f);
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
2009-01-31 20:53:58 -05:00
|
|
|
else if (d == 0) {
|
|
|
|
if (1/d < 0)
|
2009-03-11 10:52:37 -04:00
|
|
|
outs("-0.0", f);
|
2009-01-31 20:53:58 -05:00
|
|
|
else
|
2009-03-11 10:52:37 -04:00
|
|
|
outs("0.0", f);
|
|
|
|
if (type == floatsym && !princ && !weak)
|
|
|
|
outc('f', f);
|
2009-01-31 20:53:58 -05:00
|
|
|
}
|
2008-06-30 21:54:22 -04:00
|
|
|
else {
|
2008-11-23 02:12:37 -05:00
|
|
|
snprint_real(buf, sizeof(buf), d, 0, ndec, 3, 10);
|
2009-01-31 20:53:58 -05:00
|
|
|
int hasdec = (strpbrk(buf, ".eE") != NULL);
|
|
|
|
outs(buf, f);
|
2009-03-10 15:29:30 -04:00
|
|
|
if (!hasdec) outs(".0", f);
|
2009-03-11 10:52:37 -04:00
|
|
|
if (type == floatsym && !princ && !weak)
|
|
|
|
outc('f', f);
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (issymbol(type)) {
|
|
|
|
// handle other integer prims. we know it's smaller than 64 bits
|
|
|
|
// at this point, so int64 is big enough to capture everything.
|
|
|
|
tmp = conv_to_int64(data, sym_to_numtype(type));
|
|
|
|
if (fits_fixnum(tmp) || princ) {
|
|
|
|
if (weak || princ)
|
2008-08-17 14:16:31 -04:00
|
|
|
HPOS+=ios_printf(f, "%lld", tmp);
|
2008-06-30 21:54:22 -04:00
|
|
|
else
|
2008-08-17 14:16:31 -04:00
|
|
|
HPOS+=ios_printf(f, "#%s(%lld)", symbol_name(type), tmp);
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
else
|
2008-08-17 14:16:31 -04:00
|
|
|
HPOS+=ios_printf(f, "#%s(0x%08x)", symbol_name(type),
|
|
|
|
(uint32_t)(tmp&0xffffffff));
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
else if (iscons(type)) {
|
|
|
|
if (car_(type) == arraysym) {
|
|
|
|
value_t eltype = car(cdr_(type));
|
|
|
|
size_t cnt, elsize;
|
|
|
|
if (iscons(cdr_(cdr_(type)))) {
|
|
|
|
cnt = toulong(car_(cdr_(cdr_(type))), "length");
|
|
|
|
elsize = cnt ? len/cnt : 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// incomplete array type
|
|
|
|
int junk;
|
|
|
|
elsize = ctype_sizeof(eltype, &junk);
|
|
|
|
cnt = elsize ? len/elsize : 0;
|
|
|
|
}
|
2008-12-23 23:43:36 -05:00
|
|
|
if (eltype == bytesym) {
|
2008-06-30 21:54:22 -04:00
|
|
|
if (princ) {
|
2008-08-17 14:16:31 -04:00
|
|
|
ios_write(f, data, len);
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
print_string(f, (char*)data, len);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if (eltype == wcharsym) {
|
|
|
|
// TODO wchar
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
}
|
|
|
|
size_t i;
|
|
|
|
if (!weak) {
|
|
|
|
outs("#array(", f);
|
2008-12-20 01:16:00 -05:00
|
|
|
fl_print_child(f, eltype, princ);
|
2008-08-28 23:27:59 -04:00
|
|
|
if (cnt > 0)
|
|
|
|
outc(' ', f);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
outc('[', f);
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
for(i=0; i < cnt; i++) {
|
2008-08-28 23:27:59 -04:00
|
|
|
if (i > 0)
|
2008-06-30 21:54:22 -04:00
|
|
|
outc(' ', f);
|
2008-08-28 23:27:59 -04:00
|
|
|
cvalue_printdata(f, data, elsize, eltype, princ, 1);
|
2008-06-30 21:54:22 -04:00
|
|
|
data += elsize;
|
|
|
|
}
|
|
|
|
if (!weak)
|
|
|
|
outc(')', f);
|
2008-08-28 23:27:59 -04:00
|
|
|
else
|
|
|
|
outc(']', f);
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
else if (car_(type) == enumsym) {
|
2009-03-11 15:16:40 -04:00
|
|
|
int n = *(int*)data;
|
|
|
|
value_t syms = car(cdr_(type));
|
|
|
|
assert(isvector(syms));
|
2008-06-30 21:54:22 -04:00
|
|
|
if (!weak) {
|
|
|
|
outs("#enum(", f);
|
2009-03-11 15:16:40 -04:00
|
|
|
fl_print_child(f, syms, princ);
|
2008-06-30 21:54:22 -04:00
|
|
|
outc(' ', f);
|
|
|
|
}
|
2009-03-11 15:16:40 -04:00
|
|
|
if (n >= (int)vector_size(syms)) {
|
2008-06-30 21:54:22 -04:00
|
|
|
cvalue_printdata(f, data, len, int32sym, princ, 1);
|
|
|
|
}
|
|
|
|
else {
|
2009-03-11 15:16:40 -04:00
|
|
|
fl_print_child(f, vector_elt(syms, n), princ);
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
if (!weak)
|
|
|
|
outc(')', f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-11 15:16:40 -04:00
|
|
|
static void cvalue_print(ios_t *f, value_t v, int princ)
|
2008-06-30 21:54:22 -04:00
|
|
|
{
|
|
|
|
cvalue_t *cv = (cvalue_t*)ptr(v);
|
2009-01-02 18:00:21 -05:00
|
|
|
void *data = cptr(v);
|
2008-06-30 21:54:22 -04:00
|
|
|
|
2008-12-20 01:16:00 -05:00
|
|
|
if (cv_class(cv) == builtintype) {
|
2008-12-10 23:04:17 -05:00
|
|
|
HPOS+=ios_printf(f, "#<builtin @0x%08lx>",
|
|
|
|
(unsigned long)(builtin_t)data);
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
2008-12-20 01:16:00 -05:00
|
|
|
else if (cv_class(cv)->vtable != NULL &&
|
|
|
|
cv_class(cv)->vtable->print != NULL) {
|
|
|
|
cv_class(cv)->vtable->print(v, f, princ);
|
|
|
|
}
|
|
|
|
else {
|
2009-01-02 18:00:21 -05:00
|
|
|
value_t type = cv_type(cv);
|
|
|
|
size_t len = iscprim(v) ? cv_class(cv)->size : cv_len(cv);
|
|
|
|
cvalue_printdata(f, data, len, type, princ, 0);
|
2008-12-20 01:16:00 -05:00
|
|
|
}
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
|
2008-09-10 22:37:38 -04:00
|
|
|
static void set_print_width()
|
|
|
|
{
|
|
|
|
value_t pw = symbol_value(printwidthsym);
|
|
|
|
if (!isfixnum(pw)) return;
|
|
|
|
SCR_WIDTH = numval(pw);
|
|
|
|
}
|
|
|
|
|
2008-08-17 14:16:31 -04:00
|
|
|
void print(ios_t *f, value_t v, int princ)
|
2008-06-30 21:54:22 -04:00
|
|
|
{
|
switching to scheme #t, #f, and () values
porting code to sort out which NILs are false and which are
empty lists
switching to scheme-style special forms. however you feel about
scheme names vs. CL names, using both is silly.
mostly switching to scheme predicate names, with compatibility
aliases for now. adding set-constant! to make this efficient.
adding null?, eqv?, assq, assv, assoc, memq, memv, member
adding 2-argument form of if
allowing else as final cond condition
looking for init file in same directory as executable, so flisp
can be started from anywhere
renaming T to FL_T, since exporting a 1-character symbol is
not very nice
adding opaque type boilerplate example file
adding correctness checking for the pattern-lambda benchmark
bugfix in int2str
2009-01-28 20:04:23 -05:00
|
|
|
print_pretty = (symbol_value(printprettysym) != FL_F);
|
2008-09-10 22:37:38 -04:00
|
|
|
if (print_pretty)
|
|
|
|
set_print_width();
|
2008-06-30 21:54:22 -04:00
|
|
|
printlabel = 0;
|
|
|
|
print_traverse(v);
|
|
|
|
HPOS = VPOS = 0;
|
2008-09-10 22:37:38 -04:00
|
|
|
|
2008-12-20 01:16:00 -05:00
|
|
|
fl_print_child(f, v, princ);
|
2008-09-10 22:37:38 -04:00
|
|
|
|
2008-11-23 02:12:37 -05:00
|
|
|
htable_reset(&printconses, 32);
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|