Adding the -R<module> option to run "main" procedures directly from modules,

analogous to Python's -m.  With no argument, runs chibi.repl.
This commit is contained in:
Alex Shinn 2013-10-04 12:04:50 +09:00
parent e037027fcf
commit f9d73ddc30
4 changed files with 65 additions and 39 deletions

View file

@ -6,7 +6,7 @@ chibi-scheme \- a tiny Scheme interpreter
.SH SYNOPSIS .SH SYNOPSIS
.B chibi-scheme .B chibi-scheme
[-qQrfV] [-qQrRfV]
[-I [-I
.I path .I path
] ]
@ -103,9 +103,15 @@ The resulting environment will only contain the core syntactic
forms and primitives coded in C. This is very fast and guaranteed forms and primitives coded in C. This is very fast and guaranteed
not to load any external files, but is also very limited. not to load any external files, but is also very limited.
.TP .TP
.BI -r .BI -r [main]
Run the "main" procedure when the script finishes loading as in SRFI-22. Run the "main" procedure when the script finishes loading as in SRFI-22.
.TP .TP
.BI -R [module]
Loads the given module and runs the "main" procedure it defines (which
need not be exported) with a single argument of the list of command-line
arguments as in SRFI-22. The name "main" can be overridden with the -r
option.
.TP
.BI -s .BI -s
Strict mode, escalating warnings to fatal errors. Strict mode, escalating warnings to fatal errors.
.TP .TP

View file

@ -110,8 +110,8 @@ are listed below.
The command-line programs \ccode{chibi-scheme}, \ccode{chibi-doc} and The command-line programs \ccode{chibi-scheme}, \ccode{chibi-doc} and
\ccode{chibi-ffi} are installed by default, along with manpages. \ccode{chibi-ffi} are installed by default, along with manpages.
\ccode{chibi-scheme} provides a REPL and way to run scripts. In the \ccode{chibi-scheme} provides a REPL and way to run scripts. Run -?
interest of size it has no --help option - see the man page for usage. for a brief list of options, or see the man page for more details.
\ccode{chibi-doc} is the command-line interface to the literate \ccode{chibi-doc} is the command-line interface to the literate
documentation system described in documentation system described in
\hyperlink["lib/chibi/scribble.html"]{(chibi scribble)}, and used to \hyperlink["lib/chibi/scribble.html"]{(chibi scribble)}, and used to

View file

@ -2,15 +2,13 @@
;; Copyright (c) 2012-2013 Alex Shinn. All rights reserved. ;; Copyright (c) 2012-2013 Alex Shinn. All rights reserved.
;; BSD-style license: http://synthcode.com/license.txt ;; BSD-style license: http://synthcode.com/license.txt
;;> A user-friendly REPL with line editing and signal handling. ;;> A user-friendly REPL with line editing and signal handling. The
;;> The default REPL provided by chibi-scheme is very minimal, ;;> default REPL provided by chibi-scheme is very minimal, meant
;;> meant primarily to be small and work on any platform. This ;;> primarily to be small and work on any platform. This module
;;> module provides an advanced REPL that handles vt100 line ;;> provides an advanced REPL that handles vt100 line editing and
;;> editing and signal handling, so that C-c will interrupt a ;;> signal handling, so that C-c will interrupt a computation and
;;> computation and bring you back to the REPL prompt. To use ;;> bring you back to the REPL prompt. To use this repl, run
;;> this repl, run ;;> \command{chibi-scheme -R} from the command line or within Emacs.
;;> \command{chibi-scheme -mchibi.repl -e'(repl)'}
;;> from the command line or within Emacs.
(define (with-signal-handler sig handler thunk) (define (with-signal-handler sig handler thunk)
(let ((old-handler #f)) (let ((old-handler #f))
@ -448,3 +446,6 @@
(newline (current-error-port))))) (newline (current-error-port)))))
(call-with-output-file (repl-history-file rp) (call-with-output-file (repl-history-file rp)
(lambda (out) (write (history->list (repl-history rp)) out))))))) (lambda (out) (write (history->list (repl-history rp)) out)))))))
(define (main args)
(repl))

