aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bitbucket@bruce-hill.com>2018-06-15 03:11:38 -0700
committerBruce Hill <bitbucket@bruce-hill.com>2018-06-15 03:11:56 -0700
commit9d6932a8721322a73861a26b7316c0a920eb7084 (patch)
treeb51fab3f7cae53856df1fc84666d94375ffb9b47
parent5629b81f78c722e8001b8cee1628085a78a8ea9f (diff)
Cleaned up/improved the command line interface, and fixed the
REPL/autoformatting.
-rw-r--r--README.md4
-rwxr-xr-xcompile_lib.sh12
-rw-r--r--nomsu.lua124
-rwxr-xr-xnomsu.moon98
4 files changed, 129 insertions, 109 deletions
diff --git a/README.md b/README.md
index fe679b0..57c26bd 100644
--- a/README.md
+++ b/README.md
@@ -11,8 +11,8 @@ Nomsu's only dependencies are [Lua 5.2 or later](https://www.lua.org/) (tested w
## Usage
* To get a nomsu [REPL](https://en.wikipedia.org/wiki/Read-eval-print_loop), simply run `lua nomsu.lua`.
-* To run a .nom file with nomsu code, run `lua nomsu.lua your_file.nom`. Or `lua nomsu.lua -` if reading from stdin.
-* (Advanced/optional) To precompile a .nom file into lua, run `lua nomsu.lua -o <output_filename> <input_file>` to precompile your file into lua (by default, saved at `<your_file>.lua`). If you run the compiler with the "-O" (for Optimized) flag, the compiler will run the precompiled lua files directly, instead of parsing and compiling the .nom files before running them. This is not necessary, but it can speed things up if you precompile a bunch of code that involves macros or compile-time activity.
+* To run a .nom file with nomsu code, run `lua nomsu.lua your_file.nom`.
+* (Advanced/optional) To precompile a .nom file into lua, run `lua nomsu.lua -c <input_file>` to precompile your file into lua (by default, saved in the same location, but with a `.lua` extension instead of `.nom`). If you run the compiler with the "-O" (for Optimized) flag, the compiler will run the precompiled lua files directly, instead of parsing and compiling the .nom files before running them. This is not necessary, but it can speed things up if you precompile a bunch of code that involves macros or compile-time activity.
* More usage options are avilable via `lua nomsu.lua --help`.
## Layout
diff --git a/compile_lib.sh b/compile_lib.sh
index d7df5f8..463bb20 100755
--- a/compile_lib.sh
+++ b/compile_lib.sh
@@ -4,13 +4,5 @@
set -e
moonc *.moon
rm -f core/*.lua lib/*.lua
-for file in core/*.nom; do
- printf "Compiling $file ..."
- luajit ./nomsu.lua -O -o "core/$(basename $file .nom).lua" $file
- echo "done."
-done
-for file in lib/*.nom; do
- printf "Compiling $file ..."
- luajit ./nomsu.lua -O -o "lib/$(basename $file .nom).lua" $file
- echo "done."
-done
+luajit ./nomsu.lua -c core lib
+echo "done."
diff --git a/nomsu.lua b/nomsu.lua
index ea1ba1b..a162b65 100644
--- a/nomsu.lua
+++ b/nomsu.lua
@@ -316,10 +316,7 @@ do
end
return tree
end,
- run = function(self, nomsu_code, compile_fn)
- if compile_fn == nil then
- compile_fn = nil
- end
+ run = function(self, nomsu_code)
local tree = assert(self:parse(nomsu_code))
if type(tree) == 'number' then
return nil
@@ -327,15 +324,12 @@ do
local lua = self:tree_to_lua(tree):as_statements()
lua:declare_locals()
lua:prepend("-- File: " .. tostring(nomsu_code.source or "") .. "\n")
- if compile_fn then
- compile_fn(lua)
+ if self.compile_fn then
+ self.compile_fn(lua, nomsu_code.source.filename)
end
return self:run_lua(lua)
end,
- run_file = function(self, filename, compile_fn)
- if compile_fn == nil then
- compile_fn = nil
- end
+ run_file = function(self, filename)
local loaded = self.environment.LOADED
if loaded[filename] then
return loaded[filename]
@@ -384,7 +378,7 @@ do
if not file then
error("File does not exist: " .. tostring(filename), 0)
end
- ret = self:run(Nomsu(Source(filename, 1, #file), file), compile_fn)
+ ret = self:run(Nomsu(Source(filename, 1, #file), file))
else
error("Invalid filetype for " .. tostring(filename), 0)
end
@@ -1355,7 +1349,8 @@ if arg and debug_getinfo(2).func ~= require then
/ {:format: ("-f" -> true) :}
/ {:syntax: ("-s" -> true) :}
/ {:print_file: "-p" ";" {file} :}
- / {:output_file: "-o" ";" {file} :}
+ / {:compile: ("-c" -> true) :}
+ / {:verbose: ("-v" -> true) :}
/ {:help: (("-h" / "--help") -> true) :}
file <- "-" / [^;]+
]], {
@@ -1368,15 +1363,16 @@ if arg and debug_getinfo(2).func ~= require then
if not args or args.help then
print([=[Nomsu Compiler
-Usage: (lua nomsu.lua | moon nomsu.moon) [-i] [-O] [-f] [-s] [--help] [-o output] [-p print_file] file1 file2... [-- nomsu args...]
+Usage: (lua nomsu.lua | moon nomsu.moon) [-i] [-O] [-v] [-c] [-f] [-s] [--help] [-p print_file] file1 file2... [-- nomsu args...]
OPTIONS
-i Run the compiler in interactive mode (REPL)
-O Run the compiler in optimized mode (use precompiled .lua versions of Nomsu files, when available)
+ -v Verbose: print compiled lua code
+ -c Compile .nom files into .lua files
-f Auto-format the given Nomsu file and print the result.
-s Check the program for syntax errors.
-h/--help Print this message.
- -o <file> Output the compiled Lua file to the given file (use "-" to output to stdout; if outputting to stdout and -p is not specified, -p will default to /dev/null)
-p <file> Print to the specified file instead of stdout.
<input> Input file can be "-" to use stdin.
]=])
@@ -1613,8 +1609,6 @@ OPTIONS
print_file = io.stdout
elseif args.print_file then
print_file = io.open(args.print_file, 'w')
- elseif args.output_file == '-' then
- print_file = nil
else
print_file = io.stdout
end
@@ -1634,55 +1628,64 @@ OPTIONS
return print_file:flush()
end
end
- local compile_fn
- if args.output_file then
- compile_fn = function(code)
- local output_file
- if args.output_file == "-" then
- output_file = io.stdout
- elseif args.output_file then
- output_file = io.open(args.output_file, 'w')
+ local input_files = { }
+ local to_run = { }
+ local _list_0 = args.inputs
+ for _index_0 = 1, #_list_0 do
+ local input = _list_0[_index_0]
+ for f in all_files(input) do
+ input_files[#input_files + 1] = f
+ to_run[f] = true
+ end
+ end
+ if args.compile or args.verbose then
+ nomsu.compile_fn = function(code, from_file)
+ if to_run[from_file] then
+ if args.verbose then
+ io.write(tostring(code), "\n")
+ end
+ if args.compile and from_file:match("%.nom$") then
+ local output_filename = from_file:gsub("%.nom$", ".lua")
+ local output_file = io.open(output_filename, 'w')
+ output_file:write("local IMMEDIATE = true;\n", tostring(code))
+ output_file:flush()
+ print(("Compiled %-25s -> %s"):format(from_file, output_filename))
+ return output_file:close()
+ end
end
- output_file:write("local IMMEDIATE = true;\n" .. tostring(code))
- return output_file:flush()
end
else
- compile_fn = nil
+ nomsu.compile_fn = nil
end
local parse_errs = { }
- local _list_0 = args.inputs
- for _index_0 = 1, #_list_0 do
- local input = _list_0[_index_0]
+ for _index_0 = 1, #input_files do
+ local filename = input_files[_index_0]
if args.syntax then
- for input_file in all_files(input) do
- local err
- ok, err = pcall(nomsu.parse, nomsu, Nomsu(input_file, io.open(input_file):read("*a")))
- if not ok then
- insert(parse_errs, err)
- elseif print_file then
- print_file:write("Parse succeeded: " .. tostring(input_file) .. "\n")
- print_file:flush()
- end
+ local err
+ ok, err = pcall(nomsu.parse, nomsu, Nomsu(filename, io.open(filename):read("*a")))
+ if not ok then
+ insert(parse_errs, err)
+ elseif print_file then
+ print_file:write("Parse succeeded: " .. tostring(filename) .. "\n")
+ print_file:flush()
end
elseif args.format then
- for input_file in all_files(input) do
- local tree = nomsu:parse(io.open(input_file):read("*a"))
- local formatted = tostring(self:tree_to_nomsu(tree))
- if output_file then
- output_file:write(formatted, "\n")
- output_file:flush()
- end
- if print_file then
- print_file:write(formatted, "\n")
- print_file:flush()
- end
+ local file = FILE_CACHE[filename]
+ if not file then
+ error("File does not exist: " .. tostring(filename), 0)
end
- elseif input == STDIN then
+ local tree = nomsu:parse(Nomsu(Source(filename, 1, #file), file))
+ local formatted = tostring(nomsu:tree_to_nomsu(tree))
+ if print_file then
+ print_file:write(formatted, "\n")
+ print_file:flush()
+ end
+ elseif filename == STDIN then
local file = io.input():read("*a")
FILE_CACHE.stdin = file
- nomsu:run(Nomsu(Source('stdin', 1, #file), file), compile_fn)
+ nomsu:run(Nomsu(Source('stdin', 1, #file), file))
else
- nomsu:run_file(input, compile_fn)
+ nomsu:run_file(filename)
end
end
if #parse_errs > 0 then
@@ -1693,9 +1696,9 @@ OPTIONS
os.exit(true, true)
end
if args.interactive then
- while true do
+ for repl_line = 1, math.huge do
io.write(colored.bright(colored.yellow(">> ")))
- local buff = ""
+ local buff = { }
while true do
local line = io.read("*L")
if line == "\n" or not line then
@@ -1705,14 +1708,21 @@ OPTIONS
break
end
line = line:gsub("\t", " ")
- buff = buff .. line
+ insert(buff, line)
io.write(colored.dim(colored.yellow(".. ")))
end
if #buff == 0 then
break
end
+ buff = concat(buff)
+ FILE_CACHE["REPL#" .. repl_line] = buff
+ local code = Nomsu(Source("REPL#" .. repl_line, 1, #buff), buff)
+ local err_hand
+ err_hand = function(error_message)
+ return print_err_msg(error_message)
+ end
local ret
- ok, ret = pcall(nomsu.run, nomsu, buff)
+ ok, ret = xpcall(nomsu.run, err_hand, nomsu, code)
if ok and ret ~= nil then
print("= " .. repr(ret))
elseif not ok then
diff --git a/nomsu.moon b/nomsu.moon
index 3c38b1f..94e6aa2 100755
--- a/nomsu.moon
+++ b/nomsu.moon
@@ -9,7 +9,7 @@
-- nomsu = Nomsu()
-- nomsu:run(your_nomsu_code)
-- Or from the command line:
--- lua nomsu.lua [input_file [output_file or -]]
+-- lua nomsu.lua your_file.nom
export lpeg, re
_pairs, _ipairs = pairs, ipairs
if jit
@@ -324,19 +324,19 @@ class NomsuCompiler
return tree
- run: (nomsu_code, compile_fn=nil)=>
+ run: (nomsu_code)=>
tree = assert(@parse(nomsu_code))
if type(tree) == 'number' -- Happens if pattern matches, but there are no captures, e.g. an empty string
return nil
lua = @tree_to_lua(tree)\as_statements!
lua\declare_locals!
lua\prepend "-- File: #{nomsu_code.source or ""}\n"
- if compile_fn
- compile_fn(lua)
+ if @compile_fn
+ self.compile_fn(lua, nomsu_code.source.filename)
return @run_lua(lua)
_running_files = {} -- For detecting circular imports
- run_file: (filename, compile_fn=nil)=>
+ run_file: (filename)=>
loaded = @environment.LOADED
if loaded[filename]
return loaded[filename]
@@ -367,7 +367,7 @@ class NomsuCompiler
file = file or FILE_CACHE[filename]
if not file
error("File does not exist: #{filename}", 0)
- ret = @run(Nomsu(Source(filename,1,#file), file), compile_fn)
+ ret = @run(Nomsu(Source(filename,1,#file), file))
else
error("Invalid filetype for #{filename}", 0)
loaded[filename] = ret or true
@@ -966,7 +966,8 @@ if arg and debug_getinfo(2).func != require
/ {:format: ("-f" -> true) :}
/ {:syntax: ("-s" -> true) :}
/ {:print_file: "-p" ";" {file} :}
- / {:output_file: "-o" ";" {file} :}
+ / {:compile: ("-c" -> true) :}
+ / {:verbose: ("-v" -> true) :}
/ {:help: (("-h" / "--help") -> true) :}
file <- "-" / [^;]+
]], {true: -> true})
@@ -976,15 +977,16 @@ if arg and debug_getinfo(2).func != require
print [=[
Nomsu Compiler
-Usage: (lua nomsu.lua | moon nomsu.moon) [-i] [-O] [-f] [-s] [--help] [-o output] [-p print_file] file1 file2... [-- nomsu args...]
+Usage: (lua nomsu.lua | moon nomsu.moon) [-i] [-O] [-v] [-c] [-f] [-s] [--help] [-p print_file] file1 file2... [-- nomsu args...]
OPTIONS
-i Run the compiler in interactive mode (REPL)
-O Run the compiler in optimized mode (use precompiled .lua versions of Nomsu files, when available)
+ -v Verbose: print compiled lua code
+ -c Compile .nom files into .lua files
-f Auto-format the given Nomsu file and print the result.
-s Check the program for syntax errors.
-h/--help Print this message.
- -o <file> Output the compiled Lua file to the given file (use "-" to output to stdout; if outputting to stdout and -p is not specified, -p will default to /dev/null)
-p <file> Print to the specified file instead of stdout.
<input> Input file can be "-" to use stdin.
]=]
@@ -1131,7 +1133,6 @@ OPTIONS
print_file = if args.print_file == "-" then io.stdout
elseif args.print_file then io.open(args.print_file, 'w')
- elseif args.output_file == '-' then nil
else io.stdout
nomsu.skip_precompiled = not args.optimized
@@ -1147,42 +1148,53 @@ OPTIONS
print_file\write('\n')
print_file\flush!
- compile_fn = if args.output_file
- (code)->
- output_file = if args.output_file == "-" then io.stdout
- elseif args.output_file then io.open(args.output_file, 'w')
- output_file\write("local IMMEDIATE = true;\n"..tostring(code))
- output_file\flush!
+ input_files = {}
+ to_run = {}
+ for input in *args.inputs
+ for f in all_files(input)
+ input_files[#input_files+1] = f
+ to_run[f] = true
+
+ nomsu.compile_fn = if args.compile or args.verbose
+ (code, from_file)->
+ if to_run[from_file]
+ if args.verbose
+ io.write(tostring(code), "\n")
+ if args.compile and from_file\match("%.nom$")
+ output_filename = from_file\gsub("%.nom$", ".lua")
+ output_file = io.open(output_filename, 'w')
+ output_file\write("local IMMEDIATE = true;\n", tostring(code))
+ output_file\flush!
+ print ("Compiled %-25s -> %s")\format(from_file, output_filename)
+ output_file\close!
else nil
parse_errs = {}
- for input in *args.inputs
+ for filename in *input_files
if args.syntax
-- Check syntax:
- for input_file in all_files(input)
- ok,err = pcall nomsu.parse, nomsu, Nomsu(input_file, io.open(input_file)\read("*a"))
- if not ok
- insert parse_errs, err
- elseif print_file
- print_file\write("Parse succeeded: #{input_file}\n")
- print_file\flush!
+ ok,err = pcall nomsu.parse, nomsu, Nomsu(filename, io.open(filename)\read("*a"))
+ if not ok
+ insert parse_errs, err
+ elseif print_file
+ print_file\write("Parse succeeded: #{filename}\n")
+ print_file\flush!
elseif args.format
-- Auto-format
- for input_file in all_files(input)
- tree = nomsu\parse(io.open(input_file)\read("*a"))
- formatted = tostring(@tree_to_nomsu(tree))
- if output_file
- output_file\write(formatted, "\n")
- output_file\flush!
- if print_file
- print_file\write(formatted, "\n")
- print_file\flush!
- elseif input == STDIN
+ file = FILE_CACHE[filename]
+ if not file
+ error("File does not exist: #{filename}", 0)
+ tree = nomsu\parse(Nomsu(Source(filename,1,#file), file))
+ formatted = tostring(nomsu\tree_to_nomsu(tree))
+ if print_file
+ print_file\write(formatted, "\n")
+ print_file\flush!
+ elseif filename == STDIN
file = io.input!\read("*a")
FILE_CACHE.stdin = file
- nomsu\run(Nomsu(Source('stdin',1,#file), file), compile_fn)
+ nomsu\run(Nomsu(Source('stdin',1,#file), file))
else
- nomsu\run_file(input, compile_fn)
+ nomsu\run_file(filename)
if #parse_errs > 0
io.stderr\write concat(parse_errs, "\n\n")
@@ -1193,9 +1205,9 @@ OPTIONS
if args.interactive
-- REPL
- while true
+ for repl_line=1,math.huge
io.write(colored.bright colored.yellow ">> ")
- buff = ""
+ buff = {}
while true
line = io.read("*L")
if line == "\n" or not line
@@ -1203,11 +1215,17 @@ OPTIONS
io.write("\027[1A\027[2K")
break -- Run buffer
line = line\gsub("\t", " ")
- buff ..= line
+ insert buff, line
io.write(colored.dim colored.yellow ".. ")
if #buff == 0
break -- Exit
- ok, ret = pcall(nomsu.run, nomsu, buff)
+
+ buff = concat(buff)
+ FILE_CACHE["REPL#"..repl_line] = buff
+ code = Nomsu(Source("REPL#"..repl_line, 1, #buff), buff)
+ err_hand = (error_message)->
+ print_err_msg error_message
+ ok, ret = xpcall(nomsu.run, err_hand, nomsu, code)
if ok and ret != nil
print "= "..repr(ret)
elseif not ok