aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/nomsu.141
-rw-r--r--nomsu.lua232
-rwxr-xr-xnomsu.moon75
-rw-r--r--nomsu_environment.lua36
-rw-r--r--nomsu_environment.moon5
5 files changed, 219 insertions, 170 deletions
diff --git a/doc/nomsu.1 b/doc/nomsu.1
index 23a3549..ddeedfa 100644
--- a/doc/nomsu.1
+++ b/doc/nomsu.1
@@ -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.
@@ -75,12 +83,17 @@ 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
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
diff --git a/nomsu.lua b/nomsu.lua
index 08ab170..1b5a73e 100644
--- a/nomsu.lua
+++ b/nomsu.lua
@@ -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,98 +141,138 @@ 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
- local _continue_0 = false
- repeat
- local filename = file_queue[_index_0]
- if not (filename == "stdin" or filename:match("%.nom$")) then
+ for nomsupath in package.nomsupath:gmatch("[^;]+") do
+ local _continue_0 = false
+ repeat
+ 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
- if args.check_syntax then
- local code = Files.read(filename)
- local source = Source(filename, 1, #code)
- nomsu_environment._1_parsed(NomsuCode:from(source, code))
- print("Parse succeeded: " .. tostring(filename))
- elseif args.compile then
- local output
- if filename == 'stdin' then
- output = io.output()
- else
- output = io.open(filename:gsub("%.nom$", ".lua"), "w")
- end
- local code = Files.read(filename)
- local source = Source(filename, 1, #code)
- code = NomsuCode:from(source, code)
- local tree = nomsu_environment._1_parsed(code)
- if not (tree.type == 'FileChunks') then
- tree = {
- tree
- }
- end
- for chunk_no, chunk in ipairs(tree) do
- local lua = nomsu_environment.compile(chunk)
- lua:declare_locals()
- lua:prepend((chunk_no > 1) and '\n' or '', "-- File " .. tostring(filename) .. " chunk #" .. tostring(chunk_no) .. "\n")
- if args.verbose then
- print(lua:text())
+ 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
- nomsu_environment.run_1_in(chunk, nomsu_environment)
- output:write(lua:text(), "\n")
- end
- print(("Compiled %-25s -> %s"):format(filename, filename:gsub("%.nom$", ".lua")))
- output:close()
- elseif args.verbose then
- local code = Files.read(filename)
- local source = Source(filename, 1, #code)
- code = NomsuCode:from(source, code)
- local tree = nomsu_environment._1_parsed(code)
- if not (tree.type == 'FileChunks') then
- tree = {
- tree
- }
+ else
+ files = Files.list(f)
end
- for chunk_no, chunk in ipairs(tree) do
- local lua = nomsu_environment.compile(chunk)
- lua:declare_locals()
- lua:prepend((chunk_no > 1) and '\n' or '', "-- File " .. tostring(filename) .. " chunk #" .. tostring(chunk_no) .. "\n")
+ 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)
+ nomsu_environment._1_parsed(NomsuCode:from(source, code))
+ print("Parse succeeded: " .. tostring(filename))
+ elseif args.compile then
+ local output
+ if filename == 'stdin' then
+ output = io.output()
+ else
+ output = io.open(filename:gsub("%.nom$", ".lua"), "w")
+ end
+ local code = Files.read(filename)
+ local source = Source(filename, 1, #code)
+ code = NomsuCode:from(source, code)
+ local tree = nomsu_environment._1_parsed(code)
+ if not (tree.type == 'FileChunks') then
+ tree = {
+ tree
+ }
+ end
+ for chunk_no, chunk in ipairs(tree) do
+ local lua = nomsu_environment.compile(chunk)
+ lua:declare_locals()
+ lua:prepend((chunk_no > 1) and '\n' or '', "-- File " .. tostring(filename) .. " chunk #" .. tostring(chunk_no) .. "\n")
+ if args.verbose then
print(lua:text())
- nomsu_environment.run_1_in(lua, nomsu_environment)
end
- else
- nomsu_environment.run_file_1_in(filename, nomsu_environment, 0)
+ nomsu_environment.run_1_in(chunk, nomsu_environment)
+ output:write(lua:text(), "\n")
+ end
+ print(("Compiled %-25s -> %s"):format(filename, filename:gsub("%.nom$", ".lua")))
+ output:close()
+ elseif args.verbose then
+ local code = Files.read(filename)
+ local source = Source(filename, 1, #code)
+ code = NomsuCode:from(source, code)
+ local tree = nomsu_environment._1_parsed(code)
+ if not (tree.type == 'FileChunks') then
+ tree = {
+ tree
+ }
end
- _continue_0 = true
- until true
- if not _continue_0 then
- break
+ for chunk_no, chunk in ipairs(tree) do
+ local lua = nomsu_environment.compile(chunk)
+ lua:declare_locals()
+ lua:prepend((chunk_no > 1) and '\n' or '', "-- File " .. tostring(filename) .. " chunk #" .. tostring(chunk_no) .. "\n")
+ print(lua:text())
+ nomsu_environment.run_1_in(lua, nomsu_environment)
+ end
+ else
+ nomsu_environment.run_file_1_in(filename, nomsu_environment, 0)
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
if args.debugger == "nil" then
diff --git a/nomsu.moon b/nomsu.moon
index fd4e727..d9a7d18 100755
--- a/nomsu.moon
+++ b/nomsu.moon
@@ -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)
-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)
- os.exit(EXIT_SUCCESS)
-
run = ->
- input_files = {}
- for f in *file_queue
- unless Files.exists(f)
- error("Could not find: '#{f}'")
- for filename in *Files.list(f)
- input_files[filename] = true
-
unless args.no_core
- nomsu_environment.run_file_1_in 'core', nomsu_environment, nomsu_environment.OPTIMIZATION
+ 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_1_in("say (Nomsu version)", nomsu_environment)
+ os.exit(EXIT_SUCCESS)
+
+ input_files = {}
+ 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
+ table.insert input_files, filename
- 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
diff --git a/nomsu_environment.lua b/nomsu_environment.lua
index 5838a1d..fc5ab31 100644
--- a/nomsu_environment.lua
+++ b/nomsu_environment.lua
@@ -312,35 +312,25 @@ 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
- local file = Files.read(lua_filename)
- code = LuaCode:from(Source(filename, 1, #file), file)
- else
- local file = Files.read(filename)
- code = NomsuCode:from(Source(filename, 1, #file), file)
- end
- environment.run_1_in(code, mod)
- did_anything = true
- _continue_1 = true
- until true
- if not _continue_1 then
- break
+ local filename = files[_index_0]
+ local lua_filename = filename:gsub("%.nom$", ".lua")
+ local code
+ if optimization ~= 0 and Files.read(lua_filename) then
+ local file = Files.read(lua_filename)
+ code = LuaCode:from(Source(filename, 1, #file), file)
+ else
+ local file = Files.read(filename)
+ code = NomsuCode:from(Source(filename, 1, #file), file)
end
+ environment.run_1_in(code, mod)
+ did_anything = true
end
break
end
diff --git a/nomsu_environment.moon b/nomsu_environment.moon
index add852a..5d26701 100644
--- a/nomsu_environment.moon
+++ b/nomsu_environment.moon
@@ -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