diff options
-rw-r--r-- | ChangeLog | 29 | ||||
-rw-r--r-- | eval.c | 31 | ||||
-rw-r--r-- | lib.c | 56 | ||||
-rw-r--r-- | lib.h | 4 | ||||
-rw-r--r-- | stream.c | 112 | ||||
-rw-r--r-- | stream.h | 4 | ||||
-rw-r--r-- | txr.vim | 43 |
7 files changed, 244 insertions, 35 deletions
@@ -1,5 +1,34 @@ 2011-11-28 Kaz Kylheku <kaz@kylheku.com> + Adding streams functions to Lisp evaluator. + + * eval.c (op_let): Bugfix: was not evaluating var init forms. + (reg_var): New static function. + (eval_init): Registered numerous stream functions and the + three standard streams. + + * lib.c (obj_print, obj_pprint): Modified to return a value. + (init): eval_init called after stream_init, because eval + needs the three standrad streams prepared. + + * lib.h (obj_print, obj_pprint): Declarations updated. + + * stream.c (format): Support t as a shorthand for standard output. + (formatv, open_directory, open_file, open_pipe): New functions. + (w_opendir): New static function. + + * stream.h (formatv, open_directory, open_file, open_pipe): + Declared. + + * txr.vim: set iskeyword such that keyword can contain special + characters. Set b:current_syntax to "lisp". + (txl_keyword): New keyword category populated with TXR Lisp keywords + defined as separate category. + (txr_list): Contains txl_keyword. + (txr_meta): Contains txl_keyword and txr_list. + +2011-11-28 Kaz Kylheku <kaz@kylheku.com> + mapcar, mappend and apply functions. fun operator. @@ -359,7 +359,7 @@ static val op_let(val form, val env) if (!consp(cdr(item))) eval_error(form, lit("let: invalid syntax: ~s"), item, nao); var = first(item); - val = second(item); + val = eval(second(item), env, form); } if (symbolp(var)) { @@ -766,6 +766,11 @@ static void reg_fun(val sym, val fun) sethash(top_fb, sym, cons(sym, fun)); } +static void reg_var(val sym, val obj) +{ + sethash(top_vb, sym, cons(sym, obj)); +} + void eval_init(void) { protect(&top_vb, &top_fb, &op_table, (val *) 0); @@ -858,6 +863,30 @@ void eval_init(void) reg_fun(intern(lit("eval"), user_package), func_n2(eval_intrinsic)); + reg_var(intern(lit("*stdout*"), user_package), std_output); + reg_var(intern(lit("*stdin*"), user_package), std_input); + reg_var(intern(lit("*stderr*"), user_package), std_error); + reg_fun(intern(lit("format"), user_package), func_n2v(formatv)); + reg_fun(intern(lit("print"), user_package), func_n2(obj_print)); + reg_fun(intern(lit("pprint"), user_package), func_n2(obj_pprint)); + reg_fun(intern(lit("make-string-input-stream"), user_package), func_n1(make_string_input_stream)); + reg_fun(intern(lit("make-string-byte-input-stream"), user_package), func_n1(make_string_byte_input_stream)); + reg_fun(intern(lit("make-string-output-stream"), user_package), func_n0(make_string_output_stream)); + reg_fun(intern(lit("get-string-from-stream"), user_package), func_n1(get_string_from_stream)); + reg_fun(intern(lit("make-strlist-output-stream"), user_package), func_n0(make_strlist_output_stream)); + reg_fun(intern(lit("get-list-from-stream"), user_package), func_n1(get_list_from_stream)); + reg_fun(intern(lit("close-stream"), user_package), func_n2(close_stream)); + reg_fun(intern(lit("get-line"), user_package), func_n1(get_line)); + reg_fun(intern(lit("get-char"), user_package), func_n1(get_char)); + reg_fun(intern(lit("get-byte"), user_package), func_n1(get_byte)); + reg_fun(intern(lit("put-string"), user_package), func_n2(put_string)); + reg_fun(intern(lit("put-line"), user_package), func_n2(put_line)); + reg_fun(intern(lit("put-char"), user_package), func_n2(put_char)); + reg_fun(intern(lit("flush-stream"), user_package), func_n1(flush_stream)); + reg_fun(intern(lit("open-directory"), user_package), func_n1(open_directory)); + reg_fun(intern(lit("open-file"), user_package), func_n2(open_file)); + reg_fun(intern(lit("open-pipe"), user_package), func_n2(open_pipe)); + eval_error_s = intern(lit("eval-error"), user_package); uw_register_subtype(eval_error_s, error_s); } @@ -2970,11 +2970,11 @@ static void obj_init(void) prog_string = string(progname); } -void obj_print(val obj, val out) +val obj_print(val obj, val out) { if (obj == nil) { put_string(out, lit("nil")); - return; + return obj; } switch (type(obj)) { @@ -3009,7 +3009,7 @@ void obj_print(val obj, val out) } } } - return; + return obj; case LIT: case STR: { @@ -3036,7 +3036,7 @@ void obj_print(val obj, val out) } put_char(out, chr('"')); } - return; + return obj; case CHR: { wchar_t ch = c_chr(obj); @@ -3060,10 +3060,10 @@ void obj_print(val obj, val out) format(out, lit("x~x"), num(ch), nao); } } - return; + return obj; case NUM: format(out, lit("~s"), obj, nao); - return; + return obj; case SYM: if (obj->s.package != user_package) { if (!obj->s.package) @@ -3073,13 +3073,13 @@ void obj_print(val obj, val out) put_char(out, chr(':')); } put_string(out, symbol_name(obj)); - return; + return obj; case PKG: format(out, lit("#<package: ~s>"), obj->pk.name, nao); - return; + return obj; case FUN: format(out, lit("#<function: type ~a>"), num(obj->f.functype), nao); - return; + return obj; case VEC: { cnum i, fill = c_num(obj->v.vec[vec_fill]); @@ -3091,27 +3091,28 @@ void obj_print(val obj, val out) } put_char(out, chr(')')); } - return; + return obj; case LSTR: obj_print(obj->ls.prefix, out); put_string(out, lit("#<... lazy string>")); - return; + return obj; case COBJ: obj->co.ops->print(obj, out); - return; + return obj; case ENV: format(out, lit("#<environment: ~p>"), (void *) obj, nao); - return; + return obj; } format(out, lit("#<garbage: ~p>"), (void *) obj, nao); + return obj; } -void obj_pprint(val obj, val out) +val obj_pprint(val obj, val out) { if (obj == nil) { put_string(out, lit("nil")); - return; + return obj; } switch (type(obj)) { @@ -3146,26 +3147,26 @@ void obj_pprint(val obj, val out) } } } - return; + return obj; case LIT: case STR: put_string(out, obj); - return; + return obj; case CHR: put_char(out, obj); - return; + return obj; case NUM: format(out, lit("~s"), obj, nao); - return; + return obj; case SYM: put_string(out, symbol_name(obj)); - return; + return obj; case PKG: format(out, lit("#<package: ~s>"), obj->pk.name, nao); - return; + return obj; case FUN: format(out, lit("#<function: type ~a>"), num(obj->f.functype), nao); - return; + return obj; case VEC: { cnum i, fill = c_num(obj->v.vec[vec_fill]); @@ -3177,20 +3178,21 @@ void obj_pprint(val obj, val out) } put_char(out, chr(')')); } - return; + return obj; case LSTR: obj_pprint(obj->ls.prefix, out); put_string(out, lit("...")); - return; + return obj; case COBJ: obj->co.ops->print(obj, out); - return; + return obj; case ENV: format(out, lit("#<environment: ~p>"), (void *) obj, nao); - return; + return obj; } format(out, lit("#<garbage: ~p>"), (void *) obj, nao); + return obj; } void init(const wchar_t *pn, mem_t *(*oom)(mem_t *, size_t), @@ -3204,8 +3206,8 @@ void init(const wchar_t *pn, mem_t *(*oom)(mem_t *, size_t), gc_init(stack_bottom); obj_init(); uw_init(); - eval_init(); stream_init(); + eval_init(); filter_init(); gc_state(gc_save); @@ -489,8 +489,8 @@ val find(val list, val key, val testfun, val keyfun); val set_diff(val list1, val list2, val testfun, val keyfun); val env(void); -void obj_print(val obj, val stream); -void obj_pprint(val obj, val stream); +val obj_print(val obj, val stream); +val obj_pprint(val obj, val stream); void init(const wchar_t *progname, mem_t *(*oom_realloc)(mem_t *, size_t), val *stack_bottom); void dump(val obj, val stream); @@ -1018,7 +1018,9 @@ val vformat_to_string(val fmtstr, va_list vl) val format(val stream, val str, ...) { - val st = or2(stream, make_string_output_stream()); + val st = if3(stream == t, + std_output, + or2(stream, make_string_output_stream())); type_check (st, COBJ); type_assert (st->co.cls == stream_s, (lit("~a is not a stream"), st, nao)); @@ -1032,6 +1034,53 @@ val format(val stream, val str, ...) } } +val formatv(val stream, val string, val args) +{ + val arg[32], *p = arg; + + for (; args && p - arg < 32; args = cdr(args), p++) + *p = car(args); + + switch (p - arg) { + case 0: return format(stream, string, nao); + case 1: return format(stream, string, arg[0], nao); + case 2: return format(stream, string, arg[0], arg[1], nao); + case 3: return format(stream, string, arg[0], arg[1], arg[2], nao); + case 4: return format(stream, string, arg[0], arg[1], arg[2], arg[3], nao); + case 5: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], nao); + case 6: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], nao); + case 7: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], nao); + case 8: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], nao); + case 9: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], nao); + case 10: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], nao); + case 11: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], nao); + case 12: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], nao); + case 13: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], nao); + case 14: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13], nao); + case 15: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13], arg[14], nao); + case 16: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13], arg[14], arg[15], nao); + case 17: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13], arg[14], arg[15], arg[16], nao); + case 18: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13], arg[14], arg[15], arg[16], arg[17], nao); + case 19: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13], arg[14], arg[15], arg[16], arg[17], arg[18], nao); + case 20: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13], arg[14], arg[15], arg[16], arg[17], arg[18], arg[19], nao); + case 21: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13], arg[14], arg[15], arg[16], arg[17], arg[18], arg[19], arg[20], nao); + case 22: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13], arg[14], arg[15], arg[16], arg[17], arg[18], arg[19], arg[20], arg[21], nao); + case 23: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13], arg[14], arg[15], arg[16], arg[17], arg[18], arg[19], arg[20], arg[21], arg[22], nao); + case 24: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13], arg[14], arg[15], arg[16], arg[17], arg[18], arg[19], arg[20], arg[21], arg[22], arg[23], nao); + case 25: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13], arg[14], arg[15], arg[16], arg[17], arg[18], arg[19], arg[20], arg[21], arg[22], arg[23], arg[24], nao); + case 26: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13], arg[14], arg[15], arg[16], arg[17], arg[18], arg[19], arg[20], arg[21], arg[22], arg[23], arg[24], arg[25], nao); + case 27: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13], arg[14], arg[15], arg[16], arg[17], arg[18], arg[19], arg[20], arg[21], arg[22], arg[23], arg[24], arg[25], arg[26], nao); + case 28: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13], arg[14], arg[15], arg[16], arg[17], arg[18], arg[19], arg[20], arg[21], arg[22], arg[23], arg[24], arg[25], arg[26], arg[27], nao); + case 29: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13], arg[14], arg[15], arg[16], arg[17], arg[18], arg[19], arg[20], arg[21], arg[22], arg[23], arg[24], arg[25], arg[26], arg[27], arg[28], nao); + case 30: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13], arg[14], arg[15], arg[16], arg[17], arg[18], arg[19], arg[20], arg[21], arg[22], arg[23], arg[24], arg[25], arg[26], arg[27], arg[28], arg[29], nao); + case 31: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13], arg[14], arg[15], arg[16], arg[17], arg[18], arg[19], arg[20], arg[21], arg[22], arg[23], arg[24], arg[25], arg[26], arg[27], arg[28], arg[29], arg[30], nao); + case 32: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13], arg[14], arg[15], arg[16], arg[17], arg[18], arg[19], arg[20], arg[21], arg[22], arg[23], arg[24], arg[25], arg[26], arg[27], arg[28], arg[29], arg[30], arg[31], nao); + } + + uw_throwf(file_error_s, lit("too many arguments to format"), nao); + abort(); +} + val put_string(val stream, val string) { type_check (stream, COBJ); @@ -1073,6 +1122,67 @@ val flush_stream(val stream) } } +static DIR *w_opendir(const wchar_t *wname) +{ + char *name = (char *) utf8_dup_to(wname); + DIR *d = opendir(name); + free(name); + return d; +} + +val open_directory(val path) +{ + DIR *d = w_opendir(c_str(path)); + + if (!d) + uw_throwf(file_error_s, lit("error opening directory ~a: ~a/~s"), + path, num(errno), string_utf8(strerror(errno)), nao); + + return make_dir_stream(d); +} + +val open_file(val path, val mode_str) +{ + FILE *f = w_fopen(c_str(path), c_str(mode_str)); + val input = nil, output = nil; + + if (!f) + uw_throwf(file_error_s, lit("error opening ~a: ~a/~s"), + path, num(errno), string_utf8(strerror(errno)), nao); + + if (break_str(mode_str, lit("w"))) + output = t; + if (break_str(mode_str, lit("a"))) + output = t; + if (break_str(mode_str, lit("r"))) + input = t; + if (break_str(mode_str, lit("+"))) + input = output = t; + + return make_stdio_stream(f, path, input, output); +} + +val open_pipe(val path, val mode_str) +{ + FILE *f = w_popen(c_str(path), c_str(mode_str)); + val input = nil, output = nil; + + if (!f) + uw_throwf(file_error_s, lit("error opening pipe ~a: ~a/~s"), + path, num(errno), string_utf8(strerror(errno)), nao); + + if (break_str(mode_str, lit("w"))) + output = t; + if (break_str(mode_str, lit("a"))) + output = t; + if (break_str(mode_str, lit("r"))) + input = t; + if (break_str(mode_str, lit("+"))) + input = output = t; + + return make_pipe_stream(f, path, input, output); +} + void stream_init(void) { protect(&std_input, &std_output, &std_error, (val *) 0); @@ -42,9 +42,13 @@ val get_byte(val); val vformat(val stream, val string, va_list); val vformat_to_string(val string, va_list); val format(val stream, val string, ...); +val formatv(val stream, val string, val args); val put_string(val stream, val string); val put_line(val stream, val string); val put_char(val stream, val ch); val flush_stream(val stream); +val open_directory(val path); +val open_file(val path, val mode_str); +val open_pipe(val path, val mode_str); void stream_init(void); @@ -8,7 +8,7 @@ " put this file there. " 2. In your .vimrc, add this command to associate *.txr files " with the txr filetype. -" :au BufRead,BufNewFile *.txr set filetype=txr +" :au BufRead,BufNewFile *.txr set filetype=txr | set lisp " " If you want syntax highlighting to be on automatically (for any language) " you need to add ":syntax on" in your .vimrc also. But you knew that already! @@ -16,6 +16,8 @@ syn case match syn spell toplevel +setlocal iskeyword=a-z,+,-,*,<,>,= + syn keyword txr_keyword contained skip trailer freeform block accept fail syn keyword txr_keyword contained next some all none and or syn keyword txr_keyword contained maybe cases choose gather collect coll until last end @@ -24,7 +26,37 @@ syn keyword txr_keyword contained repeat rep first last single empty syn keyword txr_keyword contained define try catch finally throw syn keyword txr_keyword contained defex throw deffilter filter eof eol -syn match txr_at "@[ \t]*@" +syn keyword txl_keyword contained let lambda call cond if and or defvar defun +syn keyword txl_keyword contained inc dec push pop gethash list append apply +syn keyword txl_keyword contained cons list atom null consp listp proper-listp +syn keyword txl_keyword contained length mapcar mappend apply +syn keyword txl_keyword contained + - * trunc mod numberp > < >= <= max min +syn keyword txl_keyword contained int-str + +syn keyword txl_keyword contained search-regex match-regex + +syn keyword txl_keyword contained make-hash gethash sethash pushhash remhash +syn keyword txl_keyword contained hash-count get-hash-userdata +syn keyword txl_keyword contained set-hash-userdata + +syn keyword txl_keyword contained eval + +syn keyword txl_keyword contained *stdout* *stdin* *stderr* +syn keyword txl_keyword contained format print pprint +syn keyword txl_keyword contained make-string-input-stream +syn keyword txl_keyword contained make-string-byte-input-stream +syn keyword txl_keyword contained make-string-output-stream +syn keyword txl_keyword contained get-string-from-stream +syn keyword txl_keyword contained make-strlist-output-stream +syn keyword txl_keyword contained get-list-from-stream +syn keyword txl_keyword contained close-stream +syn keyword txl_keyword contained get-line get-char get-byte +syn keyword txl_keyword contained put-string put-line put-char +syn keyword txl_keyword contained flush-stream open-directory +syn keyword txl_keyword contained open-file open-pipe + +set lispwords=let open-file + syn match txr_comment "@[ \t]*#.*" syn match txr_contin "@[ \t]*\\$" syn match txr_hashbang "^#!.*" @@ -42,9 +74,9 @@ syn region txr_bracevar matchgroup=Delimiter start="@[ \t]*[*]\?{" matchgroup=De syn region txr_directive matchgroup=Delimiter start="@[ \t]*(" matchgroup=Delimiter end=")" contains=txr_keyword,txr_string,txr_list,txr_meta,txr_quasilit,txr_num,txr_ident,txr_regex,txr_string,txr_variable,txr_chr -syn region txr_list contained matchgroup=Delimiter start="(" matchgroup=Delimiter end=")" contains=txr_string,txr_regex,txr_num,txr_ident,txr_variable,txr_meta,txr_list,txr_quasilit,txr_chr +syn region txr_list contained matchgroup=Delimiter start="(" matchgroup=Delimiter end=")" contains=txl_keyword,txr_string,txr_regex,txr_num,txr_ident,txr_variable,txr_meta,txr_list,txr_quasilit,txr_chr -syn region txr_meta contained matchgroup=Delimiter start="@[ \t]*(" matchgroup=Delimiter end=")" contains=txr_string,txr_regex,txr_num,txr_ident,txr_variable,txr_quasilit,txr_chr +syn region txr_meta contained matchgroup=Delimiter start="@[ \t]*(" matchgroup=Delimiter end=")" contains=txl_keyword,txr_string,txr_list,txr_regex,txr_num,txr_ident,txr_variable,txr_quasilit,txr_chrb syn region txr_string contained oneline start=+"+ skip=+\\\\\|\\"+ end=+"+ syn region txr_quasilit contained oneline start=+`+ skip=+\\\\\|\\`+ end=+`+ contains=txr_directive,txr_variable,txr_bracevar @@ -56,6 +88,7 @@ hi def link txr_hashbang Comment hi def link txr_contin Comment hi def link txr_char String hi def link txr_keyword Keyword +hi def link txl_keyword Keyword hi def link txr_string String hi def link txr_chr String hi def link txr_quasilit String @@ -65,3 +98,5 @@ hi def link txr_variable Identifier hi def link txr_bracevar Identifier hi def link txr_ident Identifier hi def link txr_num Number + +let b:current_syntax = "lisp" |