diff --git a/config.scm b/config.scm index 141e95f3..0e26ab90 100644 --- a/config.scm +++ b/config.scm @@ -4,7 +4,6 @@ (define *modules* '()) (define *this-module* '()) -(define *load-path* (list "./lib" (string-append *module-directory* "/lib"))) (define (make-module exports env meta) (vector exports env meta)) (define (module-exports mod) (vector-ref mod 0)) @@ -12,12 +11,6 @@ (define (module-meta-data mod) (vector-ref mod 2)) (define (module-env-set! mod env) (vector-set! mod 1 env)) -(define (find-module-file name file) - (let lp ((ls *load-path*)) - (and (pair? ls) - (let ((path (string-append (car ls) "/" file))) - (if (file-exists? path) path (lp (cdr ls))))))) - (define (module-name->strings ls res) (if (null? ls) res @@ -36,7 +29,7 @@ (define (load-module-definition name) (let* ((file (module-name->file name)) - (path (find-module-file name file))) + (path (find-module-file file))) (if path (load path *config-env*)))) (define (find-module name) @@ -109,7 +102,7 @@ dir f (if (eq? (car x) 'include) "" *shared-object-extension*)))) (cond - ((find-module-file name f) => (lambda (x) (load x env))) + ((find-module-file f) => (lambda (x) (load x env))) (else (error "couldn't find include" f))))) (cdr x))) ((body) diff --git a/eval.c b/eval.c index f9ed2efe..6d16a352 100644 --- a/eval.c +++ b/eval.c @@ -7,7 +7,6 @@ /************************************************************************/ static int scheme_initialized_p = 0; -char *sexp_module_dir = NULL; #if SEXP_USE_DEBUG #include "opt/debug.c" @@ -19,6 +18,8 @@ char *sexp_module_dir = NULL; static sexp analyze (sexp ctx, sexp x); static void generate (sexp ctx, sexp x); +static sexp sexp_load_module_file_op (sexp ctx, sexp file, sexp env); +static sexp sexp_find_module_file_op (sexp ctx, sexp file); static sexp sexp_compile_error (sexp ctx, char *message, sexp obj) { sexp exn; @@ -273,20 +274,41 @@ static sexp sexp_make_lit (sexp ctx, sexp value) { #define SEXP_STACK_SIZE (sexp_sizeof(stack)+sizeof(sexp)*SEXP_INIT_STACK_SIZE) +static void sexp_add_path (sexp ctx, char *str) { + char *colon; + if (str && *str) { + colon = strchr(str, ':'); + if (colon) + sexp_add_path(ctx, colon+1); + else + colon = str + strlen(str); + sexp_push(ctx, sexp_global(ctx, SEXP_G_MODULE_PATH), SEXP_VOID); + sexp_car(sexp_global(ctx, SEXP_G_MODULE_PATH)) + = sexp_c_string(ctx, str, colon-str); + } +} + void sexp_init_eval_context_globals (sexp ctx) { - sexp_gc_var2(bc, vec); + sexp_gc_var2(tmp, vec); ctx = sexp_make_child_context(ctx, NULL); - sexp_gc_preserve2(ctx, bc, vec); + sexp_gc_preserve2(ctx, tmp, vec); emit(ctx, SEXP_OP_RESUMECC); sexp_global(ctx, SEXP_G_RESUMECC_BYTECODE) = finalize_bytecode(ctx); ctx = sexp_make_child_context(ctx, NULL); emit(ctx, SEXP_OP_DONE); - bc = finalize_bytecode(ctx); + tmp = finalize_bytecode(ctx); vec = sexp_make_vector(ctx, 0, SEXP_VOID); sexp_global(ctx, SEXP_G_FINAL_RESUMER) - = sexp_make_procedure(ctx, SEXP_ZERO, SEXP_ZERO, bc, vec); + = sexp_make_procedure(ctx, SEXP_ZERO, SEXP_ZERO, tmp, vec); sexp_bytecode_name(sexp_procedure_code(sexp_global(ctx, SEXP_G_FINAL_RESUMER))) = sexp_intern(ctx, "final-resumer"); + sexp_global(ctx, SEXP_G_MODULE_PATH) = SEXP_NULL; + sexp_add_path(ctx, sexp_default_module_dir); + sexp_add_path(ctx, getenv(SEXP_MODULE_PATH_VAR)); + tmp = sexp_c_string(ctx, "./lib", 5); + sexp_push(ctx, sexp_global(ctx, SEXP_G_MODULE_PATH), tmp); + tmp = sexp_c_string(ctx, ".", 1); + sexp_push(ctx, sexp_global(ctx, SEXP_G_MODULE_PATH), tmp); sexp_gc_release2(ctx); } @@ -2371,68 +2393,90 @@ sexp sexp_make_primitive_env (sexp ctx, sexp version) { return e; } +sexp sexp_find_module_file (sexp ctx, char *file) { + sexp res=SEXP_FALSE, ls; + char *dir, *path; + sexp_uint_t slash, dirlen, filelen, len; #ifdef PLAN9 #define file_exists_p(path, buf) (stat(path, buf, 128) >= 0) -#else -#include -#define file_exists_p(path, buf) (! stat(path, buf)) -#endif - -sexp sexp_find_module_file (sexp ctx, char *file) { - sexp res; - int mlen, flen; - char *path; -#ifdef PLAN9 unsigned char buf[128]; #else +#define file_exists_p(path, buf) (! stat(path, buf)) struct stat buf_str; struct stat *buf = &buf_str; #endif - if (file_exists_p(file, buf)) - return sexp_c_string(ctx, file, -1); - if (! sexp_module_dir) { -#ifndef PLAN9 - sexp_module_dir = getenv("CHIBI_MODULE_DIR"); - if (! sexp_module_dir) -#endif - sexp_module_dir = sexp_module_dir; + filelen = strlen(file); + + ls = sexp_global(ctx, SEXP_G_MODULE_PATH); + for ( ; sexp_pairp(ls) && sexp_not(res); ls=sexp_cdr(ls)) { + dir = sexp_string_data(sexp_car(ls)); + dirlen = sexp_string_length(sexp_car(ls)); + slash = dir[dirlen-1] == '/'; + len = dirlen+filelen+2-slash; + path = (char*) malloc(len); + memcpy(path, dir, dirlen); + if (! slash) path[dirlen] = '/'; + memcpy(path+len-filelen-1, file, filelen); + path[len-1] = '\0'; + if (file_exists_p(path, buf)) + res = sexp_c_string(ctx, path, len-1); + free(path); } - mlen = strlen(sexp_module_dir); - flen = strlen(file); - path = (char*) malloc(mlen+flen+2); - memcpy(path, sexp_module_dir, mlen); - path[mlen] = '/'; - memcpy(path+mlen+1, file, flen); - path[mlen+flen+1] = '\0'; - if (file_exists_p(path, buf)) - res = sexp_c_string(ctx, path, mlen+flen+2); - else - res = SEXP_FALSE; - free(path); + return res; } -#define sexp_file_not_found "couldn't find file to load in ./ or module dir" +static sexp sexp_find_module_file_op (sexp ctx, sexp file) { + if (! sexp_stringp(file)) + return sexp_type_exception(ctx, "not a string", file); + else + return sexp_find_module_file(ctx, sexp_string_data(file)); +} + +#define sexp_file_not_found "couldn't find file in module path" sexp sexp_load_module_file (sexp ctx, char *file, sexp env) { - sexp res = SEXP_VOID; - sexp_gc_var2(path, irr); - sexp_gc_preserve2(ctx, path, irr); + sexp res; + sexp_gc_var1(path); + sexp_gc_preserve1(ctx, path); path = sexp_find_module_file(ctx, file); - if (! sexp_stringp(path)) { - path = sexp_c_string(ctx, sexp_module_dir, -1); - irr = sexp_cons(ctx, path, SEXP_NULL); - path = sexp_c_string(ctx, file, -1); - irr = sexp_cons(ctx, path, irr); - res = sexp_user_exception(ctx, SEXP_FALSE, sexp_file_not_found, irr); - } else { + if (sexp_stringp(path)) { res = sexp_load(ctx, path, env); + } else { + path = sexp_c_string(ctx, file, -1); + res = sexp_user_exception(ctx, SEXP_FALSE, sexp_file_not_found, path); } - sexp_gc_release2(ctx); + sexp_gc_release1(ctx); return res; } +sexp sexp_load_module_file_op (sexp ctx, sexp file, sexp env) { + if (! sexp_stringp(file)) + return sexp_type_exception(ctx, "not a string", file); + else if (! sexp_envp(env)) + return sexp_type_exception(ctx, "not an environment", env); + return sexp_load_module_file(ctx, sexp_string_data(file), env); +} + +sexp sexp_add_module_directory (sexp ctx, sexp dir, sexp appendp) { + sexp ls; + if (! sexp_stringp(dir)) + return sexp_type_exception(ctx, "not a string", dir); + if (sexp_truep(appendp)) { + if (sexp_pairp(ls=sexp_global(ctx, SEXP_G_MODULE_PATH))) { + for ( ; sexp_pairp(sexp_cdr(ls)); ls=sexp_cdr(ls)) + ; + sexp_cdr(ls) = sexp_list1(ctx, dir); + } else { + sexp_global(ctx, SEXP_G_MODULE_PATH) = sexp_list1(ctx, dir); + } + } else { + sexp_push(ctx, sexp_global(ctx, SEXP_G_MODULE_PATH), dir); + } + return SEXP_VOID; +} + sexp sexp_load_standard_env (sexp ctx, sexp e, sexp version) { sexp_gc_var3(op, tmp, sym); sexp_gc_preserve3(ctx, op, tmp, sym); @@ -2444,8 +2488,6 @@ sexp sexp_load_standard_env (sexp ctx, sexp e, sexp version) { sexp_env_define(ctx, e, sexp_global(ctx, SEXP_G_CUR_ERR_SYMBOL), sexp_make_output_port(ctx, stderr, SEXP_FALSE)); sexp_env_define(ctx, e, sexp_global(ctx, SEXP_G_INTERACTION_ENV_SYMBOL), e); - sexp_env_define(ctx, e, sym=sexp_intern(ctx, "*module-directory*"), - sexp_c_string(ctx, sexp_default_module_dir, -1)); #if SEXP_USE_DL sexp_env_define(ctx, e, sexp_intern(ctx, "*shared-object-extension*"), sexp_c_string(ctx, sexp_so_extension, -1)); @@ -2471,7 +2513,9 @@ sexp sexp_load_standard_env (sexp ctx, sexp e, sexp version) { if (! sexp_exceptionp(tmp)) { sexp_global(ctx, SEXP_G_CONFIG_ENV) = tmp; sexp_env_copy(ctx, tmp, e, SEXP_FALSE); - sexp_load_module_file(ctx, sexp_config_file, tmp); + op = sexp_load_module_file(ctx, sexp_config_file, tmp); + if (sexp_exceptionp(op)) + sexp_print_exception(ctx, op, sexp_current_error_port(ctx)); sexp_env_define(ctx, tmp, sym, tmp); } } diff --git a/include/chibi/eval.h b/include/chibi/eval.h index 342607eb..a2afa062 100644 --- a/include/chibi/eval.h +++ b/include/chibi/eval.h @@ -15,8 +15,6 @@ #define sexp_init_file "init.scm" #define sexp_config_file "config.scm" -SEXP_API char *sexp_module_dir; - enum sexp_core_form_names { SEXP_CORE_DEFINE = 1, SEXP_CORE_SET, @@ -135,7 +133,9 @@ SEXP_API sexp sexp_make_null_env (sexp context, sexp version); SEXP_API sexp sexp_make_primitive_env (sexp context, sexp version); SEXP_API sexp sexp_make_standard_env (sexp context, sexp version); SEXP_API sexp sexp_load_standard_env (sexp context, sexp env, sexp version); +SEXP_API sexp sexp_find_module_file (sexp ctx, char *file); SEXP_API sexp sexp_load_module_file (sexp ctx, char *file, sexp env); +SEXP_API sexp sexp_add_module_directory (sexp ctx, sexp dir, sexp appendp); SEXP_API sexp sexp_extend_env (sexp context, sexp env, sexp vars, sexp value); SEXP_API sexp sexp_env_copy (sexp context, sexp to, sexp from, sexp ls); SEXP_API void sexp_env_define (sexp context, sexp env, sexp sym, sexp val); diff --git a/include/chibi/sexp.h b/include/chibi/sexp.h index dc9448f7..8283d601 100644 --- a/include/chibi/sexp.h +++ b/include/chibi/sexp.h @@ -5,6 +5,8 @@ #ifndef SEXP_H #define SEXP_H +#define SEXP_MODULE_PATH_VAR "CHIBI_MODULE_PATH" + #include "chibi/config.h" #include "chibi/install.h" @@ -686,6 +688,7 @@ enum sexp_context_globals { SEXP_G_OOS_ERROR, /* out of stack exception object */ SEXP_G_OPTIMIZATIONS, SEXP_G_CONFIG_ENV, + SEXP_G_MODULE_PATH, SEXP_G_QUOTE_SYMBOL, SEXP_G_QUASIQUOTE_SYMBOL, SEXP_G_UNQUOTE_SYMBOL, diff --git a/main.c b/main.c index 03bd3b34..85ee9ba1 100644 --- a/main.c +++ b/main.c @@ -7,6 +7,9 @@ #define sexp_argv_symbol "*command-line-arguments*" #define sexp_argv_proc "(define (command-line-arguments) "sexp_argv_symbol")" +#define sexp_import_prefix "(import (" +#define sexp_import_suffix "))" + static void repl (sexp ctx) { sexp in, out, err; sexp_gc_var4(obj, tmp, res, env); @@ -57,9 +60,12 @@ static sexp check_exception (sexp ctx, sexp res) { return res; } +#define sexp_load_init() if (! init_loaded++) check_exception(ctx, sexp_load_standard_env(ctx, env, SEXP_FIVE)) + void run_main (int argc, char **argv) { + char *arg, *impmod, *p; sexp env, out=NULL, res=SEXP_VOID, ctx; - sexp_sint_t i, quit=0, init_loaded=0; + sexp_sint_t i, len, quit=0, print=0, init_loaded=0; sexp_gc_var2(str, args); ctx = sexp_make_eval_context(NULL, NULL, NULL); @@ -73,29 +79,49 @@ void run_main (int argc, char **argv) { switch (argv[i][1]) { case 'e': case 'p': - if (! init_loaded++) - check_exception(ctx, sexp_load_standard_env(ctx, env, SEXP_FIVE)); - res = check_exception(ctx, sexp_read_from_string(ctx, argv[i+1])); + print = (argv[i][1] == 'p'); + arg = ((argv[i][2] == '\0') ? argv[++i] : argv[i]+2); + sexp_load_init(); + res = check_exception(ctx, sexp_read_from_string(ctx, arg)); res = check_exception(ctx, sexp_eval(ctx, res, env)); - if (argv[i][1] == 'p') { + if (print) { if (! sexp_oportp(out)) out = sexp_eval_string(ctx, "(current-output-port)", env); sexp_write(ctx, res, out); sexp_write_char(ctx, '\n', out); } - quit=1; + quit = 1; i++; break; case 'l': - if (! init_loaded++) - check_exception(ctx, sexp_load_standard_env(ctx, env, SEXP_FIVE)); + arg = ((argv[i][2] == '\0') ? argv[++i] : argv[i]+2); + sexp_load_init(); check_exception(ctx, sexp_load_module_file(ctx, argv[++i], env)); break; + case 'u': + arg = ((argv[i][2] == '\0') ? argv[++i] : argv[i]+2); + sexp_load_init(); + len = strlen(arg)+strlen(sexp_import_prefix)+strlen(sexp_import_suffix); + impmod = (char*) malloc(len+1); + strcpy(impmod, sexp_import_prefix); + strcpy(impmod+strlen(sexp_import_prefix), arg); + strcpy(impmod+len-+strlen(sexp_import_suffix), sexp_import_suffix); + impmod[len] = '\0'; + for (p=impmod; *p; p++) + if (*p == '.') *p=' '; + check_exception(ctx, sexp_eval_string(ctx, impmod, env)); + free(impmod); + break; case 'q': init_loaded = 1; break; - case 'm': - sexp_module_dir = argv[++i]; + case 'A': + arg = ((argv[i][2] == '\0') ? argv[++i] : argv[i]+2); + sexp_add_module_directory(ctx, str=sexp_c_string(ctx,arg,-1), SEXP_TRUE); + break; + case 'I': + arg = ((argv[i][2] == '\0') ? argv[++i] : argv[i]+2); + sexp_add_module_directory(ctx, str=sexp_c_string(ctx,arg,-1), SEXP_FALSE); break; case 's': for (argc=argc-1; argc>i+1; argc--) @@ -108,8 +134,7 @@ void run_main (int argc, char **argv) { } if (! quit) { - if (! init_loaded) - check_exception(ctx, sexp_load_standard_env(ctx, env, SEXP_FIVE)); + sexp_load_init(); sexp_env_define(ctx, env, sexp_intern(ctx, sexp_argv_symbol), args); sexp_eval_string(ctx, sexp_argv_proc, env); if (i < argc) diff --git a/opcodes.c b/opcodes.c index 12949b3d..c65ef3d5 100644 --- a/opcodes.c +++ b/opcodes.c @@ -143,5 +143,10 @@ _FN2OPTP(SEXP_PROCEDURE, SEXP_OPORT, "disasm", (sexp)"*current-error-port*", sex #include "opt/plan9-opcodes.c" #endif _FN1(SEXP_STRING, "file-exists?", 0, sexp_file_exists_p), +#if SEXP_USE_MODULES +_FN1(SEXP_STRING, "find-module-file", 0, sexp_find_module_file_op), +_FN2(SEXP_STRING, SEXP_ENV, "load-module-file", 0, sexp_load_module_file_op), +_FN2(SEXP_STRING, SEXP_BOOLEAN, "add-module-directory", 0, sexp_add_module_directory), +#endif };