diff --git a/Makefile b/Makefile index c66720a5..08108bd1 100644 --- a/Makefile +++ b/Makefile @@ -147,7 +147,7 @@ build/core_image.c: build/janet_boot ########################################################## JANET_CORE_OBJECTS=$(patsubst src/%.c,build/%.o,$(JANET_CORE_SOURCES)) build/core_image.o -JANET_MAINCLIENT_OBJECTS=$(patsubst src/%.c,build/%.o,$(JANET_MAINCLIENT_SOURCES)) build/init.gen.o +JANET_MAINCLIENT_OBJECTS=$(patsubst src/%.c,build/%.o,$(JANET_MAINCLIENT_SOURCES)) # Compile the core image generated by the bootstrap build build/core_image.o: build/core_image.c $(JANET_HEADERS) $(JANET_LOCAL_HEADERS) @@ -204,8 +204,6 @@ emscripten: $(JANET_EMTARGET) build/xxd: tools/xxd.c $(CC) $< -o $@ -build/init.gen.c: src/mainclient/init.janet build/xxd - build/xxd $< $@ janet_gen_init build/webinit.gen.c: src/webclient/webinit.janet build/xxd build/xxd $< $@ janet_gen_webinit build/boot.gen.c: src/boot/boot.janet build/xxd diff --git a/build_win.bat b/build_win.bat index f2ddb738..f339a7b9 100644 --- a/build_win.bat +++ b/build_win.bat @@ -40,14 +40,10 @@ link /nologo /out:build\xxd.exe build\xxd.obj @if errorlevel 1 goto :BUILDFAIL @rem Generate the embedded sources -build\xxd.exe src\mainclient\init.janet build\init.gen.c janet_gen_init -@if errorlevel 1 goto :BUILDFAIL build\xxd.exe src\boot\boot.janet build\boot.gen.c janet_gen_boot @if errorlevel 1 goto :BUILDFAIL @rem Build the generated sources -%JANET_COMPILE% /Fobuild\mainclient\init.gen.obj build\init.gen.c -@if errorlevel 1 goto :BUILDFAIL %JANET_COMPILE% /Fobuild\boot\boot.gen.obj build\boot.gen.c @if errorlevel 1 goto :BUILDFAIL diff --git a/meson.build b/meson.build index 31bcea8d..f4984c9d 100644 --- a/meson.build +++ b/meson.build @@ -83,7 +83,6 @@ gen = generator(xxd, output : '@BASENAME@.gen.c', arguments : ['@INPUT@', '@OUTPUT@', '@EXTRA_ARGS@']) boot_gen = gen.process('src/boot/boot.janet', extra_args: 'janet_gen_boot') -init_gen = gen.process('src/mainclient/init.janet', extra_args: 'janet_gen_init') # Order is important here, as some headers # depend on other headers for the amalg target @@ -185,14 +184,14 @@ else extra_cross_cflags = [] endif -janet_mainclient = executable('janet', core_src, core_image, init_gen, mainclient_src, +janet_mainclient = executable('janet', core_src, core_image, mainclient_src, include_directories : incdir, dependencies : [m_dep, dl_dep], c_args : extra_native_cflags, install : true) if meson.is_cross_build() - janet_nativeclient = executable('janet-native', core_src, core_image, init_gen, mainclient_src, + janet_nativeclient = executable('janet-native', core_src, core_image, mainclient_src, include_directories : incdir, dependencies : [m_dep, dl_dep], c_args : extra_cross_cflags, @@ -216,7 +215,7 @@ amalg = custom_target('amalg', command : [janet_nativeclient, '@INPUT@']) # Amalgamated client -janet_amalgclient = executable('janet-amalg', amalg, init_gen, mainclient_src, +janet_amalgclient = executable('janet-amalg', amalg, mainclient_src, include_directories : incdir, dependencies : [m_dep, dl_dep], build_by_default : false) diff --git a/src/boot/boot.janet b/src/boot/boot.janet index 6311e487..8468d0ae 100644 --- a/src/boot/boot.janet +++ b/src/boot/boot.janet @@ -1906,6 +1906,8 @@ (def ret (bad-compile x y z)) (if exit-on-error (os/exit 1)) ret) + (unless f + (error (string "could not find file " path))) (run-context {:env env :chunks chunks :on-parse-error bp @@ -2054,6 +2056,125 @@ _fiber is bound to the suspended fiber (put _env 'env-walk nil) (put _env '_env nil) +### +### +### CLI Tool Main +### +### + +(defn cli-main + "Entrance for the Janet CLI tool. Call this functions with the command line + arguments as an array or tuple of strings to invoke the CLI interface." + [args] + (setdyn :args args) + + (var *should-repl* false) + (var *no-file* true) + (var *quiet* false) + (var *raw-stdin* false) + (var *handleopts* true) + (var *exit-on-error* true) + (var *colorize* true) + (var *compile-only* false) + + (if-let [jp (os/getenv "JANET_PATH")] (setdyn :syspath jp)) + (if-let [jp (os/getenv "JANET_HEADERPATH")] (setdyn :headerpath jp)) + + # Flag handlers + (def handlers :private + {"h" (fn [&] + (print "usage: " (dyn :executable "janet") " [options] script args...") + (print + `Options are: + -h : Show this help + -v : Print the version string + -s : Use raw stdin instead of getline like functionality + -e code : Execute a string of janet + -r : Enter the repl after running all scripts + -p : Keep on executing if there is a top level error (persistent) + -q : Hide prompt, logo, and repl output (quiet) + -k : Compile scripts but do not execute + -m syspath : Set system path for loading global modules + -c source output : Compile janet source code into an image + -n : Disable ANSI color output in the repl + -l path : Execute code in a file before running the main script + -- : Stop handling options`) + (os/exit 0) + 1) + "v" (fn [&] (print janet/version "-" janet/build) (os/exit 0) 1) + "s" (fn [&] (set *raw-stdin* true) (set *should-repl* true) 1) + "r" (fn [&] (set *should-repl* true) 1) + "p" (fn [&] (set *exit-on-error* false) 1) + "q" (fn [&] (set *quiet* true) 1) + "k" (fn [&] (set *compile-only* true) (set *exit-on-error* false) 1) + "n" (fn [&] (set *colorize* false) 1) + "m" (fn [i &] (setdyn :syspath (get args (+ i 1))) 2) + "c" (fn [i &] + (def e (dofile (get args (+ i 1)))) + (spit (get args (+ i 2)) (make-image e)) + (set *no-file* false) + 3) + "-" (fn [&] (set *handleopts* false) 1) + "l" (fn [i &] + (import* (get args (+ i 1)) + :prefix "" :exit *exit-on-error*) + 2) + "e" (fn [i &] + (set *no-file* false) + (eval-string (get args (+ i 1))) + 2)}) + + (defn- dohandler [n i &] + (def h (get handlers n)) + (if h (h i) (do (print "unknown flag -" n) ((get handlers "h"))))) + + (def- safe-forms {'defn true 'defn- true 'defmacro true 'defmacro- true}) + (def- importers {'import true 'import* true 'use true 'dofile true 'require true}) + (defn- evaluator + [thunk source env where] + (if *compile-only* + (when (tuple? source) + (cond + (safe-forms (source 0)) (thunk) + (importers (source 0)) + (do + (let [[l c] (tuple/sourcemap source) + newtup (tuple/setmap (tuple ;source :evaluator evaluator) l c)] + ((compile newtup env where)))))) + (thunk))) + + # Process arguments + (var i 0) + (def lenargs (length args)) + (while (< i lenargs) + (def arg (get args i)) + (if (and *handleopts* (= "-" (string/slice arg 0 1))) + (+= i (dohandler (string/slice arg 1 2) i)) + (do + (set *no-file* false) + (dofile arg :prefix "" :exit *exit-on-error* :evaluator evaluator) + (set i lenargs)))) + + (when (and (not *compile-only*) (or *should-repl* *no-file*)) + (if-not *quiet* + (print "Janet " janet/version "-" janet/build " Copyright (C) 2017-2019 Calvin Rose")) + (defn noprompt [_] "") + (defn getprompt [p] + (def [line] (parser/where p)) + (string "janet:" line ":" (parser/state p :delimiters) "> ")) + (def prompter (if *quiet* noprompt getprompt)) + (defn getstdin [prompt buf] + (file/write stdout prompt) + (file/flush stdout) + (file/read stdin :line buf)) + (def getter (if *raw-stdin* getstdin getline)) + (defn getchunk [buf p] + (getter (prompter p) buf)) + (def onsig (if *quiet* (fn [x &] x) nil)) + (setdyn :pretty-format (if *colorize* "%.20Q" "%.20q")) + (setdyn :err-color (if *colorize* true)) + (repl getchunk onsig))) + ### ### ### Bootstrap diff --git a/src/mainclient/init.janet b/src/mainclient/init.janet deleted file mode 100644 index 5892aa65..00000000 --- a/src/mainclient/init.janet +++ /dev/null @@ -1,111 +0,0 @@ -# Copyright 2017-2019 (C) Calvin Rose - -(do - - (var *should-repl* false) - (var *no-file* true) - (var *quiet* false) - (var *raw-stdin* false) - (var *handleopts* true) - (var *exit-on-error* true) - (var *colorize* true) - (var *compile-only* false) - - (if-let [jp (os/getenv "JANET_PATH")] (setdyn :syspath jp)) - (if-let [jp (os/getenv "JANET_HEADERPATH")] (setdyn :headerpath jp)) - (def args (dyn :args)) - - # Flag handlers - (def handlers :private - {"h" (fn [&] - (print "usage: " (get args 0) " [options] script args...") - (print - `Options are: - -h : Show this help - -v : Print the version string - -s : Use raw stdin instead of getline like functionality - -e code : Execute a string of janet - -r : Enter the repl after running all scripts - -p : Keep on executing if there is a top level error (persistent) - -q : Hide prompt, logo, and repl output (quiet) - -k : Compile scripts but do not execute - -m syspath : Set system path for loading global modules - -c source output : Compile janet source code into an image - -n : Disable ANSI color output in the repl - -l path : Execute code in a file before running the main script - -- : Stop handling options`) - (os/exit 0) - 1) - "v" (fn [&] (print janet/version "-" janet/build) (os/exit 0) 1) - "s" (fn [&] (set *raw-stdin* true) (set *should-repl* true) 1) - "r" (fn [&] (set *should-repl* true) 1) - "p" (fn [&] (set *exit-on-error* false) 1) - "q" (fn [&] (set *quiet* true) 1) - "k" (fn [&] (set *compile-only* true) (set *exit-on-error* false) 1) - "n" (fn [&] (set *colorize* false) 1) - "m" (fn [i &] (setdyn :syspath (get args (+ i 1))) 2) - "c" (fn [i &] - (def e (dofile (get args (+ i 1)))) - (spit (get args (+ i 2)) (make-image e)) - (set *no-file* false) - 3) - "-" (fn [&] (set *handleopts* false) 1) - "l" (fn [i &] - (import* (get args (+ i 1)) - :prefix "" :exit *exit-on-error*) - 2) - "e" (fn [i &] - (set *no-file* false) - (eval-string (get args (+ i 1))) - 2)}) - - (defn- dohandler [n i &] - (def h (get handlers n)) - (if h (h i) (do (print "unknown flag -" n) ((get handlers "h"))))) - - (def- safe-forms {'defn true 'defn- true 'defmacro true 'defmacro- true}) - (def- importers {'import true 'import* true 'use true 'dofile true 'require true}) - (defn- evaluator - [thunk source env where] - (if *compile-only* - (when (tuple? source) - (cond - (safe-forms (source 0)) (thunk) - (importers (source 0)) - (do - (let [[l c] (tuple/sourcemap source) - newtup (tuple/setmap (tuple ;source :evaluator evaluator) l c)] - ((compile newtup env where)))))) - (thunk))) - - # Process arguments - (var i 0) - (def lenargs (length args)) - (while (< i lenargs) - (def arg (get args i)) - (if (and *handleopts* (= "-" (string/slice arg 0 1))) - (+= i (dohandler (string/slice arg 1 2) i)) - (do - (set *no-file* false) - (dofile arg :prefix "" :exit *exit-on-error* :evaluator evaluator) - (set i lenargs)))) - - (when (and (not *compile-only*) (or *should-repl* *no-file*)) - (if-not *quiet* - (print "Janet " janet/version "-" janet/build " Copyright (C) 2017-2019 Calvin Rose")) - (defn noprompt [_] "") - (defn getprompt [p] - (def [line] (parser/where p)) - (string "janet:" line ":" (parser/state p :delimiters) "> ")) - (def prompter (if *quiet* noprompt getprompt)) - (defn getstdin [prompt buf] - (file/write stdout prompt) - (file/flush stdout) - (file/read stdin :line buf)) - (def getter (if *raw-stdin* getstdin getline)) - (defn getchunk [buf p] - (getter (prompter p) buf)) - (def onsig (if *quiet* (fn [x &] x) nil)) - (setdyn :pretty-format (if *colorize* "%.20Q" "%.20q")) - (setdyn :err-color (if *colorize* true)) - (repl getchunk onsig))) diff --git a/src/mainclient/main.c b/src/mainclient/main.c index 767da630..a04f2932 100644 --- a/src/mainclient/main.c +++ b/src/mainclient/main.c @@ -31,9 +31,6 @@ #endif #endif -extern const unsigned char *janet_gen_init; -extern int32_t janet_gen_init_size; - int main(int argc, char **argv) { int i, status; JanetArray *args; @@ -83,13 +80,15 @@ int main(int argc, char **argv) { args = janet_array(argc); for (i = 1; i < argc; i++) janet_array_push(args, janet_cstringv(argv[i])); - janet_table_put(env, janet_ckeywordv("args"), janet_wrap_array(args)); /* Save current executable path to (dyn :executable) */ janet_table_put(env, janet_ckeywordv("executable"), janet_cstringv(argv[0])); /* Run startup script */ - status = janet_dobytes(env, janet_gen_init, janet_gen_init_size, "init.janet", NULL); + Janet mainfun, out; + janet_resolve(env, janet_csymbol("cli-main"), &mainfun); + Janet mainargs[1] = { janet_wrap_array(args) }; + status = janet_pcall(janet_unwrap_function(mainfun), 1, mainargs, &out, NULL); /* Deinitialize vm */ janet_deinit();