ref: c8c59b1dfc38561e21a16e97bbf7325e62b1a0e1
parent: 6f934a817b7347109eb189f29c01cb48246c0b02
author: JeffBezanson <jeff.bezanson@gmail.com>
date: Wed Sep 10 22:37:38 EDT 2008
added globals *install-dir* and *print-width*, parameterized prettyprinter by screen width decent accumulate-while and accumulate-for
--- a/femtolisp/builtins.c
+++ b/femtolisp/builtins.c
@@ -254,14 +254,6 @@
type_error(fname, "number", a);
}
-static value_t return_from_cstr(char *str)
-{
- size_t n = strlen(str);
- value_t v = cvalue_string(n);
- memcpy(cvalue_data(v), str, n);
- return v;
-}
-
value_t fl_time_string(value_t *args, uint32_t nargs)
{
argcount("time.string", nargs, 1);
@@ -268,7 +260,7 @@
double t = value_to_double(args[0], "time.string");
char buf[64];
timestring(t, buf, sizeof(buf));
- return return_from_cstr(buf);
+ return string_from_cstr(buf);
}
value_t fl_path_cwd(value_t *args, uint32_t nargs)
@@ -278,7 +270,7 @@
if (nargs == 0) {
char buf[1024];
get_cwd(buf, sizeof(buf));
- return return_from_cstr(buf);
+ return string_from_cstr(buf);
}
char *ptr = tostring(args[0], "path.cwd");
if (set_cwd(ptr))
@@ -294,7 +286,7 @@
if (val == NULL) return NIL;
if (*val == 0)
return symbol_value(emptystringsym);
- return cvalue_pinned_cstring(val);
+ return cvalue_static_cstring(val);
}
value_t fl_os_setenv(value_t *args, uint32_t nargs)
--- a/femtolisp/cvalues.c
+++ b/femtolisp/cvalues.c
@@ -176,7 +176,7 @@
return cv;
}
-value_t cvalue_pinned_cstring(char *str)
+value_t cvalue_static_cstring(char *str)
{
value_t v = cvalue_from_ref(symbol_value(stringtypesym), str, strlen(str),
NIL);
@@ -184,6 +184,14 @@
return v;
}
+value_t string_from_cstr(char *str)
+{
+ size_t n = strlen(str);
+ value_t v = cvalue_string(n);
+ memcpy(cvalue_data(v), str, n);
+ return v;
+}
+
int isstring(value_t v)
{
return (iscvalue(v) && ((cvalue_t*)ptr(v))->flags.cstring);
@@ -956,7 +964,7 @@
setc(wcstringtypesym, list2(arraysym, wcharsym));
emptystringsym = symbol("*empty-string*");
- setc(emptystringsym, cvalue_pinned_cstring(""));
+ setc(emptystringsym, cvalue_static_cstring(""));
}
#define RETURN_NUM_AS(var, type) return(mk_##type((type##_t)var))
--- a/femtolisp/flisp.c
+++ b/femtolisp/flisp.c
@@ -80,6 +80,7 @@
value_t DivideError, BoundsError, Error;
value_t conssym, symbolsym, fixnumsym, vectorsym, builtinsym;
value_t defunsym, defmacrosym, forsym, labelsym, printprettysym;
+value_t printwidthsym;
static value_t eval_sexpr(value_t e, uint32_t penv, int tail);
static value_t *alloc_words(int n);
@@ -826,14 +827,15 @@
break;
case F_PROGN:
// return last arg
- pv = &Stack[saveSP]; v = NIL;
+ pv = &Stack[saveSP];
if (iscons(*pv)) {
while (iscons(cdr_(*pv))) {
- v = eval(car_(*pv));
+ (void)eval(car_(*pv));
*pv = cdr_(*pv);
}
tail_eval(car_(*pv));
}
+ v = NIL;
break;
case F_TRYCATCH:
v = do_trycatch(car(Stack[saveSP]), penv);
@@ -1124,7 +1126,6 @@
if (selfevaluating(e)) { SP=saveSP; return e; }
SP = penv+2;
goto eval_top;
- break;
case F_RAISE:
argcount("raise", nargs, 1);
raise(Stack[SP-1]);
@@ -1307,6 +1308,8 @@
extern void builtins_init();
extern void comparehash_init();
+static char *EXEDIR;
+
void lisp_init(void)
{
int i;
@@ -1349,6 +1352,7 @@
forsym = symbol("for");
labelsym = symbol("label");
set(printprettysym=symbol("*print-pretty*"), T);
+ set(printwidthsym=symbol("*print-width*"), fixnum(SCR_WIDTH));
lasterror = NIL;
lerrorbuf[0] = '\0';
special_apply_form = fl_cons(builtin(F_SPECIAL_APPLY), NIL);
@@ -1374,6 +1378,15 @@
cvalues_init();
set(symbol("gensym"), guestfunc(gensym));
+
+ char buf[1024];
+ char *exename = get_exename(buf, sizeof(buf));
+ if (exename != NULL) {
+ path_to_dirname(exename);
+ EXEDIR = strdup(exename);
+ setc(symbol("*install-dir*"), cvalue_static_cstring(EXEDIR));
+ }
+
builtins_init();
}
@@ -1462,7 +1475,7 @@
PUSH(NIL);
if (argc > 1) { argc--; argv++; }
for(i=argc-1; i >= 0; i--)
- Stack[SP-1] = fl_cons(cvalue_pinned_cstring(argv[i]), Stack[SP-1]);
+ Stack[SP-1] = fl_cons(cvalue_static_cstring(argv[i]), Stack[SP-1]);
return POP();
}
@@ -1482,11 +1495,11 @@
}
FL_CATCH {
print_toplevel_exception();
-
lerrorbuf[0] = '\0';
lasterror = NIL;
ios_puts("\n\n", ios_stderr);
- goto repl;
+ if (argc > 1) return 1;
+ else goto repl;
}
load_file("system.lsp");
if (argc > 1) { load_file(argv[1]); return 0; }
--- a/femtolisp/flisp.h
+++ b/femtolisp/flisp.h
@@ -249,7 +249,8 @@
value_t size_wrap(size_t sz);
size_t toulong(value_t n, char *fname);
value_t cvalue_string(size_t sz);
-value_t cvalue_pinned_cstring(char *str);
+value_t cvalue_static_cstring(char *str);
+value_t string_from_cstr(char *str);
int isstring(value_t v);
int isnumber(value_t v);
value_t cvalue_compare(value_t a, value_t b);
--- a/femtolisp/print.c
+++ b/femtolisp/print.c
@@ -1,6 +1,8 @@
static ptrhash_t printconses;
static u_int32_t printlabel;
static int print_pretty;
+static int SCR_WIDTH = 80;
+static int R_MARGIN, C_MARGIN, R_EDGE, L_PAD, R_PAD;
static int HPOS, VPOS;
static void outc(char c, ios_t *f)
@@ -250,15 +252,15 @@
est = lengthestimate(car_(cd));
nextsmall = smallp(car_(cd));
ind = (((n > 0) &&
- ((!nextsmall && HPOS>28) || (VPOS > lastv))) ||
+ ((!nextsmall && HPOS>L_PAD) || (VPOS > lastv))) ||
((VPOS > lastv) && (!nextsmall || n==0)) ||
- (HPOS > 50 && !nextsmall) ||
+ (HPOS > R_PAD && !nextsmall) ||
- (HPOS > 74) ||
+ (HPOS > R_MARGIN) ||
- (est!=-1 && (HPOS+est > 78)) ||
+ (est!=-1 && (HPOS+est > R_EDGE)) ||
((head == LAMBDA || head == labelsym) && !nextsmall) ||
@@ -341,8 +343,9 @@
}
else {
est = lengthestimate(vector_elt(v,i+1));
- if (HPOS > 74 || (est!=-1 && (HPOS+est > 78)) ||
- (HPOS > 40 && !smallp(vector_elt(v,i+1))))
+ if (HPOS > R_MARGIN ||
+ (est!=-1 && (HPOS+est > R_EDGE)) ||
+ (HPOS > C_MARGIN && !smallp(vector_elt(v,i+1))))
outindent(newindent, f);
else
outc(' ', f);
@@ -580,12 +583,28 @@
cvalue_printdata(f, data, cv_len(cv), cv_type(cv), princ, 0);
}
+static void set_print_width()
+{
+ value_t pw = symbol_value(printwidthsym);
+ if (!isfixnum(pw)) return;
+ SCR_WIDTH = numval(pw);
+ R_MARGIN = SCR_WIDTH-6;
+ R_EDGE = SCR_WIDTH-2;
+ C_MARGIN = SCR_WIDTH/2;
+ L_PAD = (SCR_WIDTH*7)/20;
+ R_PAD = L_PAD*2;
+}
+
void print(ios_t *f, value_t v, int princ)
{
print_pretty = (symbol_value(printprettysym) != NIL);
- ptrhash_reset(&printconses, 32);
+ if (print_pretty)
+ set_print_width();
printlabel = 0;
print_traverse(v);
HPOS = VPOS = 0;
+
do_print(f, v, princ);
+
+ ptrhash_reset(&printconses, 32);
}
--- a/femtolisp/test.lsp
+++ b/femtolisp/test.lsp
@@ -205,27 +205,41 @@
;(tt)
;(tt)
-(defmacro delay (expr)
- (let ((g (gensym)))
+(let ((g (gensym)))
+ (defmacro delay (expr)
`(let ((,g ',g))
(lambda () (if (eq ,g ',g) (setq ,g ,expr) ,g)))))
+(defun force (p) (p))
+
(defmacro accumulate-while (cnd what . body)
(let ((first (gensym))
- (acc (gensym))
- (forms (f-body body)))
- `(let ((,first (prog1 (cons ,what nil) ,forms))
- (,acc nil))
- (setq ,acc ,first)
+ (acc (gensym)))
+ `(let ((,first nil)
+ (,acc (list nil)))
+ (setq ,first ,acc)
(while ,cnd
- (progn (rplacd ,acc (cons ,what nil))
- (setq ,acc (cdr ,acc))
- ,forms))
- ,first)))
+ (progn (setq ,acc
+ (cdr (rplacd ,acc (cons ,what nil))))
+ ,@body))
+ (cdr ,first))))
+(defmacro accumulate-for (var lo hi what . body)
+ (let ((first (gensym))
+ (acc (gensym)))
+ `(let ((,first nil)
+ (,acc (list nil)))
+ (setq ,first ,acc)
+ (for ,lo ,hi
+ (lambda (,var)
+ (progn (setq ,acc
+ (cdr (rplacd ,acc (cons ,what nil))))
+ ,@body)))
+ (cdr ,first))))
+
(defun map-indexed (f lst)
(if (atom lst) lst
(let ((i 0))
(accumulate-while (consp lst) (f (car lst) i)
- (setq lst (cdr lst))
- (setq i (1+ i))))))
+ (progn (setq lst (cdr lst))
+ (setq i (1+ i)))))))
--- a/femtolisp/todo
+++ b/femtolisp/todo
@@ -778,11 +778,12 @@
design of new toplevel
-system.lsp is compiled into the executable, and contains definitions of
-(load) and (repl).
+system.lsp contains definitions of (load) and (toplevel) and is loaded
+from *install-dir* by a bootstrap loader in C. at the end of system.lsp,
+we check whether (load) is builtin. if it is, we redefine it and reload
+system.lsp with the new loader. the C code then invokes (toplevel).
-start with load bound to bootstrap_load (in C)
-on startup we call load on system, then call it again afterwards
+(toplevel) either runs a script or a repl using (while T (trycatch ...))
(load) reads and evaluates every form, keeping track of defined functions
and macros (at the top level), and grabs a (main ...) form if it sees
--- a/llt/dirpath.c
+++ b/llt/dirpath.c
@@ -24,6 +24,7 @@
#endif
#include "dtypes.h"
+#include "dirpath.h"
void get_cwd(char *buf, size_t size)
{
@@ -44,6 +45,18 @@
return 1;
#endif
return 0;
+}
+
+// destructively convert path to directory part
+void path_to_dirname(char *path)
+{
+ char *sep = strrchr(path, PATHSEP);
+ if (sep != NULL) {
+ *sep = '\0';
+ }
+ else {
+ path[0] = '\0';
+ }
}
#ifdef LINUX
--- a/llt/dirpath.h
+++ b/llt/dirpath.h
@@ -19,5 +19,6 @@
void get_cwd(char *buf, size_t size);
int set_cwd(char *buf);
char *get_exename(char *buf, size_t size);
+void path_to_dirname(char *path);
#endif