diff --git a/bin/moonc b/bin/moonc index bb9c0d0..f5b1184 100755 --- a/bin/moonc +++ b/bin/moonc @@ -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 diff --git a/moonscript-dev-1.rockspec b/moonscript-dev-1.rockspec index 7fd5ef1..f1b4a1c 100644 --- a/moonscript-dev-1.rockspec +++ b/moonscript-dev-1.rockspec @@ -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", diff --git a/moonscript/cmd/moonc.lua b/moonscript/cmd/moonc.lua new file mode 100644 index 0000000..642e68c --- /dev/null +++ b/moonscript/cmd/moonc.lua @@ -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 +} diff --git a/moonscript/cmd/moonc.moon b/moonscript/cmd/moonc.moon new file mode 100644 index 0000000..79cefe1 --- /dev/null +++ b/moonscript/cmd/moonc.moon @@ -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 +} diff --git a/spec/cmd_spec.moon b/spec/cmd_spec.moon new file mode 100644 index 0000000..cee4bbe --- /dev/null +++ b/spec/cmd_spec.moon @@ -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 +