moonscript/bin/moonc

233 lines
5.2 KiB
Plaintext
Raw Normal View History

2011-08-13 04:07:44 +00:00
#!/usr/bin/env lua
local argparse = require "argparse"
2013-02-28 03:17:16 +00:00
local lfs = require "lfs"
local parser = argparse()
parser:flag("-l --lint", "Perform a lint on the file instead of compiling")
parser:flag("-v --version", "Print version")
parser:flag("-w --watch", "Watch file/directory for updates")
parser:mutex(
parser:flag("-t --output-to", "Specify where to place compiled files"),
parser:flag("-o", "Write output to file"):args(1),
parser:flag("-p", "Write output to standard output"),
parser:flag("-T", "Write parse tree instead of code (to stdout)"),
parser:flag("-b", "Write parse and compile time instead of code(to stdout)"),
parser:flag("-X", "Write line rewrite map instead of code (to stdout)")
)
parser:flag("-",
"Read from standard in, print to standard out (Must be only argument)")
local read_stdin = arg[1] == "--" -- luacheck: ignore 113
if not read_stdin then
parser:argument("file/directory"):args("+")
end
2012-01-22 19:53:13 +00:00
local opts = parser:parse()
if opts.version then
2011-07-19 06:53:43 +00:00
local v = require "moonscript.version"
v.print_version()
os.exit()
end
2013-12-27 06:44:54 +00:00
function log_msg(...)
2011-08-13 04:07:44 +00:00
if not opts.p then
2013-12-27 06:44:54 +00:00
io.stderr:write(table.concat({...}, " ") .. "\n")
end
2011-08-13 04:07:44 +00:00
end
2014-06-18 16:23:41 +00:00
local moonc = require("moonscript.cmd.moonc")
2015-03-12 08:09:17 +00:00
local util = require "moonscript.util"
2014-06-18 16:23:41 +00:00
local normalize_dir = moonc.normalize_dir
2014-06-18 16:48:25 +00:00
local compile_and_write = moonc.compile_and_write
2014-06-18 17:14:26 +00:00
local path_to_target = moonc.path_to_target
2011-08-13 04:07:44 +00:00
2014-06-18 16:48:25 +00:00
local function scan_directory(root, collected)
2014-06-18 16:23:41 +00:00
root = normalize_dir(root)
collected = collected or {}
for fname in lfs.dir(root) do
2014-06-17 07:03:13 +00:00
if not fname:match("^%.") then
local full_path = root..fname
if lfs.attributes(full_path, "mode") == "directory" then
scan_directory(full_path, collected)
2016-09-25 17:18:42 +00:00
elseif fname:match("%.moon$") then
table.insert(collected, full_path)
end
end
end
return collected
end
2014-06-18 16:48:25 +00:00
local function remove_dups(tbl, key_fn)
local hash = {}
local final = {}
for _, v in ipairs(tbl) do
2014-06-17 17:45:42 +00:00
local dup_key = key_fn and key_fn(v) or v
if not hash[dup_key] then
table.insert(final, v)
2014-06-17 17:45:42 +00:00
hash[dup_key] = true
end
end
return final
end
2014-06-17 17:45:42 +00:00
-- creates tuples of input and target
2014-06-18 16:48:25 +00:00
local function get_files(fname, files)
files = files or {}
if lfs.attributes(fname, "mode") == "directory" then
2014-06-17 17:45:42 +00:00
for _, sub_fname in ipairs(scan_directory(fname)) do
2014-06-18 17:14:26 +00:00
table.insert(files, {
2014-06-18 17:26:20 +00:00
sub_fname,
path_to_target(sub_fname, opts.output_to, fname)
2014-06-18 17:26:20 +00:00
})
2014-06-17 17:45:42 +00:00
end
else
2014-06-18 17:14:26 +00:00
table.insert(files, {
2014-06-18 17:26:20 +00:00
fname,
path_to_target(fname, opts.output_to)
2014-06-18 17:26:20 +00:00
})
end
return files
end
2012-01-22 19:53:13 +00:00
if read_stdin then
2014-06-18 17:26:20 +00:00
local parse = require "moonscript.parse"
local compile = require "moonscript.compile"
2012-01-22 19:53:13 +00:00
local text = io.stdin:read("*a")
local tree, err = parse.string(text)
2014-06-18 17:26:20 +00:00
2012-01-22 19:53:13 +00:00
if not tree then error(err) end
local code, err, pos = compile.tree(tree)
if not code then
error(compile.format_error(err, pos, text))
end
print(code)
os.exit()
end
local inputs = opts["file/directory"]
local files = {}
for _, input in ipairs(inputs) do
get_files(input, files)
end
files = remove_dups(files, function(f)
2014-06-18 17:26:20 +00:00
return f[2]
end)
2014-06-17 17:45:42 +00:00
-- returns an iterator that returns files that have been updated
2014-06-18 16:48:25 +00:00
local function create_watcher(files)
2016-04-14 02:47:27 +00:00
local watchers = require("moonscript.cmd.watchers")
2016-04-14 02:47:27 +00:00
if watchers.InotifyWacher:available() then
return watchers.InotifyWacher(files):each_update()
end
2016-04-14 03:05:51 +00:00
return watchers.SleepWatcher(files):each_update()
end
if opts.watch then
2015-12-28 06:14:55 +00:00
-- build function to check for lint or compile in watch
local handle_file
if opts.lint then
2015-12-28 06:14:55 +00:00
local lint = require "moonscript.cmd.lint"
handle_file = lint.lint_file
else
handle_file = compile_and_write
end
local watcher = create_watcher(files)
-- catches interrupt error for ctl-c
local protected = function()
local status, file = true, watcher()
if status then
return file
elseif file ~= "interrupted!" then
error(file)
end
end
for fname in protected do
2014-06-19 07:00:10 +00:00
local target = path_to_target(fname, opts.t)
2014-06-19 07:04:10 +00:00
if opts.o then
target = opts.o
end
2015-12-28 06:14:55 +00:00
local success, err = handle_file(fname, target)
if opts.lint then
2015-12-28 04:36:54 +00:00
if success then
io.stderr:write(success .. "\n\n")
elseif err then
io.stderr:write(fname .. "\n" .. err .. "\n\n")
end
elseif not success then
2013-12-27 06:44:54 +00:00
io.stderr:write(table.concat({
"",
"Error: " .. fname,
err,
"\n",
}, "\n"))
2014-06-18 16:23:41 +00:00
elseif success == "build" then
log_msg("Built", fname, "->", target)
end
end
2013-12-27 06:44:54 +00:00
io.stderr:write("\nQuitting...\n")
elseif opts.lint then
2016-01-07 23:37:47 +00:00
local has_linted_with_error;
2015-12-28 06:14:55 +00:00
local lint = require "moonscript.cmd.lint"
for _, tuple in pairs(files) do
local fname = tuple[1]
2015-12-28 06:14:55 +00:00
local res, err = lint.lint_file(fname)
2013-12-26 09:29:00 +00:00
if res then
2016-01-07 23:37:47 +00:00
has_linted_with_error = true
2013-12-27 06:44:54 +00:00
io.stderr:write(res .. "\n\n")
2013-12-27 23:32:06 +00:00
elseif err then
2016-01-07 23:37:47 +00:00
has_linted_with_error = true
2013-12-27 23:32:06 +00:00
io.stderr:write(fname .. "\n" .. err.. "\n\n")
2013-12-26 09:29:00 +00:00
end
end
2016-01-07 23:37:47 +00:00
if has_linted_with_error then
os.exit(1)
end
else
for _, tuple in ipairs(files) do
2015-03-12 08:09:17 +00:00
local fname, target = util.unpack(tuple)
2014-06-19 07:04:10 +00:00
if opts.o then
target = opts.o
end
2014-07-09 06:28:45 +00:00
local success, err = compile_and_write(fname, target, {
2015-02-28 19:47:58 +00:00
print = opts.p,
fname = fname,
benchmark = opts.b,
show_posmap = opts.X,
show_parse_tree = opts.T,
2014-07-09 06:28:45 +00:00
})
2015-02-28 19:47:58 +00:00
if not success then
2013-12-27 06:44:54 +00:00
io.stderr:write(fname .. "\t" .. err .. "\n")
2011-09-19 06:23:23 +00:00
os.exit(1)
2014-06-18 16:23:41 +00:00
elseif success == "build" then
log_msg("Built", fname)
end
end
end