start moving moonc code to moonscript

This commit is contained in:
leaf corcoran 2014-06-18 09:23:41 -07:00
parent a4585f8b1c
commit c60d83c546
5 changed files with 351 additions and 102 deletions

128
bin/moonc
View File

@ -55,62 +55,19 @@ function print_help(err)
end
end
function mkdir(path)
local chunks = util.split(path, dirsep)
local accum
for _, dir in ipairs(chunks) do
accum = accum and accum.. dirsep ..dir or dir
lfs.mkdir(accum)
end
return lfs.attributes(path, "mode")
end
function normalize(path)
return path:match("^(.-)" .. dirsep .. "*$")..dirsep
end
function parse_dir(fname)
return fname:match("^(.-)[^" .. dirsep .. "]*$")
end
function parse_file(fname)
return fname:match("^.-([^" .. dirsep .. "]*)$")
end
-- convert .moon to .lua
function convert_path(path)
local new_path = path:gsub("%.moon$", ".lua")
if new_path == path then
new_path = path .. ".lua"
end
return new_path
end
function log_msg(...)
if not opts.p then
io.stderr:write(table.concat({...}, " ") .. "\n")
end
end
local gettime = nil
if opts.b then
pcall(function()
require "socket"
gettime = socket.gettime
end)
function format_time(time)
return ("%.3fms"):format(time*1000)
end
if not gettime then
print_help"LuaSocket needed for benchmark"
end
else
gettime = function() return 0 end
end
local moonc = require("moonscript.cmd.moonc")
local mkdir = moonc.mkdir
local normalize_dir = moonc.normalize_dir
local parse_dir = moonc.parse_dir
local parse_file = moonc.parse_file
local convert_path = moonc.convert_path
local compile_file_text = moonc.compile_file_text
function write_file(fname, code)
if opts.p then
@ -125,50 +82,8 @@ function write_file(fname, code)
out_f:write(code.."\n")
out_f:close()
end
return true
end
function compile_file(text, fname)
local parse_time = gettime()
local tree, err = parse.string(text)
parse_time = gettime() - parse_time
if not tree then
return nil, err
end
if opts.T then
opts.p = true
dump_tree(tree)
return ""
else
local compile_time = gettime()
local code, posmap_or_err, err_pos = compile.tree(tree)
compile_time = gettime() - compile_time
if not code then
return nil, compile.format_error(posmap_or_err, err_pos, text)
end
if opts.X then
opts.p = true
print("Pos", "Lua", ">>", "Moon")
print(util.debug_posmap(posmap_or_err, text, code))
return ""
end
if opts.b then
opts.p = true
return table.concat({
fname,
"Parse time \t" .. format_time(parse_time),
"Compile time\t" .. format_time(compile_time),
""
}, "\n")
end
return code
end
return "built"
end
function compile_and_write(from, to)
@ -178,16 +93,25 @@ function compile_and_write(from, to)
end
local text = f:read("*a")
local code, err = compile_file(text, from)
if not code then
local code, err = compile_file_text(text, from, {
benchmark = opts.b,
show_posmap = opts.X,
show_parse_tree = opts.T,
})
if not code and err then
return nil, err
end
if not code then
return true
end
return write_file(to, code)
end
function scan_directory(root, collected)
root = normalize(root)
root = normalize_dir(root)
collected = collected or {}
for fname in lfs.dir(root) do
@ -247,7 +171,7 @@ function get_files(fname, files)
end
end
target_fname = normalize(opts.t) .. target_fname
target_fname = normalize_dir(opts.t) .. target_fname
end
table.insert(files, {sub_fname, target_fname})
@ -255,7 +179,7 @@ function get_files(fname, files)
else
local target_fname = convert_path(fname)
if opts.t then
local prefix = normalize(opts.t)
local prefix = normalize_dir(opts.t)
if is_abs_path(target_fname) then
target_fname = parse_file(target_fname)
@ -426,8 +350,8 @@ if opts.w then
err,
"\n",
}, "\n"))
else
log_msg("Built:", fname, "->", target)
elseif success == "build" then
log_msg("Built", fname, "->", target)
end
end
@ -450,8 +374,8 @@ else
if not success then
io.stderr:write(fname .. "\t" .. err .. "\n")
os.exit(1)
else
log_msg("Built", fname, "->", target)
elseif success == "build" then
log_msg("Built", fname)
end
end
end

