klisp

an open source interpreter for the Kernel Programming Language.
git clone http://git.hanabi.in/repos/klisp.git
Log | Files | Refs | README

commit b2460708bd14e45c1c32de32dcb55eec5c20a8ea
parent 98e9f11606b8470e2bf27f835e76c01f2651c90d
Author: Andres Navarro <canavarro82@gmail.com>
Date:   Mon, 21 Nov 2011 03:56:26 -0300

Added script running to the new standalone interpreter.

Diffstat:
Msrc/kerror.c | 24+++++++++++++++++-------
Msrc/kerror.h | 17++++++++++++++++-
Msrc/klisp.c | 204+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
Msrc/kport.c | 5+++--
4 files changed, 231 insertions(+), 19 deletions(-)

diff --git a/src/kerror.c b/src/kerror.c @@ -32,6 +32,21 @@ TValue klispE_new(klisp_State *K, TValue who, TValue cont, TValue msg, return gc2error(new_error); } +TValue klispE_new_with_errno_irritants(klisp_State *K, const char *service, + int errnum, TValue irritants) +{ + TValue error_description = klispE_describe_errno(K, service, errnum); + krooted_tvs_push(K, error_description); + TValue all_irritants = kimm_cons(K, error_description, irritants); + krooted_tvs_push(K, all_irritants); + TValue error_obj = klispE_new(K, K->next_obj, K->curr_cont, + kcaddr(error_description), + all_irritants); + krooted_tvs_pop(K); + krooted_tvs_pop(K); + return error_obj; +} + void klispE_free(klisp_State *K, Error *error) { klispM_free(K, error); @@ -105,13 +120,8 @@ void klispE_throw_with_irritants(klisp_State *K, char *msg, TValue irritants) void klispE_throw_system_error_with_irritants( klisp_State *K, const char *service, int errnum, TValue irritants) { - TValue error_description = klispE_describe_errno(K, service, errnum); - krooted_tvs_push(K, error_description); - TValue all_irritants = kimm_cons(K, error_description, irritants); - krooted_tvs_push(K, all_irritants); - TValue error_obj = klispE_new(K, K->next_obj, K->curr_cont, - kcaddr(error_description), - all_irritants); + TValue error_obj = klispE_new_with_errno_irritants(K, service, errnum, + irritants); krooted_tvs_push(K, error_obj); clear_buffers(K); kcall_cont(K, K->system_error_cont, error_obj); diff --git a/src/kerror.h b/src/kerror.h @@ -17,13 +17,28 @@ TValue klispE_new(klisp_State *K, TValue who, TValue cont, TValue msg, TValue irritants); +TValue klispE_new_with_errno_irritants(klisp_State *K, const char *service, + int errnum, TValue irritants); void klispE_free(klisp_State *K, Error *error); void klispE_throw_simple(klisp_State *K, char *msg); void klispE_throw_with_irritants(klisp_State *K, char *msg, TValue irritants); -void klispE_throw_system_error_with_irritants(klisp_State *K, const char *service, int errnum, TValue irritants); +void klispE_throw_system_error_with_irritants( + klisp_State *K, const char *service, int errnum, TValue irritants); + +/* the objects should be rooted */ +#define klispE_new_simple_with_errno_irritants(K__, service__, ...) \ + ({ \ + int errnum__ = errno; \ + TValue ls__ = klist(K__, __VA_ARGS__); \ + krooted_tvs_push(K__, ls__); \ + TValue err__ = klispE_new_with_errno_irritants(K__, service__, \ + errnum__, ls__); \ + krooted_tvs_pop(K__); \ + err__; \ + }) /* evaluates K__ more than once */ /* the objects should be rooted */ diff --git a/src/klisp.c b/src/klisp.c @@ -5,6 +5,7 @@ */ #include <stdio.h> +#include <string.h> #include <stdlib.h> #include <assert.h> @@ -25,11 +26,44 @@ #include "kwrite.h" #include "kerror.h" #include "kgcontinuations.h" /* for do_pass_value */ +#include "kgcontrol.h" /* for do_seq */ #include "kscript.h" /* TODO update dependencies in makefile */ /* TODO this should be moved to a file named like klispconf.h (see lua) */ + +/* +** ================================================================== +** Search for "@@" to find all configurable definitions. +** =================================================================== +*/ + +/* +@@ KLISP_ANSI controls the use of non-ansi features. +** CHANGE it (define it) if you want Klisp to avoid the use of any +** non-ansi feature or library. +*/ +#if defined(__STRICT_ANSI__) +#define KLISP_ANSI +#endif + + +#if !defined(KLISP_ANSI) && defined(_WIN32) +#define KLISP_WIN +#endif + +#if defined(KLISP_USE_LINUX) +#define KLISP_USE_POSIX +#define KLISP_USE_DLOPEN /* needs an extra library: -ldl */ +#define KLISP_USE_READLINE /* needs some extra libraries */ +#endif + +#if defined(KLISP_USE_MACOSX) +#define KLISP_USE_POSIX +#define KLISP_DL_DYLD /* does not need extra library */ +#endif + /* @@ KLISP_PROGNAME is the default name for the stand-alone klisp program. ** CHANGE it if your stand-alone interpreter has a different name and @@ -46,6 +80,18 @@ /* /TODO */ /* +@@ KLISP_USE_POSIX includes all functionallity listed as X/Open System +@* Interfaces Extension (XSI). +** CHANGE it (define it) if your system is XSI compatible. +*/ +#if defined(KLISP_USE_POSIX) +#define KLISP_USE_MKSTEMP +#define KLISP_USE_ISATTY +#define KLISP_USE_POPEN +#define KLISP_USE_ULONGJMP +#endif + +/* @@ LUA_PATH and LUA_CPATH are the names of the environment variables that @* Lua check to set its paths. @@ KLISP_INIT is the name of the environment variable that klisp @@ -56,6 +102,23 @@ //#define LUA_CPATH "LUA_CPATH" #define KLISP_INIT "KLISP_INIT" +/* +@@ klisp_stdin_is_tty detects whether the standard input is a 'tty' (that +@* is, whether we're running klisp interactively). +** CHANGE it if you have a better definition for non-POSIX/non-Windows +** systems. +*/ +#if defined(KLISP_USE_ISATTY) +#include <unistd.h> +#define klisp_stdin_is_tty() isatty(0) +#elif defined(KLISP_WIN) +#include <io.h> +#include <stdio.h> +#define klisp_stdin_is_tty() _isatty(_fileno(stdin)) +#else +#define klisp_stdin_is_tty() 1 /* assume stdin is a tty */ +#endif + static const char *progname = KLISP_PROGNAME; static void print_usage (void) @@ -242,7 +305,7 @@ static int dostring (klisp_State *K, const char *s, const char *name) krooted_tvs_pop(K); /* already in guard */ krooted_tvs_push(K, exit_guard); TValue exit_guards = kcons(K, exit_guard, KNIL); - krooted_tvs_pop(K); /* alread in guards */ + krooted_tvs_pop(K); /* already in guards */ krooted_tvs_push(K, exit_guards); TValue entry_guards = KNIL; @@ -285,6 +348,125 @@ static int dostring (klisp_State *K, const char *s, const char *name) return report(K, status); } +void do_file_eval(klisp_State *K, TValue *xparams, TValue obj) +{ + /* + ** xparams[0]: dynamic environment + */ + TValue denv = xparams[0]; + TValue ls = obj; + if (!ttisnil(ls)) { + TValue new_cont = kmake_continuation(K, kget_cc(K), do_seq, 2, ls, denv); + kset_cc(K, new_cont); + } + kapply_cc(K, KINERT); +} + +void do_file_read(klisp_State *K, TValue *xparams, TValue obj) +{ + UNUSED(obj); + TValue port = xparams[0]; + /* read all file as a list (as immutable data) */ + TValue ls = kread_list_from_port(K, port, false); + + /* all ok, just one exp read (or none and obj1 is eof) */ + kapply_cc(K, ls); +} + +/* name = NULL means use stdin */ +static int dofile(klisp_State *K, const char *name) +{ + bool errorp = false; /* may be set to true in error handler */ + + /* create a file input port (unless it's stdin, then just use) */ + TValue port; + + if (name == NULL) { + port = kcdr(K->kd_in_port_key); + } else { + FILE *file = fopen(name, "r"); + if (file == NULL) { + TValue mode_str = kstring_new_b(K, "r"); + krooted_tvs_push(K, mode_str); + TValue error_obj = klispE_new_simple_with_errno_irritants + (K, "fopen", 2, name, mode_str); + krooted_tvs_pop(K); + K->next_value = error_obj; + return 1; + } + + TValue name_str = kstring_new_b(K, name); + krooted_tvs_push(K, name_str); + port = kmake_std_fport(K, name_str, false, false, file); + krooted_tvs_pop(K); + } + + krooted_tvs_push(K, port); + /* TODO this is exactly the same as in string, factor the code out */ + /* create the guard set error flag after errors */ + TValue exit_int = kmake_operative(K, do_int_mark_error, + 1, p2tv(&errorp)); + krooted_tvs_push(K, exit_int); + TValue exit_guard = kcons(K, K->error_cont, exit_int); + krooted_tvs_pop(K); /* already in guard */ + krooted_tvs_push(K, exit_guard); + TValue exit_guards = kcons(K, exit_guard, KNIL); + krooted_tvs_pop(K); /* already in guards */ + krooted_tvs_push(K, exit_guards); + + TValue entry_guards = KNIL; + + /* this is needed for interception code */ + TValue env = kmake_empty_environment(K); + krooted_tvs_push(K, env); + TValue outer_cont = kmake_continuation(K, K->root_cont, + do_pass_value, 2, entry_guards, env); + kset_outer_cont(outer_cont); + krooted_tvs_push(K, outer_cont); + TValue inner_cont = kmake_continuation(K, outer_cont, + do_pass_value, 2, exit_guards, env); + kset_inner_cont(inner_cont); + krooted_tvs_pop(K); krooted_tvs_pop(K); krooted_tvs_pop(K); + + /* only port remains in the root stack */ + krooted_tvs_push(K, inner_cont); + + /* XXX This should probably be an extra param to the function */ + env = K->next_env; /* this is the standard env that should be used for + evaluation */ + TValue eval_cont = kmake_continuation(K, inner_cont, do_file_eval, + 1, env); + krooted_tvs_pop(K); /* pop inner cont */ + krooted_tvs_push(K, eval_cont); + TValue read_cont = kmake_continuation(K, eval_cont, do_file_read, + 1, port); + krooted_tvs_pop(K); /* pop eval cont */ + krooted_tvs_pop(K); /* pop port */ + kset_cc(K, read_cont); /* this will protect all conts from gc */ + klispS_apply_cc(K, KINERT); + + klispS_run(K); + + int status = errorp? 1 : 0; + + /* get the standard environment again in K->next_env */ + K->next_env = env; + return report(K, status); +} + +static int handle_script(klisp_State *K, char **argv, int n) +{ + const char *fname; + /* XXX/TODO save arguments to script */ +// int narg = getargs(L, argv, n); /* collect arguments */ +// lua_setglobal(L, "arg"); + fname = argv[n]; + if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0) + fname = NULL; /* stdin */ + + return dofile(K, fname); +} + /* check that argument has no extra characters at the end */ #define notail(x) {if ((x)[2] != '\0') return -1;} @@ -414,19 +596,23 @@ static int pmain(klisp_State *K) if (s->status != 0) return 0; - if (script > 0) /* XXX FIX script */ - s->status = 0; + if (script > 0) { + s->status = handle_script(K, argv, script); + } if (s->status != 0) return 0; - if (has_i) /* TODO FIX REPL */ + if (has_i) { /* TODO FIX REPL */ s->status = 0; - else if (script == 0 && !has_e && !has_v) { - print_version(); - s->status = 0; /* TODO FIX REPL */ - } else - s->status = 0; /* TODO do FILE */ + } else if (script == 0 && !has_e && !has_v) { + if (true) { + print_version(); + s->status = 0; /* TODO FIX REPL */ + } else { + s->status = dofile(K, NULL); + } + } return 0; } diff --git a/src/kport.c b/src/kport.c @@ -88,8 +88,9 @@ TValue kmake_fport(klisp_State *K, TValue filename, bool writep, bool binaryp) FILE *f = fopen(kstring_buf(filename), mode); if (f == NULL) { - klispE_throw_errno_with_irritants(K, "fopen", 2, filename, - kstring_new_b_imm(K, mode)); + TValue mode_str = kstring_new_b(K, mode); + krooted_tvs_push(K, mode_str); + klispE_throw_errno_with_irritants(K, "fopen", 2, filename, mode_str); return KINERT; } else { return kmake_std_fport(K, filename, writep, binaryp, f);