71
main.c
View file

@ -27,26 +27,27 @@
void sexp_usage(int err) { void sexp_usage(int err) {
printf("usage: chibi-scheme [<options> ...] [<file> <args> ...]\n" printf("usage: chibi-scheme [<options> ...] [<file> <args> ...]\n"
#if SEXP_USE_FOLD_CASE_SYMS #if SEXP_USE_FOLD_CASE_SYMS
" -f - case-fold symbols\n" " -f - case-fold symbols\n"
#endif #endif
" -q - \"quick\" load, use the core -xchibi language\n" " -q - \"quick\" load, use the core -xchibi language\n"
" -Q - extra \"quick\" load, -xchibi.primitive\n" " -Q - extra \"quick\" load, -xchibi.primitive\n"
" -V - print version information\n" " -V - print version information\n"
#if ! SEXP_USE_BOEHM #if ! SEXP_USE_BOEHM
" -h <size> - specify the initial heap size\n" " -h <size> - specify the initial heap size\n"
#endif #endif
#if SEXP_USE_MODULES #if SEXP_USE_MODULES
" -A <dir> - append a module search directory\n" " -A <dir> - append a module search directory\n"
" -I <dir> - prepend a module search directory\n" " -I <dir> - prepend a module search directory\n"
" -m <module> - import a module\n" " -m <module> - import a module\n"
" -x <module> - import only a module\n" " -x <module> - import only a module\n"
#endif #endif
" -e <expr> - evaluate an expression\n" " -e <expr> - evaluate an expression\n"
" -p <expr> - evaluate and print an expression\n" " -p <expr> - evaluate and print an expression\n"
" -r[<main>] - run a SRFI-22 main\n" " -r[<main>] - run a SRFI-22 main\n"
" -R[<module>] - run main from a module\n"
#if SEXP_USE_IMAGE_LOADING #if SEXP_USE_IMAGE_LOADING
" -d <file> - dump an image file and exit\n" " -d <file> - dump an image file and exit\n"
" -i <file> - load an image file\n" " -i <file> - load an image file\n"
#endif #endif
); );
if (err == 0) exit_success(); if (err == 0) exit_success();
@ -261,6 +262,18 @@ static sexp_uint_t multiplier (char c) {
} }
#endif #endif
static char* make_import(const char* prefix, const char* mod, const char* suffix) {
int len = strlen(mod) + strlen(prefix) + strlen(suffix);
char *p, *impmod = (char*) malloc(len+1);
strcpy(impmod, prefix);
strcpy(impmod+strlen(prefix), mod);
strcpy(impmod+len-+strlen(suffix), suffix);
impmod[len] = '\0';
for (p=impmod; *p; p++)
if (*p == '.') *p=' ';
return impmod;
}
static void check_nonull_arg (int c, char *arg) { static void check_nonull_arg (int c, char *arg) {
if (! arg) { if (! arg) {
fprintf(stderr, "chibi-scheme: option '%c' requires an argument\n", c); fprintf(stderr, "chibi-scheme: option '%c' requires an argument\n", c);
@ -341,10 +354,9 @@ static void do_init_context (sexp* ctx, sexp* env, sexp_uint_t heap_size,
void run_main (int argc, char **argv) { void run_main (int argc, char **argv) {
#if SEXP_USE_MODULES #if SEXP_USE_MODULES
char *impmod, *p; char *impmod;
sexp_sint_t len;
#endif #endif
char *arg, *prefix=NULL, *suffix=NULL, *main_symbol=NULL; char *arg, *prefix=NULL, *suffix=NULL, *main_symbol=NULL, *main_module=NULL;
sexp_sint_t i, j, c, quit=0, print=0, init_loaded=0, mods_loaded=0, sexp_sint_t i, j, c, quit=0, print=0, init_loaded=0, mods_loaded=0,
no_script=0, fold_case=SEXP_DEFAULT_FOLD_CASE_SYMS; no_script=0, fold_case=SEXP_DEFAULT_FOLD_CASE_SYMS;
sexp_uint_t heap_size=0, heap_max_size=SEXP_MAXIMUM_HEAP_SIZE; sexp_uint_t heap_size=0, heap_max_size=SEXP_MAXIMUM_HEAP_SIZE;
@ -400,14 +412,7 @@ void run_main (int argc, char **argv) {
/* explicitly setting a language */ /* explicitly setting a language */
#if SEXP_USE_MODULES #if SEXP_USE_MODULES
check_nonull_arg(c, arg); check_nonull_arg(c, arg);
len = strlen(arg)+strlen(prefix)+strlen(suffix); impmod = make_import(prefix, arg, suffix);
impmod = (char*) malloc(len+1);
strcpy(impmod, prefix);
strcpy(impmod+strlen(prefix), arg);
strcpy(impmod+len-+strlen(suffix), suffix);
impmod[len] = '\0';
for (p=impmod; *p; p++)
if (*p == '.') *p=' ';
tmp = check_exception(ctx, sexp_eval_string(ctx, impmod, -1, (c=='x' ? sexp_global(ctx, SEXP_G_META_ENV) : env))); tmp = check_exception(ctx, sexp_eval_string(ctx, impmod, -1, (c=='x' ? sexp_global(ctx, SEXP_G_META_ENV) : env)));
free(impmod); free(impmod);
if (c == 'x') { if (c == 'x') {
@ -502,6 +507,10 @@ void run_main (int argc, char **argv) {
sexp_global(ctx, SEXP_G_FOLD_CASE_P) = SEXP_TRUE; sexp_global(ctx, SEXP_G_FOLD_CASE_P) = SEXP_TRUE;
break; break;
#endif #endif
case 'R':
main_module = argv[i][2] == '\0' ? "chibi.repl" : argv[i]+2;
if (main_symbol == NULL) main_symbol = "main";
break;
case 'r': case 'r':
main_symbol = argv[i][2] == '\0' ? "main" : argv[i]+2; main_symbol = argv[i][2] == '\0' ? "main" : argv[i]+2;
break; break;
@ -530,6 +539,15 @@ void run_main (int argc, char **argv) {
/* no script or main, run interactively */ /* no script or main, run interactively */
repl(ctx, env); repl(ctx, env);
} else { } else {
#if SEXP_USE_MODULES
/* load the module or script */
if (main_module != NULL) {
impmod = make_import("(load-module '(", main_module, "))");
env = check_exception(ctx, sexp_eval_string(ctx, impmod, -1, sexp_global(ctx, SEXP_G_META_ENV)));
if (sexp_vectorp(env)) env = sexp_vector_ref(env, SEXP_ONE);
free(impmod);
} else
#endif
if (i < argc && !no_script) { /* script usage */ if (i < argc && !no_script) { /* script usage */
#if SEXP_USE_MODULES #if SEXP_USE_MODULES
/* reset the environment to have only the `import' and */ /* reset the environment to have only the `import' and */
@ -548,7 +566,6 @@ void run_main (int argc, char **argv) {
sexp_env_define(ctx, env, sym, tmp); sexp_env_define(ctx, env, sym, tmp);
} }
#endif #endif
/* load the script */
sexp_context_tracep(ctx) = 1; sexp_context_tracep(ctx) = 1;
tmp = sexp_env_bindings(env); tmp = sexp_env_bindings(env);
#if SEXP_USE_MODULES #if SEXP_USE_MODULES
@ -573,6 +590,8 @@ void run_main (int argc, char **argv) {
if (sexp_procedurep(tmp)) { if (sexp_procedurep(tmp)) {
args = sexp_list1(ctx, args); args = sexp_list1(ctx, args);
check_exception(ctx, sexp_apply(ctx, tmp, args)); check_exception(ctx, sexp_apply(ctx, tmp, args));
} else {
fprintf(stderr, "couldn't find main binding: %s in %s\n", main_symbol, main_module ? main_module : argv[i]);
} }
} }
} }