Updated and fixed the command line API. Introduced the "-t tool" flag

for more concisely running tools, removed the "-I file" and replaced it
with "-m files..."
This commit is contained in:
Bruce Hill 2018-11-26 16:16:08 -08:00
parent 1a794c6487
commit cbbe6b1c14
5 changed files with 223 additions and 174 deletions

View File

@ -10,30 +10,44 @@ nomsu \- run a Nomsu program
]
[
.I nomsu_file
|
.I -t tool
|
.I -e nomsu_code
|
.I -m nomsu_files...
[--]
]
[
.I args
]
]
.SH DESCRIPTION
\fBnomsu\fR is the compiler/interpreter for the Nomsu programming language.
.SH INPUT
.TP
If an input file is provided, \fBnomsu\fR will run that file.
.TP
If an input directory is provided, \fBnomsu\fR will run every .nom file in the directory and its subdirectories.
.TP
If "-" is used, \fBnomsu\fR will read from standard input
.TP
If no input files are provided, \fBnomsu\fR will run in interactive mode.
.SH OPTIONS
.TP
.BI \-t " tool"
Run the specified Nomsu tool (one of the tools/*.nom files provided with the compiler).
.TP
.BI \-m " file1 file2... " [--]
Run multiple files. If a "--" is supplied, any additional arguments will be treated as arguments for the files, rather than additional files.
.TP
.BI \-e " code"
Execute the given nomsu code string.
.TP
.BI \-V " version"
Specify the desired Nomsu version (defaults to the latest installed version). E.g. \fBnomsu -V 1.2\fR or \fBnomsu -V 1.2.5.9\fR
.TP
.BI \-L
List the installed versions of Nomsu (if \fB-V\fR is supplied, only print versions that match the requested pattern).
.TP
.B \-O " level"
.BI \-O " optimization"
Run the compiler with the given optimization level (default: 1). If \fBlevel\fR is >0, use precompiled .lua versions of .nom files, when available.
.TP
.B \-v
@ -42,23 +56,17 @@ Verbose: print compiled lua code as it's generated for the input files.
.B \-c
Compile the input files into .lua files.
.TP
.B \-s " file"
.B \-s
Check the input files for syntax errors without running them.
.TP
.B \-I " file"
Include the specified file (or all .nom files in a directory and its subdirectories) in the input files.
.TP
.B \-e " code"
Execute the given nomsu code string.
.TP
.B \-d " debugger"
.BI \-d " debugger"
If provided, \fBnomsu\fR will attempt to use the specified debugger to wrap the main body of execution.
.TP
.B \--version
Print the version number and exit.
.TP
.B \--no-core
Disable the default behavior of running the files in 'core' before running anything else.
Run \fBnomsu\fR without running the files in the 'core' directory (this will disable most functionality).
.TP
.B \--help
Print the command line usage.
@ -73,6 +81,11 @@ Runs nomsu in interactive mode (a read-evaluate-print loop)
nomsu my_file.nom
Runs the Nomsu file 'my_file.nom'
.TP
.B
nomsu -t autoformat -i my_file.nom
Runs the tools/autoformat.nom script with arguments "-i my_file.nom", which will automatically format my_file.nom in-place.
.TP
.B
nomsu -c my_file.nom
@ -80,7 +93,7 @@ Compiles the Nomsu file 'my_file.nom' into a Lua file called 'my_file.lua'
.TP
.B
nomsu -I one.nom -I two.nom three.nom
nomsu -m one.nom two.nom three.nom
Runs 'one.nom', then 'two.nom', then 'three.nom'.
.TP

134
nomsu.lua
View File

@ -59,15 +59,16 @@ else
end
local usage = [=[Nomsu Compiler
Usage: (nomsu | lua nomsu.lua | moon nomsu.moon) [-V version] [-O optimization level] [-v] [-c] [-s] [-I file] [--help | -h] [--version] [--no-core] [file [nomsu args...]]
Usage: (nomsu | lua nomsu.lua | moon nomsu.moon) [-V version] [--help | -h] [--version] [-O optimization level] [-v] [-c] [-s] [-d debugger] [--no-core] [(file | -t tool | -e "nomsu code..." | -m files... [--]) [nomsu args...]]
OPTIONS
-t <tool> Run a tool.
-e Execute the specified string.
-m Run multiple files (all extra arguments).
-O <level> Run the compiler with the given optimization level (>0: use precompiled .lua versions of Nomsu files, when available).
-v Verbose: print compiled lua code.
-c Compile the input files into a .lua files.
-e Execute the specified string.
-s Check the input files for syntax errors.
-I <file> Add an additional input file or directory.
-d <debugger> Attempt to use the specified debugger to wrap the main body of execution.
-h/--help Print this message.
--version Print the version number and exit.
@ -99,36 +100,31 @@ local nomsu_environment = require('nomsu_environment')
if not arg or debug.getinfo(2).func == require then
return nomsu_environment
end
local file_queue = List({ })
local sep = "\3"
local parser = re.compile([[ args <- {| (flag %sep)* (({~ file ~} -> add_file) {:primary_file: %true :} %sep)?
{:nomsu_args: {| (nomsu_flag %sep)* {:extra_args: {| ({[^%sep]+} %sep)* |} :} |} :} |} !.
local parser = re.compile([[ args <- {| (flag %sep)*
(("-e" %sep {:execute: {[^%sep]+} :} %sep)
/ {:files: {|
("-t" %sep {~ {[^%sep]+} -> "nomsu://tools/%1.nom" ~} %sep
/ "-m" %sep (!("--" %sep) {[^%sep]+} %sep)* ("--" %sep)?
/ {[^%sep]+} %sep
/ {~ '' %sep? -> 'nomsu://tools/repl.nom' ~}) |} :})
{:nomsu_args: {| (nomsu_flag %sep)* {:extra_args: {| ({[^%sep]+} %sep)* |} :} |} :}
|} !.
flag <-
{:optimization: "-O" (%sep? %number)? :}
/ ("-I" %sep? ({~ file ~} -> add_file))
/ ("-e" %sep? (({} {~ file ~}) -> add_exec_string) {:exec_strings: %true :})
/ ({:check_syntax: "-s" %true:})
/ ({:compile: "-c" %true:})
/ {:verbose: "-v" %true :}
/ {:help: ("-h" / "--help") %true :}
/ {:version: "--version" %true :}
/ {:no_core: "--no-core" %true :}
/ {:debugger: ("-d" %sep? {(!%sep .)*}) :}
/ {:debugger: ("-d" %sep? {[^%sep]*}) :}
/ {:requested_version: "-V" (%sep? {([0-9.])+})? :}
nomsu_flag <- {| ({:key: ('-' [a-z]) :} {:value: %true :}) / ({:key: ('--' [^%sep=]+) :} {:value: ('=' {[^%sep]+}) / %true :}) |}
file <- ("-" -> "stdin") / {(!%sep .)+}
]], {
["true"] = lpeg.Cc(true),
number = lpeg.R("09") ^ 1 / tonumber,
sep = lpeg.P(sep),
add_file = function(f)
return file_queue:add(f)
end,
add_exec_string = function(pos, s)
local name = "command line arg @" .. tostring(pos) .. ".nom"
Files.spoof(name, s)
return file_queue:add(name)
end
sep = lpeg.P(sep)
})
local arg_string = table.concat(arg, sep) .. sep
local args = parser:match(arg_string)
@ -145,36 +141,84 @@ end
nomsu_args.extra_args = List(args.nomsu_args.extra_args or { })
nomsu_environment.command_line_args = nomsu_args
nomsu_environment.OPTIMIZATION = tonumber(args.optimization or 1)
if args.version then
nomsu_environment.run_file_1_in('core', nomsu_environment, nomsu_environment.OPTIMIZATION)
nomsu_environment.run_1_in([[say (Nomsu version)]], nomsu_environment)
os.exit(EXIT_SUCCESS)
end
local run
run = function()
local input_files = { }
for _index_0 = 1, #file_queue do
local f = file_queue[_index_0]
if not (Files.exists(f)) then
error("Could not find: '" .. tostring(f) .. "'")
end
local _list_1 = Files.list(f)
for _index_1 = 1, #_list_1 do
local filename = _list_1[_index_1]
input_files[filename] = true
end
end
if not (args.no_core) then
nomsu_environment.run_file_1_in('core', nomsu_environment, nomsu_environment.OPTIMIZATION)
end
for _index_0 = 1, #file_queue do
for nomsupath in package.nomsupath:gmatch("[^;]+") do
local _continue_0 = false
repeat
local filename = file_queue[_index_0]
if not (filename == "stdin" or filename:match("%.nom$")) then
local files = Files.list(nomsupath .. "/core")
if not (files) then
_continue_0 = true
break
end
for _index_0 = 1, #files do
local _continue_1 = false
repeat
local f = files[_index_0]
if not (f:match("%.nom$")) then
_continue_1 = true
break
end
nomsu_environment.run_file_1_in(f, nomsu_environment, nomsu_environment.OPTIMIZATION)
_continue_1 = true
until true
if not _continue_1 then
break
end
end
_continue_0 = true
until true
if not _continue_0 then
break
end
end
end
if args.version then
nomsu_environment.run_1_in("say (Nomsu version)", nomsu_environment)
os.exit(EXIT_SUCCESS)
end
local input_files = { }
if args.execute then
table.insert(input_files, Files.spoof("<input command>", args.execute))
end
if args.files then
local _list_1 = args.files
for _index_0 = 1, #_list_1 do
local f = _list_1[_index_0]
local files
do
local nomsu_name = f:match("^nomsu://(.*)")
if nomsu_name then
for nomsupath in package.nomsupath:gmatch("[^;]+") do
local _continue_0 = false
repeat
files = Files.list(nomsupath .. "/" .. nomsu_name)
if not (files) then
_continue_0 = true
break
end
_continue_0 = true
until true
if not _continue_0 then
break
end
end
else
files = Files.list(f)
end
end
if not (files and #files > 0) then
error("Could not find: '" .. tostring(f) .. "'")
end
for _index_1 = 1, #files do
local filename = files[_index_1]
table.insert(input_files, filename)
end
end
end
for _index_0 = 1, #input_files do
local filename = input_files[_index_0]
if args.check_syntax then
local code = Files.read(filename)
local source = Source(filename, 1, #code)
@ -228,14 +272,6 @@ run = function()
else
nomsu_environment.run_file_1_in(filename, nomsu_environment, 0)
end
_continue_0 = true
until true
if not _continue_0 then
break
end
end
if not (args.primary_file or args.exec_strings) then
return nomsu_environment.run_file_1_in("tools/repl.nom", nomsu_environment, nomsu_environment.OPTIMIZATION)
end
end
local debugger

View File

@ -20,15 +20,16 @@ else
usage = [=[
Nomsu Compiler
Usage: (nomsu | lua nomsu.lua | moon nomsu.moon) [-V version] [-O optimization level] [-v] [-c] [-s] [-I file] [--help | -h] [--version] [--no-core] [file [nomsu args...]]
Usage: (nomsu | lua nomsu.lua | moon nomsu.moon) [-V version] [--help | -h] [--version] [-O optimization level] [-v] [-c] [-s] [-d debugger] [--no-core] [(file | -t tool | -e "nomsu code..." | -m files... [--]) [nomsu args...]]
OPTIONS
-t <tool> Run a tool.
-e Execute the specified string.
-m Run multiple files (all extra arguments).
-O <level> Run the compiler with the given optimization level (>0: use precompiled .lua versions of Nomsu files, when available).
-v Verbose: print compiled lua code.
-c Compile the input files into a .lua files.
-e Execute the specified string.
-s Check the input files for syntax errors.
-I <file> Add an additional input file or directory.
-d <debugger> Attempt to use the specified debugger to wrap the main body of execution.
-h/--help Print this message.
--version Print the version number and exit.
@ -57,32 +58,30 @@ nomsu_environment = require('nomsu_environment')
if not arg or debug.getinfo(2).func == require
return nomsu_environment
file_queue = List{}
sep = "\3"
parser = re.compile([[
args <- {| (flag %sep)* (({~ file ~} -> add_file) {:primary_file: %true :} %sep)?
{:nomsu_args: {| (nomsu_flag %sep)* {:extra_args: {| ({[^%sep]+} %sep)* |} :} |} :} |} !.
args <- {| (flag %sep)*
(("-e" %sep {:execute: {[^%sep]+} :} %sep)
/ {:files: {|
("-t" %sep {~ {[^%sep]+} -> "nomsu://tools/%1.nom" ~} %sep
/ "-m" %sep (!("--" %sep) {[^%sep]+} %sep)* ("--" %sep)?
/ {[^%sep]+} %sep
/ {~ '' %sep? -> 'nomsu://tools/repl.nom' ~}) |} :})
{:nomsu_args: {| (nomsu_flag %sep)* {:extra_args: {| ({[^%sep]+} %sep)* |} :} |} :}
|} !.
flag <-
{:optimization: "-O" (%sep? %number)? :}
/ ("-I" %sep? ({~ file ~} -> add_file))
/ ("-e" %sep? (({} {~ file ~}) -> add_exec_string) {:exec_strings: %true :})
/ ({:check_syntax: "-s" %true:})
/ ({:compile: "-c" %true:})
/ {:verbose: "-v" %true :}
/ {:help: ("-h" / "--help") %true :}
/ {:version: "--version" %true :}
/ {:no_core: "--no-core" %true :}
/ {:debugger: ("-d" %sep? {(!%sep .)*}) :}
/ {:debugger: ("-d" %sep? {[^%sep]*}) :}
/ {:requested_version: "-V" (%sep? {([0-9.])+})? :}
nomsu_flag <- {| ({:key: ('-' [a-z]) :} {:value: %true :}) / ({:key: ('--' [^%sep=]+) :} {:value: ('=' {[^%sep]+}) / %true :}) |}
file <- ("-" -> "stdin") / {(!%sep .)+}
]], {
true:lpeg.Cc(true), number:lpeg.R("09")^1/tonumber, sep:lpeg.P(sep)
add_file: (f)-> file_queue\add(f)
add_exec_string: (pos, s)->
name = "command line arg @#{pos}.nom"
Files.spoof(name, s)
file_queue\add name
})
arg_string = table.concat(arg, sep)..sep
args = parser\match(arg_string)
@ -96,24 +95,37 @@ nomsu_args.extra_args = List(args.nomsu_args.extra_args or {})
nomsu_environment.command_line_args = nomsu_args
nomsu_environment.OPTIMIZATION = tonumber(args.optimization or 1)
run = ->
unless args.no_core
for nomsupath in package.nomsupath\gmatch("[^;]+")
files = Files.list(nomsupath.."/core")
continue unless files
for f in *files
continue unless f\match("%.nom$")
nomsu_environment.run_file_1_in f, nomsu_environment, nomsu_environment.OPTIMIZATION
if args.version
nomsu_environment.run_file_1_in 'core', nomsu_environment, nomsu_environment.OPTIMIZATION
nomsu_environment.run_1_in([[say (Nomsu version)]], nomsu_environment)
nomsu_environment.run_1_in("say (Nomsu version)", nomsu_environment)
os.exit(EXIT_SUCCESS)
run = ->
input_files = {}
for f in *file_queue
unless Files.exists(f)
if args.execute
table.insert input_files, Files.spoof("<input command>", args.execute)
if args.files
for f in *args.files
local files
if nomsu_name = f\match("^nomsu://(.*)")
for nomsupath in package.nomsupath\gmatch("[^;]+")
files = Files.list(nomsupath.."/"..nomsu_name)
continue unless files
else
files = Files.list(f)
unless files and #files > 0
error("Could not find: '#{f}'")
for filename in *Files.list(f)
input_files[filename] = true
for filename in *files
table.insert input_files, filename
unless args.no_core
nomsu_environment.run_file_1_in 'core', nomsu_environment, nomsu_environment.OPTIMIZATION
for filename in *file_queue
continue unless filename == "stdin" or filename\match("%.nom$")
for filename in *input_files
if args.check_syntax
-- Check syntax
code = Files.read(filename)
@ -154,9 +166,6 @@ run = ->
-- Just run the file
nomsu_environment.run_file_1_in(filename, nomsu_environment, 0)
unless args.primary_file or args.exec_strings
nomsu_environment.run_file_1_in("tools/repl.nom", nomsu_environment, nomsu_environment.OPTIMIZATION)
debugger = if args.debugger == "nil" then {}
else require(args.debugger or 'error_handling')
guard = if type(debugger) == 'function' then debugger

View File

@ -312,19 +312,14 @@ local nomsu_environment = Importer({
local _continue_0 = false
repeat
do
local files = Files.list(nomsupath .. "/" .. path)
local full_path = nomsupath == "." and path or nomsupath .. "/" .. path
local files = Files.list(full_path)
if not (files) then
_continue_0 = true
break
end
for _index_0 = 1, #files do
local _continue_1 = false
repeat
local filename = files[_index_0]
if not (filename == "stdin" or filename:match("%.nom$")) then
_continue_1 = true
break
end
local lua_filename = filename:gsub("%.nom$", ".lua")
local code
if optimization ~= 0 and Files.read(lua_filename) then
@ -336,11 +331,6 @@ local nomsu_environment = Importer({
end
environment.run_1_in(code, mod)
did_anything = true
_continue_1 = true
until true
if not _continue_1 then
break
end
end
break
end

View File

@ -172,13 +172,14 @@ nomsu_environment = Importer{
did_anything = false
for nomsupath in package.nomsupath\gmatch("[^;]+")
files = Files.list(nomsupath.."/"..path)
full_path = nomsupath == "." and path or nomsupath.."/"..path
files = Files.list(full_path)
continue unless files
for filename in *files
continue unless filename == "stdin" or filename\match("%.nom$")
lua_filename = filename\gsub("%.nom$", ".lua")
-- TODO: don't automatically use precompiled version?
code = if optimization != 0 and Files.read(lua_filename)
-- TODO: use a checksum?
file = Files.read(lua_filename)
LuaCode\from(Source(filename, 1, #file), file)
else