clone url: git://git.m455.casa/fa
esperbuild/espersrc/fennel-0.7.0/old/launcher.lua
1 | #!/usr/bin/env lua |
2 |
|
3 | -- This is the old version of the launcher wrapper script; we keep it around |
4 | -- for bootstraping purposes to avoid chicken/egg problems using launcher.fnl |
5 | -- to compile Fennel itself. In general there is no need to keep this file in |
6 | -- sync with launcher.fnl; changes for new features should just go there. |
7 |
|
8 | local fennel_dir = arg[0]:match("(.-)[^\\/]+$") |
9 | package.path = fennel_dir .. "?.lua;" .. package.path |
10 | local fennel = require('fennel') |
11 | local unpack = unpack or table.unpack |
12 |
|
13 | local help = [[ |
14 | Usage: fennel [FLAG] [FILE] |
15 |
|
16 | Run fennel, a lisp programming language for the Lua runtime. |
17 |
|
18 | --repl : Command to launch an interactive repl session |
19 | --compile FILES : Command to compile files and write Lua to stdout |
20 | --eval SOURCE (-e) : Command to evaluate source code and print the result |
21 |
|
22 | --no-searcher : Skip installing package.searchers entry |
23 | --indent VAL : Indent compiler output with VAL |
24 | --add-package-path PATH : Add PATH to package.path for finding Lua modules |
25 | --add-fennel-path PATH : Add PATH to fennel.path for finding Fennel modules |
26 | --globals G1[,G2...] : Allow these globals in addition to standard ones |
27 | --globals-only G1[,G2] : Same as above, but exclude standard ones |
28 | --check-unused-locals : Raise error when compiling code with unused locals |
29 | --require-as-include : Inline required modules in the output |
30 | --metadata : Enable function metadata, even in compiled output |
31 | --no-metadata : Disable function metadata, even in REPL |
32 | --correlate : Make Lua output line numbers match Fennel input |
33 | --load FILE (-l) : Load the specified FILE before executing the command |
34 | --no-fennelrc : Skip loading ~/.fennelrc when launching repl |
35 |
|
36 | --help (-h) : Display this text |
37 | --version (-v) : Show version |
38 |
|
39 | Metadata is typically considered a development feature and is not recommended |
40 | for production. It is used for docstrings and enabled by default in the REPL. |
41 |
|
42 | When not given a command, runs the file given as the first argument. |
43 | When given neither command nor file, launches a repl. |
44 |
|
45 | If ~/.fennelrc exists, loads it before launching a repl.]] |
46 |
|
47 | local options = {} |
48 |
|
49 | local function dosafe(filename, opts, args) |
50 | local ok, val = xpcall(function() |
51 | return fennel.dofile(filename, opts, unpack(args)) |
52 | end, fennel.traceback) |
53 | if not ok then |
54 | io.stderr:write(val .. "\n") |
55 | os.exit(1) |
56 | end |
57 | return val |
58 | end |
59 |
|
60 | local function allowGlobals(globalNames) |
61 | options.allowedGlobals = {} |
62 | for g in globalNames:gmatch("([^,]+),?") do |
63 | table.insert(options.allowedGlobals, g) |
64 | end |
65 | end |
66 |
|
67 | for i=#arg, 1, -1 do |
68 | if arg[i] == "--no-searcher" then |
69 | options.no_searcher = true |
70 | table.remove(arg, i) |
71 | elseif arg[i] == "--indent" then |
72 | options.indent = table.remove(arg, i+1) |
73 | if options.indent == "false" then options.indent = false end |
74 | table.remove(arg, i) |
75 | elseif arg[i] == "--add-package-path" then |
76 | local entry = table.remove(arg, i+1) |
77 | package.path = entry .. ";" .. package.path |
78 | table.remove(arg, i) |
79 | elseif arg[i] == "--add-fennel-path" then |
80 | local entry = table.remove(arg, i+1) |
81 | fennel.path = entry .. ";" .. fennel.path |
82 | table.remove(arg, i) |
83 | elseif arg[i] == "--load" or arg[i] == "-l" then |
84 | local file = table.remove(arg, i+1) |
85 | dosafe(file, options, {}) |
86 | table.remove(arg, i) |
87 | elseif arg[i] == "--no-fennelrc" then |
88 | options.fennelrc = false |
89 | table.remove(arg, i) |
90 | elseif arg[i] == "--correlate" then |
91 | options.correlate = true |
92 | table.remove(arg, i) |
93 | elseif arg[i] == "--check-unused-locals" then |
94 | options.checkUnusedLocals = true |
95 | table.remove(arg, i) |
96 | elseif arg[i] == "--globals" then |
97 | allowGlobals(table.remove(arg, i+1)) |
98 | for globalName in pairs(_G) do |
99 | table.insert(options.allowedGlobals, globalName) |
100 | end |
101 | table.remove(arg, i) |
102 | elseif arg[i] == "--globals-only" then |
103 | allowGlobals(table.remove(arg, i+1)) |
104 | table.remove(arg, i) |
105 | elseif arg[i] == "--require-as-include" then |
106 | options.requireAsInclude = true |
107 | table.remove(arg, i) |
108 | elseif arg[i] == "--metadata" then |
109 | options.useMetadata = true |
110 | table.remove(arg, i) |
111 | elseif arg[i] == "--no-metadata" then |
112 | options.useMetadata = false |
113 | table.remove(arg, i) |
114 | end |
115 | end |
116 |
|
117 | if not options.no_searcher then |
118 | local opts = {} |
119 | for k,v in pairs(options) do opts[k] = v end |
120 | table.insert((package.loaders or package.searchers), fennel.make_searcher(opts)) |
121 | end |
122 |
|
123 | -- Try to load readline library |
124 | local function tryReadline(opts) |
125 | local readline_ok, readline = pcall(require, "readline") |
126 | if readline_ok then |
127 | if readline.set_readline_name then -- added as of readline.lua 2.6-0 |
128 | readline.set_readline_name('fennel') |
129 | end |
130 | readline.set_options({ |
131 | keeplines = 1000, histfile = '', }) |
132 | function opts.readChunk(parserState) |
133 | local prompt = parserState.stackSize > 0 and '.. ' or '>> ' |
134 | local str = readline.readline(prompt) |
135 | if str then |
136 | return str .. "\n" |
137 | end |
138 | end |
139 |
|
140 | -- completer is registered by the repl, until then returns empty list |
141 | local completer |
142 | function opts.registerCompleter(replCompleter) |
143 | completer = replCompleter |
144 | end |
145 | local function replCompleter(text, from, to) |
146 | if completer then |
147 | -- stop completed syms from adding extra space on match |
148 | readline.set_completion_append_character('') |
149 | return completer(text:sub(from, to)) |
150 | else |
151 | return {} |
152 | end |
153 | end |
154 | readline.set_complete_function(replCompleter) |
155 | return readline |
156 | end |
157 | end |
158 |
|
159 | -- TODO: generalize this instead of hardcoding it |
160 | local fok, friendly = pcall(fennel.dofile, fennel_dir .. "fennelfriend.fnl", options) |
161 | if fok then |
162 | options["assert-compile"] = friendly["assert-compile"] |
163 | options["parse-error"] = friendly["parse-error"] |
164 | end |
165 |
|
166 | if arg[1] == "--repl" or #arg == 0 then |
167 | local ppok, pp = pcall(fennel.dofile, fennel_dir .. "fennelview.fnl", options) |
168 | if ppok then |
169 | options.pp = pp |
170 | else |
171 | ppok, pp = pcall(require, "fennelview") |
172 | if ppok then |
173 | options.pp = pp |
174 | end |
175 | end |
176 |
|
177 | local readline = tryReadline(options) |
178 |
|
179 | if options.fennelrc ~= false then |
180 | local home = os.getenv("HOME") |
181 | local xdg_config_home = os.getenv("XDG_CONFIG_HOME") or home .. "/.config" |
182 | local xdg_initfile = xdg_config_home .. "/fennel/fennelrc" |
183 | local home_initfile = home .. "/.fennelrc" |
184 | local init, initFilename = io.open(xdg_initfile, "rb"), xdg_initfile |
185 | if not init then |
186 | init, initFilename = io.open(home_initfile, "rb"), home_initfile |
187 | end |
188 |
|
189 | if init then |
190 | init:close() |
191 | -- pass in options so fennerlrc can make changes to it |
192 | dosafe(initFilename, options, {options}) |
193 | end |
194 | end |
195 |
|
196 | print("Welcome to Fennel " .. fennel.version .. "!") |
197 | if options.useMetadata ~= false then |
198 | print("Use (doc something) to view documentation.") |
199 | end |
200 | fennel.repl(options) |
201 | -- if readline loaded, persist history (noop if histfile == '') |
202 | if readline then readline.save_history() end |
203 | elseif arg[1] == "--compile" then |
204 | for i = 2, #arg do |
205 | local f = arg[i] == "-" and io.stdin or assert(io.open(arg[i], "rb")) |
206 | options.filename=arg[i] |
207 | local ok, val = xpcall(function() |
208 | return fennel.compileString(f:read("*all"), options) |
209 | end, fennel.traceback) |
210 | if ok then |
211 | print(val) |
212 | else |
213 | io.stderr:write(val .. "\n") |
214 | os.exit(1) |
215 | end |
216 | f:close() |
217 | end |
218 | elseif arg[1] == "--eval" or arg[1] == "-e" then |
219 | if arg[2] and arg[2] ~= "-" then |
220 | print(fennel.eval(arg[2], options)) |
221 | else |
222 | local source = io.stdin:read("*a") |
223 | print(fennel.eval(source, options)) |
224 | end |
225 | elseif arg[1] == "--version" or arg[1] == "-v" then |
226 | print("Fennel " .. fennel.version) |
227 | elseif #arg >= 1 and arg[1] ~= "--help" and arg[1] ~= "-h" then |
228 | local filename = table.remove(arg, 1) -- let the script have remaining args |
229 | if filename == "-" then |
230 | local source = io.stdin:read("*a") |
231 | fennel.eval(source, options) |
232 | else |
233 | dosafe(filename, options, arg) |
234 | end |
235 | else |
236 | print(help) |
237 | end |