clone url: git://git.m455.casa/fa
esperbuild/espersrc/fennel-0.7.0/src/launcher.fnl
1 | ;; This is the command-line entry point for Fennel. |
2 |
|
3 | (local fennel (require :fennel)) |
4 | (local unpack (or _G.unpack table.unpack)) |
5 |
|
6 | (local help " |
7 | Usage: fennel [FLAG] [FILE] |
8 |
|
9 | Run fennel, a lisp programming language for the Lua runtime. |
10 |
|
11 | --repl : Command to launch an interactive repl session |
12 | --compile FILES : Command to AOT compile files, writing Lua to stdout |
13 | --eval SOURCE (-e) : Command to evaluate source code and print the result |
14 |
|
15 | --no-searcher : Skip installing package.searchers entry |
16 | --indent VAL : Indent compiler output with VAL |
17 | --add-package-path PATH : Add PATH to package.path for finding Lua modules |
18 | --add-fennel-path PATH : Add PATH to fennel.path for finding Fennel modules |
19 | --globals G1[,G2...] : Allow these globals in addition to standard ones |
20 | --globals-only G1[,G2] : Same as above, but exclude standard ones |
21 | --require-as-include : Inline required modules in the output |
22 | --metadata : Enable function metadata, even in compiled output |
23 | --no-metadata : Disable function metadata, even in REPL |
24 | --correlate : Make Lua output line numbers match Fennel input |
25 | --load FILE (-l) : Load the specified FILE before executing the command |
26 | --lua LUA_EXE : Run in a child process with LUA_EXE (experimental) |
27 | --no-fennelrc : Skip loading ~/.fennelrc when launching repl |
28 | --plugin FILE : Activate the compiler plugin in FILE |
29 | --compile-binary FILE |
30 | OUT LUA_LIB LUA_DIR : Compile FILE to standalone binary OUT (experimental) |
31 | --compile-binary --help : Display further help for compiling binaries |
32 | --no-compiler-sandbox : Do not limit compiler environment to minimal sandbox |
33 |
|
34 | --help (-h) : Display this text |
35 | --version (-v) : Show version |
36 |
|
37 | Globals are not checked when doing AOT (ahead-of-time) compilation unless |
38 | the --globals-only flag is provided. |
39 |
|
40 | Metadata is typically considered a development feature and is not recommended |
41 | for production. It is used for docstrings and enabled by default in the REPL. |
42 |
|
43 | When not given a command, runs the file given as the first argument. |
44 | When given neither command nor file, launches a repl. |
45 |
|
46 | If ~/.fennelrc exists, loads it before launching a repl.") |
47 |
|
48 | (local options {:plugins []}) |
49 |
|
50 | (fn dosafely [f ...] |
51 | (let [args [...] |
52 | (ok val) (xpcall #(f (unpack args)) fennel.traceback)] |
53 | (when (not ok) |
54 | (io.stderr:write (.. val "\n")) |
55 | (os.exit 1)) |
56 | val)) |
57 |
|
58 | (fn allow-globals [global-names] |
59 | (set options.allowedGlobals []) |
60 | (each [g (global-names:gmatch "([^,]+),?")] |
61 | (table.insert options.allowedGlobals g))) |
62 |
|
63 | (fn handle-load [i] |
64 | (let [file (table.remove arg (+ i 1))] |
65 | (dosafely fennel.dofile file options) |
66 | (table.remove arg i))) |
67 |
|
68 | (fn handle-lua [i] |
69 | (table.remove arg i) ; remove the --lua flag from args |
70 | (let [tgt-lua (table.remove arg i) |
71 | cmd [(string.format "%s %s" tgt-lua (. arg 0))]] |
72 | (for [i 1 (# arg)] ; quote args to prevent shell escapes when executing |
73 | (table.insert cmd (string.format "%q" (. arg i)))) |
74 | (let [ok (os.execute (table.concat cmd " "))] |
75 | (os.exit (if ok 0 1) true)))) |
76 |
|
77 | ;; check for --lua first to ensure its child process retains all flags |
78 | (for [i (# arg) 1 -1] |
79 | (match (. arg i) "--lua" (handle-lua i))) |
80 |
|
81 | (for [i (# arg) 1 -1] |
82 | (match (. arg i) |
83 | "--no-searcher" (do (set options.no_searcher true) |
84 | (table.remove arg i)) |
85 | "--indent" (do (set options.indent (table.remove arg (+ i 1))) |
86 | (when (= options.indent "false") |
87 | (set options.indent false)) |
88 | (table.remove arg i)) |
89 | "--add-package-path" (let [entry (table.remove arg (+ i 1))] |
90 | (set package.path (.. entry ";" package.path)) |
91 | (table.remove arg i)) |
92 | "--add-fennel-path" (let [entry (table.remove arg (+ i 1))] |
93 | (set fennel.path (.. entry ";" fennel.path)) |
94 | (table.remove arg i)) |
95 | "--load" (handle-load i) |
96 | "-l" (handle-load i) |
97 | "--no-fennelrc" (do (set options.fennelrc false) |
98 | (table.remove arg i)) |
99 | "--correlate" (do (set options.correlate true) |
100 | (table.remove arg i)) |
101 | "--check-unused-locals" (do (set options.checkUnusedLocals true) |
102 | (table.remove arg i)) |
103 | "--globals" (do (allow-globals (table.remove arg (+ i 1))) |
104 | (each [global-name (pairs _G)] |
105 | (table.insert options.allowedGlobals global-name)) |
106 | (table.remove arg i)) |
107 | "--globals-only" (do (allow-globals (table.remove arg (+ i 1))) |
108 | (table.remove arg i)) |
109 | "--require-as-include" (do (set options.requireAsInclude true) |
110 | (table.remove arg i)) |
111 | "--metadata" (do (set options.useMetadata true) |
112 | (table.remove arg i)) |
113 | "--no-metadata" (do (set options.useMetadata false) |
114 | (table.remove arg i)) |
115 | "--no-compiler-sandbox" (do (set options.compiler-env _G) |
116 | (table.remove arg i)) |
117 | "--plugin" (let [plugin (fennel.dofile (table.remove arg (+ i 1)) |
118 | {:env :_COMPILER})] |
119 | (table.insert options.plugins 1 plugin) |
120 | (table.remove arg i)))) |
121 |
|
122 | (when (not options.no_searcher) |
123 | (let [opts []] |
124 | (each [k v (pairs options)] |
125 | (tset opts k v)) |
126 | (table.insert (or package.loaders package.searchers) |
127 | (fennel.make-searcher opts)))) |
128 |
|
129 | (fn try-readline [ok readline] |
130 | (when ok |
131 | (when readline.set_readline_name |
132 | (readline.set_readline_name "fennel")) |
133 | (readline.set_options {:keeplines 1000 :histfile ""}) |
134 | (fn options.readChunk [parser-state] |
135 | (let [prompt (if (< 0 parser-state.stack-size) ".. " ">> ") |
136 | str (readline.readline prompt)] |
137 | (if str (.. str "\n")))) |
138 | (var completer nil) |
139 | (fn options.registerCompleter [repl-completer] |
140 | (set completer repl-completer)) |
141 | (fn repl-completer [text from to] |
142 | (if completer |
143 | (do (readline.set_completion_append_character "") |
144 | (completer (text:sub from to))) |
145 | [])) |
146 | (readline.set_complete_function repl-completer) |
147 | readline)) |
148 |
|
149 | (fn load-initfile [] |
150 | (let [home (or (os.getenv "HOME") "/") |
151 | xdg-config-home (or (os.getenv "XDG_CONFIG_HOME") (.. home "/.config")) |
152 | xdg-initfile (.. xdg-config-home "/fennel/fennelrc") |
153 | home-initfile (.. home "/.fennelrc") |
154 | init (io.open xdg-initfile :rb) |
155 | init-filename (if init xdg-initfile home-initfile) |
156 | init (or init (io.open home-initfile :rb))] |
157 | (when init |
158 | (init:close) |
159 | (dosafely fennel.dofile init-filename options options fennel)))) |
160 |
|
161 | (fn repl [] |
162 | (let [readline (try-readline (pcall require :readline))] |
163 | (set options.pp (require :fennelview)) |
164 | (when (not= false options.fennelrc) |
165 | (load-initfile)) |
166 | (print (.. "Welcome to Fennel " fennel.version " on " _VERSION "!")) |
167 | (print "Use ,help to see available commands.") |
168 | (when (not readline) |
169 | (print "Try installing readline via luarocks for a better repl experience.")) |
170 | (fennel.repl options) |
171 | (when readline |
172 | (readline.save_history)))) |
173 |
|
174 | (fn eval [form] |
175 | (print (dosafely fennel.eval (if (= form "-") |
176 | (io.stdin:read :*a) |
177 | form) options))) |
178 |
|
179 | (match arg |
180 | ([] ? (= 0 (# arg))) (repl) |
181 | ["--repl"] (repl) |
182 | ["--compile" & files] (each [_ filename (ipairs files)] |
183 | (set options.filename filename) |
184 | (let [f (if (= filename "-") |
185 | io.stdin |
186 | (assert (io.open filename :rb))) |
187 | (ok val) (xpcall #(fennel.compile-string |
188 | (f:read :*a) options) |
189 | fennel.traceback)] |
190 | (if ok |
191 | (print val) |
192 | (do (io.stderr:write (.. val "\n")) |
193 | (os.exit 1))) |
194 | (f:close))) |
195 | ["--compile-binary" filename out |
196 | static-lua lua-include-dir & args] (let [bin (require :fennel.binary)] |
197 | (set options.filename filename) |
198 | (set options.requireAsInclude true) |
199 | (bin.compile filename out |
200 | static-lua lua-include-dir |
201 | options args)) |
202 | ["--compile-binary"] (print (. (require :fennel.binary) :help)) |
203 |
|
204 | ["--eval" form] (eval form) |
205 | ["-e" form] (eval form) |
206 | ["--version"] (print (.. "Fennel " fennel.version " on " _VERSION)) |
207 | ["--help"] (print help) |
208 | ["-h"] (print help) |
209 | ["-" & args] (dosafely fennel.eval (io.stdin:read :*a)) |
210 | [filename & args] (do (tset arg -2 (. arg -1)) |
211 | (tset arg -1 (. arg 0)) |
212 | (tset arg 0 (table.remove arg 1)) |
213 | (dosafely fennel.dofile filename options (unpack args)))) |