moonscript/moonc
2011-07-16 11:51:40 -07:00

233 lines
4.2 KiB
Lua
Executable File

#!/usr/bin/lua
module("moonscript", package.seeall)
require "moonscript.parse"
require "moonscript.compile"
require "moonscript.util"
require "alt_getopt"
require "lfs"
local opts, ind = alt_getopt.get_opts(arg, "hwt:", { help = "h" })
local help = [[Usage: %s [options] file...
-h Print this message
-w Watch file/directory
-t path Specify where to place compiled files
]]
function print_help(err)
if err then print("Error: "..err) end
print(help:format(arg[0]))
os.exit()
end
function mkdir(path)
local chunks = util.split(path, "/")
local accum
for _, dir in ipairs(chunks) do
accum = accum and accum.."/"..dir or dir
lfs.mkdir(accum)
end
return lfs.attributes(path, "mode")
end
function normalize(path)
return path:match("(.-)/*$").."/"
end
function get_dir(fname)
return fname:match("^(.-)[^/]*$")
end
-- convert .moon to .lua
function convert_path(path)
return (path:gsub("%.moon$", ".lua"))
end
function compile_file(from, to)
local f = io.open(from)
if not f then
return nil, "Can't find file"
end
local text = f:read("*a")
local tree, err = parse.string(text)
if not tree then
return nil, err
end
local code, err, pos = compile.tree(tree)
if not code then
return nil, compile.format_error(err, pos, text)
end
mkdir(get_dir(to))
local out_f = io.open(to, "w")
if not out_f then
return nil, "Failed to write output: "..to
end
out_f:write(code.."\n")
out_f:close()
return true
end
function scan_directory(root, collected)
root = normalize(root)
collected = collected or {}
for fname in lfs.dir(root) do
if not fname:match("^%.") then
local full_path = root..fname
if lfs.attributes(full_path, "mode") == "directory" then
scan_directory(full_path, collected)
end
if fname:match(".moon") then
table.insert(collected, full_path)
end
end
end
return collected
end
function append(a, b)
for _, v in ipairs(b) do
table.insert(a, v)
end
end
function remove_dups(tbl)
local hash = {}
local final = {}
for _, v in ipairs(tbl) do
if not hash[v] then
table.insert(final, v)
hash[v] = true
end
end
return final
end
function get_files(fname, files)
files = files or {}
if lfs.attributes(fname, "mode") == "directory" then
append(files, scan_directory(fname))
else
table.insert(files, "./"..fname)
end
return files
end
if opts.h then print_help() end
local inputs = {}
for i = ind, #arg do
table.insert(inputs, arg[i])
end
if #inputs == 0 then
print_help("No files specified")
end
local target_dir = "."
if opts.t then
if mkdir(opts.t) ~= "directory" then
print_help("Invalid target dir")
end
target_dir = opts.t
end
target_dir = target_dir.."/"
local files = {}
for _, input in ipairs(inputs) do
get_files(input, files)
end
files = remove_dups(files)
function dump(tbl)
local items = {}
for k,v in pairs(tbl) do
table.insert(items, ('%s="%s"'):format(k,v))
end
return "{ "..table.concat(items, ", ").." }"
end
if opts.w then
local inotify
if not pcall(function()
inotify = require "inotify"
end) then
print_help("inotify not installed")
end
local dirs = {}
for _, fname in ipairs(files) do
table.insert(dirs, get_dir(fname))
end
dirs = remove_dups(dirs)
print(("Starting watch loop, Ctrl-C to exit [%d dirs]"):format(#dirs))
local wd_table = {}
local handle = inotify:init()
for _, dir in ipairs(dirs) do
local wd = handle:addwatch(dir, inotify.IN_MODIFY)
wd_table[wd] = dir
end
while true do
local success, events = pcall(handle.read, handle)
if not success then
print"\nQuitting..."
break
end
if events then
for _, ev in ipairs(events) do
local fname = wd_table[ev.wd]..ev.name
if fname:match("%.moon$") then
local target = target_dir..convert_path(fname)
local success, err = compile_file(fname, target)
if not success then
print()
print("Error: "..fname)
print(err)
print()
else
print("Built", fname)
end
end
end
else break end
end
else
for _, fname in ipairs(files) do
local success, err = compile_file(fname, target_dir..convert_path(fname))
if not success then
print(fname, err)
break
else
print("Built", fname)
end
end
end