Improvements working towards better inline tests. Improved handling of

file spoofing and adding -e command line flag for executing a string.
This commit is contained in:
Bruce Hill 2018-07-21 14:43:49 -07:00
parent 6728587dfc
commit ae4670bd8e
11 changed files with 263 additions and 229 deletions

View File

@ -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)")
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -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> ".."

106
files.lua
View File

@ -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
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"')
local _files
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
files = _tbl_0
end
if not (f:close()) then
_files = false
_BROWSE_CACHE[path] = f:close() and files or 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
if not (_BROWSE_CACHE[filename]) then
if _SPOOFED_FILES[filename] then
_BROWSE_CACHE[filename] = {
filename
}
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] = {
_BROWSE_CACHE[filename] = {
filename
}
else
_BROWSE_CACHE[filename] = false
end
elseif file_type == 'char device' then
_browse_cache[filename] = {
_BROWSE_CACHE[filename] = {
filename
}
elseif file_type == 'directory' or file_type == 'link' then
local _files = { }
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
files[#files + 1] = f
end
end
end
_browse_cache[filename] = _files
_BROWSE_CACHE[filename] = files
else
_BROWSE_CACHE[filename] = false
end
end
return _browse_cache[filename]
end
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

View File

@ -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]
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!}
_files = false unless f\close!
_browse_cache[path] = _files
return _browse_cache[path]
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
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$")
_browse_cache[filename] = {filename}
{filename}
else false
elseif file_type == 'char device'
_browse_cache[filename] = {filename}
{filename}
elseif file_type == 'directory' or file_type == 'link'
_files = {}
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]
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

View File

@ -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)")
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)")

View File

@ -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)

View File

@ -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))

View File

@ -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")

View File

@ -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"

View File

@ -10,6 +10,7 @@ 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)

View File

@ -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 = ".."