aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bitbucket@bruce-hill.com>2018-06-23 17:22:23 -0700
committerBruce Hill <bitbucket@bruce-hill.com>2018-06-23 17:22:43 -0700
commit863983202ce4ef92d9e3a296a682535d157c245d (patch)
tree288411a534c8a64542ce1b101b9532cb12f11c7d
parent0d888db6324ecd879ba770880173255b6c3f7ae5 (diff)
Fixed up nomsupath behavior and refactored file stuff into its own file.
-rw-r--r--Makefile53
-rw-r--r--error_handling.lua5
-rw-r--r--error_handling.moon5
-rw-r--r--files.lua125
-rw-r--r--files.moon86
-rw-r--r--lib/os.nom19
-rw-r--r--lib/version.nom1
-rwxr-xr-x[l---------]nomsu21
-rw-r--r--nomsu.lua140
-rwxr-xr-xnomsu.moon73
-rw-r--r--nomsu_compiler.lua66
-rw-r--r--nomsu_compiler.moon55
-rw-r--r--parser.lua10
-rw-r--r--parser.moon8
-rw-r--r--tests/metaprogramming.nom2
-rw-r--r--tests/os.nom3
16 files changed, 414 insertions, 258 deletions
diff --git a/Makefile b/Makefile
index a65ca4e..fc11273 100644
--- a/Makefile
+++ b/Makefile
@@ -9,11 +9,12 @@ LUA_BIN= $(shell which $(LUA))
PREFIX=/usr/local
NOMSU_BIN_DIR= $(PREFIX)/bin
NOMSU_LIB_DIR= $(PREFIX)/lib/nomsu
+NOMSU_SHARE_DIR= $(PREFIX)/share/nomsu
# ========= You shouldn't need to mess with any of these variables below ================
-MOON_FILES= code_obj.moon error_handling.moon nomsu.moon nomsu_compiler.moon nomsu_tree.moon parser.moon
-LUA_FILES= code_obj.lua consolecolors.lua error_handling.lua nomsu.lua nomsu_compiler.lua \
+MOON_FILES= code_obj.moon error_handling.moon files.moon nomsu.moon nomsu_compiler.moon nomsu_tree.moon parser.moon
+LUA_FILES= code_obj.lua consolecolors.lua error_handling.lua files.lua nomsu.lua nomsu_compiler.lua \
nomsu_tree.lua parser.lua utils.lua uuid.lua
CORE_NOM_FILES= $(wildcard core/*.nom)
CORE_LUA_FILES= $(patsubst %.nom,%.lua,$(CORE_NOM_FILES))
@@ -37,7 +38,7 @@ test: build optimize
.PHONY: check_header
check_header: $(PEG_FILE) nomsu.lua $(CORE_NOM_FILES) $(LIB_NOM_FILES)
@if [ -f nomsu_latest ]; then \
- NOMSU_HEADER="#!$(LUA_BIN)\\npackage.path = [[$(NOMSU_LIB_DIR)/`$(GET_VERSION)`/?.lua;]]..package.path\\npackage.nomsupath = [[$(NOMSU_LIB_DIR)/`$(GET_VERSION)`]]"; \
+ NOMSU_HEADER="#!$(LUA_BIN)\\nlocal NOMSU_VERSION, NOMSU_LIB, NOMSU_SHARE = [[`$(GET_VERSION)`]], [[$(NOMSU_LIB_DIR)]], [[$(NOMSU_SHARE_DIR)]]"; \
if [ "`head -n 3 nomsu_latest 2>/dev/null`" != "`echo $$NOMSU_HEADER`" ]; then \
rm -f nomsu_latest; \
fi; \
@@ -45,7 +46,7 @@ check_header: $(PEG_FILE) nomsu.lua $(CORE_NOM_FILES) $(LIB_NOM_FILES)
nomsu_latest: nomsu.lua
@rm -f nomsu_latest
- @NOMSU_HEADER="#!$(LUA_BIN)\\npackage.path = [[$(NOMSU_LIB_DIR)/`$(GET_VERSION)`/?.lua;]]..package.path\\npackage.nomsupath = [[$(NOMSU_LIB_DIR)/`$(GET_VERSION)`]]"; \
+ @NOMSU_HEADER="#!$(LUA_BIN)\\nlocal NOMSU_VERSION, NOMSU_LIB, NOMSU_SHARE = [[`$(GET_VERSION)`]], [[$(NOMSU_LIB_DIR)]], [[$(NOMSU_SHARE_DIR)]]"; \
echo $$NOMSU_HEADER | cat - nomsu.lua > nomsu_latest
@chmod +x nomsu_latest
@mv -f nomsu_latest nomsu`$(GET_VERSION)`
@@ -64,14 +65,46 @@ clean:
.PHONY: install
install: all
- mkdir -pv $(NOMSU_BIN_DIR) && cp -v nomsu nomsu`$(GET_VERSION)` $(NOMSU_BIN_DIR)
- mkdir -pv $(NOMSU_LIB_DIR)/`$(GET_VERSION)` && cp -rv $(LUA_FILES) $(PEG_FILE) core lib $(NOMSU_LIB_DIR)/`$(GET_VERSION)`
+ @echo "Nomsu will be installed to:"
+ @echo " $(NOMSU_BIN_DIR)"
+ @echo " $(NOMSU_LIB_DIR)"
+ @echo " $(NOMSU_SHARE_DIR)"
+ @read -p "is that okay? [Y/n] " ans; \
+ if [[ ! $$ans =~ ^[Nn] ]]; then \
+ mkdir -pv $(NOMSU_BIN_DIR) $(NOMSU_LIB_DIR)/`$(GET_VERSION)` $(NOMSU_SHARE_DIR)/`$(GET_VERSION)` \
+ && cp -v nomsu nomsu`$(GET_VERSION)` $(NOMSU_BIN_DIR) \
+ && cp -rv $(LUA_FILES) $(PEG_FILE) core lib tests $(NOMSU_SHARE_DIR)/`$(GET_VERSION)`; \
+ fi
.PHONY: uninstall
uninstall: all
- @echo "Deleting..."
- @rm -rvf $(NOMSU_LIB_DIR)/`$(GET_VERSION)` $(NOMSU_BIN_DIR)/nomsu`$(GET_VERSION)`
- @if [ "`ls $(NOMSU_BIN_DIR)/nomsu*`" == "nomsu" ]; then rm -v $(NOMSU_BIN_DIR)/nomsu; fi
- @if [ "`ls $(NOMSU_LIB_DIR) 2>/dev/null`" == "" ]; then rm -rvf $(NOMSU_LIB_DIR); fi
+ @echo "Nomsu will be uninstalled from:"
+ @echo " $(NOMSU_BIN_DIR)"
+ @echo " $(NOMSU_LIB_DIR)"
+ @echo " $(NOMSU_SHARE_DIR)"
+ @read -p "is that okay? [Y/n] " ans; \
+ if [[ ! $$ans =~ ^[Nn] ]]; then \
+ echo "Deleting..."; \
+ rm -rvf $(NOMSU_LIB_DIR)/`$(GET_VERSION)` $(NOMSU_SHARE_DIR)/`$(GET_VERSION)` $(NOMSU_BIN_DIR)/nomsu`$(GET_VERSION)`; \
+ if [ "`ls $(NOMSU_BIN_DIR)/nomsu* 2> /dev/null`" == "nomsu" ]; then \
+ rm -vf $(NOMSU_BIN_DIR)/nomsu; \
+ else \
+ if [ "`ls $(NOMSU_BIN_DIR)/nomsu* 2> /dev/null`" != "" ]; then \
+ read -p "It looks like there are other versions of Nomsu installed. Is it okay to leave the 'nomsu' cross-version launcher in place? (recommended) [Y/n]" ans; \
+ if [[ $$ans =~ ^[Nn] ]]; then \
+ echo "Deleting..."; \
+ rm -vf $(NOMSU_BIN_DIR)/nomsu; \
+ fi; \
+ fi; \
+ fi; \
+ if [ "`ls $(NOMSU_LIB_DIR) 2>/dev/null`" == "" ]; then rm -rvf $(NOMSU_LIB_DIR);\
+ else \
+ echo "Retaining $(NOMSU_LIB_DIR), since there are other files there."; \
+ fi; \
+ if [ "`ls $(NOMSU_SHARE_DIR) 2>/dev/null`" == "" ]; then rm -rvf $(NOMSU_SHARE_DIR);\
+ else \
+ echo "Retaining $(NOMSU_SHARE_DIR), since there are other files there."; \
+ fi; \
+ fi
# eof
diff --git a/error_handling.lua b/error_handling.lua
index 90c5991..b0e6dde 100644
--- a/error_handling.lua
+++ b/error_handling.lua
@@ -1,3 +1,4 @@
+local files = require("files")
local debug_getinfo = debug.getinfo
local ok, to_lua = pcall(function()
return require('moonscript.base').to_lua
@@ -97,7 +98,7 @@ print_error = function(error_message, stack_offset)
end
local filename, start, stop = calling_fn.source:match('@([^[]*)%[([0-9]+):([0-9]+)]')
assert(filename)
- local file = FILE_CACHE[filename]:sub(tonumber(start), tonumber(stop))
+ local file = read_file(filename):sub(tonumber(start), tonumber(stop))
local err_line = get_line(file, calling_fn.currentline):sub(1, -2)
local offending_statement = colored.bright(colored.red(err_line:match("^[ ]*(.*)")))
if calling_fn.name then
@@ -118,7 +119,7 @@ print_error = function(error_message, stack_offset)
else
local file
ok, file = pcall(function()
- return FILE_CACHE[calling_fn.short_src]
+ return read_file(calling_fn.short_src)
end)
if not ok then
file = nil
diff --git a/error_handling.moon b/error_handling.moon
index c71e782..5341348 100644
--- a/error_handling.moon
+++ b/error_handling.moon
@@ -1,4 +1,5 @@
-- This file contains the logic for making nicer error messages
+files = require "files"
debug_getinfo = debug.getinfo
export SOURCE_MAP
@@ -62,7 +63,7 @@ print_error = (error_message, stack_offset=3)->
--calling_fn.short_src = calling_fn.source\match('"([^[]*)')
filename,start,stop = calling_fn.source\match('@([^[]*)%[([0-9]+):([0-9]+)]')
assert(filename)
- file = FILE_CACHE[filename]\sub(tonumber(start),tonumber(stop))
+ file = read_file(filename)\sub(tonumber(start),tonumber(stop))
err_line = get_line(file, calling_fn.currentline)\sub(1,-2)
offending_statement = colored.bright(colored.red(err_line\match("^[ ]*(.*)")))
-- TODO: get name properly
@@ -73,7 +74,7 @@ print_error = (error_message, stack_offset=3)->
else "main chunk"
line = colored.yellow("#{filename}:#{calling_fn.currentline} in #{name}\n #{offending_statement}")
else
- ok, file = pcall ->FILE_CACHE[calling_fn.short_src]
+ ok, file = pcall ->read_file(calling_fn.short_src)
if not ok then file = nil
local line_num
if name == nil
diff --git a/files.lua b/files.lua
new file mode 100644
index 0000000..77bdf6d
--- /dev/null
+++ b/files.lua
@@ -0,0 +1,125 @@
+local files = { }
+local _FILE_CACHE = { }
+files.spoof = function(filename, contents)
+ _FILE_CACHE[filename] = contents
+end
+files.read = function(filename)
+ do
+ local file_contents = _FILE_CACHE[filename]
+ if file_contents then
+ return file_contents
+ end
+ end
+ local file = io.open(filename)
+ if package.nomsupath and not file then
+ for nomsupath in package.nomsupath:gmatch("[^;]+") do
+ file = io.open(nomsupath .. "/" .. filename)
+ if file then
+ break
+ end
+ end
+ end
+ if not (file) then
+ return nil
+ end
+ local contents = file:read("*a")
+ file:close()
+ _FILE_CACHE[filename] = contents
+ return contents
+end
+local iterate_single
+iterate_single = function(item, prev)
+ if item == prev then
+ return nil
+ else
+ return item
+ end
+end
+local match, sub, rep, gsub, format, byte, find
+do
+ local _obj_0 = string
+ match, sub, rep, gsub, format, byte, match, find = _obj_0.match, _obj_0.sub, _obj_0.rep, _obj_0.gsub, _obj_0.format, _obj_0.byte, _obj_0.match, _obj_0.find
+end
+iterate_single = function(item, prev)
+ if item == prev then
+ return nil
+ else
+ return item
+ end
+end
+local ok, lfs = pcall(require, "lfs")
+if ok then
+ files.walk = function(path)
+ local browse
+ browse = function(filename)
+ local file_type = lfs.attributes(filename, 'mode')
+ if file_type == 'file' then
+ if match(filename, "%.nom$") or match(filename, "%.lua$") then
+ coroutine.yield(filename)
+ return true
+ end
+ elseif file_type == 'directory' then
+ for subfile in lfs.dir(filename) do
+ if not (subfile == "." or subfile == "..") then
+ browse(filename .. "/" .. subfile)
+ end
+ end
+ return true
+ elseif file_type == 'char device' then
+ coroutine.yield(filename)
+ return true
+ end
+ return false
+ end
+ return coroutine.wrap(function()
+ if not browse(path) and package.nomsupath then
+ for nomsupath in package.nomsupath:gmatch("[^;]+") do
+ if browse(nomsupath .. "/" .. path) then
+ break
+ end
+ end
+ end
+ return nil
+ end)
+ end
+else
+ local ret = os.execute('find . -maxdepth 0')
+ if not (ret == true or ret == 0) 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
+ files.walk = function(path)
+ if match(path, "%.nom$") or match(path, "%.lua$") or match(path, "^/dev/fd/[012]$") then
+ return iterate_single, path
+ end
+ path = gsub(path, "\\", "\\\\")
+ path = gsub(path, "`", "")
+ path = gsub(path, '"', '\\"')
+ path = gsub(path, "$", "")
+ return coroutine.wrap(function()
+ local f = io.popen('find -L "' .. path .. '" -not -path "*/\\.*" -type f -name "*.nom"')
+ local found = false
+ for line in f:lines() do
+ found = true
+ coroutine.yield(line)
+ end
+ if not found and package.nomsupath then
+ f:close()
+ for nomsupath in package.nomsupath:gmatch("[^;]+") do
+ f = io.popen('find -L "' .. package.nomsupath .. '/' .. path .. '" -not -path "*/\\.*" -type f -name "*.nom"')
+ for line in f:lines() do
+ found = true
+ coroutine.yield(line)
+ end
+ f:close()
+ if found then
+ break
+ end
+ end
+ end
+ if not (found) then
+ return error("Invalid file path: " .. tostring(path))
+ end
+ end)
+ end
+end
+return files
diff --git a/files.moon b/files.moon
new file mode 100644
index 0000000..3abae95
--- /dev/null
+++ b/files.moon
@@ -0,0 +1,86 @@
+-- Some file utilities for searching for files recursively and using package.nomsupath
+files = {}
+
+_FILE_CACHE = {}
+
+-- Create a fake file and put it in the cache
+files.spoof = (filename, contents)->
+ _FILE_CACHE[filename] = contents
+
+-- Read a file's contents (searching first locally, then in the nomsupath)
+files.read = (filename)->
+ if file_contents = _FILE_CACHE[filename]
+ return file_contents
+ file = io.open(filename)
+ if package.nomsupath and not file
+ for nomsupath in package.nomsupath\gmatch("[^;]+")
+ file = io.open(nomsupath.."/"..filename)
+ break if file
+ return nil unless file
+ contents = file\read("*a")
+ file\close!
+ _FILE_CACHE[filename] = contents
+ return contents
+
+iterate_single = (item, prev) -> if item == prev then nil else item
+
+-- `walk` returns an iterator over all files matching a path.
+{:match, :sub, :rep, :gsub, :format, :byte, :match, :find} = string
+iterate_single = (item, prev) -> if item == prev then nil else item
+ok, lfs = pcall(require, "lfs")
+if ok
+ files.walk = (path)->
+ -- Return 'true' if any files or directories are found, otherwise 'false'
+ browse = (filename)->
+ file_type = lfs.attributes(filename, 'mode')
+ if file_type == 'file'
+ if match(filename, "%.nom$") or match(filename, "%.lua$")
+ coroutine.yield filename
+ return true
+ elseif file_type == 'directory'
+ for subfile in lfs.dir(filename)
+ unless subfile == "." or subfile == ".."
+ browse(filename.."/"..subfile)
+ return true
+ elseif file_type == 'char device'
+ coroutine.yield(filename)
+ return true
+ return false
+ return coroutine.wrap ->
+ if not browse(path) and package.nomsupath
+ for nomsupath in package.nomsupath\gmatch("[^;]+")
+ break if browse(nomsupath.."/"..path)
+ return nil
+else
+ ret = os.execute('find . -maxdepth 0')
+ unless ret == true or ret == 0
+ 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)->
+ -- Sanitize path
+ if match(path, "%.nom$") or match(path, "%.lua$") or match(path, "^/dev/fd/[012]$")
+ return iterate_single, path
+ -- TODO: improve sanitization
+ path = gsub(path,"\\","\\\\")
+ path = gsub(path,"`","")
+ path = gsub(path,'"','\\"')
+ path = gsub(path,"$","")
+ return coroutine.wrap ->
+ f = io.popen('find -L "'..path..'" -not -path "*/\\.*" -type f -name "*.nom"')
+ found = false
+ for line in f\lines!
+ found = true
+ coroutine.yield(line)
+ if not found and package.nomsupath
+ f\close!
+ for nomsupath in package.nomsupath\gmatch("[^;]+")
+ f = io.popen('find -L "'..package.nomsupath..'/'..path..'" -not -path "*/\\.*" -type f -name "*.nom"')
+ for line in f\lines!
+ found = true
+ coroutine.yield(line)
+ f\close!
+ break if found
+ unless found
+ error("Invalid file path: "..tostring(path))
+
+return files
diff --git a/lib/os.nom b/lib/os.nom
index be65370..8a27168 100644
--- a/lib/os.nom
+++ b/lib/os.nom
@@ -1,5 +1,10 @@
use "core"
+action [path of Nomsu file %filename]
+ lua> ".."
+ for f in files.walk(\%filename) do return f end
+ barf "Could not find file: \%filename"
+
action [sh> %cmd]
lua> ".."
local result = io.popen(\%cmd)
@@ -8,11 +13,15 @@ action [sh> %cmd]
return contents
action [read file %filename]
- lua> ".."
- local file = io.open(\%filename)
- local contents = file:read("*a")
- file:close()
- return contents
+ =lua "files.read(\%filename)"
+
+compile [for file %f in %path %body] to
+ Lua ".."
+ for \(%f as lua expr) in files.walk(\(%path as lua expr)) do
+ \(%body as lua statements)
+ \(compile as: === next %f ===)
+ end
+ \(compile as: === stop %f ===)
action [write to file %filename %text, to file %filename write %text]
lua> ".."
diff --git a/lib/version.nom b/lib/version.nom
new file mode 100644
index 0000000..3b90888
--- /dev/null
+++ b/lib/version.nom
@@ -0,0 +1 @@
+lua> "NOMSU_LIB_VERSION = 2"
diff --git a/nomsu b/nomsu
index da566d1..af9993d 120000..100755
--- a/nomsu
+++ b/nomsu
@@ -1 +1,20 @@
-nomsu_runner \ No newline at end of file
+#!/bin/bash
+while getopts ':V:' flag; do
+ case "${flag}" in
+ V) VERSION="${OPTARG/./\.}\\b" ;;
+ esac
+done
+
+if [[ $VERSION ]]; then
+ candidates=$(ls $(dirname $BASH_SOURCE) | grep "^nomsu$VERSION[0-9.]*$")
+else
+ candidates=$(ls $(dirname $BASH_SOURCE) | grep "^nomsu[0-9.]\+$")
+fi
+
+if [[ $candidates ]]; then
+ eval $(dirname $BASH_SOURCE)/$(echo "$candidates" | sort -V | tail -n 1) $@
+else
+ echo "Failed to find a Nomsu version matching the regex: \"nomsu$VERSION\""
+ echo "The versions available are:"
+ ls $(dirname $BASH_SOURCE) | grep "^nomsu[0-9.]\+$" | sed 's/^/ * /'
+fi
diff --git a/nomsu.lua b/nomsu.lua
index 44ad759..cfa515a 100644
--- a/nomsu.lua
+++ b/nomsu.lua
@@ -1,3 +1,55 @@
+if NOMSU_VERSION and NOMSU_LIB and NOMSU_SHARE then
+ local ver_bits
+ do
+ local _accum_0 = { }
+ local _len_0 = 1
+ for ver_bit in NOMSU_VERSION:gmatch("[0-9]+") do
+ _accum_0[_len_0] = ver_bit
+ _len_0 = _len_0 + 1
+ end
+ ver_bits = _accum_0
+ end
+ local partial_vers
+ do
+ local _accum_0 = { }
+ local _len_0 = 1
+ for i = #ver_bits, 1, -1 do
+ _accum_0[_len_0] = table.concat(ver_bits, '.', 1, i)
+ _len_0 = _len_0 + 1
+ end
+ partial_vers = _accum_0
+ end
+ package.path = table.concat((function()
+ local _accum_0 = { }
+ local _len_0 = 1
+ for _index_0 = 1, #partial_vers do
+ local v = partial_vers[_index_0]
+ _accum_0[_len_0] = tostring(NOMSU_SHARE) .. "/" .. tostring(v) .. "/?.lua"
+ _len_0 = _len_0 + 1
+ end
+ return _accum_0
+ end)(), ";") .. ";" .. package.path
+ package.cpath = table.concat((function()
+ local _accum_0 = { }
+ local _len_0 = 1
+ for _index_0 = 1, #partial_vers do
+ local v = partial_vers[_index_0]
+ _accum_0[_len_0] = tostring(NOMSU_LIB) .. "/" .. tostring(v) .. "/?.so"
+ _len_0 = _len_0 + 1
+ end
+ return _accum_0
+ end)(), ";") .. ";" .. package.cpath
+ package.nomsupath = table.concat((function()
+ local _accum_0 = { }
+ local _len_0 = 1
+ for _index_0 = 1, #partial_vers do
+ local v = partial_vers[_index_0]
+ _accum_0[_len_0] = tostring(NOMSU_SHARE) .. "/" .. tostring(v)
+ _len_0 = _len_0 + 1
+ end
+ return _accum_0
+ end)(), ";")
+end
local EXIT_SUCCESS, EXIT_FAILURE = 0, 1
local usage = [=[Nomsu Compiler
@@ -61,6 +113,7 @@ if not args or args.help then
print(usage)
os.exit(EXIT_FAILURE)
end
+local files = require("files")
local nomsu = NomsuCompiler
nomsu.arg = args.nomsu_args
if args.version then
@@ -79,85 +132,6 @@ FILE_CACHE = setmetatable({ }, {
return contents
end
})
-local match, sub, rep, gsub, format, byte, find
-do
- local _obj_0 = string
- match, sub, rep, gsub, format, byte, match, find = _obj_0.match, _obj_0.sub, _obj_0.rep, _obj_0.gsub, _obj_0.format, _obj_0.byte, _obj_0.match, _obj_0.find
-end
-local iterate_single
-iterate_single = function(item, prev)
- if item == prev then
- return nil
- else
- return item
- end
-end
-local lfs
-ok, lfs = pcall(require, "lfs")
-if ok then
- all_files = function(path)
- local browse
- browse = function(filename)
- local file_type = lfs.attributes(filename, 'mode')
- if file_type == 'file' then
- if match(filename, "%.nom$") or match(filename, "%.lua$") then
- coroutine.yield(filename)
- return true
- end
- elseif file_type == 'directory' then
- for subfile in lfs.dir(filename) do
- if not (subfile == "." or subfile == "..") then
- browse(filename .. "/" .. subfile)
- end
- end
- return true
- elseif file_type == 'char device' then
- coroutine.yield(filename)
- return true
- end
- return false
- end
- return coroutine.wrap(function()
- if not browse(path) and package.nomsupath then
- browse(package.nomsupath .. "/" .. path)
- end
- return nil
- end)
- end
-else
- local ret = os.execute('find . -maxdepth 0')
- if not (ret == true or ret == 0) 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
- all_files = function(path)
- if match(path, "%.nom$") or match(path, "%.lua$") or match(path, "^/dev/fd/[012]$") then
- return iterate_single, path
- end
- path = gsub(path, "\\", "\\\\")
- path = gsub(path, "`", "")
- path = gsub(path, '"', '\\"')
- path = gsub(path, "$", "")
- return coroutine.wrap(function()
- local f = io.popen('find -L "' .. path .. '" -not -path "*/\\.*" -type f -name "*.nom"')
- local found = false
- for line in f:lines() do
- found = true
- coroutine.yield(line)
- end
- if not found and package.nomsupath then
- f:close()
- f = io.popen('find -L "' .. package.nomsupath .. '/' .. path .. '" -not -path "*/\\.*" -type f -name "*.nom"')
- for line in f:lines() do
- coroutine.yield(line)
- end
- end
- local success = f:close()
- if not (success) then
- return error("Invalid file path: " .. tostring(path))
- end
- end)
- end
-end
local run
run = function()
for i, input in ipairs(args.inputs) do
@@ -199,7 +173,7 @@ run = function()
local _list_0 = args.inputs
for _index_0 = 1, #_list_0 do
local input = _list_0[_index_0]
- for f in all_files(input) do
+ for f in files.walk(input) do
input_files[#input_files + 1] = f
to_run[f] = true
end
@@ -245,7 +219,7 @@ run = function()
print_file:flush()
end
elseif args.format then
- local file = FILE_CACHE[filename]
+ local file = files.read(filename)
if not file then
error("File does not exist: " .. tostring(filename), 0)
end
@@ -257,7 +231,7 @@ run = function()
end
elseif filename == STDIN then
local file = io.input():read("*a")
- FILE_CACHE.stdin = file
+ files.spoof('stdin', file)
nomsu:run(file, Source('stdin', 1, #file))
else
nomsu:run_file(filename)
@@ -305,7 +279,7 @@ run = function()
end
buff = table.concat(buff)
local pseudo_filename = "user input #" .. repl_line
- FILE_CACHE[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 14f8992..19e7b26 100755
--- a/nomsu.moon
+++ b/nomsu.moon
@@ -1,5 +1,12 @@
#!/usr/bin/env moon
-- This file contains the command-line Nomsu runner.
+if NOMSU_VERSION and NOMSU_LIB and NOMSU_SHARE
+ ver_bits = [ver_bit for ver_bit in NOMSU_VERSION\gmatch("[0-9]+")]
+ partial_vers = [table.concat(ver_bits,'.',1,i) for i=#ver_bits,1,-1]
+ package.path = table.concat(["#{NOMSU_SHARE}/#{v}/?.lua" for v in *partial_vers],";")..";"..package.path
+ package.cpath = table.concat(["#{NOMSU_LIB}/#{v}/?.so" for v in *partial_vers],";")..";"..package.cpath
+ package.nomsupath = table.concat(["#{NOMSU_SHARE}/#{v}" for v in *partial_vers],";")
+
EXIT_SUCCESS, EXIT_FAILURE = 0, 1
usage = [=[
Nomsu Compiler
@@ -58,11 +65,12 @@ if not args or args.help
print usage
os.exit(EXIT_FAILURE)
+files = require "files"
nomsu = NomsuCompiler
nomsu.arg = args.nomsu_args
if args.version
- nomsu\run 'use "core"\nsay (Nomsu version)'
+ nomsu\run 'use "core"\nsay (Nomsu version)'
os.exit(EXIT_SUCCESS)
export FILE_CACHE
@@ -77,61 +85,6 @@ FILE_CACHE = setmetatable {}, {
return contents
}
-export all_files
-{:match, :sub, :rep, :gsub, :format, :byte, :match, :find} = string
-iterate_single = (item, prev) -> if item == prev then nil else item
-ok, lfs = pcall(require, "lfs")
-if ok
- all_files = (path)->
- browse = (filename)->
- file_type = lfs.attributes(filename, 'mode')
- if file_type == 'file'
- if match(filename, "%.nom$") or match(filename, "%.lua$")
- coroutine.yield filename
- return true
- elseif file_type == 'directory'
- for subfile in lfs.dir(filename)
- unless subfile == "." or subfile == ".."
- browse(filename.."/"..subfile)
- return true
- elseif file_type == 'char device'
- coroutine.yield(filename)
- return true
- return false
- return coroutine.wrap ->
- if not browse(path) and package.nomsupath
- browse(package.nomsupath.."/"..path)
- return nil
-else
- ret = os.execute('find . -maxdepth 0')
- unless ret == true or ret == 0
- 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
-
- all_files = (path)->
- -- Sanitize path
- if match(path, "%.nom$") or match(path, "%.lua$") or match(path, "^/dev/fd/[012]$")
- return iterate_single, path
- -- TODO: improve sanitization
- path = gsub(path,"\\","\\\\")
- path = gsub(path,"`","")
- path = gsub(path,'"','\\"')
- path = gsub(path,"$","")
- return coroutine.wrap ->
- f = io.popen('find -L "'..path..'" -not -path "*/\\.*" -type f -name "*.nom"')
- found = false
- for line in f\lines!
- found = true
- coroutine.yield(line)
- if not found and package.nomsupath
- f\close!
- f = io.popen('find -L "'..package.nomsupath..'/'..path..'" -not -path "*/\\.*" -type f -name "*.nom"')
- for line in f\lines!
- coroutine.yield(line)
- success = f\close!
- unless success
- error("Invalid file path: "..tostring(path))
-
-
run = ->
for i,input in ipairs args.inputs
if input == "-" then args.inputs[i] = STDIN
@@ -159,7 +112,7 @@ run = ->
input_files = {}
to_run = {}
for input in *args.inputs
- for f in all_files(input)
+ for f in files.walk(input)
input_files[#input_files+1] = f
to_run[f] = true
@@ -194,7 +147,7 @@ run = ->
print_file\flush!
elseif args.format
-- Auto-format
- file = FILE_CACHE[filename]
+ file = files.read(filename)
if not file
error("File does not exist: #{filename}", 0)
tree = nomsu\parse(file, Source(filename,1,#file))
@@ -204,7 +157,7 @@ run = ->
print_file\flush!
elseif filename == STDIN
file = io.input!\read("*a")
- FILE_CACHE.stdin = file
+ files.spoof('stdin', file)
nomsu\run(file, Source('stdin',1,#file))
else
nomsu\run_file(filename)
@@ -248,7 +201,7 @@ run = ->
buff = table.concat(buff)
pseudo_filename = "user input #"..repl_line
- FILE_CACHE[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 c94685a..42cdb17 100644
--- a/nomsu_compiler.lua
+++ b/nomsu_compiler.lua
@@ -2,6 +2,7 @@ local lpeg = require('lpeg')
local re = require('re')
lpeg.setmaxstack(10000)
local utils = require('utils')
+local files = require('files')
local repr, stringify, equivalent
repr, stringify, equivalent = utils.repr, utils.stringify, utils.equivalent
colors = require('consolecolors')
@@ -60,45 +61,6 @@ table.fork = function(t, values)
__index = t
})
end
-FILE_CACHE = setmetatable({ }, {
- __index = function(self, filename)
- local file = io.open(filename)
- if not (file) then
- return nil
- end
- local contents = file:read("*a")
- file:close()
- self[filename] = contents
- return contents
- end
-})
-local iterate_single
-iterate_single = function(item, prev)
- if item == prev then
- return nil
- else
- return item
- end
-end
-all_files = function(path)
- if match(path, "%.nom$") or match(path, "%.lua$") or match(path, "^/dev/fd/[012]$") then
- return iterate_single, path
- end
- path = gsub(path, "\\", "\\\\")
- path = gsub(path, "`", "")
- path = gsub(path, '"', '\\"')
- path = gsub(path, "$", "")
- return coroutine.wrap(function()
- local f = io.popen('find -L "' .. path .. '" -not -path "*/\\.*" -type f -name "*.nom"')
- for line in f:lines() do
- coroutine.yield(line)
- end
- local success = f:close()
- if not (success) then
- return error("Invalid file path: " .. tostring(path))
- end
- end)
-end
local line_counter = re.compile([[ lines <- {| line (%nl line)* |}
line <- {} (!%nl .)*
]], {
@@ -229,7 +191,7 @@ local NomsuCompiler = setmetatable({ }, {
end
})
do
- NomsuCompiler.NOMSU_COMPILER_VERSION = 1
+ NomsuCompiler.NOMSU_COMPILER_VERSION = 2
NomsuCompiler.NOMSU_SYNTAX_VERSION = Parser.version
NomsuCompiler._ENV = NomsuCompiler
NomsuCompiler.nomsu = NomsuCompiler
@@ -245,7 +207,7 @@ do
utils = utils,
lpeg = lpeg,
re = re,
- all_files = all_files,
+ files = files,
next = next,
unpack = unpack,
setmetatable = setmetatable,
@@ -299,7 +261,7 @@ do
NomsuCompiler.LOADED = { }
NomsuCompiler.AST = AST
NomsuCompiler.compile_error = function(self, tok, err_format_string, ...)
- local file = FILE_CACHE[tok.source.filename]
+ local file = files.read(tok.source.filename)
local line_no = pos_to_line(file, tok.source.start)
local line_start = LINE_STARTS[file][line_no]
local src = colored.dim(file:sub(line_start, tok.source.start - 1))
@@ -422,8 +384,8 @@ do
source = nil
end
source = source or (to_run.source or Source(to_run, 1, #to_run))
- if not rawget(FILE_CACHE, source.filename) then
- FILE_CACHE[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
@@ -465,7 +427,7 @@ do
return self.LOADED[filename]
end
local ret = nil
- for filename in all_files(filename) do
+ for filename in files.walk(filename) do
local _continue_0 = false
repeat
do
@@ -493,14 +455,14 @@ do
end
insert(_running_files, filename)
if match(filename, "%.lua$") then
- local file = assert(FILE_CACHE[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 = FILE_CACHE[lua_filename]
+ local file = files.read(lua_filename)
if file then
ret = self:run_lua(file, Source(lua_filename, 1, #file))
ran_lua = true
@@ -508,7 +470,7 @@ do
end
end
if not (ran_lua) then
- local file = file or FILE_CACHE[filename]
+ local file = file or files.read(filename)
if not file then
error("File does not exist: " .. tostring(filename), 0)
end
@@ -551,7 +513,11 @@ do
local map = { }
local offset = 1
source = source or lua.source
- local nomsu_str = tostring(FILE_CACHE[source.filename]:sub(source.start, source.stop))
+ 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 = pos_to_line(nomsu_str, source.start)
local fn
@@ -684,7 +650,7 @@ do
local bit_lua = self:compile(bit)
if not (bit_lua.is_value) then
local src = ' ' .. gsub(tostring(self:tree_to_nomsu(bit)), '\n', '\n ')
- local line = tostring(bit.source.filename) .. ":" .. tostring(pos_to_line(FILE_CACHE[bit.source.filename], bit.source.start))
+ local line = tostring(bit.source.filename) .. ":" .. tostring(pos_to_line(files.read(bit.source.filename), bit.source.start))
self:compile_error(bit, "Cannot use:\n%s\nas a string interpolation value, since it's not an expression.")
end
if #lua.bits > 0 then
diff --git a/nomsu_compiler.moon b/nomsu_compiler.moon
index 56ef86e..e16af76 100644
--- a/nomsu_compiler.moon
+++ b/nomsu_compiler.moon
@@ -13,6 +13,7 @@ lpeg = require 'lpeg'
re = require 're'
lpeg.setmaxstack 10000
utils = require 'utils'
+files = require 'files'
{:repr, :stringify, :equivalent} = utils
export colors, colored
colors = require 'consolecolors'
@@ -49,37 +50,6 @@ table.fork = (t, values)-> setmetatable(values or {}, {__index:t})
-- Add a ((%x foo %y) where {x:"asdf", y:"fdsa"}) compile-time action for substitution
-- Re-implement nomsu-to-lua comment translation?
-export FILE_CACHE
--- FILE_CACHE is a map from filename (string) -> string of file contents
-FILE_CACHE = setmetatable {}, {
- __index: (filename)=>
- file = io.open(filename)
- return nil unless file
- contents = file\read("*a")
- file\close!
- self[filename] = contents
- return contents
-}
-
-export all_files
-iterate_single = (item, prev) -> if item == prev then nil else item
-all_files = (path)->
- -- Sanitize path
- if match(path, "%.nom$") or match(path, "%.lua$") or match(path, "^/dev/fd/[012]$")
- return iterate_single, path
- -- TODO: improve sanitization
- path = gsub(path,"\\","\\\\")
- path = gsub(path,"`","")
- path = gsub(path,'"','\\"')
- path = gsub(path,"$","")
- return coroutine.wrap ->
- f = io.popen('find -L "'..path..'" -not -path "*/\\.*" -type f -name "*.nom"')
- for line in f\lines!
- coroutine.yield(line)
- success = f\close!
- unless success
- error("Invalid file path: "..tostring(path))
-
line_counter = re.compile([[
lines <- {| line (%nl line)* |}
line <- {} (!%nl .)*
@@ -158,7 +128,7 @@ dict = (t)-> setmetatable(t, _dict_mt)
MAX_LINE = 80 -- For beautification purposes, try not to make lines much longer than this value
NomsuCompiler = setmetatable({}, {__index: (k)=> if _self = rawget(@, "self") then _self[k] else nil})
with NomsuCompiler
- .NOMSU_COMPILER_VERSION = 1
+ .NOMSU_COMPILER_VERSION = 2
.NOMSU_SYNTAX_VERSION = Parser.version
._ENV = NomsuCompiler
.nomsu = NomsuCompiler
@@ -167,7 +137,7 @@ with NomsuCompiler
-- Discretionary/convenience stuff
to_add = {
- repr:repr, stringify:stringify, utils:utils, lpeg:lpeg, re:re, all_files:all_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,
@@ -187,7 +157,7 @@ with NomsuCompiler
.AST = AST
.compile_error = (tok, err_format_string, ...)=>
- file = FILE_CACHE[tok.source.filename]
+ file = files.read(tok.source.filename)
line_no = pos_to_line(file, tok.source.start)
line_start = LINE_STARTS[file][line_no]
src = colored.dim(file\sub(line_start, tok.source.start-1))
@@ -289,7 +259,7 @@ with NomsuCompiler
.run = (to_run, source=nil)=>
source or= to_run.source or Source(to_run, 1, #to_run)
- if not rawget(FILE_CACHE,source.filename) then FILE_CACHE[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)
if tree == nil -- Happens if pattern matches, but there are no captures, e.g. an empty string
return nil
@@ -321,7 +291,7 @@ with NomsuCompiler
if @LOADED[filename]
return @LOADED[filename]
ret = nil
- for filename in all_files(filename)
+ for filename in files.walk(filename)
if ret = @LOADED[filename]
continue
@@ -334,16 +304,16 @@ with NomsuCompiler
insert _running_files, filename
if match(filename, "%.lua$")
- file = assert(FILE_CACHE[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 = FILE_CACHE[lua_filename]
+ if file = files.read(lua_filename)
ret = @run_lua file, Source(lua_filename, 1, #file)
true
unless ran_lua
- file = file or FILE_CACHE[filename]
+ file = file or files.read(filename)
if not file
error("File does not exist: #{filename}", 0)
ret = @run file, Source(filename,1,#file)
@@ -368,7 +338,10 @@ with NomsuCompiler
map = {}
offset = 1
source or= lua.source
- nomsu_str = tostring(FILE_CACHE[source.filename]\sub(source.start, source.stop))
+ 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 = pos_to_line(nomsu_str, source.start)
fn = (s)->
@@ -444,7 +417,7 @@ with NomsuCompiler
bit_lua = @compile(bit)
unless bit_lua.is_value
src = ' '..gsub(tostring(@tree_to_nomsu(bit)), '\n','\n ')
- line = "#{bit.source.filename}:#{pos_to_line(FILE_CACHE[bit.source.filename], bit.source.start)}"
+ line = "#{bit.source.filename}:#{pos_to_line(files.read(bit.source.filename), bit.source.start)}"
@compile_error bit,
"Cannot use:\n%s\nas a string interpolation value, since it's not an expression."
if #lua.bits > 0 then lua\append ".."
diff --git a/parser.lua b/parser.lua
index c04e95c..ad81252 100644
--- a/parser.lua
+++ b/parser.lua
@@ -132,7 +132,15 @@ do
Parser.version = tonumber(v)
end
})
- local peg_file = io.open("nomsu.peg") or (package.nomsupath and io.open(package.nomsupath .. "/nomsu.peg"))
+ local peg_file = io.open("nomsu.peg")
+ if not peg_file and package.nomsupath then
+ for path in package.nomsupath:gmatch("[^;]+") do
+ peg_file = io.open(path .. "/nomsu.peg")
+ if peg_file then
+ break
+ end
+ end
+ end
assert(peg_file, "could not find nomsu.peg file")
local nomsu_peg = peg_tidier:match(peg_file:read('*a'))
peg_file:close()
diff --git a/parser.moon b/parser.moon
index a61b3c1..6fe54e6 100644
--- a/parser.moon
+++ b/parser.moon
@@ -56,7 +56,7 @@ NOMSU_DEFS = with {}
return #src+1
err_pos = start_pos
line_no = pos_to_line(src, err_pos)
- --src = FILE_CACHE[userdata.source.filename]
+ --src = files.read(userdata.source.filename)
line_starts = LINE_STARTS[src]
prev_line = line_no == 1 and "" or src\sub(line_starts[line_no-1] or 1, line_starts[line_no]-2)
err_line = src\sub(line_starts[line_no], (line_starts[line_no+1] or 0)-2)
@@ -100,7 +100,11 @@ NOMSU_PATTERN = do
ident <- [a-zA-Z_][a-zA-Z0-9_]*
comment <- "--" [^%nl]*
]], {set_version: (v) -> Parser.version = tonumber(v)}
- peg_file = io.open("nomsu.peg") or (package.nomsupath and io.open(package.nomsupath.."/nomsu.peg"))
+ peg_file = io.open("nomsu.peg")
+ if not peg_file and package.nomsupath
+ for path in package.nomsupath\gmatch("[^;]+")
+ peg_file = io.open(path.."/nomsu.peg")
+ break if peg_file
assert(peg_file, "could not find nomsu.peg file")
nomsu_peg = peg_tidier\match(peg_file\read('*a'))
peg_file\close!
diff --git a/tests/metaprogramming.nom b/tests/metaprogramming.nom
index e7e22c5..0150350 100644
--- a/tests/metaprogramming.nom
+++ b/tests/metaprogramming.nom
@@ -1,4 +1,4 @@
-#..
+#
Tests for the stuff defined in core/metaprogramming.nom
use "core"
diff --git a/tests/os.nom b/tests/os.nom
index f96009f..c67279e 100644
--- a/tests/os.nom
+++ b/tests/os.nom
@@ -7,4 +7,7 @@ use "lib/os.nom"
%lines <-: lines in: read file "tests/os.nom"
assume: %lines.2 = " Tests for the stuff defined in lib/os.nom"
+for file %f in "core"
+ say "\%f"
+
say "OS test passed."