aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/operators.nom5
-rw-r--r--core/text.nom6
-rw-r--r--files.lua146
-rw-r--r--files.moon109
-rw-r--r--lib/os.nom12
-rw-r--r--nomsu.lua61
-rwxr-xr-xnomsu.moon51
-rw-r--r--nomsu_compiler.lua54
-rw-r--r--nomsu_compiler.moon41
-rwxr-xr-xtools/autoformat.nom3
-rwxr-xr-xtools/upgrade.nom4
11 files changed, 263 insertions, 229 deletions
diff --git a/core/operators.nom b/core/operators.nom
index d0e3915..9a836bf 100644
--- a/core/operators.nom
+++ b/core/operators.nom
@@ -209,7 +209,8 @@ compile [not %] to (Lua value "(not \(% as lua expr))")
test:
assume ((length of [1, 2, 3]) == 3)
-compile [length of %list, || %list ||] to (Lua value "(#\(%list as lua expr))")
+compile [length of %list, len %list, || %list ||] to (Lua value "(#\(%list as lua expr))")
+compile [%list is empty] to (Lua value "(#\(%list as lua expr) == 0)")
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -221,4 +222,4 @@ parse [%var /= %] as (%var = (%var / %))
parse [%var ^= %] as (%var = (%var ^ %))
parse [%var and= %] as (%var = (%var and %))
parse [%var or= %] as (%var = (%var or %))
-parse [wrap %var around %] as (%var = (%var wrapped around %)) \ No newline at end of file
+parse [wrap %var around %] as (%var = (%var wrapped around %))
diff --git a/core/text.nom b/core/text.nom
index 641db14..40e0451 100644
--- a/core/text.nom
+++ b/core/text.nom
@@ -53,6 +53,10 @@ compile [%text matches %pattern] to (..)
Lua value ".."
(\(%text as lua expr):match(\(%pattern as lua expr)) and true or false)
+compile [%text matching %pattern] to (..)
+ Lua value ".."
+ \(%text as lua expr):match(\(%pattern as lua expr))
+
# Text literals
lua> ".."
@@ -68,4 +72,4 @@ lua> ".."
return LuaCode.Value(tree.source, lua)
end
end
- end \ No newline at end of file
+ end
diff --git a/files.lua b/files.lua
index ef5c8c1..c6da8c8 100644
--- a/files.lua
+++ b/files.lua
@@ -1,11 +1,16 @@
local lpeg = require('lpeg')
local re = require('re')
-local files = { }
-local _FILE_CACHE = { }
-files.spoof = function(filename, contents)
- _FILE_CACHE[filename] = contents
+local Files = { }
+local _SPOOFED_FILES = { }
+local _FILE_CACHE = setmetatable({ }, {
+ __index = _SPOOFED_FILES
+})
+local _BROWSE_CACHE = { }
+Files.spoof = function(filename, contents)
+ _SPOOFED_FILES[filename] = contents
+ return contents
end
-files.read = function(filename)
+Files.read = function(filename)
do
local file_contents = _FILE_CACHE[filename]
if file_contents then
@@ -13,9 +18,7 @@ files.read = function(filename)
end
end
if filename == 'stdin' then
- local contents = io.read('*a')
- _FILE_CACHE['stdin'] = contents
- return contents
+ return Files.spoof('stdin', io.read('*a'))
end
local file = io.open(filename)
if package.nomsupath and not file then
@@ -47,7 +50,10 @@ sanitize = function(path)
path = gsub(path, "$", "")
return path
end
-files.exists = function(path)
+Files.exists = function(path)
+ if _SPOOFED_FILES[path] then
+ return true
+ end
if not (io.popen("ls " .. tostring(sanitize(path))):close()) then
return true
end
@@ -60,26 +66,28 @@ files.exists = function(path)
end
return false
end
-local _browse_cache = { }
local browse
browse = function(path)
- if not (_browse_cache[path]) then
- local f = io.popen('find -L "' .. package.nomsupath .. '/' .. path .. '" -not -path "*/\\.*" -type f -name "*.nom"')
- local _files
- do
- local _tbl_0 = { }
- for line in f:lines() do
- local _key_0, _val_0 = line
- _tbl_0[_key_0] = _val_0
+ if not (_BROWSE_CACHE[path]) then
+ local files
+ if _SPOOFED_FILES[path] then
+ _BROWSE_CACHE[path] = {
+ path
+ }
+ else
+ local f = io.popen('find -L "' .. package.nomsupath .. '/' .. path .. '" -not -path "*/\\.*" -type f -name "*.nom"')
+ do
+ local _tbl_0 = { }
+ for line in f:lines() do
+ local _key_0, _val_0 = line
+ _tbl_0[_key_0] = _val_0
+ end
+ files = _tbl_0
end
- _files = _tbl_0
+ _BROWSE_CACHE[path] = f:close() and files or false
end
- if not (f:close()) then
- _files = false
- end
- _browse_cache[path] = _files
end
- return _browse_cache[path]
+ return _BROWSE_CACHE[path]
end
local ok, lfs = pcall(require, "lfs")
if ok then
@@ -92,7 +100,10 @@ if ok then
return false
end
end
- files.exists = function(path)
+ Files.exists = function(path)
+ if _SPOOFED_FILES[path] then
+ return true
+ end
if path == 'stdin' or raw_file_exists(path) then
return true
end
@@ -106,72 +117,81 @@ if ok then
return false
end
browse = function(filename)
- if not (_browse_cache[filename]) then
- _browse_cache[filename] = false
- local file_type, err = lfs.attributes(filename, 'mode')
- if file_type == 'file' then
- if match(filename, "%.nom$") or match(filename, "%.lua$") then
- _browse_cache[filename] = {
- filename
- }
- end
- elseif file_type == 'char device' then
- _browse_cache[filename] = {
+ if not (_BROWSE_CACHE[filename]) then
+ if _SPOOFED_FILES[filename] then
+ _BROWSE_CACHE[filename] = {
filename
}
- elseif file_type == 'directory' or file_type == 'link' then
- local _files = { }
- for subfile in lfs.dir(filename) do
- if not (subfile == "." or subfile == "..") then
- local _list_0 = (browse(filename .. "/" .. subfile) or { })
- for _index_0 = 1, #_list_0 do
- local f = _list_0[_index_0]
- _files[#_files + 1] = f
+ else
+ local file_type, err = lfs.attributes(filename, 'mode')
+ if file_type == 'file' then
+ if match(filename, "%.nom$") or match(filename, "%.lua$") then
+ _BROWSE_CACHE[filename] = {
+ filename
+ }
+ else
+ _BROWSE_CACHE[filename] = false
+ end
+ elseif file_type == 'char device' then
+ _BROWSE_CACHE[filename] = {
+ filename
+ }
+ elseif file_type == 'directory' or file_type == 'link' then
+ local files = { }
+ for subfile in lfs.dir(filename) do
+ if not (subfile == "." or subfile == "..") then
+ local _list_0 = (browse(filename .. "/" .. subfile) or { })
+ for _index_0 = 1, #_list_0 do
+ local f = _list_0[_index_0]
+ files[#files + 1] = f
+ end
end
end
+ _BROWSE_CACHE[filename] = files
+ else
+ _BROWSE_CACHE[filename] = false
end
- _browse_cache[filename] = _files
end
end
- return _browse_cache[filename]
+ return _BROWSE_CACHE[filename]
end
else
if io.popen('find . -maxdepth 0'):close() then
error("Could not find 'luafilesystem' module and couldn't run system command `find` (this might happen on Windows). Please install `luafilesystem` (which can be found at: http://keplerproject.github.io/luafilesystem/ or `luarocks install luafilesystem`)", 0)
end
end
-files.walk = function(path, flush_cache)
+Files.walk = function(path, flush_cache)
if flush_cache == nil then
flush_cache = false
end
if flush_cache then
- _browse_cache = { }
+ _BROWSE_CACHE = { }
end
- local _files = browse(path)
- if package.nomsupath and not _files then
+ local files = browse(path)
+ if package.nomsupath and not files then
for nomsupath in package.nomsupath:gmatch("[^;]+") do
do
- _files = browse(nomsupath .. "/" .. path)
- if _files then
+ files = browse(nomsupath .. "/" .. path)
+ if files then
break
end
end
end
end
local iter
- iter = function(_files, i)
- if not (_files) then
+ iter = function(files, i)
+ if not (files) then
return
end
i = i + 1
do
- local f = _files[i]
+ local f = files[i]
if f then
return i, f
end
end
end
- return iter, _files, 0
+ return iter, files, 0
end
local line_counter = re.compile([[ lines <- {| line (%nl line)* |}
line <- {} (!%nl .)*
@@ -179,7 +199,7 @@ local line_counter = re.compile([[ lines <- {| line (%nl line)* |}
nl = lpeg.P("\r") ^ -1 * lpeg.P("\n")
})
local _LINE_STARTS = { }
-files.get_line_starts = function(str)
+Files.get_line_starts = function(str)
if type(str) ~= 'string' then
str = tostring(str)
end
@@ -194,8 +214,8 @@ files.get_line_starts = function(str)
return line_starts
end
local log = { }
-files.get_line_number = function(str, pos)
- local line_starts = files.get_line_starts(str)
+Files.get_line_number = function(str, pos)
+ local line_starts = Files.get_line_starts(str)
local lo, hi = 1, #line_starts
while lo <= hi do
local mid = math.floor((lo + hi) / 2)
@@ -207,8 +227,8 @@ files.get_line_number = function(str, pos)
end
return hi
end
-files.get_line = function(str, line_no)
- local line_starts = files.get_line_starts(str)
+Files.get_line = function(str, line_no)
+ local line_starts = Files.get_line_starts(str)
return str:sub(line_starts[line_no] or 1, (line_starts[line_no + 1] or 1) - 2)
end
local get_lines = re.compile([[ lines <- {| line (%nl line)* |}
@@ -216,7 +236,7 @@ local get_lines = re.compile([[ lines <- {| line (%nl line)* |}
]], {
nl = lpeg.P("\r") ^ -1 * lpeg.P("\n")
})
-files.get_lines = function(str)
+Files.get_lines = function(str)
return get_lines:match(str)
end
-return files
+return Files
diff --git a/files.moon b/files.moon
index ad1956b..7f23490 100644
--- a/files.moon
+++ b/files.moon
@@ -1,22 +1,23 @@
-- Some file utilities for searching for files recursively and using package.nomsupath
lpeg = require 'lpeg'
re = require 're'
-files = {}
+Files = {}
-_FILE_CACHE = {}
+_SPOOFED_FILES = {}
+_FILE_CACHE = setmetatable {}, __index:_SPOOFED_FILES
+_BROWSE_CACHE = {}
-- Create a fake file and put it in the cache
-files.spoof = (filename, contents)->
- _FILE_CACHE[filename] = contents
+Files.spoof = (filename, contents)->
+ _SPOOFED_FILES[filename] = contents
+ return contents
-- Read a file's contents (searching first locally, then in the nomsupath)
-files.read = (filename)->
+Files.read = (filename)->
if file_contents = _FILE_CACHE[filename]
return file_contents
if filename == 'stdin'
- contents = io.read('*a')
- _FILE_CACHE['stdin'] = contents
- return contents
+ return Files.spoof('stdin', io.read('*a'))
file = io.open(filename)
if package.nomsupath and not file
for nomsupath in package.nomsupath\gmatch("[^;]+")
@@ -39,28 +40,32 @@ sanitize = (path)->
path = gsub(path,"$","")
return path
-files.exists = (path)->
+Files.exists = (path)->
+ return true if _SPOOFED_FILES[path]
return true unless io.popen("ls #{sanitize(path)}")\close!
if package.nomsupath
for nomsupath in package.nomsupath\gmatch("[^;]+")
return true unless io.popen("ls #{nomsupath}/#{sanitize(path)}")\close!
return false
-_browse_cache = {}
browse = (path)->
- unless _browse_cache[path]
- f = io.popen('find -L "'..package.nomsupath..'/'..path..'" -not -path "*/\\.*" -type f -name "*.nom"')
- _files = {line for line in f\lines!}
- _files = false unless f\close!
- _browse_cache[path] = _files
- return _browse_cache[path]
+ unless _BROWSE_CACHE[path]
+ local files
+ _BROWSE_CACHE[path] = if _SPOOFED_FILES[path]
+ {path}
+ else
+ f = io.popen('find -L "'..package.nomsupath..'/'..path..'" -not -path "*/\\.*" -type f -name "*.nom"')
+ files = {line for line in f\lines!}
+ f\close! and files or false
+ return _BROWSE_CACHE[path]
ok, lfs = pcall(require, "lfs")
if ok
raw_file_exists = (filename)->
mode = lfs.attributes(filename, 'mode')
return if mode == 'file' or mode == 'directory' or mode == 'link' then true else false
- files.exists = (path)->
+ Files.exists = (path)->
+ return true if _SPOOFED_FILES[path]
return true if path == 'stdin' or raw_file_exists(path)
if package.nomsupath
for nomsupath in package.nomsupath\gmatch("[^;]+")
@@ -69,40 +74,44 @@ if ok
export browse
browse = (filename)->
- unless _browse_cache[filename]
- _browse_cache[filename] = false
- file_type, err = lfs.attributes(filename, 'mode')
- if file_type == 'file'
- if match(filename, "%.nom$") or match(filename, "%.lua$")
- _browse_cache[filename] = {filename}
- elseif file_type == 'char device'
- _browse_cache[filename] = {filename}
- elseif file_type == 'directory' or file_type == 'link'
- _files = {}
- for subfile in lfs.dir(filename)
- unless subfile == "." or subfile == ".."
- for f in *(browse(filename.."/"..subfile) or {})
- _files[#_files+1] = f
- _browse_cache[filename] = _files
- return _browse_cache[filename]
+ unless _BROWSE_CACHE[filename]
+ _BROWSE_CACHE[filename] = if _SPOOFED_FILES[filename]
+ {filename}
+ else
+ file_type, err = lfs.attributes(filename, 'mode')
+ if file_type == 'file'
+ if match(filename, "%.nom$") or match(filename, "%.lua$")
+ {filename}
+ else false
+ elseif file_type == 'char device'
+ {filename}
+ elseif file_type == 'directory' or file_type == 'link'
+ files = {}
+ for subfile in lfs.dir(filename)
+ unless subfile == "." or subfile == ".."
+ for f in *(browse(filename.."/"..subfile) or {})
+ files[#files+1] = f
+ files
+ else false
+ return _BROWSE_CACHE[filename]
else
if io.popen('find . -maxdepth 0')\close!
error "Could not find 'luafilesystem' module and couldn't run system command `find` (this might happen on Windows). Please install `luafilesystem` (which can be found at: http://keplerproject.github.io/luafilesystem/ or `luarocks install luafilesystem`)", 0
-files.walk = (path, flush_cache=false)->
+Files.walk = (path, flush_cache=false)->
if flush_cache
- export _browse_cache
- _browse_cache = {}
- _files = browse(path)
- if package.nomsupath and not _files
+ export _BROWSE_CACHE
+ _BROWSE_CACHE = {}
+ files = browse(path)
+ if package.nomsupath and not files
for nomsupath in package.nomsupath\gmatch("[^;]+")
- if _files = browse(nomsupath.."/"..path) then break
- iter = (_files, i)->
- return unless _files
+ if files = browse(nomsupath.."/"..path) then break
+ iter = (files, i)->
+ return unless files
i += 1
- if f = _files[i]
+ if f = files[i]
return i, f
- return iter, _files, 0
+ return iter, files, 0
line_counter = re.compile([[
lines <- {| line (%nl line)* |}
@@ -111,7 +120,7 @@ line_counter = re.compile([[
-- LINE_STARTS is a mapping from strings to a table that maps line number to character positions
_LINE_STARTS = {}
-files.get_line_starts = (str)->
+Files.get_line_starts = (str)->
if type(str) != 'string'
str = tostring(str)
if starts = _LINE_STARTS[str]
@@ -121,8 +130,8 @@ files.get_line_starts = (str)->
return line_starts
log = {}
-files.get_line_number = (str, pos)->
- line_starts = files.get_line_starts(str)
+Files.get_line_number = (str, pos)->
+ line_starts = Files.get_line_starts(str)
-- Binary search for line number of position
lo, hi = 1, #line_starts
while lo <= hi
@@ -132,8 +141,8 @@ files.get_line_number = (str, pos)->
else lo = mid+1
return hi
-files.get_line = (str, line_no)->
- line_starts = files.get_line_starts(str)
+Files.get_line = (str, line_no)->
+ line_starts = Files.get_line_starts(str)
return str\sub(line_starts[line_no] or 1, (line_starts[line_no+1] or 1) - 2)
get_lines = re.compile([[
@@ -141,6 +150,6 @@ get_lines = re.compile([[
line <- {[^%nl]*}
]], nl:lpeg.P("\r")^-1 * lpeg.P("\n"))
-files.get_lines = (str)-> get_lines\match(str)
+Files.get_lines = (str)-> get_lines\match(str)
-return files
+return Files
diff --git a/lib/os.nom b/lib/os.nom
index a797d2b..1f8d6a7 100644
--- a/lib/os.nom
+++ b/lib/os.nom
@@ -5,7 +5,7 @@
use "core"
action [path of Nomsu file %filename]:
- lua> "for i,f in files.walk(\%filename) do return f end"
+ lua> "for i,f in Files.walk(\%filename) do return f end"
barf "Could not find file: \%filename"
action [sh> %cmd]:
@@ -15,10 +15,10 @@ action [sh> %cmd]:
result:close()
return contents
-action [read file %filename] (=lua "files.read(\%filename)")
+action [read file %filename] (=lua "Files.read(\%filename)")
compile [for file %f in %path %body] to (..)
Lua ".."
- for i,\(%f as lua expr) in files.walk(\(%path as lua expr)) do
+ for i,\(%f as lua expr) in Files.walk(\(%path as lua expr)) do
\(%body as lua statements)
\(compile as (===next %f ===))
end
@@ -28,7 +28,7 @@ compile [%expr for file %f in %path] to (..)
Lua value ".."
(function()
local ret = list{}
- for i,\(%f as lua expr) in files.walk(\(%path as lua expr)) do
+ for i,\(%f as lua expr) in Files.walk(\(%path as lua expr)) do
ret[#ret+1] = \(%expr as lua statements)
end
return ret
@@ -43,5 +43,5 @@ action [..]
file:write(\%text)
file:close()
-action [line number of %pos in %str] (=lua "files.get_line_number(\%str, \%pos)")
-action [line %line_num in %str] (=lua "files.get_line(\%str, \%line_num)") \ No newline at end of file
+action [line number of %pos in %str] (=lua "Files.get_line_number(\%str, \%pos)")
+action [line %line_num in %str] (=lua "Files.get_line(\%str, \%line_num)")
diff --git a/nomsu.lua b/nomsu.lua
index 621d448..d29167e 100644
--- a/nomsu.lua
+++ b/nomsu.lua
@@ -59,8 +59,8 @@ OPTIONS
-O Run the compiler in optimized mode (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.
- -t Run tests.
-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.
@@ -76,6 +76,7 @@ if not ok then
print("Error: unable to find the 'lpeg' Lua module. Please install LPEG either from http://www.inf.puc-rio.br/~roberto/lpeg/re.html or, if you use luarocks: `luarocks install lpeg`")
os.exit(EXIT_FAILURE)
end
+local Files = require("files")
local Errhand = require("error_handling")
local NomsuCompiler = require("nomsu_compiler")
local NomsuCode, LuaCode, Source
@@ -89,34 +90,41 @@ if not arg or debug.getinfo(2).func == require then
return NomsuCompiler
end
local file_queue = { }
-local parser = re.compile([[ args <- {| (flag ";")* (({~ file ~} -> add_file) ";")? {:nomsu_args: {| ({[^;]*} ";")* |} :} ";"? |} !.
+local sep = "\0"
+local parser = re.compile([[ args <- {| (flag %sep)* (({~ file ~} -> add_file) %sep)? {:nomsu_args: {| ({(!%sep .)*} %sep)* |} :} %sep? |} !.
flag <-
{:optimized: ("-O" -> true) :}
- / ("-I" (";")? ({~ file ~} -> add_file))
+ / ("-I" %sep? ({~ file ~} -> add_file))
+ / ("-e" %sep? (({} {~ file ~}) -> add_exec_string))
/ ({:check_syntax: ("-s" -> true):})
/ ({:compile: ("-c" -> true):})
- / {:run_tests: ("-t" -> true) :}
+ / ({:compile: ("-c" -> true):})
/ {:verbose: ("-v" -> true) :}
/ {:help: (("-h" / "--help") -> true) :}
/ {:version: ("--version" -> true) :}
- / {:debugger: ("-d" (";")? {([^;])*}) :}
- / {:requested_version: "-V" ((";")? {([0-9.])+})? :}
- file <- ("-" -> "stdin") / {[^;]+}
+ / {:debugger: ("-d" %sep? {(!%sep .)*}) :}
+ / {:requested_version: "-V" (%sep? {([0-9.])+})? :}
+ file <- ("-" -> "stdin") / {(!%sep .)+}
]], {
["true"] = function()
return true
end,
+ sep = lpeg.P(sep),
add_file = function(f)
return table.insert(file_queue, f)
+ end,
+ add_exec_string = function(pos, s)
+ local name = "command line arg @" .. tostring(pos) .. ".nom"
+ Files.spoof(name, s)
+ return table.insert(file_queue, name)
end
})
-local arg_string = table.concat(arg, ";") .. ";"
+local arg_string = table.concat(arg, sep) .. sep
local args = parser:match(arg_string)
if not args or args.help then
print(usage)
os.exit(EXIT_FAILURE)
end
-local files = require("files")
local nomsu = NomsuCompiler
nomsu.arg = NomsuCompiler.list(args.nomsu_args)
if args.version then
@@ -141,10 +149,10 @@ 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))
+ if not (Files.exists(f)) then
+ error("Could not find: '" .. tostring(f) .. "'")
end
- for _, filename in files.walk(f) do
+ for _, filename in Files.walk(f) do
input_files[filename] = true
end
end
@@ -157,25 +165,15 @@ run = function()
end
return true
end
- local tests = { }
- if args.run_tests then
- nomsu.COMPILE_ACTIONS["test %"] = function(self, tree, _body)
- if not (tests[tree.source.filename]) then
- tests[tree.source.filename] = { }
- end
- table.insert(tests[tree.source.filename], _body)
- return LuaCode("")
- end
- end
local get_file_and_source
get_file_and_source = function(filename)
local file, source
if filename == 'stdin' then
file = io.read("*a")
- files.spoof('stdin', file)
+ Files.spoof('stdin', file)
source = Source('stdin', 1, #file)
elseif filename:match("%.nom$") then
- file = files.read(filename)
+ file = Files.read(filename)
if not file then
error("File does not exist: " .. tostring(filename), 0)
end
@@ -212,23 +210,12 @@ run = function()
end
nomsu:run_lua(lua)
end
- if args.run_tests and tests[filename] and input_files[filename] then
- local _list_0 = tests[filename]
- for _index_0 = 1, #_list_0 do
- local t = _list_0[_index_0]
- local lua = nomsu:compile(t)
- if lua_handler then
- lua_handler(tostring(lua))
- end
- nomsu:run_lua(lua, t.source)
- end
- end
end
end
local parse_errs = { }
for _index_0 = 1, #file_queue do
local f = file_queue[_index_0]
- for _, filename in files.walk(f) do
+ for _, filename in Files.walk(f) do
local _continue_0 = false
repeat
if not (filename == "stdin" or filename:match("%.nom$")) then
@@ -308,7 +295,7 @@ say ".."
end
buff = table.concat(buff)
local pseudo_filename = "user input #" .. repl_line
- files.spoof(pseudo_filename, buff)
+ Files.spoof(pseudo_filename, buff)
local err_hand
err_hand = function(error_message)
return Errhand.print_error(error_message)
diff --git a/nomsu.moon b/nomsu.moon
index 29c49e3..c30004d 100755
--- a/nomsu.moon
+++ b/nomsu.moon
@@ -17,8 +17,8 @@ OPTIONS
-O Run the compiler in optimized mode (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.
- -t Run tests.
-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.
@@ -34,6 +34,7 @@ ok, _ = pcall ->
if not ok
print("Error: unable to find the 'lpeg' Lua module. Please install LPEG either from http://www.inf.puc-rio.br/~roberto/lpeg/re.html or, if you use luarocks: `luarocks install lpeg`")
os.exit(EXIT_FAILURE)
+Files = require "files"
Errhand = require "error_handling"
NomsuCompiler = require "nomsu_compiler"
{:NomsuCode, :LuaCode, :Source} = require "code_obj"
@@ -44,31 +45,37 @@ if not arg or debug.getinfo(2).func == require
return NomsuCompiler
file_queue = {}
+sep = "\0"
parser = re.compile([[
- args <- {| (flag ";")* (({~ file ~} -> add_file) ";")? {:nomsu_args: {| ({[^;]*} ";")* |} :} ";"? |} !.
+ args <- {| (flag %sep)* (({~ file ~} -> add_file) %sep)? {:nomsu_args: {| ({(!%sep .)*} %sep)* |} :} %sep? |} !.
flag <-
{:optimized: ("-O" -> true) :}
- / ("-I" (";")? ({~ file ~} -> add_file))
+ / ("-I" %sep? ({~ file ~} -> add_file))
+ / ("-e" %sep? (({} {~ file ~}) -> add_exec_string))
/ ({:check_syntax: ("-s" -> true):})
/ ({:compile: ("-c" -> true):})
- / {:run_tests: ("-t" -> true) :}
+ / ({:compile: ("-c" -> true):})
/ {:verbose: ("-v" -> true) :}
/ {:help: (("-h" / "--help") -> true) :}
/ {:version: ("--version" -> true) :}
- / {:debugger: ("-d" (";")? {([^;])*}) :}
- / {:requested_version: "-V" ((";")? {([0-9.])+})? :}
- file <- ("-" -> "stdin") / {[^;]+}
+ / {:debugger: ("-d" %sep? {(!%sep .)*}) :}
+ / {:requested_version: "-V" (%sep? {([0-9.])+})? :}
+ file <- ("-" -> "stdin") / {(!%sep .)+}
]], {
true: -> true
+ sep: lpeg.P(sep)
add_file: (f)-> table.insert(file_queue, f)
+ add_exec_string: (pos, s)->
+ name = "command line arg @#{pos}.nom"
+ Files.spoof(name, s)
+ table.insert(file_queue, name)
})
-arg_string = table.concat(arg, ";")..";"
+arg_string = table.concat(arg, sep)..sep
args = parser\match(arg_string)
if not args or args.help
print usage
os.exit(EXIT_FAILURE)
-files = require "files"
nomsu = NomsuCompiler
nomsu.arg = NomsuCompiler.list(args.nomsu_args)
@@ -93,9 +100,9 @@ FILE_CACHE = setmetatable {}, {
run = ->
input_files = {}
for f in *file_queue
- unless files.exists(f)
- error("Could not find: #{f}")
- for _,filename in files.walk(f)
+ unless Files.exists(f)
+ error("Could not find: '#{f}'")
+ for _,filename in Files.walk(f)
input_files[filename] = true
nomsu.can_optimize = (f)->
@@ -103,21 +110,14 @@ run = ->
return false if args.compile and input_files[f]
return true
- tests = {}
- if args.run_tests
- nomsu.COMPILE_ACTIONS["test %"] = (tree, _body)=>
- unless tests[tree.source.filename] then tests[tree.source.filename] = {}
- table.insert tests[tree.source.filename], _body
- return LuaCode ""
-
get_file_and_source = (filename)->
local file, source
if filename == 'stdin'
file = io.read("*a")
- files.spoof('stdin', file)
+ Files.spoof('stdin', file)
source = Source('stdin', 1, #file)
elseif filename\match("%.nom$")
- file = files.read(filename)
+ file = Files.read(filename)
if not file
error("File does not exist: #{filename}", 0)
source = Source(filename, 1, #file)
@@ -141,15 +141,10 @@ run = ->
lua\prepend "-- File: #{source.filename\gsub("\n.*", "...")}\n"
if lua_handler and input_files[filename] then lua_handler(tostring(lua))
nomsu\run_lua(lua)
- if args.run_tests and tests[filename] and input_files[filename]
- for t in *tests[filename]
- lua = nomsu\compile(t)
- if lua_handler then lua_handler(tostring(lua))
- nomsu\run_lua(lua, t.source)
parse_errs = {}
for f in *file_queue
- for _,filename in files.walk(f)
+ for _,filename in Files.walk(f)
continue unless filename == "stdin" or filename\match("%.nom$")
if args.check_syntax
-- Check syntax
@@ -209,7 +204,7 @@ say ".."
buff = table.concat(buff)
pseudo_filename = "user input #"..repl_line
- files.spoof(pseudo_filename, buff)
+ Files.spoof(pseudo_filename, buff)
err_hand = (error_message)->
Errhand.print_error error_message
ok, ret = xpcall(nomsu.run, err_hand, nomsu, buff, Source(pseudo_filename, 1, #buff))
diff --git a/nomsu_compiler.lua b/nomsu_compiler.lua
index f46e75b..16874a3 100644
--- a/nomsu_compiler.lua
+++ b/nomsu_compiler.lua
@@ -1,7 +1,7 @@
local lpeg = require('lpeg')
local re = require('re')
local utils = require('utils')
-local files = require('files')
+local Files = require('files')
local repr, stringify, equivalent
repr, stringify, equivalent = utils.repr, utils.stringify, utils.equivalent
colors = require('consolecolors')
@@ -174,7 +174,7 @@ do
utils = utils,
lpeg = lpeg,
re = re,
- files = files,
+ Files = Files,
next = next,
unpack = unpack,
setmetatable = setmetatable,
@@ -226,16 +226,17 @@ do
__mode = "k"
})
NomsuCompiler.LOADED = { }
+ NomsuCompiler.TESTS = { }
NomsuCompiler.AST = AST
NomsuCompiler.compile_error = function(self, source, err_format_string, ...)
err_format_string = err_format_string:gsub("%%[^s]", "%%%1")
- local file = files.read(source.filename)
- local line_starts = files.get_line_starts(file)
- local line_no = files.get_line_number(file, source.start)
+ local file = Files.read(source.filename)
+ local line_starts = Files.get_line_starts(file)
+ local line_no = Files.get_line_number(file, source.start)
local line_start = line_starts[line_no]
local src = colored.dim(file:sub(line_start, source.start - 1))
src = src .. colored.underscore(colored.bright(colored.red(file:sub(source.start, source.stop - 1))))
- local end_of_line = (line_starts[files.get_line_number(file, source.stop) + 1] or 0) - 1
+ local end_of_line = (line_starts[Files.get_line_number(file, source.stop) + 1] or 0) - 1
src = src .. colored.dim(file:sub(source.stop, end_of_line - 1))
src = ' ' .. src:gsub('\n', '\n ')
local err_msg = err_format_string:format(src, ...)
@@ -343,14 +344,27 @@ do
["use %"] = function(self, tree, _path)
if _path.type == 'Text' and #_path == 1 and type(_path[1]) == 'string' then
local path = _path[1]
- for _, f in files.walk(path) do
+ for _, f in Files.walk(path) do
self:run_file(f)
end
end
- return LuaCode(tree.source, "for i,f in files.walk(", self:compile(_path), ") do nomsu:run_file(f) end")
+ return LuaCode(tree.source, "for i,f in Files.walk(", self:compile(_path), ") do nomsu:run_file(f) end")
+ end,
+ ["tests"] = function(self, tree)
+ return LuaCode.Value(tree.source, "TESTS")
end,
["test %"] = function(self, tree, _body)
- return LuaCode("")
+ local test_str = table.concat((function()
+ local _accum_0 = { }
+ local _len_0 = 1
+ for _index_0 = 1, #_body do
+ local line = _body[_index_0]
+ _accum_0[_len_0] = tostring(self:tree_to_nomsu(line))
+ _len_0 = _len_0 + 1
+ end
+ return _accum_0
+ end)(), "\n")
+ return LuaCode(tree.source, "TESTS[" .. tostring(repr(tostring(tree.source))) .. "] = ", repr(test_str))
end
}, {
__index = function(self, stub)
@@ -370,8 +384,8 @@ do
if type(source) == 'string' then
source = Source:from_string(source)
end
- if not files.read(source.filename) then
- files.spoof(source.filename, to_run)
+ if not Files.read(source.filename) then
+ Files.spoof(source.filename, to_run)
end
local tree
if AST.is_syntax_tree(to_run) then
@@ -423,14 +437,14 @@ do
insert(_running_files, filename)
local ret = nil
if match(filename, "%.lua$") then
- local file = assert(files.read(filename), "Could not find file: " .. tostring(filename))
+ local file = assert(Files.read(filename), "Could not find file: " .. tostring(filename))
ret = self:run_lua(file, Source(filename, 1, #file))
elseif match(filename, "%.nom$") or match(filename, "^/dev/fd/[012]$") then
local ran_lua
if self.can_optimize(filename) then
local lua_filename = gsub(filename, "%.nom$", ".lua")
do
- local file = files.read(lua_filename)
+ local file = Files.read(lua_filename)
if file then
ret = self:run_lua(file, Source(lua_filename, 1, #file))
ran_lua = true
@@ -438,7 +452,7 @@ do
end
end
if not (ran_lua) then
- local file = files.read(filename)
+ local file = Files.read(filename)
if not file then
error("File does not exist: " .. tostring(filename), 0)
end
@@ -462,7 +476,7 @@ do
local line_numbered_lua = concat((function()
local _accum_0 = { }
local _len_0 = 1
- for i, line in ipairs(files.get_lines(lua_string)) do
+ for i, line in ipairs(Files.get_lines(lua_string)) do
_accum_0[_len_0] = format("%3d|%s", i, line)
_len_0 = _len_0 + 1
end
@@ -474,13 +488,13 @@ do
local source_key = tostring(source)
if not (SOURCE_MAP[source_key]) then
local map = { }
- local file = files.read(source.filename)
+ local file = Files.read(source.filename)
if not file then
error("Failed to find file: " .. tostring(source.filename))
end
local nomsu_str = tostring(file:sub(source.start, source.stop))
local lua_line = 1
- local nomsu_line = files.get_line_number(file, source.start)
+ local nomsu_line = Files.get_line_number(file, source.start)
local map_sources
map_sources = function(s)
if type(s) == 'string' then
@@ -490,7 +504,7 @@ do
end
else
if s.source and s.source.filename == source.filename then
- nomsu_line = files.get_line_number(file, s.source.start)
+ nomsu_line = Files.get_line_number(file, s.source.start)
end
local _list_0 = s.bits
for _index_0 = 1, #_list_0 do
@@ -624,7 +638,7 @@ do
local bit_lua = self:compile(bit)
if not (bit_lua.is_value) then
local src = ' ' .. gsub(tostring(recurse(bit)), '\n', '\n ')
- local line = tostring(bit.source.filename) .. ":" .. tostring(files.get_line_number(files.read(bit.source.filename), bit.source.start))
+ local line = tostring(bit.source.filename) .. ":" .. tostring(Files.get_line_number(Files.read(bit.source.filename), bit.source.start))
self:compile_error(bit.source, "Cannot use:\n%s\nas a string interpolation value, since it's not an expression.")
end
if #lua.bits > 0 then
@@ -1115,7 +1129,7 @@ do
for i, bit in ipairs(tree) do
if type(bit) == 'string' then
bit = Parser.escape(bit)
- local bit_lines = files.get_lines(bit)
+ local bit_lines = Files.get_lines(bit)
for j, line in ipairs(bit_lines) do
if j > 1 then
nomsu:append("\n")
diff --git a/nomsu_compiler.moon b/nomsu_compiler.moon
index 5e68709..7a4c6f0 100644
--- a/nomsu_compiler.moon
+++ b/nomsu_compiler.moon
@@ -12,7 +12,7 @@
lpeg = require 'lpeg'
re = require 're'
utils = require 'utils'
-files = require 'files'
+Files = require 'files'
{:repr, :stringify, :equivalent} = utils
export colors, colored
colors = require 'consolecolors'
@@ -105,7 +105,7 @@ with NomsuCompiler
-- Discretionary/convenience stuff
to_add = {
- repr:repr, stringify:stringify, utils:utils, lpeg:lpeg, re:re, files:files,
+ repr:repr, stringify:stringify, utils:utils, lpeg:lpeg, re:re, Files:Files,
-- Lua stuff:
:next, :unpack, :setmetatable, :coroutine, :rawequal, :getmetatable, :pcall,
:error, :package, :os, :require, :tonumber, :tostring, :string, :xpcall, :module,
@@ -122,17 +122,18 @@ with NomsuCompiler
.Source = Source
.ALIASES = setmetatable({}, {__mode:"k"})
.LOADED = {}
+ .TESTS = {}
.AST = AST
.compile_error = (source, err_format_string, ...)=>
err_format_string = err_format_string\gsub("%%[^s]", "%%%1")
- file = files.read(source.filename)
- line_starts = files.get_line_starts(file)
- line_no = files.get_line_number(file, source.start)
+ file = Files.read(source.filename)
+ line_starts = Files.get_line_starts(file)
+ line_no = Files.get_line_number(file, source.start)
line_start = line_starts[line_no]
src = colored.dim(file\sub(line_start, source.start-1))
src ..= colored.underscore colored.bright colored.red(file\sub(source.start, source.stop-1))
- end_of_line = (line_starts[files.get_line_number(file, source.stop) + 1] or 0) - 1
+ end_of_line = (line_starts[Files.get_line_number(file, source.stop) + 1] or 0) - 1
src ..= colored.dim(file\sub(source.stop, end_of_line-1))
src = ' '..src\gsub('\n', '\n ')
err_msg = err_format_string\format(src, ...)
@@ -222,12 +223,14 @@ with NomsuCompiler
["use %"]: (tree, _path)=>
if _path.type == 'Text' and #_path == 1 and type(_path[1]) == 'string'
path = _path[1]
- for _,f in files.walk(path)
+ for _,f in Files.walk(path)
@run_file(f)
- return LuaCode(tree.source, "for i,f in files.walk(", @compile(_path), ") do nomsu:run_file(f) end")
+ return LuaCode(tree.source, "for i,f in Files.walk(", @compile(_path), ") do nomsu:run_file(f) end")
+ ["tests"]: (tree)=> LuaCode.Value(tree.source, "TESTS")
["test %"]: (tree, _body)=>
- return LuaCode ""
+ test_str = table.concat [tostring(@tree_to_nomsu(line)) for line in *_body], "\n"
+ LuaCode tree.source, "TESTS[#{repr(tostring(tree.source))}] = ", repr(test_str)
}, {
__index: (stub)=>
if math_expression\match(stub)
@@ -237,7 +240,7 @@ with NomsuCompiler
.run = (to_run, source=nil, version=nil)=>
source or= to_run.source or Source(to_run, 1, #to_run)
if type(source) == 'string' then source = Source\from_string(source)
- if not files.read(source.filename) then files.spoof(source.filename, to_run)
+ if not Files.read(source.filename) then Files.spoof(source.filename, to_run)
tree = if AST.is_syntax_tree(to_run) then to_run else @parse(to_run, source, version)
if tree == nil -- Happens if pattern matches, but there are no captures, e.g. an empty string
return nil
@@ -271,16 +274,16 @@ with NomsuCompiler
insert _running_files, filename
ret = nil
if match(filename, "%.lua$")
- file = assert(files.read(filename), "Could not find file: #{filename}")
+ file = assert(Files.read(filename), "Could not find file: #{filename}")
ret = @run_lua file, Source(filename, 1, #file)
elseif match(filename, "%.nom$") or match(filename, "^/dev/fd/[012]$")
ran_lua = if @.can_optimize(filename) -- Look for precompiled version
lua_filename = gsub(filename, "%.nom$", ".lua")
- if file = files.read(lua_filename)
+ if file = Files.read(lua_filename)
ret = @run_lua file, Source(lua_filename, 1, #file)
true
unless ran_lua
- file = files.read(filename)
+ file = Files.read(filename)
if not file
error("File does not exist: #{filename}", 0)
ret = @run file, Source(filename,1,#file)
@@ -297,19 +300,19 @@ with NomsuCompiler
run_lua_fn, err = load(lua_string, nil and tostring(source or lua.source), "t", self)
if not run_lua_fn
line_numbered_lua = concat(
- [format("%3d|%s",i,line) for i, line in ipairs files.get_lines(lua_string)],
+ [format("%3d|%s",i,line) for i, line in ipairs Files.get_lines(lua_string)],
"\n")
error("Failed to compile generated code:\n#{colored.bright colored.blue colored.onblack line_numbered_lua}\n\n#{err}", 0)
source or= lua.source
source_key = tostring(source)
unless SOURCE_MAP[source_key]
map = {}
- file = files.read(source.filename)
+ file = Files.read(source.filename)
if not file
error "Failed to find file: #{source.filename}"
nomsu_str = tostring(file\sub(source.start, source.stop))
lua_line = 1
- nomsu_line = files.get_line_number(file, source.start)
+ nomsu_line = Files.get_line_number(file, source.start)
map_sources = (s)->
if type(s) == 'string'
for nl in s\gmatch("\n")
@@ -317,7 +320,7 @@ with NomsuCompiler
lua_line += 1
else
if s.source and s.source.filename == source.filename
- nomsu_line = files.get_line_number(file, s.source.start)
+ nomsu_line = Files.get_line_number(file, s.source.start)
for b in *s.bits do map_sources(b)
map_sources(lua)
map[lua_line] or= nomsu_line
@@ -387,7 +390,7 @@ with NomsuCompiler
bit_lua = @compile(bit)
unless bit_lua.is_value
src = ' '..gsub(tostring(recurse(bit)), '\n','\n ')
- line = "#{bit.source.filename}:#{files.get_line_number(files.read(bit.source.filename), bit.source.start)}"
+ line = "#{bit.source.filename}:#{Files.get_line_number(Files.read(bit.source.filename), bit.source.start)}"
@compile_error bit.source,
"Cannot use:\n%s\nas a string interpolation value, since it's not an expression."
if #lua.bits > 0 then lua\append ".."
@@ -726,7 +729,7 @@ with NomsuCompiler
for i, bit in ipairs tree
if type(bit) == 'string'
bit = Parser.escape(bit)
- bit_lines = files.get_lines(bit)
+ bit_lines = Files.get_lines(bit)
for j, line in ipairs bit_lines
if j > 1
nomsu\append "\n"
diff --git a/tools/autoformat.nom b/tools/autoformat.nom
index acabefb..1c591a0 100755
--- a/tools/autoformat.nom
+++ b/tools/autoformat.nom
@@ -10,10 +10,11 @@ if (%args.1 is "-i"):
for %path in %args:
for file %filename in %path:
+ unless (%filename matches "%.nom$"): do next %filename
%formatted = ".."
#!/usr/bin/env nomsu -V\(Nomsu version)
\((parse (read file %filename) from %filename) as nomsu)
if %inplace:
write %formatted to file %filename
- ..else: say %formatted \ No newline at end of file
+ ..else: say %formatted
diff --git a/tools/upgrade.nom b/tools/upgrade.nom
index a505aaa..690d4fb 100755
--- a/tools/upgrade.nom
+++ b/tools/upgrade.nom
@@ -1,5 +1,4 @@
#!/usr/bin/env nomsu -V2.5.4.3
-#!/usr/bin/env Nomsu -V2.4.4.3
use "core"
use "compatibility"
use "lib/os.nom"
@@ -18,6 +17,7 @@ if (%args.1 is "-t"):
for %path in %args:
if (%path is "-i"): %inplace = (yes)
for file %filename in %path:
+ unless (%filename matches "%.nom$"): do next %filename
%tree = (parse (read file %filename) from %filename)
%uptree = (%tree upgraded)
%text = ".."
@@ -35,4 +35,4 @@ for %path in %args:
..else:
say (bright "\%filename will be changed")
- else: say %text \ No newline at end of file
+ else: say %text