1112 lines · 24.0 KB · C
RawDownload
#include "inc/priv.h"#include "inc/str.h"#include "inc/bitvector.h"#include "inc/operators.h"#include "inc/cvalues.h"#include "inc/ieee754.h"#include "inc/print.h"#include "inc/read.h" enum {	SMALL_STR_LEN = 24,}; #define LOG2_10 3.321928094887362347870319429489 #define cons_index(c) (ptr(sl_aligned, c)-(sl_aligned*)slvm.fromspace)#define ismarked(c) bitvector_get(sl.consflags, cons_index(c))#define mark_cons(c) bitvector_set(sl.consflags, cons_index(c))#define unmark_cons(c) bitvector_reset(sl.consflags, cons_index(c)) sl_v sl_printreadablysym, sl_printprettysym;static sl_v rmarginsym, circlesym;static sl_v lengthsym, levelsym, widthsym;static sl_v radixsym, basesym;static sl_v ptrradixsym, ptrbasesym;static sl_v syntaxsugarsym; static inline voidoutc(char c){	if(sl_unlikely(ios_putc(sl.pr.f, c) != 1))		cthrow(error(sl_errio, "write failed"), c);	if(sl_likely(c != '\n'))		sl.pr.x += sl_wcwidth(c);	else		sl.pr.x = 0;} sl_nonnull(1)static inline voidoutsn(const char *s, usize n){	if(sl_unlikely(ios_write(sl.pr.f, s, n) != n))		cthrow(error(sl_errio, "write failed"), s);	const char *nl = sl_memrchr(s, '\n', n);	bool err;	if(sl_likely(nl == nil))		sl.pr.x += u8_strwidth(s, n, &err);	else if(sl_unlikely((nl+1-s) < (intptr)n))		sl.pr.x = u8_strwidth(nl+1, s+n-nl-1, &err);} sl_nonnull(1)static inline voidouts(const char *s){	outsn(s, strlen(s));} #define outsc(s) do{ \	const char vs[] = s; \	outsn(vs, sizeof(vs)-1); \}while(0) static intoutindent(int n){	// move back to left margin if we get too indented	if(sl.pr.rmargin >= 0 && n > sl.pr.rmargin-12)		n = 2;	int n0 = n;	if(sl_unlikely(ios_putc(sl.pr.f, '\n') != 1))		goto err;	sl.pr.y++;	sl.pr.x = n;	while(n){		if(sl_unlikely(ios_putc(sl.pr.f, ' ') != 1))			goto err;		n--;	}	return n0;err:	cthrow(error(sl_errio, "write failed"), n);} static intprint_radix_prefix(bool radix, int base){	if(!radix)		return 0;	switch(base){	case 2: outsc("#b"); return 0;	case 8: outsc("#o"); return 0;	case 10: outsc("#d"); return 0;	case 16: outsc("#x"); return 0;	default: return ios_printf(sl.pr.f, "#%dr", base);	}} static intprint_num(u64int x, int base){	char tmp[64+1]; 	if(sl_unlikely(base == 32)){		u8int d[8] = {x>>56, x>>48, x>>40, x>>32, x>>24, x>>16, x>>8, x};		int n;		for(n = 0; n < 7 && d[n] == 0; n++);		n = enc32(tmp, sizeof(tmp), d+n, sizeof(d)-n);		return n > 0 ? (int)ios_write(sl.pr.f, tmp, n) : 0;	} 	char *s = uint2str(tmp, sizeof(tmp), x, base);	return ios_write(sl.pr.f, s, tmp+sizeof(tmp)-1-s);} sl_nonnull(1)static voidprint_str(const char *str, usize sz){	char buf[64];	u8int c;	static const char hexdig[] = "0123456789abcdef"; 	usize i = 0;	if(!u8_isvalid(str, sz)){		// alternate print algorithm that preserves data if it's not UTF-8		for(; i < sz; i++){			c = str[i];			if(sl_unlikely(c == '\\'))				outsc("\\\\");			else if(sl_unlikely(c == '"'))				outsc("\\\"");			else if(sl_likely(c >= 32 && c < 0x7f))				outc(c);			else{				outsc("\\x");				outc(hexdig[c>>4]);				outc(hexdig[c&0xf]);			}		}	}else{		while(i < sz){			usize n = u8_escape(buf, sizeof(buf), str, &i, sz, true, false);			outsn(buf, n-1);		}	}} voidsl_print_chr(char c){	outc(c);} voidsl_print_str(const char *s, bool princ){	if(sl_likely(princ))		outs(s);	else		print_str(s, strlen(s));} voidsl_print_traverse(sl_v v){	sl_v *bp;	while(iscons(v)){		if(ismarked(v)){			bp = (sl_v*)ptrhash_bp(&sl.pr.conses, (void*)v);			if(*bp == (sl_v)HT_NOTFOUND)				*bp = fixnum(sl.pr.label++);			return;		}		mark_cons(v);		sl_print_traverse(car_(v));		v = cdr_(v);	}	if(!ismanaged(v) || issym(v))		return;	if(ismarked(v)){		bp = (sl_v*)ptrhash_bp(&sl.pr.conses, (void*)v);		if(*bp == (sl_v)HT_NOTFOUND)			*bp = fixnum(sl.pr.label++);	}else if(isvec(v)){		if(vec_size(v) > 0)			mark_cons(v);		for(int i = 0; i < vec_size(v); i++)			sl_print_traverse(vec_elt(v, i));	}else if(isfn(v)){		mark_cons(v);		sl_fn *f = ptr(sl_fn, v);		sl_print_traverse(f->bcode);		sl_print_traverse(f->vals);		sl_print_traverse(f->env);	}else if(iscvalue(v)){		sl_cv *cv = ptr(sl_cv, v);		// don't consider shared references to "" and numbers		if(!valid_numtype(cv_numtype(cv)) && (!cv_isstr(cv) || cv_len(cv) != 0))			mark_cons(v);		const sl_type *t = cv_class(cv);		if(t->vtable != nil && t->vtable->print_traverse != nil)			t->vtable->print_traverse(v);	}} sl_nonnull(1)static voidprint_sym_name(const char *name){	int i;	bool escape = false, charescape = false; 	if((name[0] == '\0') ||		(name[0] == '.' && name[1] == '\0') ||		(name[0] == '#') ||		sl_read_numtok(name, nil, 0))		escape = true;	i = 0;	while(name[i]){		if(sl_unlikely(!symchar(name[i]))){			escape = true;			if(name[i] == '|' || name[i] == '\\'){				charescape = true;				break;			}		}		i++;	}	if(sl_unlikely(escape)){		if(charescape){			outc('|');			i = 0;			while(name[i]){				if(name[i] == '|' || name[i] == '\\')					outc('\\');				outc(name[i]);				i++;			}			outc('|');		}else{			outc('|');			outs(name);			outc('|');		}	}else{		outs(name);	}} /*  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.*/static inline inttinyp(sl_v v){	if(issym(v)){		const char *s = sym_name(v);		bool err;		return u8_strwidth(s, strlen(s), &err) < SMALL_STR_LEN;	}	if(isstr(v))		return cvalue_len(v) < SMALL_STR_LEN;	if(iscvalue(v))		return valid_numtype(cvalue_numtype(v));	return isfixnum(v) || isunboxed(v) || isbuiltin(v) || isespecial(v);} static boolsmallp(sl_v v){	if(tinyp(v))		return true;	if(sl_unlikely(sl_isnum(v)))		return true;	if(iscons(v)){		if(tinyp(car_(v)) &&		   (tinyp(cdr_(v)) || (iscons(cdr_(v)) && tinyp(car_(cdr_(v))) && cdr_(cdr_(v)) == sl_nil)))			return true;		return false;	}	if(isvec(v)){		usize s = vec_size(v);		return (			s == 0 ||			(tinyp(vec_elt(v, 0)) && (s == 1 || (s == 2 && tinyp(vec_elt(v, 1)))))		);	}	return false;} static intspecialindent(sl_v head){	// indent these forms 2 spaces, not lined up with the first argument	if(head == sl_lambda || head == sl_trycatch || head == sl_defsym ||		head == sl_defmacrosym || head == sl_forsym)		return 2;	return -1;} static intlengthestimate(sl_v v){	// get the width of an expression if we can do so cheaply	if(issym(v)){		const char *s = sym_name(v);		bool err;		return u8_strwidth(s, strlen(s), &err);	}	if(sl_isrune(v))		return 4;	return -1;} static intallsmallp(sl_v v){	int n = 1;	while(iscons(v)){		if(!smallp(car_(v)))			return 0;		v = cdr_(v);		n++;		if(n > 25)			return n;	}	return n;} static intindentafter3(sl_v head, sl_v v){	// for certain X always indent (X a b c) after b	return head == sl_forsym && !allsmallp(cdr_(v));} static intindentafter2(sl_v head, sl_v v){	// for certain X always indent (X a b) after a	return (head == sl_defsym || head == sl_defmacrosym) && !allsmallp(cdr_(v));} static boolindentevery(sl_v v){	// indent before every subform of a special form, unless every	// subform is "small"	sl_v c = car_(v);	if(sl_unlikely(c == sl_lambda || c == sl_setqsym))		return false;	//if(c == sl.IF) // TODO: others	//	return !allsmallp(cdr_(v));	return false;} static boolblockindent(sl_v 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;} static voidprint_cons(sl_v v){	const char *op;	bool circle = sl.pr.circle;	if(sl.pr.syntax_sugar && iscons(cdr_(v)) &&	   cdr_(cdr_(v)) == sl_nil &&	   !ptrhash_has(&sl.pr.conses, (void*)cdr_(v)) &&	   ((car_(v) == sl_quote     && (op = "'"))  ||	    (car_(v) == sl_backquote && (op = "`"))  ||	    (car_(v) == sl_comma     && (op = ","))  ||	    (car_(v) == sl_commaat   && (op = ",@")) ||	    (car_(v) == sl_commadot  && (op = ",.")))){		// special prefix syntax		if(circle){			unmark_cons(v);			unmark_cons(cdr_(v));		}		outs(op);		sl_print_child(car_(cdr_(v)));		return;	}	int startpos = sl.pr.x;	outc('(');	int newindent = sl.pr.x;	int lastv, n = 0, si, ind, est, nextsmall, thistiny;	bool always = false, blk = blockindent(v);	if(sl_likely(!blk))		always = indentevery(v);	sl_v head = car_(v);	int after3 = indentafter3(head, v);	int after2 = indentafter2(head, v);	int n_unindented = 1;	sl_v cd;	while(1){		cd = cdr_(v);		if(sl_unlikely(sl.pr.length >= 0 && n >= sl.pr.length)){			outsc("...)");			break;		}		lastv = sl.pr.y;		if(circle)			unmark_cons(v);		sl_print_child(car_(v));		if(!iscons(cd) || ptrhash_has(&sl.pr.conses, (void*)cd)){			if(cd != sl_nil){				outsc(" . ");				sl_print_child(cd);			}			outc(')');			break;		} 		if(!sl.pr.pretty ||			(head == sl_lambda && n == 0)){			// never break line before lambda-list			ind = 0;		}else{			est = lengthestimate(car_(cd));			nextsmall = smallp(car_(cd));			thistiny = tinyp(car_(v));			ind = ((sl.pr.y > lastv || (sl.pr.rmargin >= 0 && sl.pr.x > sl.pr.rmargin/2 && !nextsmall && !thistiny && n>0)) ||				   (sl.pr.rmargin >= 0 && sl.pr.x > sl.pr.rmargin-4) ||				   (sl.pr.rmargin >= 0 && est != -1 && sl.pr.x+est > sl.pr.rmargin-2) ||				   (head == sl_lambda && !nextsmall) ||				   (n > 0 && always) ||				   (n == 2 && after3) ||				   (n == 1 && after2) ||				   (n_unindented >= 3 && !nextsmall) ||				   (n == 0 && !smallp(head)));		} 		if(ind){			newindent = outindent(newindent);			n_unindented = 1;		}else{			n_unindented++;			outc(' ');			if(n == 0){				// set indent level after printing head				si = specialindent(head);				if(si != -1)					newindent = startpos + si;				else if(!blk)					newindent = sl.pr.x;			}		}		n++;		v = cd;	}} static void unboxed_print(sl_v v);static void cvalue_print(sl_v v);static void rune_print(Rune r); static boolprint_circle_prefix(sl_v v){	sl_v label;	if((label = (sl_v)ptrhash_get(&sl.pr.conses, (void*)v)) != (sl_v)HT_NOTFOUND){		if(!ismarked(v)){			int n = ios_printf(sl.pr.f, "#%"PRIdPTR"#", (intptr)numval(label));			if(sl_unlikely(n < 1))				cthrow(error(sl_errio, "write failed"), v);			sl.pr.x += n;			return true;		}		int n = ios_printf(sl.pr.f, "#%"PRIdPTR"=", (intptr)numval(label));		if(sl_unlikely(n < 1))			cthrow(error(sl_errio, "write failed"), v);		sl.pr.x += n;	}	if(ismanaged(v))		unmark_cons(v);	return false;} voidsl_print_child(sl_v v){	const char *name;	if(sl_unlikely(sl.pr.level >= 0 && sl.pr.p_level >= sl.pr.level && (iscons(v) || isvec(v) || isfn(v)))){		outc('#');		return;	}

Lines 1–500 of 1112.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t