Overhaul in progress, mostly working. Moved all the nomsu packages into

lib/, including core/*. Changes to how nomsu environments and importing
work.
This commit is contained in:
Bruce Hill 2019-01-14 15:42:48 -08:00
parent 2309b696fc
commit c1c32688a4
53 changed files with 831 additions and 704 deletions

3
.gitignore vendored
View File

@ -1,4 +1,3 @@
core/*.lua
lib/*.lua
tests/*.lua
lib/*/*.lua
.pending-post-commit

View File

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

View File

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

View File

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

View File

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

View File

@ -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 $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
]
for $v = $ in $ACTION_UPGRADES:
$versions.$v = (yes)
$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

19
compatibility/init.nom Normal file
View File

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

View File

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

View File

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

View File

@ -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
@ -118,6 +117,10 @@ print_error = (error_message, start_fn, stop_fn)->
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]
line_num = 1
@ -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")

View File

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

View File

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

View File

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

11
lib/commandline/init.nom Normal file
View File

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

View File

@ -4,6 +4,7 @@
use "core/metaprogramming"
use "core/operators"
use "core/control_flow"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

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

View File

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

View File

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

16
lib/progressbar/init.nom Normal file
View File

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

12
lib/shell/init.nom Normal file
View File

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

View File

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

95
lib/tools/find.nom Executable file
View File

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

45
lib/tools/format.nom Executable file
View File

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

View File

@ -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,7 +37,8 @@ externally (print tree $t at indent $indent) means:
else:
say "\$indent \(quote $arg)"
for $filename in $(COMMAND LINE ARGS).extras:
command line program with $args:
for $filename in $args.extras:
$file = (read file $filename)
unless $file:
fail "File does not exist: \$filename"

86
lib/tools/repl.nom Executable file
View File

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

147
lib/tools/replace.nom Executable file
View File

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

65
lib/tools/test.nom Executable file
View File

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

43
lib/tools/upgrade.nom Executable file
View File

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

View File

@ -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")
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")
end
table.insert(nomsupath, tostring(NOMSU_PACKAGEPATH) .. "/nomsu/?.nom")
table.insert(nomsupath, tostring(NOMSU_PACKAGEPATH) .. "/nomsu/?/init.nom")
end
local suffixes
if optimization > 0 then
table.insert(nomsupath, "./?.lua")
table.insert(nomsupath, "./?/init.lua")
suffixes = {
"?.lua",
"?/init.lua",
"?.nom",
"?/init.nom"
}
else
suffixes = {
"?.nom",
"?/init.nom"
}
end
table.insert(nomsupath, "./?.nom")
table.insert(nomsupath, "./?/init.nom")
local add_path
add_path = function(p)
for _index_0 = 1, #suffixes do
local s = suffixes[_index_0]
table.insert(nomsupath, p .. "/" .. s)
end
end
if NOMSU_VERSION and NOMSU_PREFIX then
add_path(tostring(NOMSU_PREFIX) .. "/share/nomsu/" .. tostring(NOMSU_VERSION) .. "/lib")
else
add_path("./lib")
end
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

View File

@ -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 {}

View File

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

View File

@ -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!,"(")

View File

@ -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
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))
return env
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
}, {
__index = function(self, k)
return _module_imports[self][k]
return _tbl_0
end)())
return env
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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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