View File

@ -28,6 +28,7 @@ build = {
["moonscript.base"] = "moonscript/base.lua",
["moonscript.cmd.coverage"] = "moonscript/cmd/coverage.lua",
["moonscript.cmd.lint"] = "moonscript/cmd/lint.lua",
["moonscript.cmd.moonc"] = "moonscript/cmd/moonc.lua",
["moonscript.compile"] = "moonscript/compile.lua",
["moonscript.compile.statement"] = "moonscript/compile/statement.lua",
["moonscript.compile.value"] = "moonscript/compile/value.lua",

134
moonscript/cmd/moonc.lua Normal file
View File

@ -0,0 +1,134 @@
local lfs = require("lfs")
local split
do
local _obj_0 = require("moonscript.util")
split = _obj_0.split
end
local dirsep = package.config:sub(1, 1)
local dirsep_chars
if dirsep == "\\" then
dirsep_chars = "\\/"
else
dirsep_chars = dirsep
end
local mkdir
mkdir = function(path)
local chunks = split(path, dirsep)
local accum
for _index_0 = 1, #chunks do
local dir = chunks[_index_0]
accum = accum and tostring(accum) .. tostring(dirsep) .. tostring(dir) or dir
lfs.mkdir(accum)
end
return lfs.attributes(path, "mode")
end
local normalize_dir
normalize_dir = function(path)
return path:match("^(.-)[" .. tostring(dirsep_chars) .. "]*$") .. dirsep
end
local parse_dir
parse_dir = function(path)
return (path:match("^(.-)[^" .. tostring(dirsep_chars) .. "]*$"))
end
local parse_file
parse_file = function(path)
return (path:match("^.-([^" .. tostring(dirsep_chars) .. "]*)$"))
end
local convert_path
convert_path = function(path)
local new_path = path:gsub("%.moon$", ".lua")
if new_path == path then
new_path = path .. ".lua"
end
return new_path
end
local format_time
format_time = function(time)
return ("%.3fms"):format(time * 1000)
end
local gettime
do
local socket
gettime = function()
if socket == nil then
pcall(function()
socket = require("socket")
end)
if not (socket) then
socket = false
end
end
if socket then
return socket.gettime()
else
return nil, "LuaSocket needed for benchmark"
end
end
end
local compile_file_text
compile_file_text = function(text, fname, opts)
if opts == nil then
opts = { }
end
local parse = require("moonscript.parse")
local compile = require("moonscript.compile")
local parse_time
if opts.benchmark then
parse_time = assert(gettime())
end
local tree, err = parse.string(text)
if not (tree) then
return nil, err
end
if parse_time then
parse_time = gettime() - parse_time
end
if opts.show_parse_tree then
local dump = require("moonscript.dump")
dump.tree(tree)
return nil
end
local compile_time
if opts.benchmark then
compile_time = gettime()
end
local code, posmap_or_err, err_pos = compile.tree(tree)
if not (code) then
return nil, compile.format_error(posmap_or_err, err_pos, text)
end
if compile_time then
compile_time = gettime() - compile_time
end
if opts.show_posmap then
local debug_posmap
do
local _obj_0 = require("moonscript.util")
debug_posmap = _obj_0.debug_posmap
end
print("Pos", "Lua", ">>", "Moon")
print(debug_posmap(posmap_or_err, text, code))
return nil
end
if opts.benchmark then
print(table.concat({
fname,
"Parse time \t" .. format_time(parse_time),
"Compile time\t" .. format_time(compile_time),
""
}, "\n"))
return nil
end
return code
end
return {
dirsep = dirsep,
mkdir = mkdir,
normalize_dir = normalize_dir,
parse_dir = parse_dir,
parse_file = parse_file,
new_path = new_path,
convert_path = convert_path,
gettime = gettime,
format_time = format_time,
compile_file_text = compile_file_text
}

122
moonscript/cmd/moonc.moon Normal file
View File

@ -0,0 +1,122 @@
-- assorted utilities for moonc command line tool
lfs = require "lfs"
import split from require "moonscript.util"
dirsep = package.config\sub 1,1
dirsep_chars = if dirsep == "\\"
"\\/" -- windows
else
dirsep
-- similar to mkdir -p
mkdir = (path) ->
chunks = split path, dirsep
local accum
for dir in *chunks
accum = accum and "#{accum}#{dirsep}#{dir}" or dir
lfs.mkdir accum
lfs.attributes path, "mode"
-- strips excess / and ensures path ends with /
normalize_dir = (path) ->
path\match("^(.-)[#{dirsep_chars}]*$") .. dirsep
-- parse the directory out of a path
parse_dir = (path) ->
(path\match "^(.-)[^#{dirsep_chars}]*$")
-- parse the filename out of a path
parse_file = (path) ->
(path\match "^.-([^#{dirsep_chars}]*)$")
-- converts .moon to a .lua path for calcuating compile target
convert_path = (path) ->
new_path = path\gsub "%.moon$", ".lua"
if new_path == path
new_path = path .. ".lua"
new_path
format_time = (time) ->
"%.3fms"\format time*1000
gettime = do
local socket
->
if socket == nil
pcall ->
socket = require "socket"
unless socket
socket = false
if socket
socket.gettime()
else
nil, "LuaSocket needed for benchmark"
-- compiles file to lua
-- returns nil, error on error
-- returns just nil if some option handled the output instead
compile_file_text = (text, fname, opts={}) ->
parse = require "moonscript.parse"
compile = require "moonscript.compile"
parse_time = if opts.benchmark
assert gettime!
tree, err = parse.string text
return nil, err unless tree
if parse_time
parse_time = gettime! - parse_time
if opts.show_parse_tree
dump = require "moonscript.dump"
dump.tree tree
return nil
compile_time = if opts.benchmark
gettime!
code, posmap_or_err, err_pos = compile.tree tree
unless code
return nil, compile.format_error posmap_or_err, err_pos, text
if compile_time
compile_time = gettime() - compile_time
if opts.show_posmap
import debug_posmap from require "moonscript.util"
print "Pos", "Lua", ">>", "Moon"
print debug_posmap posmap_or_err, text, code
return nil
if opts.benchmark
print table.concat {
fname,
"Parse time \t" .. format_time(parse_time),
"Compile time\t" .. format_time(compile_time),
""
}, "\n"
return nil
code
{
:dirsep
:mkdir
:normalize_dir
:parse_dir
:parse_file
:new_path
:convert_path
:gettime
:format_time
:compile_file_text
}

68
spec/cmd_spec.moon Normal file
View File

@ -0,0 +1,68 @@
moonc = require "moonscript.cmd.moonc"
-- TODO: add specs for windows equivalents
describe "moonc", ->
same = (fn, a, b)->
assert.same b, fn a
it "should normalize dir", ->
same moonc.normalize_dir, "hello/world/", "hello/world/"
same moonc.normalize_dir, "hello/world//", "hello/world/"
same moonc.normalize_dir, "", "/" -- wrong
same moonc.normalize_dir, "hello", "hello/"
it "should parse dir", ->
same moonc.parse_dir, "/hello/world/file", "/hello/world/"
same moonc.parse_dir, "/hello/world/", "/hello/world/"
same moonc.parse_dir, "world", ""
same moonc.parse_dir, "", ""
it "should parse file", ->
same moonc.parse_file, "/hello/world/file", "file"
same moonc.parse_file, "/hello/world/", ""
same moonc.parse_file, "world", "world"
same moonc.parse_file, "", ""
it "convert path", ->
same moonc.convert_path, "test.moon", "test.lua"
same moonc.convert_path, "/hello/file.moon", "/hello/file.lua"
same moonc.convert_path, "/hello/world/file", "/hello/world/file.lua"
it "chould compile file text", ->
assert.same {
[[return print('hello')]]
}, {
moonc.compile_file_text "print'hello'", "test.moon"
}
describe "stubbed lfs", ->
local dirs
before_each ->
dirs = {}
package.loaded.lfs = nil
package.loaded["moonscript.cmd.moonc"] = nil
package.loaded.lfs = {
mkdir: (dir) -> table.insert dirs, dir
attributes: -> "directory"
}
moonc = require "moonscript.cmd.moonc"
after_each ->
package.loaded.lfs = nil
package.loaded["moonscript.cmd.moonc"] = nil
moonc = require "moonscript.cmd.moonc"
it "should make directory", ->
moonc.mkdir "hello/world/directory"
assert.same {
"hello"
"hello/world"
"hello/world/directory"
}, dirs