aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--Makefile41
-rw-r--r--README.md15
-rw-r--r--bootstrap.lua6
-rw-r--r--bootstrap.moon2
-rw-r--r--compatibility/compatibility.nom42
-rw-r--r--compatibility/init.nom19
-rw-r--r--consolecolors.lua41
-rw-r--r--error_handling.lua23
-rw-r--r--error_handling.moon15
-rw-r--r--examples/how_do_i.nom6
-rw-r--r--files.lua8
-rw-r--r--files.moon7
-rw-r--r--lib/base64/init.nom (renamed from lib/base64.nom)0
-rw-r--r--lib/commandline/init.nom11
-rw-r--r--lib/consolecolor/init.nom (renamed from lib/consolecolor.nom)0
-rw-r--r--lib/core/collections.nom (renamed from core/collections.nom)0
-rw-r--r--lib/core/control_flow.nom (renamed from core/control_flow.nom)0
-rw-r--r--lib/core/coroutines.nom (renamed from core/coroutines.nom)0
-rw-r--r--lib/core/errors.nom (renamed from core/errors.nom)1
-rw-r--r--lib/core/id.nom (renamed from core/id.nom)0
-rw-r--r--lib/core/init.nom (renamed from core/init.nom)0
-rw-r--r--lib/core/io.nom (renamed from core/io.nom)0
-rw-r--r--lib/core/math.nom (renamed from core/math.nom)0
-rw-r--r--lib/core/metaprogramming.nom (renamed from core/metaprogramming.nom)9
-rw-r--r--lib/core/operators.nom (renamed from core/operators.nom)0
-rw-r--r--lib/core/text.nom (renamed from core/text.nom)0
-rw-r--r--lib/file_hash/init.nom (renamed from lib/file_hash.nom)4
-rw-r--r--lib/filesystem/init.nom (renamed from lib/os.nom)15
-rw-r--r--lib/progressbar/init.nom16
-rw-r--r--lib/shell/init.nom12
-rw-r--r--lib/things.nom2
-rwxr-xr-xlib/tools/find.nom95
-rwxr-xr-xlib/tools/format.nom45
-rwxr-xr-xlib/tools/parse.nom (renamed from tools/parse.nom)18
-rwxr-xr-xlib/tools/repl.nom86
-rwxr-xr-xlib/tools/replace.nom147
-rwxr-xr-xlib/tools/test.nom65
-rwxr-xr-xlib/tools/upgrade.nom43
-rw-r--r--nomsu.lua87
-rwxr-xr-xnomsu.moon69
-rw-r--r--nomsu_compiler.lua2
-rw-r--r--nomsu_compiler.moon2
-rw-r--r--nomsu_environment.lua68
-rw-r--r--nomsu_environment.moon47
-rw-r--r--string2.lua6
-rw-r--r--string2.moon3
-rwxr-xr-xtools/find.nom93
-rwxr-xr-xtools/format.nom43
-rwxr-xr-xtools/repl.nom84
-rwxr-xr-xtools/replace.nom145
-rwxr-xr-xtools/test.nom44
-rwxr-xr-xtools/upgrade.nom41
53 files changed, 829 insertions, 702 deletions
diff --git a/.gitignore b/.gitignore
index ab1178f..458db87 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,3 @@
-core/*.lua
lib/*.lua
-tests/*.lua
+lib/*/*.lua
.pending-post-commit
diff --git a/Makefile b/Makefile
index 6f4befe..2497dde 100644
--- a/Makefile
+++ b/Makefile
@@ -14,12 +14,11 @@ UNINSTALL_VERSION=
MOON_FILES= code_obj.moon error_handling.moon files.moon nomsu.moon nomsu_compiler.moon \
syntax_tree.moon containers.moon bitops.moon parser.moon pretty_errors.moon \
string2.moon nomsu_decompiler.moon nomsu_environment.moon bootstrap.moon
-LUA_FILES= code_obj.lua consolecolors.lua error_handling.lua files.lua nomsu.lua nomsu_compiler.lua \
+LUA_FILES= code_obj.lua error_handling.lua files.lua nomsu.lua nomsu_compiler.lua \
syntax_tree.lua containers.lua bitops.lua parser.lua pretty_errors.lua \
string2.lua nomsu_decompiler.lua nomsu_environment.lua bootstrap.lua
-CORE_NOM_FILES= $(wildcard core/**.nom)
-CORE_LUA_FILES= $(patsubst %.nom,%.lua,$(CORE_NOM_FILES))
-LIB_NOM_FILES= $(wildcard lib/**.nom)
+CORE_NOM_FILES=$(shell cat lib/core/init.nom | sed -n 's;export "\(.*\)";lib/\1.nom;p') lib/core/init.nom
+LIB_NOM_FILES= $(CORE_NOM_FILES) $(wildcard lib/*.nom) $(filter-out $(CORE_NOM_FILES),$(wildcard lib/*/*.nom))
LIB_LUA_FILES= $(patsubst %.nom,%.lua,$(LIB_NOM_FILES))
PEG_FILES= $(wildcard nomsu.*.peg)
GET_VERSION= $(LUA_BIN) nomsu.lua --version
@@ -29,9 +28,9 @@ all: lua optimize
.PHONY: test
test: lua optimize
@echo "\033[1;4mRunning unoptimized tests...\033[0m"
- @$(LUA_BIN) nomsu.lua -O0 tools/test.nom $(CORE_NOM_FILES) $(LIB_NOM_FILES)
+ @$(LUA_BIN) nomsu.lua -O0 -t test $(LIB_NOM_FILES)
@echo "\n\033[1;4mRunning optimized tests...\033[0m"
- @$(LUA_BIN) nomsu.lua -O1 tools/test.nom $(CORE_LUA_FILES) $(LIB_LUA_FILES)
+ @$(LUA_BIN) nomsu.lua -O1 -t test $(LIB_LUA_FILES)
%.lua: %.moon
@moonc $<
@@ -40,18 +39,18 @@ test: lua optimize
@$(LUA_BIN) nomsu.lua -c $<
.DELETE_ON_ERROR: version
-version: $(LUA_FILES) $(CORE_NOM_FILES) $(LIB_NOM_FILES)
+version: $(LUA_FILES) $(LIB_NOM_FILES)
@$(LUA_BIN) nomsu.lua --version > version || exit
lua: $(LUA_FILES)
.PHONY: optimize
-optimize: lua $(CORE_LUA_FILES) $(LIB_LUA_FILES)
+optimize: lua $(LIB_LUA_FILES)
.PHONY: clean
clean:
@echo "\033[1mDeleting...\033[0m"
- @rm -rvf version core/**.lua lib/**.lua tools/**.lua compatibility/**.lua
+ @rm -rvf version lib/*.lua lib/*/*.lua compatibility/*.lua
.PHONY: install
install: lua version optimize
@@ -74,12 +73,12 @@ install: lua version optimize
fi; \
version="`cat version`"; \
mkdir -pv $$prefix/bin $$prefix/lib/nomsu/$$version $$prefix/share/nomsu/$$version $$prefix/share/man/man1 $$packagepath/nomsu \
- && echo "#!$(LUA_BIN)\\nlocal NOMSU_VERSION, NOMSU_PREFIX, NOMSU_PACKAGEPATH = [[$$version]], [[$$prefix]], [[$$packagepath]]" \
+ && echo "#!$(LUA_BIN)\\nlocal NOMSU_VERSION, NOMSU_PREFIX, NOMSU_PACKAGEPATH = [[$$version]], [[$$prefix]], [[$$packagepath/nomsu]]" \
| cat - nomsu.lua > $$prefix/bin/nomsu$$version \
&& chmod +x $$prefix/bin/nomsu$$version \
&& cp -v nomsu $$prefix/bin \
&& cp -v doc/nomsu.1 $$prefix/share/man/man1 \
- && cp -rv $(LUA_FILES) $(PEG_FILES) core lib compatibility tools $$prefix/share/nomsu/$$version;
+ && cp -rv $(LUA_FILES) $(PEG_FILES) lib compatibility $$prefix/share/nomsu/$$version;
.PHONY: uninstall
uninstall: version
@@ -88,17 +87,10 @@ uninstall: version
read -p $$'\033[1mWhere do you want to uninstall Nomsu from? (default: /usr/local) \033[0m' prefix; \
fi; \
if [[ ! $$prefix ]]; then prefix="/usr/local"; fi; \
- packagepath="$(PACKAGEPATH)"; \
- if [[ ! $$packagepath ]]; then \
- read -p $$'\033[1mWhere have your Nomsu packages been installed? (default: /opt) \033[0m' packagepath; \
- fi; \
- if [[ ! $$packagepath ]]; then packagepath="/opt"; fi; \
echo "\033[1mNomsu will be uninstalled from:\033[0m"; \
echo " $$prefix/bin"; \
echo " $$prefix/lib"; \
echo " $$prefix/share"; \
- echo "\033[1mNomsu packages will be uninstalled from:\033[0m"; \
- echo " $$packagepath/nomsu"; \
read -p $$'\033[1mis this okay? [Y/n]\033[0m ' ans; \
if [[ $$ans =~ ^[Nn] ]]; then exit; fi; \
echo "\033[1mDeleting...\033[0m"; \
@@ -118,12 +110,17 @@ uninstall: version
fi; \
if [ "`ls $$prefix/lib/nomsu 2>/dev/null`" == "" ]; then rm -rvf $$prefix/lib/nomsu; fi;\
if [ "`ls $$prefix/share/nomsu 2>/dev/null`" == "" ]; then rm -rvf $$prefix/share/nomsu; fi;\
+ echo $$'\033[1mDone.\033[0m';
+
+uninstallpackages:
+ @packagepath="$(PACKAGEPATH)"; \
+ if [[ ! $$packagepath ]]; then \
+ read -p $$'\033[1mWhere have your Nomsu packages been installed? (default: /opt) \033[0m' packagepath; \
+ fi; \
+ if [[ ! $$packagepath ]]; then packagepath="/opt"; fi; \
if [ -d $$packagepath/nomsu ]; then \
read -p $$'\033[1mDo you want to delete all installed libraries from /opt? [y/n] \033[0m' confirm; \
if [[ $$confirm == "y" ]]; then \
rm -rvf $$packagepath/nomsu; \
fi; \
- fi; \
- echo $$'\033[1mDone.\033[0m';
-
-# eof
+ fi;
diff --git a/README.md b/README.md
index a8873f0..695fbde 100644
--- a/README.md
+++ b/README.md
@@ -62,8 +62,7 @@ All `.moon` files have been precompiled into corresponding `.lua` files, so you
* [string2.moon](string2.moon) - A library defining some extra functionality for strings.
* [syntax\_tree.moon](syntax_tree.moon) - Datastructures used for Nomsu Abstract Syntax Trees.
* [examples/how\_do\_i.nom](examples/how_do_i.nom) - A simple walkthrough of some of the features of Nomsu, written in Nomsu code. **This is a good place to start.**
-* [core/\*.nom](core) - Core language definitions of stuff like control flow, operators, and metaprogramming, broken down into different files.
-* [lib/\*.nom](lib) - Optional language libraries for stuff you might want, like interfacing with the OS, or doing Object Oriented Programming.
+* [lib/\*/\*.nom](lib) - Language libraries, including the core language stuff like control flow, operators, and metaprogramming (in [lib/core](lib/core)) and optional language libraries for stuff you might want.
* [compatibility/\*.nom](compatibility) - Code for automatically upgrading Nomsu code from old versions to the current version.
* [tools/\*.nom](tools) - A set of utilities useful for doing code manipulation actions.
* [Makefile](Makefile) - Rules for building/installing the compiler.
@@ -72,14 +71,14 @@ All `.moon` files have been precompiled into corresponding `.lua` files, so you
## Versioning
-Nomsu uses the following versioning scheme: `[syntax version].[core library API version].[compiler internal API version].[lib/ API version]`. Which means:
+Nomsu uses the following versioning scheme: `[syntax version].[core library API version].[compiler internal API version].[minor version]`. Which means:
-* Any code that parses on `Nomsu X.a.b.c.d` will also parse on Nomsu `X.p.w.r.s`
-* Any code that compiles on Nomsu `X.Y.a.b.c` will also compile on Nomsu `X.Y.p.q.r` and run without any differences, as long as it only depends on the behavior of the core library functions (i.e. stuff defined in [core/\*.nom](core)), and doesn't mess with the compiler internals at all.
-* Any code that compiles on Nomsu `X.Y.Z.a.b` will also compile on Nomsu `X.Y.Z.p.q` and run without any differences, even if it messes with the compiler internals, as long as it doesn't use anything from [lib/\*.nom](lib).
-* Any code that compiles on Nomsu `X.Y.Z.W` will also compile on any other Nomsu `X.Y.Z.W` and run without any differences, even if it uses stuff from [lib/\*.nom](lib).
+* Any code that parses on `Nomsu X.a.b.c` will also parse on Nomsu `X.p.w.r`
+* Any code that compiles on Nomsu `X.Y.a.b` will also compile on Nomsu `X.Y.p.q` and run without any differences, as long as it only depends on the behavior of the core library functions (i.e. stuff defined in [lib/core/\*.nom](lib/core)), and doesn't mess with the compiler internals at all.
+* Any code that compiles on Nomsu `X.Y.Z.a` will also compile on Nomsu `X.Y.Z.p` and run without any differences, unless if it messes with the compiler internals.
+* Any code that compiles on Nomsu `X.Y.Z.W` will also compile on any other Nomsu `X.Y.Z.W` and run without any differences.
-When Nomsu is istalled via `make install`, all of Nomsu's lua files and [core/\*.nom](core) and [lib/\*.nom](lib) files are stored in `$PREFIX/lib/nomsu/$NOMSU_VERSION` and the Nomsu executable is installed to `$PREFIX/bin/nomsu$NOMSU_VERSION`, along with the file `nomsu` (the version-selection script), which goes to `$PREFIX/bin/nomsu`. When `make uninstall` is run, all those files are deleted (except for `nomsu`, if there are other versions installed).
+When Nomsu is istalled via `make install`, all of Nomsu's lua files and [lib/](lib) files are stored in `$PREFIX/share/nomsu/$NOMSU_VERSION` and the Nomsu executable is installed to `$PREFIX/bin/nomsu$NOMSU_VERSION`, along with the file `nomsu` (the version-selection script), which goes to `$PREFIX/bin/nomsu`. When `make uninstall` is run, all those files are deleted (except for `nomsu`, if there are other versions installed).
To run different versions, use the `-V` flag, which will select the latest version matching the specified pattern. For example, if you have v1.0.0.0, v1.0.2.1, and 1.1.0.0 installed, then `nomsu` will run v1.1.0.0, `nomsu -V 1.0` will run v1.0.2.1, and `nomsu -V 1.0.0.0` will run v1.0.0.0.
diff --git a/bootstrap.lua b/bootstrap.lua
index 10d6f3b..c257965 100644
--- a/bootstrap.lua
+++ b/bootstrap.lua
@@ -157,6 +157,12 @@ local compile_actions = {
end,
["nomsu environment name"] = function(self)
return LuaCode('"_ENV"')
+ end,
+ ["this file was run directly"] = function(self)
+ return LuaCode('WAS_RUN_DIRECTLY')
+ end,
+ ["the command line arguments"] = function(self)
+ return LuaCode('COMMAND_LINE_ARGS')
end
}
return compile_actions
diff --git a/bootstrap.moon b/bootstrap.moon
index f5b5900..05bd2a6 100644
--- a/bootstrap.moon
+++ b/bootstrap.moon
@@ -118,6 +118,8 @@ compile_actions = {
["Lua version"]: (code)=> LuaCode("_VERSION")
["nomsu environment"]: ()=> LuaCode("_ENV")
["nomsu environment name"]: ()=> LuaCode('"_ENV"')
+ ["this file was run directly"]: => LuaCode('WAS_RUN_DIRECTLY')
+ ["the command line arguments"]: => LuaCode('COMMAND_LINE_ARGS')
}
return compile_actions
diff --git a/compatibility/compatibility.nom b/compatibility/compatibility.nom
index e0449c8..444be11 100644
--- a/compatibility/compatibility.nom
+++ b/compatibility/compatibility.nom
@@ -3,7 +3,7 @@
This file contains code for defining ways to upgrade code between different versions
of Nomsu.
-use "lib/os"
+use "filesystem"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -68,18 +68,33 @@ externally [
$tree upgraded to $end_version from $start_version
] all mean:
unless ($tree is syntax tree): return $tree
+
($ver as list) means (($ as number) for $ in $ver matching "[0-9]+")
+
+ (Ver $) means:
+ [$lib, $ver] = ($, match "(.*)/([0-9.]+)")
+ if $lib:
+ return {.lib = $lib, .version = ($ver as list)}
+ return {.version = ($ as list)}
+
+ $start = (Ver $start_version)
+ $end = (Ver $end_version)
+ assume $start.lib == $end.lib
+
+ $seen = {}
$versions = {}
- for $v = $ in $UPGRADES:
- $versions.$v = (yes)
-
- for $v = $ in $ACTION_UPGRADES:
- $versions.$v = (yes)
+ for $v = $ in $UPGRADES: $versions.$v = (yes)
+ for $v = $ in $ACTION_UPGRADES: $versions.$v = (yes)
+ $versions = [
+ :for $v = $ in $versions:
+ if ((Ver $v).lib == $start.lib):
+ add $v
+ ]
- $versions = ((keys in $versions) sorted by $ -> ($ as list))
+ sort $versions by $ -> ($ as list)
for $ver in $versions:
- if (($ver as list) <= ($start_version as list)): do next $ver
- if (($ver as list) > ($end_version as list)): stop $ver
+ if (($ver as list) <= $start.version): do next $ver
+ if (($ver as list) > $end.version): stop $ver
if $ACTION_UPGRADES.$ver:
$tree =
$tree with $ ->:
@@ -115,12 +130,3 @@ externally ($tree upgraded to $end_version) means
externally ($tree upgraded) means
$tree upgraded from ($tree.version or (Nomsu version)) to (Nomsu version)
-
-externally (use $path from version $version) means:
- for $filename in (files for $path):
- if (=lua "LOADED[\$filename]"):
- do next $filename
- $file = (read file $filename)
- $tree = (parse $file from $filename)
- $tree = (upgrade $tree from $version)
- run tree $tree
diff --git a/compatibility/init.nom b/compatibility/init.nom
new file mode 100644
index 0000000..056428f
--- /dev/null
+++ b/compatibility/init.nom
@@ -0,0 +1,19 @@
+
+export "compatibility/compatibility"
+export "compatibility/2"
+export "compatibility/2.3"
+export "compatibility/2.4"
+export "compatibility/2.5"
+export "compatibility/2.5.5.5"
+export "compatibility/3"
+export "compatibility/3.5.5.6"
+export "compatibility/3.6"
+export "compatibility/3.7"
+export "compatibility/3.8"
+export "compatibility/4.8.10"
+export "compatibility/4.9"
+export "compatibility/4.10.12.7"
+export "compatibility/4.11"
+export "compatibility/4.12"
+export "compatibility/5.13"
+export "compatibility/6.14"
diff --git a/consolecolors.lua b/consolecolors.lua
deleted file mode 100644
index 650bc81..0000000
--- a/consolecolors.lua
+++ /dev/null
@@ -1,41 +0,0 @@
---
--- This file contains the ANSI escapes for console colors
---
-
-local colors = {
- -- attributes
- reset = 0,
- clear = 0,
- bright = 1,
- dim = 2,
- underscore = 4,
- blink = 5,
- reverse = 7,
- hidden = 8,
-
- -- foreground
- black = 30,
- red = 31,
- green = 32,
- yellow = 33,
- blue = 34,
- magenta = 35,
- cyan = 36,
- white = 37,
-
- -- background
- onblack = 40,
- onred = 41,
- ongreen = 42,
- onyellow = 43,
- onblue = 44,
- onmagenta = 45,
- oncyan = 46,
- onwhite = 47,
-}
-
-local _M = {}
-for c, v in pairs(colors) do
- _M[c] = string.char(27)..("[%dm"):format(v)
-end
-return _M
diff --git a/error_handling.lua b/error_handling.lua
index 76b4390..27022aa 100644
--- a/error_handling.lua
+++ b/error_handling.lua
@@ -1,5 +1,5 @@
-local files = require("files")
local debug_getinfo = debug.getinfo
+local Files = require("files")
local RED = "\027[31m"
local BRIGHT_RED = "\027[31;1m"
local RESET = "\027[0m"
@@ -119,7 +119,6 @@ print_error = function(error_message, start_fn, stop_fn)
filename, start = calling_fn.source:match('@([^[]*)%[([0-9]+)]')
end
assert(filename)
- local file = files.read(filename)
if calling_fn.name then
do
local tmp = calling_fn.name:match("^A_([a-zA-Z0-9_]*)$")
@@ -134,8 +133,10 @@ print_error = function(error_message, start_fn, stop_fn)
else
name = "main chunk"
end
+ local file = Files.read(filename)
+ local lines = file and file:lines() or { }
do
- local err_line = files.get_line(file, calling_fn.currentline)
+ local err_line = lines[calling_fn.currentline]
if err_line then
local offending_statement = tostring(BRIGHT_RED) .. tostring(err_line:match("^[ ]*(.*)")) .. tostring(RESET)
line = tostring(YELLOW) .. tostring(filename) .. ":" .. tostring(calling_fn.currentline) .. " in " .. tostring(name) .. "\n " .. tostring(offending_statement) .. tostring(RESET)
@@ -144,13 +145,6 @@ print_error = function(error_message, start_fn, stop_fn)
end
end
else
- local file
- ok, file = pcall(function()
- return files.read(calling_fn.short_src)
- end)
- if not ok then
- file = nil
- end
local line_num
if name == nil then
local search_level = level
@@ -189,6 +183,13 @@ print_error = function(error_message, start_fn, stop_fn)
end
end
end
+ local file, lines
+ do
+ file = Files.read(calling_fn.short_src)
+ if file then
+ lines = file:lines()
+ end
+ end
if file and (calling_fn.short_src:match("%.moon$") or file:match("^#![^\n]*moon\n")) and type(MOON_SOURCE_MAP[file]) == 'table' then
local char = MOON_SOURCE_MAP[file][calling_fn.currentline]
line_num = 1
@@ -206,7 +207,7 @@ print_error = function(error_message, start_fn, stop_fn)
end
if file then
do
- local err_line = files.get_line(file, line_num)
+ local err_line = lines[line_num]
if err_line then
local offending_statement = tostring(BRIGHT_RED) .. tostring(err_line:match("^[ ]*(.*)$")) .. tostring(RESET)
line = line .. ("\n " .. offending_statement)
diff --git a/error_handling.moon b/error_handling.moon
index 46580d6..c22a3ae 100644
--- a/error_handling.moon
+++ b/error_handling.moon
@@ -1,6 +1,6 @@
-- This file contains the logic for making nicer error messages
-files = require "files"
debug_getinfo = debug.getinfo
+Files = require "files"
export SOURCE_MAP
RED = "\027[31m"
@@ -78,7 +78,6 @@ print_error = (error_message, start_fn, stop_fn)->
if not filename
filename,start = calling_fn.source\match('@([^[]*)%[([0-9]+)]')
assert(filename)
- file = files.read(filename)
-- TODO: get name properly
name = if calling_fn.name
if tmp = calling_fn.name\match("^A_([a-zA-Z0-9_]*)$")
@@ -86,14 +85,14 @@ print_error = (error_message, start_fn, stop_fn)->
else "action '#{calling_fn.name}'"
else "main chunk"
- if err_line = files.get_line(file, calling_fn.currentline)
+ file = Files.read(filename)
+ lines = file and file\lines! or {}
+ if err_line = lines[calling_fn.currentline]
offending_statement = "#{BRIGHT_RED}#{err_line\match("^[ ]*(.*)")}#{RESET}"
line = "#{YELLOW}#{filename}:#{calling_fn.currentline} in #{name}\n #{offending_statement}#{RESET}"
else
line = "#{YELLOW}#{filename}:#{calling_fn.currentline} in #{name}#{RESET}"
else
- ok, file = pcall ->files.read(calling_fn.short_src)
- if not ok then file = nil
local line_num
if name == nil
search_level = level
@@ -117,6 +116,10 @@ print_error = (error_message, start_fn, stop_fn)->
name = "upvalue '#{varname}'"
if not varname\match("%(")
break
+
+ local file, lines
+ if file = Files.read(calling_fn.short_src)
+ lines = file\lines!
if file and (calling_fn.short_src\match("%.moon$") or file\match("^#![^\n]*moon\n")) and type(MOON_SOURCE_MAP[file]) == 'table'
char = MOON_SOURCE_MAP[file][calling_fn.currentline]
@@ -131,7 +134,7 @@ print_error = (error_message, start_fn, stop_fn)->
line = "#{BLUE}#{calling_fn.short_src}:#{calling_fn.currentline} in #{name or '?'}#{RESET}"
if file
- if err_line = files.get_line(file, line_num)
+ if err_line = lines[line_num]
offending_statement = "#{BRIGHT_RED}#{err_line\match("^[ ]*(.*)$")}#{RESET}"
line ..= "\n "..offending_statement
io.stderr\write(line,"\n")
diff --git a/examples/how_do_i.nom b/examples/how_do_i.nom
index 14e7481..906ef74 100644
--- a/examples/how_do_i.nom
+++ b/examples/how_do_i.nom
@@ -6,11 +6,9 @@
is considered part of the comment
(including any deeper-level indented text)
The comment ends when the indentation ends
-# How do I import a file?
-use "lib/os"
-# How do I import all the files in a directory?
-use "lib"
+# How do I import a libarary?
+use "consolecolor"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/files.lua b/files.lua
index 036471f..0c8558d 100644
--- a/files.lua
+++ b/files.lua
@@ -213,12 +213,4 @@ Files.get_line = function(str, line_no)
end
return (str:sub(start, stop - 2))
end
-local get_lines = re.compile([[ lines <- {| line (%nl line)* |}
- line <- {[^%nl]*}
-]], {
- nl = lpeg.P("\r") ^ -1 * lpeg.P("\n")
-})
-Files.get_lines = function(str)
- return get_lines:match(str)
-end
return Files
diff --git a/files.moon b/files.moon
index 3950ce3..a9fbb5c 100644
--- a/files.moon
+++ b/files.moon
@@ -134,11 +134,4 @@ Files.get_line = (str, line_no)->
return unless stop
return (str\sub(start, stop - 2))
-get_lines = re.compile([[
- lines <- {| line (%nl line)* |}
- line <- {[^%nl]*}
-]], nl:lpeg.P("\r")^-1 * lpeg.P("\n"))
-
-Files.get_lines = (str)-> get_lines\match(str)
-
return Files
diff --git a/lib/base64.nom b/lib/base64/init.nom
index 54f785f..54f785f 100644
--- a/lib/base64.nom
+++ b/lib/base64/init.nom
diff --git a/lib/commandline/init.nom b/lib/commandline/init.nom
new file mode 100644
index 0000000..f28e02b
--- /dev/null
+++ b/lib/commandline/init.nom
@@ -0,0 +1,11 @@
+#
+ A library defining some command line program functionality
+
+(command line program with $args $body) parses as:
+ externally (run with $args) means $body
+ if (this file was run directly):
+ run with (the command line arguments)
+
+externally (usage $) means:
+ say "Usage: \$"
+ exit 1
diff --git a/lib/consolecolor.nom b/lib/consolecolor/init.nom
index d1da247..d1da247 100644
--- a/lib/consolecolor.nom
+++ b/lib/consolecolor/init.nom
diff --git a/core/collections.nom b/lib/core/collections.nom
index 4cf54cd..4cf54cd 100644
--- a/core/collections.nom
+++ b/lib/core/collections.nom
diff --git a/core/control_flow.nom b/lib/core/control_flow.nom
index b0c4f27..b0c4f27 100644
--- a/core/control_flow.nom
+++ b/lib/core/control_flow.nom
diff --git a/core/coroutines.nom b/lib/core/coroutines.nom
index 6a99f7e..6a99f7e 100644
--- a/core/coroutines.nom
+++ b/lib/core/coroutines.nom
diff --git a/core/errors.nom b/lib/core/errors.nom
index 45fc8c5..c878bb7 100644
--- a/core/errors.nom
+++ b/lib/core/errors.nom
@@ -4,6 +4,7 @@
use "core/metaprogramming"
use "core/operators"
+use "core/control_flow"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/core/id.nom b/lib/core/id.nom
index d2427b5..d2427b5 100644
--- a/core/id.nom
+++ b/lib/core/id.nom
diff --git a/core/init.nom b/lib/core/init.nom
index 0c8051d..0c8051d 100644
--- a/core/init.nom
+++ b/lib/core/init.nom
diff --git a/core/io.nom b/lib/core/io.nom
index 7afe889..7afe889 100644
--- a/core/io.nom
+++ b/lib/core/io.nom
diff --git a/core/math.nom b/lib/core/math.nom
index 685ab1e..685ab1e 100644
--- a/core/math.nom
+++ b/lib/core/math.nom
diff --git a/core/metaprogramming.nom b/lib/core/metaprogramming.nom
index fa29a8a..936f9bd 100644
--- a/core/metaprogramming.nom
+++ b/lib/core/metaprogramming.nom
@@ -85,7 +85,7 @@ test:
fail "compile to is leaking variables"
lua> ("
- COMPILE_RULES["1 compiles to"] = function(env, \$action, \$body)
+ COMPILE_RULES["1 compiles to"] = function(\(nomsu environment), \$action, \$body)
local \$args = List{"\(nomsu environment)", unpack(\$action:get_args())}
if \$body.type == "Text" then
\$body = SyntaxTree{source=\$body.source, type="Action", "Lua", \$body}
@@ -274,7 +274,7 @@ test:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[$action parses as $body] all parse as ([$action] all parse as $body)
-externally ($tree as lua expr) means:
+externally (in (nomsu environment) $tree as lua expr) means:
lua> ("
local tree_lua = \(nomsu environment):compile(\$tree)
if \$tree.type == 'Block' then
@@ -287,6 +287,11 @@ externally ($tree as lua expr) means:
return tree_lua
")
+# Need to make sure the proper environment is used for compilation (i.e. the caller's environment)
+($tree as lua expr) compiles to (\(in \(nomsu environment) $tree as lua expr) as lua)
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
externally [$var as lua identifier, $var as lua id] all mean:
lua> ("
local lua = \($var as lua)
diff --git a/core/operators.nom b/lib/core/operators.nom
index dee76b6..dee76b6 100644
--- a/core/operators.nom
+++ b/lib/core/operators.nom
diff --git a/core/text.nom b/lib/core/text.nom
index 1351af6..1351af6 100644
--- a/core/text.nom
+++ b/lib/core/text.nom
diff --git a/lib/file_hash.nom b/lib/file_hash/init.nom
index 70446ca..7b428cd 100644
--- a/lib/file_hash.nom
+++ b/lib/file_hash/init.nom
@@ -2,8 +2,8 @@
#
This file defines some actions for hashing files and looking up files by hash.
-use "lib/os"
-use "lib/base64"
+use "filesystem"
+use "base64"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/lib/os.nom b/lib/filesystem/init.nom
index 87b3426..a228bdc 100644
--- a/lib/os.nom
+++ b/lib/filesystem/init.nom
@@ -1,6 +1,6 @@
#!/usr/bin/env nomsu -V6.14
#
- This file defines some actions that interact with the operating system and filesystem.
+ This file defines some actions that interact with the filesystem.
externally (files for $path) means:
$files = (=lua "Files.list(\$path)")
@@ -8,19 +8,6 @@ externally (files for $path) means:
$files = (List $files)
return $files
-externally (=sh $cmd) means:
- lua> ("
- local result = io.popen(\$cmd)
- local contents = result:read("*a")
- result:close()
- return contents
- ")
-
-external $(sh> $) = $os.execute
-
-test:
- read file "lib/os.nom"
-
external $(read file $filename) = $Files.read
externally [
write to file $filename $text, to file $filename write $text
diff --git a/lib/progressbar/init.nom b/lib/progressbar/init.nom
new file mode 100644
index 0000000..a7ff5aa
--- /dev/null
+++ b/lib/progressbar/init.nom
@@ -0,0 +1,16 @@
+# A progress bar
+
+externally ($x / $w progress bar) means:
+ $x = ($x clamped between 0 and $w)
+ $bits = [" ", "▏", "▎", "▍", "▌", "▋", "▊", "▉", "█"]
+ $middle =
+ "" if ($x == $w) else
+ $bits.(1 + (floor ((#$bits) * ($x mod 1))))
+
+ return ("
+ \027[32;40m\($bits, last, rep (floor $x))\$middle\
+ ..\(" ", rep ($w - ((floor $x) + 1)))\027[0m
+ ")
+
+externally ($w wide $ progress bar) means
+ ($ * $w) / $w progress bar
diff --git a/lib/shell/init.nom b/lib/shell/init.nom
new file mode 100644
index 0000000..6a8970e
--- /dev/null
+++ b/lib/shell/init.nom
@@ -0,0 +1,12 @@
+#
+ This file defines some actions for running shell commands.
+
+externally (=sh $cmd) means:
+ lua> ("
+ local result = io.popen(\$cmd)
+ local contents = result:read("*a")
+ result:close()
+ return contents
+ ")
+
+external $(sh> $) = $os.execute
diff --git a/lib/things.nom b/lib/things.nom
index 84682b3..95f175d 100644
--- a/lib/things.nom
+++ b/lib/things.nom
@@ -36,7 +36,7 @@ test:
assume (($d, bark) == "Bark!")
a (Corgi) is a thing:
- $it [set up, gets pissed off] like a (Dog)
+ $it can [set up, gets pissed off] like a (Dog)
($it, as text) means "Dogloaf \{: for $k = $v in $it: add $k = $v}"
($its, sploot) means "sploooot"
[($its, bark), ($its, woof)] all mean:
diff --git a/lib/tools/find.nom b/lib/tools/find.nom
new file mode 100755
index 0000000..aa4bc7b
--- /dev/null
+++ b/lib/tools/find.nom
@@ -0,0 +1,95 @@
+#!/usr/bin/env nomsu -V6.14
+#
+ This is a tool to find syntax trees matching a pattern. "*" is a wildcard
+ that will match any subtree, and "**" is a wildcard that will match any
+ 0 or more subtrees. "**" is greedy, so extra arguments after it will
+ not match.
+
+ nomsu -t find [flags] "* squared" file1 file2...
+
+ Flags:
+ -l List only the names of the files with matches
+ --wildcard=<wildcard> Specify a custom wildcard (in case you need to
+ match an action with a "*" in the name)
+
+ Output:
+ <filename>:<line number>:
+ <matching lines>
+
+use "filesystem"
+use "consolecolor"
+use "commandline"
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+command line program with $args:
+ $wildcard = ($args.wildcard or "%*")
+ $pattern = $args.extras.1
+ if (any of [not $pattern, $pattern == "*", $pattern == "**"]):
+ usage ("
+ nomsu -t find [-l] [--wildcard=<wildcard>] <pattern>, where <pattern> is valid Nomsu code
+ ")
+ $pattern = ($pattern, with "\$wildcard\$wildcard" -> "$multi_wildcard")
+ $pattern = ($pattern, with $wildcard -> "$wildcard")
+ $pattern_tree = ($pattern parsed)
+ ($tree matches $patt) means:
+ when:
+ (not ($tree is syntax tree)): return (no)
+ (($patt.type == "Var") and ($patt.1 == "wildcard")): return (yes)
+ ($tree.type != $patt.type): return (no)
+ ($tree.type == "Action"):
+ if (($tree, get stub) != ($patt, get stub)): return (no)
+
+ for $ in 1 to (#$patt):
+ if ($patt.$ is syntax tree):
+ if ($patt.$ == \$multi_wildcard): return (yes)
+ unless ($tree.$ matches $patt.$): return (no)
+ ..else:
+ unless ($tree.$ == $patt.$): return (no)
+
+ if ((#$tree) != (#$patt)): return (no)
+ return (yes)
+ $filenames = ($args.extras, from 2 to -1)
+ if ((#$filenames) == 0):
+ say ("
+ Warning: searching stdin (ctrl-d to abort). To avoid this message, use nomsu -t find -
+ ")
+ $filenames = ["stdin"]
+
+ for $filename in $filenames:
+ $file = (read file $filename)
+ unless $file:
+ fail "File does not exist: \$filename"
+ $code = (NomsuCode from ($Source $filename 1 (size of $file)) $file)
+ try:
+ $tree = ($code parsed)
+ ..if it fails $msg:
+ say
+ red ("
+ \$filename failed to parse:
+ \$msg
+ ")
+ $tree = (nil)
+
+ unless $tree:
+ do next $filename
+
+ $results = []
+ for $t in recursive $tree:
+ if ($t matches $pattern_tree):
+ $line_num = ($file, line number at $t.source.start)
+ $results, add {
+ .line = $line_num, .text = "\(blue "\$filename:\$line_num:")\n\(source lines of $t)"
+ }
+
+ for $sub in $t:
+ if ($sub is syntax tree):
+ recurse $t on $sub
+
+ if $args.l:
+ if ((#$results) > 0):
+ say $filename
+ ..else:
+ sort $results by $ -> $.line
+ for $ in $results:
+ say $.text
diff --git a/lib/tools/format.nom b/lib/tools/format.nom
new file mode 100755
index 0000000..e60d12e
--- /dev/null
+++ b/lib/tools/format.nom
@@ -0,0 +1,45 @@
+#!/usr/bin/env nomsu -V6.14
+#
+ Auto-format Nomsu code. Usage:
+ nomsu -t format [-i] file1 file2...
+
+ If the "-i" flag is used, the file will be edited in-place.
+ If the "-q" flag is used and an error occurs, the original file will be printed.
+ If no files are passed in, this will read from stdin.
+
+use "filesystem"
+use "commandline"
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+command line program with $args:
+ $filenames = $args.extras
+ if ((#$filenames) == 0):
+ say ("
+ Warning: reading from stdin (ctrl-d to abort). To avoid this message, use nomsu -t format -
+ ")
+ $filenames = ["stdin"]
+
+ for $filename in $filenames:
+ $file = (read file $filename)
+ unless $file:
+ fail "File does not exist: \$filename"
+ $leading_indent = ($file, matching "\n*([ ]*)")
+ $code = (NomsuCode from ($Source $filename 1 (size of $file)) $file)
+ try:
+ $tree = ($code parsed)
+ ..if it fails $msg:
+ if $args.q:
+ $formatted = $file
+ ..else:
+ say $msg
+
+ if ($tree and (not $formatted)):
+ $formatted =
+ "\$leading_indent\($tree as nomsu, text, with "\n" -> "\n\$leading_indent")"
+
+ if $formatted:
+ if $args.i:
+ write $formatted to file $filename
+ ..else:
+ say $formatted inline
diff --git a/tools/parse.nom b/lib/tools/parse.nom
index 22bfdc3..63cc247 100755
--- a/tools/parse.nom
+++ b/lib/tools/parse.nom
@@ -3,7 +3,8 @@
Tool to print out a parse tree of files in an easy-to-read format. Usage:
nomsu tools/parse.nom file1 file2 directory1 ...
-use "lib/os"
+use "filesystem"
+use "commandline"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -36,10 +37,11 @@ externally (print tree $t at indent $indent) means:
else:
say "\$indent \(quote $arg)"
-for $filename in $(COMMAND LINE ARGS).extras:
- $file = (read file $filename)
- unless $file:
- fail "File does not exist: \$filename"
- $nomsu = (NomsuCode from (Source $filename 1 (size of $file)) $file)
- $tree = ($nomsu parsed)
- print tree $tree at indent ""
+command line program with $args:
+ for $filename in $args.extras:
+ $file = (read file $filename)
+ unless $file:
+ fail "File does not exist: \$filename"
+ $nomsu = (NomsuCode from (Source $filename 1 (size of $file)) $file)
+ $tree = ($nomsu parsed)
+ print tree $tree at indent ""
diff --git a/lib/tools/repl.nom b/lib/tools/repl.nom
new file mode 100755
index 0000000..2c0d3df
--- /dev/null
+++ b/lib/tools/repl.nom
@@ -0,0 +1,86 @@
+#!/usr/bin/env nomsu -V6.14
+#
+ This file defines a Read-Evaluate-Print-Loop (REPL) for Nomsu
+
+use "consolecolor"
+use "filesystem"
+use "commandline"
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+externally (help) means:
+ say ("
+ This is the Nomsu v\(Nomsu version) interactive console.
+ You can type in Nomsu code here and hit 'enter' twice to run it.
+ To exit, type 'exit' or 'quit' and hit enter twice.
+ ")
+
+command line program with $args:
+ say ("
+
+ \(bright)\(underscore)Welcome to the Nomsu v\(Nomsu version) interactive console!\
+ ..\(reset color)
+ press 'enter' twice to run a command
+
+ ")
+
+ repeat:
+ say (bright (yellow ">> ")) inline
+ $buff = []
+ repeat:
+ say (bright) inline
+ $line = ($io.read "*L")
+ say (reset color) inline
+ if (($line == "\n") or (not $line)):
+ if ((size of $buff) > 0):
+ # clear the line
+ say "\027[1A\027[2K" inline
+ go to (run buffer)
+ $buff, add ($line, with "\t" -> " ")
+ say (dim (yellow ".. ")) inline
+
+ --- (run buffer) ---
+
+ if ((size of $buff) == 0): stop
+ $buff = ($buff, joined)
+ spoof file $buff
+ try:
+ $tree = ($buff parsed)
+ ..if it fails with $err:
+ say $err
+ do next
+
+ unless $tree:
+ do next
+
+ for $chunk in $tree:
+ try:
+ $lua = ($chunk as lua)
+ ..if it fails with $err: say $err
+
+ unless $lua:
+ do next
+
+ # TODO: this is a bit hacky, it just defaults variables to global
+ so that stuff mostly works across multiple lines. It would be
+ nicer if local variables actually worked.
+ $lua, remove free vars
+ try:
+ $ret = (run $lua)
+ ..if it fails with $err: say $err
+ ..if it succeeds:
+ if (type of $ret) is:
+ "nil":
+ do nothing
+
+ "boolean":
+ say "= \("yes" if $ret else "no")"
+
+ "table":
+ if $ret.as_nomsu:
+ say "= \($ret, as nomsu)"
+ ..else:
+ say "= \$ret"
+
+ else:
+ say "= \$ret"
diff --git a/lib/tools/replace.nom b/lib/tools/replace.nom
new file mode 100755
index 0000000..fdb8e38
--- /dev/null
+++ b/lib/tools/replace.nom
@@ -0,0 +1,147 @@
+#!/usr/bin/env nomsu -V6.14
+#
+ This is a tool to replace syntax trees with something new.
+
+ Usage:
+ nomsu -t replace [-i] [-f] [-q] [--literal="$v1 $v2..."] <pattern> <replacement> file1 file2...
+
+ Example:
+ nomsu -t replace "($1 and $2) and $3" "all of [$1, $2, $3]" my_file.nom
+
+ If the "-i" flag is used, the file(s) will be edited in-place.
+ When editing in-place, if the "-f" flag is not used, each change will be
+ run past the user first.
+ If the "-q" flag is used and a file fails to parse, the original file
+ contents will be output.
+ If no files are passed in, this will read from stdin.
+
+use "filesystem"
+use "consolecolor"
+use "commandline"
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+command line program with $args:
+ if ((#$args.extras) < 2):
+ fail ("
+ Usage: nomsu -t replace [--literal="$v1 $v2..."] <pattern> <replacement> file1 file2...
+ ")
+ $pattern = $args.extras.1
+ $replacement = $args.extras.2
+ $pattern_tree = ($pattern parsed)
+ $replacement_tree = ($replacement parsed)
+ $literal_vars = {}
+ if $args.literal:
+ for $var in ($args.literal, all matches of "$([^ ]*)"):
+ $literal_vars.$var = (yes)
+
+ if (($pattern_tree.type == "Var") and (not $literal_vars.($pattern_tree.1))):
+ fail "Pattern matches every part of the file."
+
+ $pattern_vars = {
+ : for $ in recursive $pattern_tree:
+ if (($.type == "Var") and (not $literal_vars.($.1))): add $.1
+ for $child in $:
+ if ($child is a "Syntax Tree"):
+ recurse $ on $child
+ }
+
+ # TODO: support wildcards and unpacking
+ e.g. nomsu -t replace "test(: $test; *$more_tests)" "*$more_tests; *$test"
+ ($tree matches $patt with $substitution_values) means:
+ # TODO: optimize
+ $substitution_values = {: for $k = $v in $substitution_values: add $k = $v}
+ when:
+ (not ($tree is syntax tree)): return (no)
+ (($patt.type == "Var") and $pattern_vars.($patt.1)):
+ if $substitution_values.($patt.1):
+ if ($tree == $substitution_values.($patt.1)):
+ return $substitution_values
+ ..else:
+ return (nil)
+ ..else:
+ $substitution_values.($patt.1) = $tree
+ return $substitution_values
+ ($tree.type != $patt.type): return (nil)
+ ($tree.type == "Action"):
+ if (($tree, get stub) != ($patt, get stub)): return (nil)
+
+ for $ in 1 to (#$patt):
+ if ($patt.$ is syntax tree):
+ $new_values = ($tree.$ matches $patt.$ with $substitution_values)
+ unless $new_values:
+ return (nil)
+
+ for $k = $v in $new_values:
+ $substitution_values.$k = $v
+ ..else:
+ unless ($tree.$ == $patt.$): return (nil)
+
+ if ((#$tree) != (#$patt)): return (nil)
+ return $substitution_values
+ $filenames = ($args.extras, from 3 to -1)
+ if ((#$filenames) == 0):
+ say ("
+ Warning: searching stdin (ctrl-d to abort). To avoid this message, use nomsu -t find -
+ ")
+ $filenames = ["stdin"]
+
+ for $filename in $filenames:
+ $file = (read file $filename)
+ unless $file:
+ fail "File does not exist: \$filename"
+ $code = (NomsuCode from ($Source $filename 1 (size of $file)) $file)
+ try:
+ $tree = ($code parsed)
+ ..if it fails $msg:
+ if $args.q:
+ unless $args.i: say $code
+ ..else:
+ say $msg
+
+ unless $tree:
+ do next $filename
+
+ $replaced = {}
+ $matched = {}
+ $user_answers = {}
+ ($tree with replacements) means
+ $tree, map
+ for $t:
+ $values = ($t matches $pattern_tree with {})
+ if $values:
+ $matched.$t = (yes)
+ for $k = $v in $values:
+ $values.$k = ($v with replacements)
+ $ret = ($replacement_tree with vars $values)
+ if ($args.i and (not $args.f)):
+ if ($user_answers.$t == (nil)):
+ if ((#$user_answers) > 0): say ""
+ $user_answers.$t = "n"
+ say "\(bright)Should this:"
+ say ("
+ \(bright)\(yellow)\("\(($t with replacements) as nomsu)", with "\n" -> "\n ")\
+ ..\(reset color)
+ ")
+ say "\(bright)..be replaced with:"
+
+ say ("
+ \(bright)\(blue)\("\($ret as nomsu)", with "\n" -> "\n ")\(reset color)
+ ")
+
+ $user_answers.$t = (ask "\(bright)..? [Y/n]\(reset color) ")
+
+ if ($user_answers.$t == "n"): return (nil)
+ $replaced.$t = (yes)
+ return $ret
+ $tree2 = ($tree with replacements)
+ if $args.i:
+ if ((#$user_answers) > 0): say ""
+ say ("
+ \(#$replaced)/\(#$matched) replacement\("" if ((#$replaced) == 1) else "s") in \$filename
+ ")
+
+ if ((#$replaced) > 0):
+ write "\($tree2 as nomsu)" to file $filename
+ ..else:
+ say ($tree2 as nomsu)
diff --git a/lib/tools/test.nom b/lib/tools/test.nom
new file mode 100755
index 0000000..4663bd4
--- /dev/null
+++ b/lib/tools/test.nom
@@ -0,0 +1,65 @@
+#!/usr/bin/env nomsu -V6.14
+#
+ Tool to run all tests in a file (i.e. the code block inside a call to 'test $'). Usage:
+ nomsu tools/test.nom file1 file2 directory1 ...
+
+use "filesystem"
+use "consolecolor"
+use "commandline"
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+command line program with $args:
+ for $filename in $args.extras at $i:
+ $file = (read file $filename)
+ unless $file:
+ fail "Couldn't find \$filename"
+
+ $(test environment) = (new environment)
+ $(test environment), export $filename
+ $version =
+ $file, matching ("
+ #![^
+ ]* nomsu %-V[ ]*([^
+ ]*)
+ ")
+ $file_tests = []
+ for $src = $test in $(test environment).TESTS:
+ if $version:
+ $test = ("
+ #!/usr/bin/env nomsu -V\$version
+ \$test
+ ")
+ $file_tests, add {.test = $test, .source = $src}
+
+ unless ($file_tests is empty):
+ sort $file_tests by $ -> $.source
+ say "[ .. ] \$filename" inline
+ $io.flush()
+
+ if $args.v: say ""
+
+ $failures = []
+ for $ in $file_tests:
+ if $args.v:
+ say " \(yellow ($.test, with "\n" -> "\n "))"
+ try:
+ $(test environment), run $.test
+ ..if it fails with $msg:
+ $src = ($Source, from string $.source)
+ $l1 = ($file, line number at $src.start)
+ $l2 = ($file, line number at $src.stop)
+ $failures, add "\(yellow "\($src.filename):\($l1)-\$l2:")\n\(bright (red ($msg, indented)))"
+
+ if ($failures is empty):
+ if $args.v:
+ say (green "PASS")
+ ..else:
+ say "\r[\(green "PASS")"
+ ..else:
+ if $args.v:
+ say (red (bright "FAIL"))
+ ..else:
+ say "\r[\(red (bright "FAIL"))"
+ say "\($failures, joined with "\n", indented)"
+
diff --git a/lib/tools/upgrade.nom b/lib/tools/upgrade.nom
new file mode 100755
index 0000000..1ef91b9
--- /dev/null
+++ b/lib/tools/upgrade.nom
@@ -0,0 +1,43 @@
+#!/usr/bin/env nomsu -V6.14
+#
+ Tool to automatically update code from old versions of Nomsu. Usage:
+ nomsu tools/upgrade.nom [-i] file1 file2 directory1 ...
+ If "-i" is the first argument, upgrades will be performed in-place. Otherwise, the
+ upgraded code will be printed.
+
+use "compatibility"
+use "filesystem"
+use "consolecolor"
+use "commandline"
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+command line program with $args:
+ $inplace = ($args.i or $args.inplace)
+ $start_version = $args."upgrade-from"
+ $version = ($args."upgrade-to" or (Nomsu version))
+ $test = ($args.t or $args.test)
+ for $filename in $args.extras:
+ $file = (read file $filename)
+ unless $file:
+ fail "File does not exist: \$filename"
+ $leading_indent = ($file, matching "\n*([ ]*)")
+ $code = (NomsuCode from (Source $filename 1 (size of $file)) $file)
+ $tree = ($code parsed $start_version)
+ $uptree =
+ $tree upgraded from ($start_version or ($tree.version or (Nomsu version))) to
+ $version
+ $text = "\$leading_indent\($uptree as nomsu, text, with "\n" -> "\n\$leading_indent")"
+ when:
+ $inplace:
+ say "Upgraded \$filename"
+ write $text to file $filename
+
+ $test:
+ if ($uptree == $tree):
+ say (dim "\$filename will not be changed")
+ ..else:
+ say (bright "\$filename will be changed")
+
+ else:
+ say $text inline
diff --git a/nomsu.lua b/nomsu.lua
index 88bf986..6f523c8 100644
--- a/nomsu.lua
+++ b/nomsu.lua
@@ -48,16 +48,16 @@ end
local sep = "\3"
local parser = re.compile([[ args <- {| (flag %sep)*
{:files: {|
- ( ("-m" %sep)? (!("--" %sep) file)* ("--" %sep)
- / file
+ ( ("-m" %sep)? (file %sep)+ "--" %sep
+ / file %sep
/ {~ '' %sep? -> 'nomsu://tools/repl.nom' ~}) |} :}
{:nomsu_args: {| (nomsu_flag %sep)* {:extras: {| ({[^%sep]+} %sep)* |} :} |} :}
- |} !.
+ |} ({.+}?)
file <-
- ( "-e" %sep ({[^%sep]+} -> spoof) %sep
- / "-t" %sep {~ {[^%sep]+} -> "nomsu://tools/%1.nom" ~} %sep
- / {[^%sep]+} %sep)
+ ( "-e" %sep ({[^%sep]+} -> spoof)
+ / "-t" %sep {~ {[^%sep]+} -> "nomsu://tools/%1.nom" ~}
+ / !"--" {[^%sep]+})
flag <- longflag / shortflag / "-" shortboolflag+
longflag <-
@@ -84,8 +84,11 @@ local parser = re.compile([[ args <- {| (flag %sep)*
spoof = Files.spoof
})
local arg_string = table.concat(arg, sep) .. sep
-local args = parser:match(arg_string)
-if not args or args.help then
+local args, err = parser:match(arg_string)
+if not args or err or args.help then
+ if err then
+ print("Didn't understand: \x1b[31;1m" .. tostring(err) .. "\x1b[0m")
+ end
print(usage)
os.exit(EXIT_FAILURE)
end
@@ -98,28 +101,35 @@ end
nomsu_args.extras = List(args.nomsu_args.extras or { })
local optimization = tonumber(args.optimization or 1)
local nomsupath = { }
-if NOMSU_VERSION and NOMSU_PREFIX then
- if optimization > 0 then
- table.insert(nomsupath, tostring(NOMSU_PREFIX) .. "/share/nomsu/" .. tostring(NOMSU_VERSION) .. "/?.lua")
- table.insert(nomsupath, tostring(NOMSU_PREFIX) .. "/share/nomsu/" .. tostring(NOMSU_VERSION) .. "/?/init.lua")
- end
- table.insert(nomsupath, tostring(NOMSU_PREFIX) .. "/share/nomsu/" .. tostring(NOMSU_VERSION) .. "/?.nom")
- table.insert(nomsupath, tostring(NOMSU_PREFIX) .. "/share/nomsu/" .. tostring(NOMSU_VERSION) .. "/?/init.nom")
+local suffixes
+if optimization > 0 then
+ suffixes = {
+ "?.lua",
+ "?/init.lua",
+ "?.nom",
+ "?/init.nom"
+ }
+else
+ suffixes = {
+ "?.nom",
+ "?/init.nom"
+ }
end
-if NOMSU_PACKAGEPATH then
- if optimization > 0 then
- table.insert(nomsupath, tostring(NOMSU_PACKAGEPATH) .. "/nomsu/?.lua")
- table.insert(nomsupath, tostring(NOMSU_PACKAGEPATH) .. "/nomsu/?/init.lua")
+local add_path
+add_path = function(p)
+ for _index_0 = 1, #suffixes do
+ local s = suffixes[_index_0]
+ table.insert(nomsupath, p .. "/" .. s)
end
- table.insert(nomsupath, tostring(NOMSU_PACKAGEPATH) .. "/nomsu/?.nom")
- table.insert(nomsupath, tostring(NOMSU_PACKAGEPATH) .. "/nomsu/?/init.nom")
end
-if optimization > 0 then
- table.insert(nomsupath, "./?.lua")
- table.insert(nomsupath, "./?/init.lua")
+if NOMSU_VERSION and NOMSU_PREFIX then
+ add_path(tostring(NOMSU_PREFIX) .. "/share/nomsu/" .. tostring(NOMSU_VERSION) .. "/lib")
+else
+ add_path("./lib")
end
-table.insert(nomsupath, "./?.nom")
-table.insert(nomsupath, "./?/init.nom")
+local NOMSU_PACKAGEPATH = NOMSU_PACKAGEPATH or "/opt"
+add_path(NOMSU_PACKAGEPATH)
+add_path(".")
package.nomsupath = table.concat(nomsupath, ";")
local nomsu_environment = require('nomsu_environment')
nomsu_environment.COMMAND_LINE_ARGS = nomsu_args
@@ -143,7 +153,8 @@ run = function()
do
local nomsu_name = f:match("^nomsu://(.*)%.nom")
if nomsu_name then
- local path, err = package.searchpath(nomsu_name, package.nomsupath, "/")
+ local path
+ path, err = package.searchpath(nomsu_name, package.nomsupath, "/")
if not path then
error(err)
end
@@ -171,20 +182,22 @@ run = function()
local code = Files.read(filename)
local source = Source(filename, 1, #code)
code = NomsuCode:from(source, code)
- local tree = nomsu_environment._1_parsed(code)
+ local env = nomsu_environment.new_environment()
+ env.MODULE_NAME = filename
+ local tree = env._1_parsed(code)
if not (tree.type == 'FileChunks') then
tree = {
tree
}
end
for chunk_no, chunk in ipairs(tree) do
- local lua = nomsu_environment:compile(chunk)
+ local lua = env:compile(chunk)
lua:declare_locals()
lua:prepend((chunk_no > 1) and '\n' or '', "-- File " .. tostring(filename) .. " chunk #" .. tostring(chunk_no) .. "\n")
if args.verbose then
print(lua:text())
end
- nomsu_environment:run(chunk)
+ env:run(chunk)
output:write(lua:text(), "\n")
end
print(("Compiled %-25s -> %s"):format(filename, filename:gsub("%.nom$", ".lua")))
@@ -193,25 +206,31 @@ run = function()
local code = Files.read(filename)
local source = Source(filename, 1, #code)
code = NomsuCode:from(source, code)
- local tree = nomsu_environment._1_parsed(code)
+ local env = nomsu_environment.new_environment()
+ env.MODULE_NAME = filename
+ env.WAS_RUN_DIRECTLY = true
+ local tree = env._1_parsed(code)
if not (tree.type == 'FileChunks') then
tree = {
tree
}
end
for chunk_no, chunk in ipairs(tree) do
- local lua = nomsu_environment:compile(chunk)
+ local lua = env:compile(chunk)
lua:declare_locals()
lua:prepend((chunk_no > 1) and '\n' or '', "-- File " .. tostring(filename) .. " chunk #" .. tostring(chunk_no) .. "\n")
print(lua:text())
- nomsu_environment:run(lua)
+ env:run(lua)
end
else
local f = Files.read(filename)
if filename:match("%.lua$") then
f = LuaCode:from(Source(filename, 1, #f), f)
end
- nomsu_environment:run(f)
+ local env = nomsu_environment.new_environment()
+ env.MODULE_NAME = filename
+ env.WAS_RUN_DIRECTLY = true
+ env:run(f)
end
end
end
diff --git a/nomsu.moon b/nomsu.moon
index b837170..472bed5 100755
--- a/nomsu.moon
+++ b/nomsu.moon
@@ -48,16 +48,16 @@ sep = "\3"
parser = re.compile([[
args <- {| (flag %sep)*
{:files: {|
- ( ("-m" %sep)? (!("--" %sep) file)* ("--" %sep)
- / file
+ ( ("-m" %sep)? (file %sep)+ "--" %sep
+ / file %sep
/ {~ '' %sep? -> 'nomsu://tools/repl.nom' ~}) |} :}
{:nomsu_args: {| (nomsu_flag %sep)* {:extras: {| ({[^%sep]+} %sep)* |} :} |} :}
- |} !.
+ |} ({.+}?)
file <-
- ( "-e" %sep ({[^%sep]+} -> spoof) %sep
- / "-t" %sep {~ {[^%sep]+} -> "nomsu://tools/%1.nom" ~} %sep
- / {[^%sep]+} %sep)
+ ( "-e" %sep ({[^%sep]+} -> spoof)
+ / "-t" %sep {~ {[^%sep]+} -> "nomsu://tools/%1.nom" ~}
+ / !"--" {[^%sep]+})
flag <- longflag / shortflag / "-" shortboolflag+
longflag <-
@@ -82,8 +82,10 @@ parser = re.compile([[
spoof: Files.spoof
})
arg_string = table.concat(arg, sep)..sep
-args = parser\match(arg_string)
-if not args or args.help
+args, err = parser\match(arg_string)
+if not args or err or args.help
+ if err
+ print("Didn't understand: \x1b[31;1m#{err}\x1b[0m")
print usage
os.exit(EXIT_FAILURE)
nomsu_args = Dict{}
@@ -93,25 +95,18 @@ nomsu_args.extras = List(args.nomsu_args.extras or {})
optimization = tonumber(args.optimization or 1)
nomsupath = {}
+suffixes = if optimization > 0
+ {"?.lua", "?/init.lua", "?.nom", "?/init.nom"}
+else {"?.nom", "?/init.nom"}
+add_path = (p)->
+ for s in *suffixes do table.insert(nomsupath, p.."/"..s)
if NOMSU_VERSION and NOMSU_PREFIX
- if optimization > 0
- table.insert nomsupath, "#{NOMSU_PREFIX}/share/nomsu/#{NOMSU_VERSION}/?.lua"
- table.insert nomsupath, "#{NOMSU_PREFIX}/share/nomsu/#{NOMSU_VERSION}/?/init.lua"
- table.insert nomsupath, "#{NOMSU_PREFIX}/share/nomsu/#{NOMSU_VERSION}/?.nom"
- table.insert nomsupath, "#{NOMSU_PREFIX}/share/nomsu/#{NOMSU_VERSION}/?/init.nom"
-
-if NOMSU_PACKAGEPATH
- if optimization > 0
- table.insert nomsupath, "#{NOMSU_PACKAGEPATH}/nomsu/?.lua"
- table.insert nomsupath, "#{NOMSU_PACKAGEPATH}/nomsu/?/init.lua"
- table.insert nomsupath, "#{NOMSU_PACKAGEPATH}/nomsu/?.nom"
- table.insert nomsupath, "#{NOMSU_PACKAGEPATH}/nomsu/?/init.nom"
-
-if optimization > 0
- table.insert nomsupath, "./?.lua"
- table.insert nomsupath, "./?/init.lua"
-table.insert nomsupath, "./?.nom"
-table.insert nomsupath, "./?/init.nom"
+ add_path "#{NOMSU_PREFIX}/share/nomsu/#{NOMSU_VERSION}/lib"
+else
+ add_path "./lib"
+NOMSU_PACKAGEPATH or= "/opt"
+add_path NOMSU_PACKAGEPATH
+add_path "."
package.nomsupath = table.concat(nomsupath, ";")
nomsu_environment = require('nomsu_environment')
@@ -152,14 +147,16 @@ run = ->
code = Files.read(filename)
source = Source(filename, 1, #code)
code = NomsuCode\from(source, code)
- tree = nomsu_environment._1_parsed(code)
+ env = nomsu_environment.new_environment!
+ env.MODULE_NAME = filename
+ tree = env._1_parsed(code)
tree = {tree} unless tree.type == 'FileChunks'
for chunk_no, chunk in ipairs tree
- lua = nomsu_environment\compile(chunk)
+ lua = env\compile(chunk)
lua\declare_locals!
lua\prepend((chunk_no > 1) and '\n' or '', "-- File #{filename} chunk ##{chunk_no}\n")
if args.verbose then print(lua\text!)
- nomsu_environment\run(chunk)
+ env\run(chunk)
output\write(lua\text!, "\n")
print ("Compiled %-25s -> %s")\format(filename, filename\gsub("%.nom$", ".lua"))
output\close!
@@ -167,20 +164,26 @@ run = ->
code = Files.read(filename)
source = Source(filename, 1, #code)
code = NomsuCode\from(source, code)
- tree = nomsu_environment._1_parsed(code)
+ env = nomsu_environment.new_environment!
+ env.MODULE_NAME = filename
+ env.WAS_RUN_DIRECTLY = true
+ tree = env._1_parsed(code)
tree = {tree} unless tree.type == 'FileChunks'
for chunk_no, chunk in ipairs tree
- lua = nomsu_environment\compile(chunk)
+ lua = env\compile(chunk)
lua\declare_locals!
lua\prepend((chunk_no > 1) and '\n' or '', "-- File #{filename} chunk ##{chunk_no}\n")
print(lua\text!)
- nomsu_environment\run(lua)
+ env\run(lua)
else
-- Just run the file
f = Files.read(filename)
if filename\match("%.lua$")
f = LuaCode\from(Source(filename, 1, #f), f)
- nomsu_environment\run(f)
+ env = nomsu_environment.new_environment!
+ env.MODULE_NAME = filename
+ env.WAS_RUN_DIRECTLY = true
+ env\run(f)
--nomsu_environment.run_file_1_in(filename, nomsu_environment, 0)
debugger = if args.debugger == "nil" then {}
diff --git a/nomsu_compiler.lua b/nomsu_compiler.lua
index 9c8c9ac..fee94f3 100644
--- a/nomsu_compiler.lua
+++ b/nomsu_compiler.lua
@@ -97,6 +97,8 @@ compile = function(self, tree)
if ret ~= tree then
return self:compile(ret)
end
+ elseif tree.stub == "1 if 2 else" then
+ require('ldt').breakpoint()
end
local lua = LuaCode:from(tree.source)
lua:add((stub):as_lua_id(), "(")
diff --git a/nomsu_compiler.moon b/nomsu_compiler.moon
index f3530e9..fd7403f 100644
--- a/nomsu_compiler.moon
+++ b/nomsu_compiler.moon
@@ -68,6 +68,8 @@ compile = (tree)=>
return ret
if ret != tree
return @compile(ret)
+ elseif tree.stub == "1 if 2 else"
+ require('ldt').breakpoint!
lua = LuaCode\from(tree.source)
lua\add((stub)\as_lua_id!,"(")
diff --git a/nomsu_environment.lua b/nomsu_environment.lua
index 9181d92..94e68e0 100644
--- a/nomsu_environment.lua
+++ b/nomsu_environment.lua
@@ -64,9 +64,20 @@ do
compile, compile_error = _obj_0.compile, _obj_0.compile_error
end
local _currently_running_files = List({ })
-local nomsu_environment
local _module_imports = { }
-nomsu_environment = setmetatable({
+local _importer_mt = {
+ __index = function(self, k)
+ return _module_imports[self][k]
+ end
+}
+local Importer
+Importer = function(t, imports)
+ _module_imports[t] = imports or { }
+ t._IMPORTS = _module_imports[t]
+ return setmetatable(t, _importer_mt)
+end
+local nomsu_environment
+nomsu_environment = Importer({
NOMSU_COMPILER_VERSION = 13,
NOMSU_SYNTAX_VERSION = max_parser_version,
next = next,
@@ -230,7 +241,6 @@ nomsu_environment = setmetatable({
end
local mod = self:new_environment()
mod.MODULE_NAME = package_name
- mod.TESTS = Dict({ })
local code = Files.read(path)
if path:match("%.lua$") then
code = LuaCode:from(Source(path, 1, #code), code)
@@ -250,19 +260,41 @@ nomsu_environment = setmetatable({
for k, v in pairs(mod) do
imports[k] = v
end
+ local cr_imports = assert(_module_imports[self.COMPILE_RULES])
+ for k, v in pairs(mod.COMPILE_RULES) do
+ cr_imports[k] = v
+ end
return mod
end,
export = function(self, package_name)
local mod = self:load_module(package_name)
local imports = assert(_module_imports[self])
for k, v in pairs(_module_imports[mod]) do
- imports[k] = v
+ if rawget(imports, k) == nil then
+ imports[k] = v
+ end
end
for k, v in pairs(mod) do
- if k ~= "_G" and k ~= "_ENV" then
+ if rawget(self, k) == nil then
self[k] = v
end
end
+ local cr_imports = assert(_module_imports[self.COMPILE_RULES])
+ for k, v in pairs(_module_imports[mod.COMPILE_RULES]) do
+ if rawget(cr_imports, k) == nil then
+ cr_imports[k] = v
+ end
+ end
+ for k, v in pairs(mod.COMPILE_RULES) do
+ if rawget(self.COMPILE_RULES, k) == nil then
+ self.COMPILE_RULES[k] = v
+ end
+ end
+ for k, v in pairs(mod.TESTS) do
+ if rawget(self.TESTS, k) == nil then
+ self.TESTS[k] = v
+ end
+ end
return mod
end,
run = function(self, to_run)
@@ -303,7 +335,7 @@ nomsu_environment = setmetatable({
do
local _accum_0 = { }
local _len_0 = 1
- for i, line in ipairs(Files.get_lines(lua_string)) do
+ for i, line in ipairs(lua_string:lines()) do
_accum_0[_len_0] = ("%3d|%s"):format(i, line)
_len_0 = _len_0 + 1
end
@@ -351,27 +383,29 @@ nomsu_environment = setmetatable({
end
end,
new_environment = function()
- local env = { }
- do
+ local env = Importer({ }, (function()
local _tbl_0 = { }
for k, v in pairs(nomsu_environment) do
_tbl_0[k] = v
end
- _module_imports[env] = _tbl_0
- end
+ return _tbl_0
+ end)())
env._ENV = env
env._G = env
- setmetatable(env, getmetatable(nomsu_environment))
+ env.TESTS = Dict({ })
+ env.COMPILE_RULES = Importer({ }, (function()
+ local _tbl_0 = { }
+ for k, v in pairs(nomsu_environment.COMPILE_RULES) do
+ _tbl_0[k] = v
+ end
+ return _tbl_0
+ end)())
return env
end
-}, {
- __index = function(self, k)
- return _module_imports[self][k]
- end
})
nomsu_environment._ENV = nomsu_environment
nomsu_environment._G = nomsu_environment
-nomsu_environment.COMPILE_RULES = require('bootstrap')
-_module_imports[nomsu_environment] = { }
+nomsu_environment.COMPILE_RULES = Importer(require('bootstrap'))
+nomsu_environment.MODULE_NAME = "nomsu"
SOURCE_MAP = nomsu_environment.SOURCE_MAP
return nomsu_environment
diff --git a/nomsu_environment.moon b/nomsu_environment.moon
index f82bb4e..6049555 100644
--- a/nomsu_environment.moon
+++ b/nomsu_environment.moon
@@ -34,9 +34,15 @@ for version=1,999
{:tree_to_nomsu, :tree_to_inline_nomsu} = require "nomsu_decompiler"
{:compile, :compile_error} = require('nomsu_compiler')
_currently_running_files = List{} -- Used to check for circular imports in run_file_1_in
-local nomsu_environment
_module_imports = {}
-nomsu_environment = setmetatable({
+_importer_mt = {__index: (k)=> _module_imports[@][k]}
+Importer = (t, imports)->
+ _module_imports[t] = imports or {}
+ t._IMPORTS = _module_imports[t]
+ return setmetatable(t, _importer_mt)
+
+local nomsu_environment
+nomsu_environment = Importer{
NOMSU_COMPILER_VERSION: 13, NOMSU_SYNTAX_VERSION: max_parser_version
-- Lua stuff:
:next, unpack: unpack or table.unpack, :setmetatable, :rawequal, :getmetatable, :pcall,
@@ -118,7 +124,6 @@ nomsu_environment = setmetatable({
error("Circular import detected:\n "..circle\joined_with("\n..imports "))
mod = @new_environment!
mod.MODULE_NAME = package_name
- mod.TESTS = Dict{}
code = Files.read(path)
if path\match("%.lua$")
code = LuaCode\from(Source(path, 1, #code), code)
@@ -136,16 +141,31 @@ nomsu_environment = setmetatable({
imports = assert _module_imports[@]
for k,v in pairs(mod)
imports[k] = v
+ cr_imports = assert _module_imports[@COMPILE_RULES]
+ for k,v in pairs(mod.COMPILE_RULES)
+ cr_imports[k] = v
return mod
export: (package_name)=>
mod = @load_module(package_name)
imports = assert _module_imports[@]
for k,v in pairs(_module_imports[mod])
- imports[k] = v
+ if rawget(imports, k) == nil
+ imports[k] = v
for k,v in pairs(mod)
- if k != "_G" and k != "_ENV"
+ if rawget(@, k) == nil
+ --if k != "_G" and k != "_ENV" and k != "COMPILE_RULES" and k != "MODULE_NAME"
@[k] = v
+ cr_imports = assert _module_imports[@COMPILE_RULES]
+ for k,v in pairs(_module_imports[mod.COMPILE_RULES])
+ if rawget(cr_imports, k) == nil
+ cr_imports[k] = v
+ for k,v in pairs(mod.COMPILE_RULES)
+ if rawget(@COMPILE_RULES, k) == nil
+ @COMPILE_RULES[k] = v
+ for k,v in pairs(mod.TESTS)
+ if rawget(@TESTS, k) == nil
+ @TESTS[k] = v
return mod
run: (to_run)=>
@@ -179,7 +199,7 @@ nomsu_environment = setmetatable({
-- If you replace tostring(source) with "nil", source mapping won't happen
run_lua_fn, err = load(lua_string, tostring(source), "t", @)
if not run_lua_fn
- lines =[("%3d|%s")\format(i,line) for i, line in ipairs Files.get_lines(lua_string)]
+ lines =[("%3d|%s")\format(i,line) for i, line in ipairs lua_string\lines!]
line_numbered_lua = table.concat(lines, "\n")
error("Failed to compile generated code:\n\027[1;34m#{line_numbered_lua}\027[0m\n\n#{err}", 0)
source_key = tostring(source)
@@ -210,19 +230,18 @@ nomsu_environment = setmetatable({
error("Attempt to run unknown thing: "..tostring(to_run))
new_environment: ->
- env = {}
- _module_imports[env] = {k,v for k,v in pairs(nomsu_environment)}
+ env = Importer({}, {k,v for k,v in pairs(nomsu_environment)})
env._ENV = env
env._G = env
- setmetatable(env, getmetatable(nomsu_environment))
+ env.TESTS = Dict{}
+ env.COMPILE_RULES = Importer({}, {k,v for k,v in pairs(nomsu_environment.COMPILE_RULES)})
return env
-}, {
- __index: (k)=> _module_imports[@][k]
-})
+}
+
nomsu_environment._ENV = nomsu_environment
nomsu_environment._G = nomsu_environment
-nomsu_environment.COMPILE_RULES = require('bootstrap')
-_module_imports[nomsu_environment] = {}
+nomsu_environment.COMPILE_RULES = Importer(require('bootstrap'))
+nomsu_environment.MODULE_NAME = "nomsu"
-- Hacky use of globals:
export SOURCE_MAP
diff --git a/string2.lua b/string2.lua
index 09cb5ea..429ab7f 100644
--- a/string2.lua
+++ b/string2.lua
@@ -130,6 +130,12 @@ local string2 = {
end
return table.concat(lines, "\n")
end,
+ indented = function(self, indent)
+ if indent == nil then
+ indent = " "
+ end
+ return indent .. (gsub(self, "\n", "\n" .. indent))
+ end,
as_lua = function(self)
local escaped = gsub(self, "\\", "\\\\")
escaped = gsub(escaped, "\n", "\\n")
diff --git a/string2.moon b/string2.moon
index e6db628..de2980d 100644
--- a/string2.moon
+++ b/string2.moon
@@ -51,6 +51,9 @@ string2 = {
lines[#lines+1] = line
return table.concat(lines, "\n")
+ indented: (indent=" ")=>
+ indent..(gsub(@, "\n", "\n"..indent))
+
as_lua: =>
escaped = gsub(@, "\\", "\\\\")
escaped = gsub(escaped, "\n", "\\n")
diff --git a/tools/find.nom b/tools/find.nom
deleted file mode 100755
index f9a63b9..0000000
--- a/tools/find.nom
+++ /dev/null
@@ -1,93 +0,0 @@
-#!/usr/bin/env nomsu -V6.14
-#
- This is a tool to find syntax trees matching a pattern. "*" is a wildcard
- that will match any subtree, and "**" is a wildcard that will match any
- 0 or more subtrees. "**" is greedy, so extra arguments after it will
- not match.
-
- nomsu -t find [flags] "* squared" file1 file2...
-
- Flags:
- -l List only the names of the files with matches
- --wildcard=<wildcard> Specify a custom wildcard (in case you need to
- match an action with a "*" in the name)
-
- Output:
- <filename>:<line number>:
- <matching lines>
-
-use "lib/os"
-use "lib/consolecolor"
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-$wildcard = ($(COMMAND LINE ARGS).wildcard or "%*")
-$pattern = $(COMMAND LINE ARGS).extras.1
-if (any of [not $pattern, $pattern == "*", $pattern == "**"]):
- fail ("
- Usage: nomsu -t find [-l] [--wildcard=<wildcard>] <pattern>, where <pattern> is valid Nomsu code
- ")
-$pattern = ($pattern, with "\$wildcard\$wildcard" -> "$multi_wildcard")
-$pattern = ($pattern, with $wildcard -> "$wildcard")
-$pattern_tree = ($pattern parsed)
-($tree matches $patt) means:
- when:
- (not ($tree is syntax tree)): return (no)
- (($patt.type == "Var") and ($patt.1 == "wildcard")): return (yes)
- ($tree.type != $patt.type): return (no)
- ($tree.type == "Action"):
- if (($tree, get stub) != ($patt, get stub)): return (no)
-
- for $ in 1 to (#$patt):
- if ($patt.$ is syntax tree):
- if ($patt.$ == \$multi_wildcard): return (yes)
- unless ($tree.$ matches $patt.$): return (no)
- ..else:
- unless ($tree.$ == $patt.$): return (no)
-
- if ((#$tree) != (#$patt)): return (no)
- return (yes)
-$filenames = ($(COMMAND LINE ARGS).extras, from 2 to -1)
-if ((#$filenames) == 0):
- say ("
- Warning: searching stdin (ctrl-d to abort). To avoid this message, use nomsu -t find -
- ")
- $filenames = ["stdin"]
-
-for $filename in $filenames:
- $file = (read file $filename)
- unless $file:
- fail "File does not exist: \$filename"
- $code = (NomsuCode from ($Source $filename 1 (size of $file)) $file)
- try:
- $tree = ($code parsed)
- ..if it fails $msg:
- say
- red ("
- \$filename failed to parse:
- \$msg
- ")
- $tree = (nil)
-
- unless $tree:
- do next $filename
-
- $results = []
- for $t in recursive $tree:
- if ($t matches $pattern_tree):
- $line_num = ($file, line number at $t.source.start)
- $results, add {
- .line = $line_num, .text = "\(blue "\$filename:\$line_num:")\n\(source lines of $t)"
- }
-
- for $sub in $t:
- if ($sub is syntax tree):
- recurse $t on $sub
-
- if $(COMMAND LINE ARGS).l:
- if ((#$results) > 0):
- say $filename
- ..else:
- sort $results by $ -> $.line
- for $ in $results:
- say $.text
diff --git a/tools/format.nom b/tools/format.nom
deleted file mode 100755
index 07f7980..0000000
--- a/tools/format.nom
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env nomsu -V6.14
-#
- Auto-format Nomsu code. Usage:
- nomsu -t format [-i] file1 file2...
-
- If the "-i" flag is used, the file will be edited in-place.
- If the "-q" flag is used and an error occurs, the original file will be printed.
- If no files are passed in, this will read from stdin.
-
-use "lib/os"
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-$filenames = $(COMMAND LINE ARGS).extras
-if ((#$filenames) == 0):
- say ("
- Warning: reading from stdin (ctrl-d to abort). To avoid this message, use nomsu -t format -
- ")
- $filenames = ["stdin"]
-
-for $filename in $filenames:
- $file = (read file $filename)
- unless $file:
- fail "File does not exist: \$filename"
- $leading_indent = ($file, matching "\n*([ ]*)")
- $code = (NomsuCode from ($Source $filename 1 (size of $file)) $file)
- try:
- $tree = ($code parsed)
- ..if it fails $msg:
- if $(COMMAND LINE ARGS).q:
- $formatted = $file
- ..else:
- say $msg
-
- if ($tree and (not $formatted)):
- $formatted =
- "\$leading_indent\($tree as nomsu, text, with "\n" -> "\n\$leading_indent")"
-
- if $formatted:
- if $(COMMAND LINE ARGS).i:
- write $formatted to file $filename
- ..else:
- say $formatted inline
diff --git a/tools/repl.nom b/tools/repl.nom
deleted file mode 100755
index 175d068..0000000
--- a/tools/repl.nom
+++ /dev/null
@@ -1,84 +0,0 @@
-#!/usr/bin/env nomsu -V6.14
-#
- This file defines a Read-Evaluate-Print-Loop (REPL) for Nomsu
-
-use "lib/consolecolor"
-use "lib/os"
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-externally (help) means:
- say ("
- This is the Nomsu v\(Nomsu version) interactive console.
- You can type in Nomsu code here and hit 'enter' twice to run it.
- To exit, type 'exit' or 'quit' and hit enter twice.
- ")
-
-say ("
-
- \(bright)\(underscore)Welcome to the Nomsu v\(Nomsu version) interactive console!\
- ..\(reset color)
- press 'enter' twice to run a command
-
-")
-
-repeat:
- say (bright (yellow ">> ")) inline
- $buff = []
- repeat:
- say (bright) inline
- $line = ($io.read "*L")
- say (reset color) inline
- if (($line == "\n") or (not $line)):
- if ((size of $buff) > 0):
- # clear the line
- say "\027[1A\027[2K" inline
- go to (run buffer)
- $buff, add ($line, with "\t" -> " ")
- say (dim (yellow ".. ")) inline
-
- --- (run buffer) ---
-
- if ((size of $buff) == 0): stop
- $buff = ($buff, joined)
- spoof file $buff
- try:
- $tree = ($buff parsed)
- ..if it fails with $err:
- say $err
- do next
-
- unless $tree:
- do next
-
- for $chunk in $tree:
- try:
- $lua = ($chunk as lua)
- ..if it fails with $err: say $err
-
- unless $lua:
- do next
-
- # TODO: this is a bit hacky, it just defaults variables to global
- so that stuff mostly works across multiple lines. It would be
- nicer if local variables actually worked.
- $lua, remove free vars
- try:
- $ret = (run $lua)
- ..if it fails with $err: say $err
- ..if it succeeds:
- if (type of $ret) is:
- "nil":
- do nothing
-
- "boolean":
- say "= \("yes" if $ret else "no")"
-
- "table":
- if $ret.as_nomsu:
- say "= \($ret, as nomsu)"
- ..else:
- say "= \$ret"
-
- else:
- say "= \$ret"
diff --git a/tools/replace.nom b/tools/replace.nom
deleted file mode 100755
index f4df0e4..0000000
--- a/tools/replace.nom
+++ /dev/null
@@ -1,145 +0,0 @@
-#!/usr/bin/env nomsu -V6.14
-#
- This is a tool to replace syntax trees with something new.
-
- Usage:
- nomsu -t replace [-i] [-f] [-q] [--literal="$v1 $v2..."] <pattern> <replacement> file1 file2...
-
- Example:
- nomsu -t replace "($1 and $2) and $3" "all of [$1, $2, $3]" my_file.nom
-
- If the "-i" flag is used, the file(s) will be edited in-place.
- When editing in-place, if the "-f" flag is not used, each change will be
- run past the user first.
- If the "-q" flag is used and a file fails to parse, the original file
- contents will be output.
- If no files are passed in, this will read from stdin.
-
-use "lib/os"
-use "lib/consolecolor"
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-if ((#$(COMMAND LINE ARGS).extras) < 2):
- fail ("
- Usage: nomsu -t replace [--literal="$v1 $v2..."] <pattern> <replacement> file1 file2...
- ")
-$pattern = $(COMMAND LINE ARGS).extras.1
-$replacement = $(COMMAND LINE ARGS).extras.2
-$pattern_tree = ($pattern parsed)
-$replacement_tree = ($replacement parsed)
-$literal_vars = {}
-if $(COMMAND LINE ARGS).literal:
- for $var in ($(COMMAND LINE ARGS).literal, all matches of "$([^ ]*)"):
- $literal_vars.$var = (yes)
-
-if (($pattern_tree.type == "Var") and (not $literal_vars.($pattern_tree.1))):
- fail "Pattern matches every part of the file."
-
-$pattern_vars = {
- : for $ in recursive $pattern_tree:
- if (($.type == "Var") and (not $literal_vars.($.1))): add $.1
- for $child in $:
- if ($child is a "Syntax Tree"):
- recurse $ on $child
-}
-
-# TODO: support wildcards and unpacking
- e.g. nomsu -t replace "test(: $test; *$more_tests)" "*$more_tests; *$test"
-($tree matches $patt with $substitution_values) means:
- # TODO: optimize
- $substitution_values = {: for $k = $v in $substitution_values: add $k = $v}
- when:
- (not ($tree is syntax tree)): return (no)
- (($patt.type == "Var") and $pattern_vars.($patt.1)):
- if $substitution_values.($patt.1):
- if ($tree == $substitution_values.($patt.1)):
- return $substitution_values
- ..else:
- return (nil)
- ..else:
- $substitution_values.($patt.1) = $tree
- return $substitution_values
- ($tree.type != $patt.type): return (nil)
- ($tree.type == "Action"):
- if (($tree, get stub) != ($patt, get stub)): return (nil)
-
- for $ in 1 to (#$patt):
- if ($patt.$ is syntax tree):
- $new_values = ($tree.$ matches $patt.$ with $substitution_values)
- unless $new_values:
- return (nil)
-
- for $k = $v in $new_values:
- $substitution_values.$k = $v
- ..else:
- unless ($tree.$ == $patt.$): return (nil)
-
- if ((#$tree) != (#$patt)): return (nil)
- return $substitution_values
-$filenames = ($(COMMAND LINE ARGS).extras, from 3 to -1)
-if ((#$filenames) == 0):
- say ("
- Warning: searching stdin (ctrl-d to abort). To avoid this message, use nomsu -t find -
- ")
- $filenames = ["stdin"]
-
-for $filename in $filenames:
- $file = (read file $filename)
- unless $file:
- fail "File does not exist: \$filename"
- $code = (NomsuCode from ($Source $filename 1 (size of $file)) $file)
- try:
- $tree = ($code parsed)
- ..if it fails $msg:
- if $(COMMAND LINE ARGS).q:
- unless $(COMMAND LINE ARGS).i: say $code
- ..else:
- say $msg
-
- unless $tree:
- do next $filename
-
- $replaced = {}
- $matched = {}
- $user_answers = {}
- ($tree with replacements) means
- $tree, map
- for $t:
- $values = ($t matches $pattern_tree with {})
- if $values:
- $matched.$t = (yes)
- for $k = $v in $values:
- $values.$k = ($v with replacements)
- $ret = ($replacement_tree with vars $values)
- if ($(COMMAND LINE ARGS).i and (not $(COMMAND LINE ARGS).f)):
- if ($user_answers.$t == (nil)):
- if ((#$user_answers) > 0): say ""
- $user_answers.$t = "n"
- say "\(bright)Should this:"
- say ("
- \(bright)\(yellow)\("\(($t with replacements) as nomsu)", with "\n" -> "\n ")\
- ..\(reset color)
- ")
- say "\(bright)..be replaced with:"
-
- say ("
- \(bright)\(blue)\("\($ret as nomsu)", with "\n" -> "\n ")\(reset color)
- ")
-
- $user_answers.$t = (ask "\(bright)..? [Y/n]\(reset color) ")
-
- if ($user_answers.$t == "n"): return (nil)
- $replaced.$t = (yes)
- return $ret
- $tree2 = ($tree with replacements)
- if $(COMMAND LINE ARGS).i:
- if ((#$user_answers) > 0): say ""
- say ("
- \(#$replaced)/\(#$matched) replacement\("" if ((#$replaced) == 1) else "s") in \$filename
- ")
-
- if ((#$replaced) > 0):
- write "\($tree2 as nomsu)" to file $filename
- ..else:
- say ($tree2 as nomsu)
diff --git a/tools/test.nom b/tools/test.nom
deleted file mode 100755
index 44d783b..0000000
--- a/tools/test.nom
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/usr/bin/env nomsu -V6.14
-#
- Tool to run all tests in a file (i.e. the code block inside a call to 'test $'). Usage:
- nomsu tools/test.nom file1 file2 directory1 ...
-
-use "lib/os"
-use "lib/consolecolor"
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-for $filename in $(COMMAND LINE ARGS).extras:
- $(test environment) = (new environment)
- $(test environment), use $filename
- $file = (read file $filename)
- $version =
- $file, matching ("
- #![^
- ]* nomsu %-V[ ]*([^
- ]*)
- ")
- $file_tests = []
- for $src = $test in $(test environment).TESTS:
- if $version:
- $test = ("
- #!/usr/bin/env nomsu -V\$version
- \$test
- ")
- $file_tests, add {.test = $test, .source = $src}
-
- unless ($file_tests is empty):
- sort $file_tests by $ -> $.source
- lua> "io.write('[ .. ] ', \$filename); io.flush()"
-
- if (command line args).v: say ""
-
- for $ in $file_tests:
- if (command line args).v:
- say " \(yellow ($.test, with "\n" -> "\n "))"
- $(test environment), run $.test
-
- if (command line args).v:
- say (green "PASS")
- ..else:
- say "\r[\(green "PASS")"
diff --git a/tools/upgrade.nom b/tools/upgrade.nom
deleted file mode 100755
index b9b8255..0000000
--- a/tools/upgrade.nom
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/usr/bin/env nomsu -V6.14
-#
- Tool to automatically update code from old versions of Nomsu. Usage:
- nomsu tools/upgrade.nom [-i] file1 file2 directory1 ...
- If "-i" is the first argument, upgrades will be performed in-place. Otherwise, the
- upgraded code will be printed.
-
-use "compatibility"
-use "lib/os"
-use "lib/consolecolor"
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-$inplace = ($(COMMAND LINE ARGS).i or $(COMMAND LINE ARGS).inplace)
-$start_version = $(COMMAND LINE ARGS)."upgrade-from"
-$version = ($(COMMAND LINE ARGS)."upgrade-to" or (Nomsu version))
-$test = ($(COMMAND LINE ARGS).t or $(COMMAND LINE ARGS).test)
-for $filename in $(COMMAND LINE ARGS).extras:
- $file = (read file $filename)
- unless $file:
- fail "File does not exist: \$filename"
- $leading_indent = ($file, matching "\n*([ ]*)")
- $code = (NomsuCode from (Source $filename 1 (size of $file)) $file)
- $tree = ($code parsed $start_version)
- $uptree =
- $tree upgraded from ($start_version or ($tree.version or (Nomsu version))) to
- $version
- $text = "\$leading_indent\($uptree as nomsu, text, with "\n" -> "\n\$leading_indent")"
- when:
- $inplace:
- say "Upgraded \$filename"
- write $text to file $filename
-
- $test:
- if ($uptree == $tree):
- say (dim "\$filename will not be changed")
- ..else:
- say (bright "\$filename will be changed")
-
- else:
- say $text inline