aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2019-01-10 16:33:37 -0800
committerBruce Hill <bruce@bruce-hill.com>2019-01-10 16:35:08 -0800
commit0f0fb2256a46a8808794d7d4746d112278da3730 (patch)
tree7cfb6b255beeb49705044876913e0332376b66d9
parentdb552f56dc1f2c6ea19a7d39d38ac66e52ed156e (diff)
Major overhaul of how modules and environments work, along with some
steamlining and tweaks to the makefile. Version bump: 6.14.13.8
-rw-r--r--Makefile34
-rw-r--r--bootstrap.lua163
-rw-r--r--bootstrap.moon125
-rw-r--r--code_obj.lua3
-rw-r--r--code_obj.moon2
-rw-r--r--compatibility/2.3.nom2
-rw-r--r--compatibility/2.4.nom2
-rw-r--r--compatibility/2.5.5.5.nom2
-rw-r--r--compatibility/2.5.nom2
-rw-r--r--compatibility/2.nom2
-rw-r--r--compatibility/3.5.5.6.nom2
-rw-r--r--compatibility/3.6.nom2
-rw-r--r--compatibility/3.7.nom2
-rw-r--r--compatibility/3.nom2
-rw-r--r--compatibility/4.10.12.7.nom2
-rw-r--r--compatibility/4.11.nom2
-rw-r--r--compatibility/4.12.nom2
-rw-r--r--compatibility/4.8.10.nom2
-rw-r--r--compatibility/4.9.nom2
-rw-r--r--compatibility/5.13.nom2
-rw-r--r--compatibility/6.14.nom2
-rw-r--r--compatibility/compatibility.nom2
-rw-r--r--core/collections.nom6
-rw-r--r--core/control_flow.nom51
-rw-r--r--core/coroutines.nom6
-rw-r--r--core/errors.nom4
-rw-r--r--core/id.nom10
-rw-r--r--core/init.nom11
-rw-r--r--core/io.nom2
-rw-r--r--core/math.nom10
-rw-r--r--core/metaprogramming.nom79
-rw-r--r--core/operators.nom4
-rw-r--r--core/text.nom8
-rw-r--r--doc/nomsu.17
-rw-r--r--examples/how_do_i.nom2
-rw-r--r--files.lua6
-rw-r--r--files.moon6
-rw-r--r--importer.lua85
-rw-r--r--importer.moon47
-rw-r--r--lib/consolecolor.nom2
-rw-r--r--lib/file_hash.nom4
-rw-r--r--lib/object.nom2
-rw-r--r--lib/os.nom9
-rw-r--r--lib/things.nom4
-rw-r--r--nomsu.lua183
-rwxr-xr-xnomsu.moon113
-rw-r--r--nomsu_compiler.lua642
-rw-r--r--nomsu_compiler.moon545
-rw-r--r--nomsu_decompiler.lua2
-rw-r--r--nomsu_decompiler.moon3
-rw-r--r--nomsu_environment.lua226
-rw-r--r--nomsu_environment.moon157
-rwxr-xr-xtools/find.nom4
-rwxr-xr-xtools/format.nom2
-rwxr-xr-xtools/parse.nom2
-rwxr-xr-xtools/repl.nom10
-rwxr-xr-xtools/replace.nom4
-rwxr-xr-xtools/test.nom26
-rwxr-xr-xtools/upgrade.nom4
59 files changed, 1280 insertions, 1369 deletions
diff --git a/Makefile b/Makefile
index 2a0464f..6f4befe 100644
--- a/Makefile
+++ b/Makefile
@@ -7,15 +7,16 @@ LUA= lua
LUA_BIN= $(shell which $(LUA))
PREFIX=
+PACKAGEPATH=
UNINSTALL_VERSION=
# ========= You shouldn't need to mess with any of these variables below ================
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 importer.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 \
syntax_tree.lua containers.lua bitops.lua parser.lua pretty_errors.lua \
- string2.lua nomsu_decompiler.lua nomsu_environment.lua importer.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)
@@ -30,7 +31,7 @@ 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)
@echo "\n\033[1;4mRunning optimized tests...\033[0m"
- @$(LUA_BIN) nomsu.lua -O1 tools/test.nom $(CORE_NOM_FILES) $(LIB_NOM_FILES)
+ @$(LUA_BIN) nomsu.lua -O1 tools/test.nom $(CORE_LUA_FILES) $(LIB_LUA_FILES)
%.lua: %.moon
@moonc $<
@@ -58,9 +59,12 @@ install: lua version optimize
if [[ ! $$prefix ]]; then \
read -p $$'\033[1mWhere do you want to install Nomsu? (default: /usr/local) \033[0m' prefix; \
fi; \
- if [[ ! $$prefix ]]; then \
- prefix="/usr/local"; \
+ if [[ ! $$prefix ]]; then prefix="/usr/local"; fi; \
+ packagepath="$(PACKAGEPATH)"; \
+ if [[ ! $$packagepath ]]; then \
+ read -p $$'\033[1mWhere do you want Nomsu to put packages you install in the future? (default: /opt) \033[0m' packagepath; \
fi; \
+ if [[ ! $$packagepath ]]; then packagepath="/opt"; fi; \
if [[ $$prefix != "`realpath $$prefix`" ]]; then \
echo $$'\033[1;31mWarning: '$$prefix$$' is not an absolute path. This may cause problems.\033[0m'; \
read -p $$'\033[1mWould you rather use '`realpath $$prefix`$$' instead? (recommended)[Y/n]\033[0m ' use_real; \
@@ -69,8 +73,9 @@ install: lua version optimize
fi; \
fi; \
version="`cat version`"; \
- mkdir -pv $$prefix/bin $$prefix/lib/nomsu/$$version $$prefix/share/nomsu/$$version $$prefix/share/man/man1 \
- && echo "#!$(LUA_BIN)\\nlocal NOMSU_VERSION, NOMSU_PREFIX = [[$$version]], [[$$prefix]]" | cat - nomsu.lua > $$prefix/bin/nomsu$$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]]" \
+ | 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 \
@@ -82,13 +87,18 @@ uninstall: version
if [[ ! $$prefix ]]; then \
read -p $$'\033[1mWhere do you want to uninstall Nomsu from? (default: /usr/local) \033[0m' prefix; \
fi; \
- if [[ ! $$prefix ]]; then \
- prefix="/usr/local"; \
+ 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"; \
@@ -108,6 +118,12 @@ 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;\
+ 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
diff --git a/bootstrap.lua b/bootstrap.lua
new file mode 100644
index 0000000..844bcca
--- /dev/null
+++ b/bootstrap.lua
@@ -0,0 +1,163 @@
+local match, sub, gsub, format, byte, find
+do
+ local _obj_0 = string
+ match, sub, gsub, format, byte, find = _obj_0.match, _obj_0.sub, _obj_0.gsub, _obj_0.format, _obj_0.byte, _obj_0.find
+end
+local LuaCode, Source
+do
+ local _obj_0 = require("code_obj")
+ LuaCode, Source = _obj_0.LuaCode, _obj_0.Source
+end
+local SyntaxTree = require("syntax_tree")
+local Files = require("files")
+local pretty_error = require("pretty_errors")
+local compile_error
+compile_error = function(source, err_msg, hint)
+ if hint == nil then
+ hint = nil
+ end
+ local file
+ if SyntaxTree:is_instance(source) then
+ file = source:get_source_file()
+ source = source.source
+ elseif type(source) == 'string' then
+ source = Source:from_string(source)
+ end
+ if source and not file then
+ file = Files.read(source.filename)
+ end
+ local err_str = pretty_error({
+ title = "Compile error",
+ error = err_msg,
+ hint = hint,
+ source = file,
+ start = source.start,
+ stop = source.stop,
+ filename = source.filename
+ })
+ return error(err_str, 0)
+end
+local MAX_LINE = 80
+local ENVNAME = jit and "_G" or "_ENV"
+local compile_actions = {
+ [""] = function(self, fn, ...)
+ local lua = LuaCode()
+ local fn_lua = self:compile(fn)
+ lua:add(fn_lua)
+ if not (fn_lua:text():match("^%(.*%)$") or fn_lua:text():match("^[_a-zA-Z][_a-zA-Z0-9.]*$")) then
+ lua:parenthesize()
+ end
+ lua:add("(")
+ for i = 1, select('#', ...) do
+ if i > 1 then
+ lua:add(", ")
+ end
+ lua:add(self:compile((select(i, ...))))
+ end
+ lua:add(")")
+ return lua
+ end,
+ ["Lua"] = function(self, code)
+ if not code then
+ return LuaCode("LuaCode()")
+ end
+ if code.type ~= "Text" then
+ return LuaCode("LuaCode:from(", tostring(code.source):as_lua(), ", ", self:compile(code), ")")
+ end
+ local operate_on_text
+ operate_on_text = function(text)
+ local lua = LuaCode:from(text.source, "LuaCode:from(", tostring(text.source):as_lua())
+ for _index_0 = 1, #text do
+ local bit = text[_index_0]
+ local bit_lua
+ if type(bit) == "string" then
+ bit_lua = bit:as_lua()
+ elseif bit.type == "Text" then
+ bit_lua = operate_on_text(bit)
+ elseif bit.type == "Block" then
+ bit_lua = LuaCode:from(bit.source, "(function()", "\n local _lua = LuaCode:from(", tostring(bit.source):as_lua(), ")", "\n local function add(...) _lua:add(...) end", "\n local function join_with(glue)", "\n local old_bits = _lua.bits", "\n _lua = LuaCode:from(_lua.source)", "\n _lua:concat_add(old_bits, glue)", "\n end", "\n ", self:compile(bit), "\n return _lua", "\nend)()")
+ else
+ bit_lua = self:compile(bit)
+ end
+ local bit_leading_len = #(bit_lua:match("^[^\n]*"))
+ lua:add(lua:trailing_line_len() + bit_leading_len > MAX_LINE and ",\n " or ", ")
+ lua:add(bit_lua)
+ end
+ lua:add(")")
+ return lua
+ end
+ return operate_on_text(code)
+ end,
+ ["lua >"] = function(self, code)
+ if code.type ~= "Text" then
+ return code
+ end
+ local operate_on_text
+ operate_on_text = function(text)
+ local lua = LuaCode:from(text.source)
+ for _index_0 = 1, #text do
+ local bit = text[_index_0]
+ if type(bit) == "string" then
+ lua:add(bit)
+ elseif bit.type == "Text" then
+ lua:add(operate_on_text(bit))
+ else
+ lua:add(self:compile(bit))
+ end
+ end
+ return lua
+ end
+ return operate_on_text(code)
+ end,
+ ["= lua"] = function(self, code)
+ return self:compile(SyntaxTree({
+ type = "Action",
+ "lua",
+ ">",
+ code
+ }))
+ end,
+ ["1 as lua"] = function(self, code)
+ return LuaCode(tostring(ENVNAME) .. ":compile(", self:compile(code), ")")
+ end,
+ ["use"] = function(self, path)
+ return LuaCode(tostring(ENVNAME) .. ":use(" .. tostring(self:compile(path)) .. ")")
+ end,
+ ["export"] = function(self, path)
+ return LuaCode(tostring(ENVNAME) .. ":export(" .. tostring(self:compile(path)) .. ")")
+ end,
+ ["run"] = function(self, path)
+ return LuaCode(tostring(ENVNAME) .. ":run(" .. tostring(self:compile(path)) .. ")")
+ end,
+ ["test"] = function(self, body)
+ if not (body.type == 'Block') then
+ compile_error(body, "This should be a Block")
+ end
+ local test_nomsu = body:get_source_code():match(":[ ]*(.*)")
+ do
+ local indent = test_nomsu:match("\n([ ]*)")
+ if indent then
+ test_nomsu = test_nomsu:gsub("\n" .. indent, "\n")
+ end
+ end
+ local test_text = self:compile(SyntaxTree({
+ type = "Text",
+ source = body.source,
+ test_nomsu
+ }))
+ return LuaCode("TESTS[" .. tostring(tostring(body.source):as_lua()) .. "] = ", test_text)
+ end,
+ ["is jit"] = function(self, code)
+ return LuaCode("jit")
+ end,
+ ["Lua version"] = function(self, code)
+ return LuaCode("_VERSION")
+ end,
+ ["nomsu environment"] = function(self)
+ return LuaCode(ENVNAME)
+ end,
+ ["nomsu environment name"] = function(self)
+ return LuaCode(ENVNAME:as_lua())
+ end
+}
+return compile_actions
diff --git a/bootstrap.moon b/bootstrap.moon
new file mode 100644
index 0000000..66c8553
--- /dev/null
+++ b/bootstrap.moon
@@ -0,0 +1,125 @@
+-- This file contains a set of compile actions needed for bootstrapping
+{:match, :sub, :gsub, :format, :byte, :find} = string
+{:LuaCode, :Source} = require "code_obj"
+SyntaxTree = require "syntax_tree"
+Files = require "files"
+
+-- TODO: de-duplicate this
+pretty_error = require("pretty_errors")
+compile_error = (source, err_msg, hint=nil)->
+ local file
+ if SyntaxTree\is_instance(source)
+ file = source\get_source_file!
+ source = source.source
+ elseif type(source) == 'string'
+ source = Source\from_string(source)
+ if source and not file
+ file = Files.read(source.filename)
+
+ err_str = pretty_error{
+ title: "Compile error"
+ error:err_msg, hint:hint, source:file
+ start:source.start, stop:source.stop, filename:source.filename
+ }
+ error(err_str, 0)
+
+MAX_LINE = 80 -- For beautification purposes, try not to make lines much longer than this value
+--ENVNAME = jit and "getfenv(1)" or "_ENV"
+ENVNAME = jit and "_G" or "_ENV"
+compile_actions = {
+ [""]: (fn, ...)=>
+ lua = LuaCode!
+ fn_lua = @compile(fn)
+ lua\add fn_lua
+ unless fn_lua\text!\match("^%(.*%)$") or fn_lua\text!\match("^[_a-zA-Z][_a-zA-Z0-9.]*$")
+ lua\parenthesize!
+ lua\add "("
+ for i=1,select('#',...)
+ lua\add(", ") if i > 1
+ lua\add @compile((select(i, ...)))
+ lua\add ")"
+ return lua
+
+ ["Lua"]: (code)=>
+ if not code
+ return LuaCode("LuaCode()")
+ if code.type != "Text"
+ return LuaCode("LuaCode:from(", tostring(code.source)\as_lua!, ", ", @compile(code), ")")
+
+ operate_on_text = (text)->
+ lua = LuaCode\from(text.source, "LuaCode:from(", tostring(text.source)\as_lua!)
+ for bit in *text
+ local bit_lua
+ if type(bit) == "string"
+ bit_lua = bit\as_lua!
+ elseif bit.type == "Text"
+ bit_lua = operate_on_text(bit)
+ elseif bit.type == "Block"
+ bit_lua = LuaCode\from bit.source, "(function()",
+ "\n local _lua = LuaCode:from(", tostring(bit.source)\as_lua!, ")",
+ "\n local function add(...) _lua:add(...) end",
+ "\n local function join_with(glue)",
+ "\n local old_bits = _lua.bits",
+ "\n _lua = LuaCode:from(_lua.source)",
+ "\n _lua:concat_add(old_bits, glue)",
+ "\n end",
+ "\n ", @compile(bit),
+ "\n return _lua",
+ "\nend)()"
+ else
+ bit_lua = @compile(bit)
+
+ bit_leading_len = #(bit_lua\match("^[^\n]*"))
+ lua\add(lua\trailing_line_len! + bit_leading_len > MAX_LINE and ",\n " or ", ")
+ lua\add(bit_lua)
+ lua\add ")"
+ return lua
+
+ return operate_on_text code
+
+ ["lua >"]: (code)=>
+ if code.type != "Text"
+ return code
+ operate_on_text = (text)->
+ lua = LuaCode\from(text.source)
+ for bit in *text
+ if type(bit) == "string"
+ lua\add bit
+ elseif bit.type == "Text"
+ lua\add(operate_on_text(bit))
+ else
+ lua\add @compile(bit)
+ return lua
+ return operate_on_text code
+
+ ["= lua"]: (code)=>
+ @compile(SyntaxTree{type:"Action", "lua", ">", code})
+
+ ["1 as lua"]: (code)=>
+ LuaCode("#{ENVNAME}:compile(", @compile(code), ")")
+
+ ["use"]: (path)=>
+ LuaCode("#{ENVNAME}:use(#{@compile(path)})")
+
+ ["export"]: (path)=>
+ LuaCode("#{ENVNAME}:export(#{@compile(path)})")
+
+ ["run"]: (path)=>
+ LuaCode("#{ENVNAME}:run(#{@compile(path)})")
+
+ ["test"]: (body)=>
+ unless body.type == 'Block'
+ compile_error(body, "This should be a Block")
+ test_nomsu = body\get_source_code!\match(":[ ]*(.*)")
+ if indent = test_nomsu\match("\n([ ]*)")
+ test_nomsu = test_nomsu\gsub("\n"..indent, "\n")
+ test_text = @compile(SyntaxTree{type:"Text", source:body.source, test_nomsu})
+ return LuaCode "TESTS[#{tostring(body.source)\as_lua!}] = ", test_text
+
+ ["is jit"]: (code)=> LuaCode("jit")
+ ["Lua version"]: (code)=> LuaCode("_VERSION")
+ ["nomsu environment"]: ()=> LuaCode(ENVNAME)
+ ["nomsu environment name"]: ()=> LuaCode(ENVNAME\as_lua!)
+}
+
+return compile_actions
diff --git a/code_obj.lua b/code_obj.lua
index a09608f..05de45b 100644
--- a/code_obj.lua
+++ b/code_obj.lua
@@ -163,6 +163,9 @@ do
repeat
local b = select(i, ...)
assert(b, "code bit is nil")
+ if b.Dict then
+ require('ldt').breakpoint()
+ end
assert(not Source:is_instance(b), "code bit is a Source")
if b == '' then
_continue_0 = true
diff --git a/code_obj.moon b/code_obj.moon
index 9315264..3c0294a 100644
--- a/code_obj.moon
+++ b/code_obj.moon
@@ -98,6 +98,8 @@ class Code
for i=1,n
b = select(i, ...)
assert(b, "code bit is nil")
+ if b.Dict
+ require('ldt').breakpoint()
assert(not Source\is_instance(b), "code bit is a Source")
if b == '' then continue
bits[#bits+1] = b
diff --git a/compatibility/2.3.nom b/compatibility/2.3.nom
index 5b62bc3..67870ac 100644
--- a/compatibility/2.3.nom
+++ b/compatibility/2.3.nom
@@ -2,7 +2,7 @@
#
This file defines upgrades from Nomsu <2.3 to Nomsu 2.3
-use "compatibility/compatibility.nom"
+use "compatibility/compatibility"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/compatibility/2.4.nom b/compatibility/2.4.nom
index 213966b..e0d2e02 100644
--- a/compatibility/2.4.nom
+++ b/compatibility/2.4.nom
@@ -2,7 +2,7 @@
#
This file defines upgrades from Nomsu <2.4 to Nomsu 2.4
-use "compatibility/compatibility.nom"
+use "compatibility/compatibility"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/compatibility/2.5.5.5.nom b/compatibility/2.5.5.5.nom
index 52f21eb..c026a42 100644
--- a/compatibility/2.5.5.5.nom
+++ b/compatibility/2.5.5.5.nom
@@ -2,7 +2,7 @@
#
This file defines upgrades from Nomsu <2.5.5.5 to Nomsu 2.5.5.5
-use "compatibility/compatibility.nom"
+use "compatibility/compatibility"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/compatibility/2.5.nom b/compatibility/2.5.nom
index 92fb2ac..03b3f61 100644
--- a/compatibility/2.5.nom
+++ b/compatibility/2.5.nom
@@ -2,7 +2,7 @@
#
This file defines upgrades from Nomsu <2.5 to Nomsu 2.5
-use "compatibility/compatibility.nom"
+use "compatibility/compatibility"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/compatibility/2.nom b/compatibility/2.nom
index cd84546..caf7a86 100644
--- a/compatibility/2.nom
+++ b/compatibility/2.nom
@@ -2,7 +2,7 @@
#
This file defines upgrades from Nomsu 1 to Nomsu 2
-use "compatibility/compatibility.nom"
+use "compatibility/compatibility"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/compatibility/3.5.5.6.nom b/compatibility/3.5.5.6.nom
index 4323749..6528526 100644
--- a/compatibility/3.5.5.6.nom
+++ b/compatibility/3.5.5.6.nom
@@ -2,7 +2,7 @@
#
This file defines upgrades from Nomsu <3.5.5.6 to Nomsu 3.5.5.6
-use "compatibility/compatibility.nom"
+use "compatibility/compatibility"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/compatibility/3.6.nom b/compatibility/3.6.nom
index 2f1a460..5db2aae 100644
--- a/compatibility/3.6.nom
+++ b/compatibility/3.6.nom
@@ -2,7 +2,7 @@
#
This file defines upgrades from Nomsu <3.6 to 3.6
-use "compatibility/compatibility.nom"
+use "compatibility/compatibility"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/compatibility/3.7.nom b/compatibility/3.7.nom
index b68d64c..ed877a6 100644
--- a/compatibility/3.7.nom
+++ b/compatibility/3.7.nom
@@ -2,7 +2,7 @@
#
This file defines upgrades from Nomsu <3.7 to 3.7
-use "compatibility/compatibility.nom"
+use "compatibility/compatibility"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/compatibility/3.nom b/compatibility/3.nom
index 9606073..af5c2fd 100644
--- a/compatibility/3.nom
+++ b/compatibility/3.nom
@@ -2,7 +2,7 @@
#
This file defines upgrades from Nomsu <=2 to Nomsu 3
-use "compatibility/compatibility.nom"
+use "compatibility/compatibility"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/compatibility/4.10.12.7.nom b/compatibility/4.10.12.7.nom
index e8a3161..e88b5be 100644
--- a/compatibility/4.10.12.7.nom
+++ b/compatibility/4.10.12.7.nom
@@ -1,7 +1,7 @@
#!/usr/bin/env nomsu -V6.14
#
This file defines upgrades from Nomsu <4.10.12.7 to 4.10.12.7
-use "compatibility/compatibility.nom"
+use "compatibility/compatibility"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/compatibility/4.11.nom b/compatibility/4.11.nom
index 8ca9edc..7864bc2 100644
--- a/compatibility/4.11.nom
+++ b/compatibility/4.11.nom
@@ -3,7 +3,7 @@
This file defines upgrades from Nomsu <4.11 to Nomsu 4.11
(overhaul of function literals, deleting (if all of ...), etc. shorthand)
-use "compatibility/compatibility.nom"
+use "compatibility/compatibility"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/compatibility/4.12.nom b/compatibility/4.12.nom
index 215c114..a76e7df 100644
--- a/compatibility/4.12.nom
+++ b/compatibility/4.12.nom
@@ -3,7 +3,7 @@
This file defines upgrades from Nomsu <4.11 to Nomsu 4.11
(overhaul of function literals, deleting (if all of ...), etc. shorthand)
-use "compatibility/compatibility.nom"
+use "compatibility/compatibility"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/compatibility/4.8.10.nom b/compatibility/4.8.10.nom
index 0752744..250dc4a 100644
--- a/compatibility/4.8.10.nom
+++ b/compatibility/4.8.10.nom
@@ -1,7 +1,7 @@
#!/usr/bin/env nomsu -V6.14
#
This file defines upgrades from Nomsu <4.8.10 to 4.8.10 (renaming "action" -> "means")
-use "compatibility/compatibility.nom"
+use "compatibility/compatibility"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/compatibility/4.9.nom b/compatibility/4.9.nom
index c1b5d3e..14b5dd6 100644
--- a/compatibility/4.9.nom
+++ b/compatibility/4.9.nom
@@ -1,7 +1,7 @@
#!/usr/bin/env nomsu -V6.14
#
This file defines upgrades from Nomsu <4.9 to 4.9
-use "compatibility/compatibility.nom"
+use "compatibility/compatibility"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/compatibility/5.13.nom b/compatibility/5.13.nom
index b4100bf..1e0db6d 100644
--- a/compatibility/5.13.nom
+++ b/compatibility/5.13.nom
@@ -1,7 +1,7 @@
#!/usr/bin/env nomsu -V5.13
#
This file defines upgrades from Nomsu <5.13 to 5.13
-use "compatibility/compatibility.nom"
+use "compatibility/compatibility"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/compatibility/6.14.nom b/compatibility/6.14.nom
index 01d3fac..affdabf 100644
--- a/compatibility/6.14.nom
+++ b/compatibility/6.14.nom
@@ -1,7 +1,7 @@
#!/usr/bin/env nomsu -V6.14
#
This file defines upgrades from Nomsu <6.14 to 6.14
-use "compatibility/compatibility.nom"
+use "compatibility/compatibility"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/compatibility/compatibility.nom b/compatibility/compatibility.nom
index 60baf17..e0449c8 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.nom"
+use "lib/os"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/core/collections.nom b/core/collections.nom
index 18b1af6..4cf54cd 100644
--- a/core/collections.nom
+++ b/core/collections.nom
@@ -3,9 +3,9 @@
This file contains code that supports manipulating and using collections like lists
and dictionaries.
-use "core/metaprogramming.nom"
-use "core/control_flow.nom"
-use "core/operators.nom"
+use "core/metaprogramming"
+use "core/control_flow"
+use "core/operators"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/core/control_flow.nom b/core/control_flow.nom
index 5c90bcc..b0c4f27 100644
--- a/core/control_flow.nom
+++ b/core/control_flow.nom
@@ -3,8 +3,8 @@
This file contains compile-time actions that define basic control flow structures
like "if" statements and loops.
-use "core/metaprogramming.nom"
-use "core/operators.nom"
+use "core/metaprogramming"
+use "core/operators"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -464,29 +464,26 @@ test:
assume (sorted $flat) == [1, 2, 3, 4, 5, 6]
# Recurion control flow
+(recurse $v on $x) compiles to
+ Lua "table.insert(_stack_\($v as lua expr), \($x as lua expr))"
(for $var in recursive $structure $body) compiles to:
- with local compile actions:
- define mangler
- (recurse $v on $x) compiles to
- Lua "table.insert(\(mangle "stack \($v.1)"), \($x as lua expr))"
-
- $lua =
- Lua ("
- do
- local \(mangle "stack \($var.1)") = List{\($structure as lua expr)}
- while #\(mangle "stack \($var.1)") > 0 do
- \($var as lua expr) = table.remove(\(mangle "stack \($var.1)"), 1)
- \($body as lua)
- ")
-
- if ($body has subtree \(do next)):
- $lua, add "\n ::continue::"
-
- if ($body has subtree \(do next $var)):
- $lua, add "\n \(\(---next $var ---) as lua)"
-
- $lua, add "\n end -- Recursive loop"
- if ($body has subtree \(stop $var)):
- $lua, add "\n \(\(---stop $var ---) as lua)"
- $lua, add "\nend -- Recursive scope"
- return $lua
+ $lua =
+ Lua ("
+ do
+ local _stack_\($var as lua expr) = List{\($structure as lua expr)}
+ while #_stack_\($var as lua expr) > 0 do
+ \($var as lua expr) = table.remove(_stack_\($var as lua expr), 1)
+ \($body as lua)
+ ")
+
+ if ($body has subtree \(do next)):
+ $lua, add "\n ::continue::"
+
+ if ($body has subtree \(do next $var)):
+ $lua, add "\n \(\(---next $var ---) as lua)"
+
+ $lua, add "\n end -- Recursive loop"
+ if ($body has subtree \(stop $var)):
+ $lua, add "\n \(\(---stop $var ---) as lua)"
+ $lua, add "\nend -- Recursive scope"
+ return $lua
diff --git a/core/coroutines.nom b/core/coroutines.nom
index 4b4639a..6a99f7e 100644
--- a/core/coroutines.nom
+++ b/core/coroutines.nom
@@ -2,9 +2,9 @@
#
This file defines the code that creates and manipulates coroutines
-use "core/metaprogramming.nom"
-use "core/operators.nom"
-use "core/control_flow.nom"
+use "core/metaprogramming"
+use "core/operators"
+use "core/control_flow"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/core/errors.nom b/core/errors.nom
index 12b0065..45fc8c5 100644
--- a/core/errors.nom
+++ b/core/errors.nom
@@ -2,8 +2,8 @@
#
This file contains basic error reporting code
-use "core/metaprogramming.nom"
-use "core/operators.nom"
+use "core/metaprogramming"
+use "core/operators"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/core/id.nom b/core/id.nom
index 61ffeaa..d2427b5 100644
--- a/core/id.nom
+++ b/core/id.nom
@@ -2,11 +2,11 @@
#
A simple UUID function based on RFC 4122: http://www.ietf.org/rfc/rfc4122.txt
-use "core/metaprogramming.nom"
-use "core/operators.nom"
-use "core/math.nom"
-use "core/collections.nom"
-use "core/control_flow.nom"
+use "core/metaprogramming"
+use "core/operators"
+use "core/math"
+use "core/collections"
+use "core/control_flow"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/core/init.nom b/core/init.nom
new file mode 100644
index 0000000..0c8051d
--- /dev/null
+++ b/core/init.nom
@@ -0,0 +1,11 @@
+# Export everything
+export "core/metaprogramming"
+export "core/operators"
+export "core/control_flow"
+export "core/errors"
+export "core/collections"
+export "core/coroutines"
+export "core/math"
+export "core/id"
+export "core/io"
+export "core/text"
diff --git a/core/io.nom b/core/io.nom
index 0084834..7afe889 100644
--- a/core/io.nom
+++ b/core/io.nom
@@ -2,7 +2,7 @@
#
This file contains basic input/output code
-use "core/metaprogramming.nom"
+use "core/metaprogramming"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/core/math.nom b/core/math.nom
index decb0bc..685ab1e 100644
--- a/core/math.nom
+++ b/core/math.nom
@@ -2,11 +2,11 @@
#
This file defines some common math literals and functions
-use "core/metaprogramming.nom"
-use "core/text.nom"
-use "core/operators.nom"
-use "core/control_flow.nom"
-use "core/collections.nom"
+use "core/metaprogramming"
+use "core/text"
+use "core/operators"
+use "core/control_flow"
+use "core/collections"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/core/metaprogramming.nom b/core/metaprogramming.nom
index c950e97..85d342c 100644
--- a/core/metaprogramming.nom
+++ b/core/metaprogramming.nom
@@ -16,15 +16,15 @@ lua> ("
end
end
end
- compile.action["define mangler"] = function(compile)
+ COMPILE_RULES["define mangler"] = function(\(nomsu environment))
return LuaCode("local mangle = mangler()")
end
")
lua> ("
- compile.action["1 ->"] = function(compile, \$args, \$body)
+ COMPILE_RULES["1 ->"] = function(\(nomsu environment), \$args, \$body)
if \$args and not \$body then \$args, \$body = {}, \$args end
- local body_lua = SyntaxTree:is_instance(\$body) and compile(\$body) or \$body
+ local body_lua = SyntaxTree:is_instance(\$body) and \(nomsu environment):compile(\$body) or \$body
if SyntaxTree:is_instance(\$body) and \$body.type ~= "Block" then body_lua:prepend("\
..return ") end
local lua = LuaCode("(function(")
@@ -32,7 +32,7 @@ lua> ("
\$args = \$args:get_args()
elseif SyntaxTree:is_instance(\$args) and \$args.type == "Var" then \$args = {\$args} end
for i, arg in ipairs(\$args) do
- local arg_lua = SyntaxTree:is_instance(arg) and compile(arg):text() or arg
+ local arg_lua = SyntaxTree:is_instance(arg) and \(nomsu environment):compile(arg):text() or arg
if arg_lua == "..." then
if i < #\$args then
compile_error_at(SyntaxTree:is_instance(arg) and arg or nil,
@@ -52,8 +52,8 @@ lua> ("
lua:add(")\\n ", body_lua, "\\nend)")
return lua
end
- compile.action["->"] = compile.action["1 ->"]
- compile.action["for"] = compile.action["1 ->"]
+ COMPILE_RULES["->"] = COMPILE_RULES["1 ->"]
+ COMPILE_RULES["for"] = COMPILE_RULES["1 ->"]
")
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -85,12 +85,12 @@ test:
fail "compile to is leaking variables"
lua> ("
- compile.action["1 compiles to"] = function(compile, \$action, \$body)
- local \$args = List{\(\$compile), unpack(\$action:get_args())}
+ COMPILE_RULES["1 compiles to"] = function(env, \$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}
end
- return LuaCode("compile.action[", \$action:get_stub():as_lua(),
+ return LuaCode("COMPILE_RULES[", \$action:get_stub():as_lua(),
"] = ", \(\($args -> $body) as lua))
end
")
@@ -103,18 +103,21 @@ lua> ("
compile_error(\$actions, "This should be a list of actions.")
end
local lua = \(\($actions.1 compiles to $body) as lua)
- local \$args = List{\(\$compile), unpack(\$actions[1]:get_args())}
- local \$compiled_args = List(table.map(\$args, compile))
+ local \$args = List{"\(nomsu environment)", unpack(\$actions[1]:get_args())}
+ local \$compiled_args = List{"\(nomsu environment)"};
+ for i=2,#\$args do \$compiled_args[i] = \(nomsu environment):compile(\$args[i]) end
for i=2,#\$actions do
local alias = \$actions[i]
- local \$alias_args = List{\(\$compile), unpack(alias:get_args())}
- lua:add("\\ncompile.action[", alias:get_stub():as_lua(), "] = ")
+ local \$alias_args = List{"\(nomsu environment)", unpack(alias:get_args())}
+ lua:add("\\nCOMPILE_RULES[", alias:get_stub():as_lua(), "] = ")
if \$alias_args == \$args then
- lua:add("compile.action[", \$actions[1]:get_stub():as_lua(), "]")
+ lua:add("COMPILE_RULES[", \$actions[1]:get_stub():as_lua(), "]")
else
lua:add("function(")
- lua:concat_add(table.map(\$alias_args, compile), ", ")
- lua:add(") return compile.action[", \$actions[1]:get_stub():as_lua(), "](")
+ local \$compiled_alias_args = List{"\(nomsu environment)"};
+ for i=2,#\$alias_args do \$compiled_alias_args[i] = \(nomsu environment):compile(\$alias_args[i]) end
+ lua:concat_add(\$compiled_alias_args, ", ")
+ lua:add(") return COMPILE_RULES[", \$actions[1]:get_stub():as_lua(), "](")
lua:concat_add(\$compiled_args, ", ")
lua:add(") end")
end
@@ -145,7 +148,7 @@ test:
local lua = LuaCode()
if \$action.type == "MethodCall" then
- lua:add(compile(\$action[1]), ".", \$action[2]:get_stub():as_lua_id())
+ lua:add(\(nomsu environment):compile(\$action[1]), ".", \$action[2]:get_stub():as_lua_id())
elseif \$action.type == "Action" then
lua:add(\$action:get_stub():as_lua_id())
lua:add_free_vars({\$action:get_stub():as_lua_id()})
@@ -160,7 +163,7 @@ test:
lua> ("
local lua = \(\($actions.1 means $body) as lua)
local first_def = (\$actions[1].type == "MethodCall"
- and LuaCode(compile(\$actions[1][1]), ".", \$actions[1]:get_stub():as_lua_id())
+ and LuaCode(\(nomsu environment):compile(\$actions[1][1]), ".", \$actions[1]:get_stub():as_lua_id())
or LuaCode(\$actions[1]:get_stub():as_lua_id()))
local \$args = List(\$actions[1]:get_args())
for i=2,#\$actions do
@@ -168,7 +171,7 @@ test:
local \$alias_args = List(alias:get_args())
lua:add("\\n")
if alias.type == "MethodCall" then
- lua:add(compile(alias[1]), ".", alias:get_stub():as_lua_id())
+ lua:add(\(nomsu environment):compile(alias[1]), ".", alias:get_stub():as_lua_id())
else
lua:add(alias:get_stub():as_lua_id())
lua:add_free_vars({alias_name})
@@ -229,7 +232,7 @@ test:
compile_error(\$actions, "This should be a list.")
end
for i,arg in ipairs(\$actions[1]:get_args()) do
- replacements[arg[1]] = compile(arg):text()
+ replacements[arg[1]] = \(nomsu environment):compile(arg):text()
end
local function make_tree(t)
if SyntaxTree:is_instance(t) and t.type == "Var" then
@@ -273,7 +276,7 @@ test:
[$action parses as $body] all parse as ([$action] all parse as $body)
externally ($tree as lua expr) means:
lua> ("
- local tree_lua = compile(\$tree)
+ local tree_lua = \(nomsu environment):compile(\$tree)
if \$tree.type == 'Block' then
tree_lua = LuaCode:from(\$tree.source, '(function()\\n ', tree_lua, '\\nend)()')
elseif \$tree.type == 'MethodCall' and #\$tree > 2 then
@@ -404,18 +407,6 @@ externally (type of $) means:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test:
- assume ((run "return (2 + 99)") == 101)
- $x = 0
- externally (set to $) means:
- external $x = $
- run "set to 1"
- assume $x == 1
- assume (run \(return \(\(5) + \(5)))) == 10
-(run $nomsu_code) compiles to "run_1_in(\($nomsu_code as lua expr), _ENV)"
-[compile $block, compiled $block, $block compiled] all compile to
- "compile(\($block as lua))"
-
-test:
(foo) means:
return 100 200 300
assume (select 2 (foo)) == 200
@@ -427,7 +418,7 @@ test:
local lua = \(Lua "do return ")
for i=1,select('#',...) do
if i > 1 then lua:add(", ") end
- lua:add(_1_as_lua((select(i, ...))))
+ lua:add(\(nomsu environment):compile((select(i, ...))))
end
lua:add(" end")
return lua
@@ -445,15 +436,17 @@ test:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-(with local compile actions $body) compiles to ("
- do
- --local compile = _1_forked(compile)
- local old_action = compile.action
- compile.action = _1_forked(old_action)
- \($body as lua)
- compile.action = old_action
- end
-")
+#
+ (with local compile actions $body) compiles to ("
+ do
+ local OLD_RULES = COMPILE_RULES
+ local OLD_ENV = \(nomsu environment)
+ local \(nomsu environment) = setmetatable({
+ COMPILE_RULES=setmetatable({}, {__index=OLD_RULES})
+ }, {__index=OLD_ENV})
+ \($body as lua)
+ end
+ ")
externally (Nomsu version) means:
return ("
diff --git a/core/operators.nom b/core/operators.nom
index 4d72643..dee76b6 100644
--- a/core/operators.nom
+++ b/core/operators.nom
@@ -2,7 +2,7 @@
#
This file contains definitions of operators like "+" and "and".
-use "core/metaprogramming.nom"
+use "core/metaprogramming"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -101,7 +101,7 @@ test:
(with external $externs $body) compiles to:
$body_lua = ($body as lua)
lua> ("
- \$body_lua:remove_free_vars(table.map(\$externs, function(v) return compile(v):text() end))
+ \$body_lua:remove_free_vars(table.map(\$externs, function(v) return \(nomsu environment):compile(v):text() end))
")
return $body_lua
diff --git a/core/text.nom b/core/text.nom
index ad57498..1351af6 100644
--- a/core/text.nom
+++ b/core/text.nom
@@ -3,9 +3,9 @@
This file contains some definitions of text escape sequences, including ANSI console
color codes.
-use "core/metaprogramming.nom"
-use "core/operators.nom"
-use "core/control_flow.nom"
+use "core/metaprogramming"
+use "core/operators"
+use "core/control_flow"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -75,4 +75,4 @@ $escapes = {
for $name = $str in $escapes:
with [$lua = (Lua (quote $str))]:
- $compile.action.$name = (-> $lua)
+ $(COMPILE RULES).$name = (-> $lua)
diff --git a/doc/nomsu.1 b/doc/nomsu.1
index ddeedfa..29e5f93 100644
--- a/doc/nomsu.1
+++ b/doc/nomsu.1
@@ -15,8 +15,7 @@ nomsu \- run a Nomsu program
|
.I -e nomsu_code
|
-.I -m nomsu_files...
-[--]
+.I nomsu_files... --
]
[
.I args
@@ -35,7 +34,7 @@ If no input files are provided, \fBnomsu\fR will run in interactive mode.
.BI \-t " tool"
Run the specified Nomsu tool (one of the tools/*.nom files provided with the compiler).
.TP
-.BI \-m " file1 file2... " [--]
+.BI " file1 file2... --"
Run multiple files. If a "--" is supplied, any additional arguments will be treated as arguments for the files, rather than additional files.
.TP
.BI \-e " code"
@@ -93,7 +92,7 @@ Compiles the Nomsu file 'my_file.nom' into a Lua file called 'my_file.lua'
.TP
.B
-nomsu -m one.nom two.nom three.nom
+nomsu one.nom two.nom three.nom --
Runs 'one.nom', then 'two.nom', then 'three.nom'.
.TP
diff --git a/examples/how_do_i.nom b/examples/how_do_i.nom
index edd226a..14e7481 100644
--- a/examples/how_do_i.nom
+++ b/examples/how_do_i.nom
@@ -7,7 +7,7 @@
(including any deeper-level indented text)
The comment ends when the indentation ends
# How do I import a file?
-use "lib/os.nom"
+use "lib/os"
# How do I import all the files in a directory?
use "lib"
diff --git a/files.lua b/files.lua
index d346945..036471f 100644
--- a/files.lua
+++ b/files.lua
@@ -3,7 +3,7 @@ local re = require('re')
local Files = { }
local run_cmd
run_cmd = function(cmd)
- local f = io.popen(cmd)
+ local f = io.popen(cmd .. ' 2>/dev/null')
local lines
do
local _accum_0 = { }
@@ -84,7 +84,7 @@ Files.list = function(path)
path
}
else
- _BROWSE_CACHE[path] = run_cmd('find -L "' .. path .. '" -not -path "*/\\.*" -type f 2>/dev/null') or false
+ _BROWSE_CACHE[path] = run_cmd('find -L "' .. path .. '" -not -path "*/\\.*" -type f') or false
end
end
return _BROWSE_CACHE[path]
@@ -158,7 +158,7 @@ if ok then
return _BROWSE_CACHE[path]
end
else
- if not (run_cmd('find . -maxdepth 0 2>/dev/null')) then
+ if not (run_cmd('find . -maxdepth 0')) then
local url
if jit then
url = 'https://github.com/spacewander/luafilesystem'
diff --git a/files.moon b/files.moon
index b277120..3950ce3 100644
--- a/files.moon
+++ b/files.moon
@@ -4,7 +4,7 @@ re = require 're'
Files = {}
run_cmd = (cmd)->
- f = io.popen(cmd)
+ f = io.popen(cmd..' 2>/dev/null')
lines = [line for line in f\lines!]
return nil unless f\close!
return lines
@@ -57,7 +57,7 @@ Files.list = (path)->
local files
_BROWSE_CACHE[path] = if _SPOOFED_FILES[path] or path == 'stdin' or path == '-'
{path}
- else run_cmd('find -L "'..path..'" -not -path "*/\\.*" -type f 2>/dev/null') or false
+ else run_cmd('find -L "'..path..'" -not -path "*/\\.*" -type f') or false
return _BROWSE_CACHE[path]
ok, lfs = pcall(require, "lfs")
@@ -93,7 +93,7 @@ if ok
if f\match("^%./") then _BROWSE_CACHE[path][i] = f\sub(3)
return _BROWSE_CACHE[path]
else
- unless run_cmd('find . -maxdepth 0 2>/dev/null')
+ unless run_cmd('find . -maxdepth 0')
url = if jit
'https://github.com/spacewander/luafilesystem'
else 'https://github.com/keplerproject/luafilesystem'
diff --git a/importer.lua b/importer.lua
deleted file mode 100644
index 0d45db8..0000000
--- a/importer.lua
+++ /dev/null
@@ -1,85 +0,0 @@
-local import_to_1_from
-import_to_1_from = function(host, to_import, prefix)
- if prefix == nil then
- prefix = nil
- end
- do
- local host_mt = getmetatable(host)
- if host_mt then
- if host_mt.__import then
- host_mt.__import(host, to_import, prefix)
- return
- end
- end
- end
- for k, v in pairs(to_import) do
- if k == to_import then
- k = host
- end
- if v == to_import then
- v = host
- end
- if prefix and type(k) == 'string' then
- k = prefix .. k
- end
- host[k] = v
- end
-end
-local _imports = setmetatable({ }, {
- __mode = "k"
-})
-local Importer = setmetatable({
- __index = function(self, key)
- return _imports[self][key]
- end,
- __import = function(self, to_import, prefix)
- if prefix == nil then
- prefix = nil
- end
- local imports = assert(_imports[self])
- for k, v in pairs(to_import) do
- local _continue_0 = false
- repeat
- if prefix and type(k) == 'string' then
- k = prefix .. k
- end
- imports[k] = v
- if v == to_import then
- _continue_0 = true
- break
- end
- local conflict = self[k]
- do
- local conflict_mt = getmetatable(host)
- if conflict_mt then
- if conflict_mt.__import then
- conflict_mt.__import(conflict, v, prefix)
- end
- end
- end
- _continue_0 = true
- until true
- if not _continue_0 then
- break
- end
- end
- end
-}, {
- __call = function(self, t)
- _imports[t] = { }
- setmetatable(t, self)
- return t
- end
-})
-local _1_forked
-_1_forked = function(self, t)
- local f = Importer(t or { })
- _imports[f] = assert(_imports[self])
- import_to_1_from(f, self)
- return f
-end
-return {
- Importer = Importer,
- import_to_1_from = import_to_1_from,
- _1_forked = _1_forked
-}
diff --git a/importer.moon b/importer.moon
deleted file mode 100644
index 26b78f7..0000000
--- a/importer.moon
+++ /dev/null
@@ -1,47 +0,0 @@
--- This file defines Importer, which is a type of table that can import from other tables
-
-import_to_1_from = (host, to_import, prefix=nil)->
- if host_mt = getmetatable(host)
- if host_mt.__import
- host_mt.__import(host, to_import, prefix)
- return
- for k,v in pairs(to_import)
- if k == to_import then k = host
- if v == to_import then v = host
- if prefix and type(k) == 'string'
- --print "PREFIXING #{k} -> #{prefix..k}"
- k = prefix..k
- --print("IMPORTED (#{k})")
- host[k] = v
-_imports = setmetatable({}, {__mode:"k"})
-Importer = setmetatable({
- __index: (key)=> _imports[@][key]
- __import: (to_import, prefix=nil)=>
- imports = assert _imports[@]
- for k,v in pairs(to_import)
- if prefix and type(k) == 'string'
- k = prefix..k
- --print("IMPORTED (#{k})")
- imports[k] = v
- continue if v == to_import
- conflict = @[k]
- if conflict_mt = getmetatable(host)
- if conflict_mt.__import
- conflict_mt.__import(conflict, v, prefix)
- --__newindex: (k,v)=>
- -- print("DEFINED (#{k})")
- -- rawset(@, k, v)
-}, {
- __call: (t)=>
- _imports[t] = {}
- setmetatable(t, @)
- return t
-})
-
-_1_forked = (t)=>
- f = Importer(t or {})
- _imports[f] = assert _imports[@]
- import_to_1_from(f, @)
- return f
-
-return {:Importer, :import_to_1_from, :_1_forked}
diff --git a/lib/consolecolor.nom b/lib/consolecolor.nom
index db29b9f..d1da247 100644
--- a/lib/consolecolor.nom
+++ b/lib/consolecolor.nom
@@ -18,7 +18,7 @@ $colors = {
for $name = $colornum in $colors:
$colornum = "\$colornum"
- $compile.action.$name =
+ $(COMPILE RULES).$name =
for ($compile $text):
if $text:
return (Lua "('\\027[\($colornum)m'..\($text as lua expr)..'\\027[0m')")
diff --git a/lib/file_hash.nom b/lib/file_hash.nom
index ec39e29..70446ca 100644
--- a/lib/file_hash.nom
+++ b/lib/file_hash.nom
@@ -2,8 +2,8 @@
#
This file defines some actions for hashing files and looking up files by hash.
-use "lib/os.nom"
-use "lib/base64.nom"
+use "lib/os"
+use "lib/base64"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/lib/object.nom b/lib/object.nom
index 13a9ec5..a3a8d93 100644
--- a/lib/object.nom
+++ b/lib/object.nom
@@ -108,7 +108,7 @@ test:
return inst
end,
})
- _ENV[class.name:as_lua_id()] = class
+ \(nomsu environment name)[class.name:as_lua_id()] = class
class.__index = class
class.class = class
class.__tostring = function(inst)
diff --git a/lib/os.nom b/lib/os.nom
index 916f18c..87b3426 100644
--- a/lib/os.nom
+++ b/lib/os.nom
@@ -2,21 +2,12 @@
#
This file defines some actions that interact with the operating system and filesystem.
-test:
- assume (nomsu files for "core")
-
externally (files for $path) means:
$files = (=lua "Files.list(\$path)")
if $files:
$files = (List $files)
return $files
-externally (nomsu files for $path) means:
- for $nomsupath in ($package.nomsupath, all matches of "[^;]+"):
- $files = (files for "\($nomsupath)/\$path")
- if $files:
- return $files
-
externally (=sh $cmd) means:
lua> ("
local result = io.popen(\$cmd)
diff --git a/lib/things.nom b/lib/things.nom
index 32942d9..84682b3 100644
--- a/lib/things.nom
+++ b/lib/things.nom
@@ -5,7 +5,6 @@
test:
an (Empty) is a thing
a (Dog) is a thing:
- [$it, $its] = [Dog, Dog]
($its, set up) means:
$its.barks or= 0
@@ -37,7 +36,6 @@ test:
assume (($d, bark) == "Bark!")
a (Corgi) is a thing:
- [$it, $its] = [Corgi, Corgi]
$it [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"
@@ -61,7 +59,6 @@ test:
assume (($d, bark) == "Bark! Bark!")
a (Vec) is a thing with {.x, .y}:
- $its = (Vec)
($its, + $other) means (Vec {.x = ($its.x + $other.x), .y = ($its.y + $other.y)})
assume ((Vec {.x = 1, .y = 2}) + (Vec {.x = 10, .y = 10})) ==
@@ -145,6 +142,7 @@ externally (a class named $classname with $members $(initialize $)) means:
(
Lua ("
, function(\$class_id)
+ local it, its = \$class_id, \$class_id;
\$body_lua
end
")
diff --git a/nomsu.lua b/nomsu.lua
index 2f8856f..88bf986 100644
--- a/nomsu.lua
+++ b/nomsu.lua
@@ -1,70 +1,19 @@
+if NOMSU_VERSION and NOMSU_PREFIX then
+ package.path = tostring(NOMSU_PREFIX) .. "/share/nomsu/" .. tostring(NOMSU_VERSION) .. "/?.lua;" .. package.path
+ package.cpath = tostring(NOMSU_PREFIX) .. "/lib/nomsu/" .. tostring(NOMSU_VERSION) .. "/?.so;" .. package.cpath
+end
local EXIT_SUCCESS, EXIT_FAILURE = 0, 1
if _VERSION == "Lua 5.1" and not jit then
print("Sorry, Nomsu does not run on Lua 5.1. Please use LuaJIT 2+ or Lua 5.2+")
os.exit(EXIT_FAILURE)
end
-if NOMSU_VERSION and NOMSU_PREFIX then
- local ver_bits
- do
- local _accum_0 = { }
- local _len_0 = 1
- for ver_bit in NOMSU_VERSION:gmatch("[0-9]+") do
- _accum_0[_len_0] = ver_bit
- _len_0 = _len_0 + 1
- end
- ver_bits = _accum_0
- end
- local partial_vers
- do
- local _accum_0 = { }
- local _len_0 = 1
- for i = #ver_bits, 1, -1 do
- _accum_0[_len_0] = table.concat(ver_bits, '.', 1, i)
- _len_0 = _len_0 + 1
- end
- partial_vers = _accum_0
- end
- package.path = table.concat((function()
- local _accum_0 = { }
- local _len_0 = 1
- for _index_0 = 1, #partial_vers do
- local v = partial_vers[_index_0]
- _accum_0[_len_0] = tostring(NOMSU_PREFIX) .. "/share/nomsu/" .. tostring(v) .. "/?.lua"
- _len_0 = _len_0 + 1
- end
- return _accum_0
- end)(), ";") .. ";" .. package.path
- package.cpath = table.concat((function()
- local _accum_0 = { }
- local _len_0 = 1
- for _index_0 = 1, #partial_vers do
- local v = partial_vers[_index_0]
- _accum_0[_len_0] = tostring(NOMSU_PREFIX) .. "/lib/nomsu/" .. tostring(v) .. "/?.so"
- _len_0 = _len_0 + 1
- end
- return _accum_0
- end)(), ";") .. ";" .. package.cpath
- package.nomsupath = table.concat((function()
- local _accum_0 = { }
- local _len_0 = 1
- for _index_0 = 1, #partial_vers do
- local v = partial_vers[_index_0]
- _accum_0[_len_0] = tostring(NOMSU_PREFIX) .. "/share/nomsu/" .. tostring(v)
- _len_0 = _len_0 + 1
- end
- return _accum_0
- end)(), ";") .. ";."
-else
- package.nomsupath = "."
-end
local usage = [=[Nomsu Compiler
-Usage: (nomsu | lua nomsu.lua | moon nomsu.moon) [-V version] [--help | -h] [--version] [-O optimization level] [-v] [-c] [-s] [-d debugger] [--no-core] [(file | -t tool | -e "nomsu code..." | -m files... [--]) [nomsu args...]]
+Usage: (nomsu | lua nomsu.lua | moon nomsu.moon) [-V version] [--help | -h] [--version] [-O optimization level] [-v] [-c] [-s] [-d debugger] [--no-core] [(file | -t tool | -e "nomsu code..." | files... -- ) [nomsu args...]]
OPTIONS
-t <tool> Run a tool.
-e Execute the specified string.
- -m Run multiple files (all extra arguments).
-O <level> Run the compiler with the given optimization level (>0: use precompiled .lua versions of Nomsu files, when available).
-v Verbose: print compiled lua code.
-c Compile the input files into a .lua files.
@@ -96,21 +45,20 @@ do
local _obj_0 = require('containers')
List, Dict, Text = _obj_0.List, _obj_0.Dict, _obj_0.Text
end
-local nomsu_environment = require('nomsu_environment')
-if not arg or debug.getinfo(2).func == require then
- return nomsu_environment
-end
local sep = "\3"
local parser = re.compile([[ args <- {| (flag %sep)*
- (("-e" %sep {:execute: {[^%sep]+} :} %sep)
- / {:files: {|
- ("-t" %sep {~ {[^%sep]+} -> "nomsu://tools/%1.nom" ~} %sep
- / "-m" %sep (!("--" %sep) {[^%sep]+} %sep)* ("--" %sep)?
- / {[^%sep]+} %sep
- / {~ '' %sep? -> 'nomsu://tools/repl.nom' ~}) |} :})
+ {:files: {|
+ ( ("-m" %sep)? (!("--" %sep) file)* ("--" %sep)
+ / file
+ / {~ '' %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)
+
flag <- longflag / shortflag / "-" shortboolflag+
longflag <-
{:help: "--help" %true :}
@@ -132,7 +80,8 @@ local parser = re.compile([[ args <- {| (flag %sep)*
]], {
["true"] = lpeg.Cc(true),
number = lpeg.R("09") ^ 1 / tonumber,
- sep = lpeg.P(sep)
+ sep = lpeg.P(sep),
+ spoof = Files.spoof
})
local arg_string = table.concat(arg, sep) .. sep
local args = parser:match(arg_string)
@@ -147,74 +96,62 @@ for _index_0 = 1, #_list_0 do
nomsu_args[argpair.key] = argpair.value
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
+if optimization > 0 then
+ table.insert(nomsupath, "./?.lua")
+ table.insert(nomsupath, "./?/init.lua")
+end
+table.insert(nomsupath, "./?.nom")
+table.insert(nomsupath, "./?/init.nom")
+package.nomsupath = table.concat(nomsupath, ";")
+local nomsu_environment = require('nomsu_environment')
nomsu_environment.COMMAND_LINE_ARGS = nomsu_args
-nomsu_environment.OPTIMIZATION = tonumber(args.optimization or 1)
+nomsu_environment.OPTIMIZATION = optimization
+nomsu_environment.NOMSU_PACKAGEPATH = NOMSU_PACKAGEPATH
+nomsu_environment.NOMSU_PREFIX = NOMSU_PREFIX
local run
run = function()
if not (args.no_core) then
- for nomsupath in package.nomsupath:gmatch("[^;]+") do
- local _continue_0 = false
- repeat
- local files = Files.list(nomsupath .. "/core")
- if not (files) then
- _continue_0 = true
- break
- end
- for _index_0 = 1, #files do
- local _continue_1 = false
- repeat
- local f = files[_index_0]
- if not (f:match("%.nom$")) then
- _continue_1 = true
- break
- end
- nomsu_environment.run_file_1_in(f, nomsu_environment, nomsu_environment.OPTIMIZATION)
- _continue_1 = true
- until true
- if not _continue_1 then
- break
- end
- end
- _continue_0 = true
- until true
- if not _continue_0 then
- break
- end
- end
+ nomsu_environment:export("core")
end
if args.version then
- nomsu_environment.run_1_in("say (Nomsu version)", nomsu_environment)
+ nomsu_environment:run("say (Nomsu version)")
os.exit(EXIT_SUCCESS)
end
local input_files = { }
- if args.execute then
- table.insert(input_files, Files.spoof("<input command>", args.execute))
- end
if args.files then
local _list_1 = args.files
for _index_0 = 1, #_list_1 do
local f = _list_1[_index_0]
- local files
do
- local nomsu_name = f:match("^nomsu://(.*)")
+ local nomsu_name = f:match("^nomsu://(.*)%.nom")
if nomsu_name then
- for nomsupath in package.nomsupath:gmatch("[^;]+") do
- files = Files.list(nomsupath .. "/" .. nomsu_name)
- if files then
- break
- end
+ local path, err = package.searchpath(nomsu_name, package.nomsupath, "/")
+ if not path then
+ error(err)
end
+ table.insert(input_files, path)
else
- files = Files.list(f)
+ table.insert(input_files, f)
end
end
- if not (files and #files > 0) then
- error("Could not find: '" .. tostring(f) .. "'")
- end
- for _index_1 = 1, #files do
- local filename = files[_index_1]
- table.insert(input_files, filename)
- end
end
end
for _index_0 = 1, #input_files do
@@ -241,13 +178,13 @@ run = function()
}
end
for chunk_no, chunk in ipairs(tree) do
- local lua = nomsu_environment.compile(chunk)
+ local lua = nomsu_environment: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_1_in(chunk, nomsu_environment)
+ nomsu_environment:run(chunk)
output:write(lua:text(), "\n")
end
print(("Compiled %-25s -> %s"):format(filename, filename:gsub("%.nom$", ".lua")))
@@ -263,14 +200,18 @@ run = function()
}
end
for chunk_no, chunk in ipairs(tree) do
- local lua = nomsu_environment.compile(chunk)
+ local lua = nomsu_environment: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_1_in(lua, nomsu_environment)
+ nomsu_environment:run(lua)
end
else
- nomsu_environment.run_file_1_in(filename, nomsu_environment, 0)
+ local f = Files.read(filename)
+ if filename:match("%.lua$") then
+ f = LuaCode:from(Source(filename, 1, #f), f)
+ end
+ nomsu_environment:run(f)
end
end
end
diff --git a/nomsu.moon b/nomsu.moon
index d2981ef..b837170 100755
--- a/nomsu.moon
+++ b/nomsu.moon
@@ -1,6 +1,10 @@
#!/usr/bin/env moon
-- This file contains the command-line Nomsu runner.
+if NOMSU_VERSION and NOMSU_PREFIX
+ package.path = "#{NOMSU_PREFIX}/share/nomsu/#{NOMSU_VERSION}/?.lua;"..package.path
+ package.cpath = "#{NOMSU_PREFIX}/lib/nomsu/#{NOMSU_VERSION}/?.so;"..package.cpath
+
EXIT_SUCCESS, EXIT_FAILURE = 0, 1
if _VERSION == "Lua 5.1" and not jit
@@ -8,24 +12,14 @@ if _VERSION == "Lua 5.1" and not jit
print("Sorry, Nomsu does not run on Lua 5.1. Please use LuaJIT 2+ or Lua 5.2+")
os.exit(EXIT_FAILURE)
-if NOMSU_VERSION and NOMSU_PREFIX
- ver_bits = [ver_bit for ver_bit in NOMSU_VERSION\gmatch("[0-9]+")]
- partial_vers = [table.concat(ver_bits,'.',1,i) for i=#ver_bits,1,-1]
- package.path = table.concat(["#{NOMSU_PREFIX}/share/nomsu/#{v}/?.lua" for v in *partial_vers],";")..";"..package.path
- package.cpath = table.concat(["#{NOMSU_PREFIX}/lib/nomsu/#{v}/?.so" for v in *partial_vers],";")..";"..package.cpath
- package.nomsupath = table.concat(["#{NOMSU_PREFIX}/share/nomsu/#{v}" for v in *partial_vers],";")..";."
-else
- package.nomsupath = "."
-
usage = [=[
Nomsu Compiler
-Usage: (nomsu | lua nomsu.lua | moon nomsu.moon) [-V version] [--help | -h] [--version] [-O optimization level] [-v] [-c] [-s] [-d debugger] [--no-core] [(file | -t tool | -e "nomsu code..." | -m files... [--]) [nomsu args...]]
+Usage: (nomsu | lua nomsu.lua | moon nomsu.moon) [-V version] [--help | -h] [--version] [-O optimization level] [-v] [-c] [-s] [-d debugger] [--no-core] [(file | -t tool | -e "nomsu code..." | files... -- ) [nomsu args...]]
OPTIONS
-t <tool> Run a tool.
-e Execute the specified string.
- -m Run multiple files (all extra arguments).
-O <level> Run the compiler with the given optimization level (>0: use precompiled .lua versions of Nomsu files, when available).
-v Verbose: print compiled lua code.
-c Compile the input files into a .lua files.
@@ -47,29 +41,24 @@ if not ok
os.exit(EXIT_FAILURE)
Files = require "files"
Errhand = require "error_handling"
---NomsuCompiler = require "nomsu_compiler"
{:NomsuCode, :LuaCode, :Source} = require "code_obj"
---{:Importer, :import_to_1_from, :_1_forked} = require 'importer'
{:List, :Dict, :Text} = require 'containers'
---SyntaxTree = require "syntax_tree"
-nomsu_environment = require('nomsu_environment')
-
--- If this file was reached via require(), then just return the Nomsu compiler
-if not arg or debug.getinfo(2).func == require
- return nomsu_environment
sep = "\3"
parser = re.compile([[
args <- {| (flag %sep)*
- (("-e" %sep {:execute: {[^%sep]+} :} %sep)
- / {:files: {|
- ("-t" %sep {~ {[^%sep]+} -> "nomsu://tools/%1.nom" ~} %sep
- / "-m" %sep (!("--" %sep) {[^%sep]+} %sep)* ("--" %sep)?
- / {[^%sep]+} %sep
- / {~ '' %sep? -> 'nomsu://tools/repl.nom' ~}) |} :})
+ {:files: {|
+ ( ("-m" %sep)? (!("--" %sep) file)* ("--" %sep)
+ / file
+ / {~ '' %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)
+
flag <- longflag / shortflag / "-" shortboolflag+
longflag <-
{:help: "--help" %true :}
@@ -89,7 +78,8 @@ parser = re.compile([[
nomsu_shortboolflag <- {| {:key: [a-zA-Z] :} {:value: %true :} |}
nomsu_longflag <- '--' {| {:key: [^%sep=]+ :} {:value: ('=' {[^%sep]+}) / %true :} |}
]], {
- true:lpeg.Cc(true), number:lpeg.R("09")^1/tonumber, sep:lpeg.P(sep)
+ true:lpeg.Cc(true), number:lpeg.R("09")^1/tonumber, sep:lpeg.P(sep),
+ spoof: Files.spoof
})
arg_string = table.concat(arg, sep)..sep
args = parser\match(arg_string)
@@ -100,39 +90,54 @@ nomsu_args = Dict{}
for argpair in *args.nomsu_args
nomsu_args[argpair.key] = argpair.value
nomsu_args.extras = List(args.nomsu_args.extras or {})
+optimization = tonumber(args.optimization or 1)
+
+nomsupath = {}
+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"
+package.nomsupath = table.concat(nomsupath, ";")
+
+nomsu_environment = require('nomsu_environment')
nomsu_environment.COMMAND_LINE_ARGS = nomsu_args
-nomsu_environment.OPTIMIZATION = tonumber(args.optimization or 1)
+nomsu_environment.OPTIMIZATION = optimization
+nomsu_environment.NOMSU_PACKAGEPATH = NOMSU_PACKAGEPATH
+nomsu_environment.NOMSU_PREFIX = NOMSU_PREFIX
run = ->
unless args.no_core
- for nomsupath in package.nomsupath\gmatch("[^;]+")
- files = Files.list(nomsupath.."/core")
- continue unless files
- for f in *files
- continue unless f\match("%.nom$")
- nomsu_environment.run_file_1_in f, nomsu_environment, nomsu_environment.OPTIMIZATION
+ nomsu_environment\export("core")
if args.version
- nomsu_environment.run_1_in("say (Nomsu version)", nomsu_environment)
+ nomsu_environment\run("say (Nomsu version)")
os.exit(EXIT_SUCCESS)
input_files = {}
- if args.execute
- table.insert input_files, Files.spoof("<input command>", args.execute)
if args.files
for f in *args.files
- local files
- if nomsu_name = f\match("^nomsu://(.*)")
- for nomsupath in package.nomsupath\gmatch("[^;]+")
- files = Files.list(nomsupath.."/"..nomsu_name)
- break if files
+ if nomsu_name = f\match("^nomsu://(.*)%.nom")
+ path, err = package.searchpath(nomsu_name, package.nomsupath, "/")
+ if not path then error(err)
+ table.insert input_files, path
else
- files = Files.list(f)
- unless files and #files > 0
- error("Could not find: '#{f}'")
- for filename in *files
- table.insert input_files, filename
-
+ table.insert input_files, f
+
for filename in *input_files
if args.check_syntax
-- Check syntax
@@ -150,11 +155,11 @@ run = ->
tree = nomsu_environment._1_parsed(code)
tree = {tree} unless tree.type == 'FileChunks'
for chunk_no, chunk in ipairs tree
- lua = nomsu_environment.compile(chunk)
+ lua = nomsu_environment\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_1_in(chunk, nomsu_environment)
+ nomsu_environment\run(chunk)
output\write(lua\text!, "\n")
print ("Compiled %-25s -> %s")\format(filename, filename\gsub("%.nom$", ".lua"))
output\close!
@@ -165,14 +170,18 @@ run = ->
tree = nomsu_environment._1_parsed(code)
tree = {tree} unless tree.type == 'FileChunks'
for chunk_no, chunk in ipairs tree
- lua = nomsu_environment.compile(chunk)
+ lua = nomsu_environment\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_1_in(lua, nomsu_environment)
+ nomsu_environment\run(lua)
else
-- Just run the file
- nomsu_environment.run_file_1_in(filename, nomsu_environment, 0)
+ f = Files.read(filename)
+ if filename\match("%.lua$")
+ f = LuaCode\from(Source(filename, 1, #f), f)
+ nomsu_environment\run(f)
+ --nomsu_environment.run_file_1_in(filename, nomsu_environment, 0)
debugger = if args.debugger == "nil" then {}
else require(args.debugger or 'error_handling')
diff --git a/nomsu_compiler.lua b/nomsu_compiler.lua
index 20ea6a0..9c8c9ac 100644
--- a/nomsu_compiler.lua
+++ b/nomsu_compiler.lua
@@ -1,17 +1,8 @@
-local lpeg = require('lpeg')
-local R, P, S
-R, P, S = lpeg.R, lpeg.P, lpeg.S
-local re = require('re')
local List, Dict, Text
do
local _obj_0 = require('containers')
List, Dict, Text = _obj_0.List, _obj_0.Dict, _obj_0.Text
end
-local insert, remove, concat
-do
- local _obj_0 = table
- insert, remove, concat = _obj_0.insert, _obj_0.remove, _obj_0.concat
-end
local unpack = unpack or table.unpack
local match, sub, gsub, format, byte, find
do
@@ -24,23 +15,7 @@ do
LuaCode, Source = _obj_0.LuaCode, _obj_0.Source
end
local SyntaxTree = require("syntax_tree")
-local Importer, import_to_1_from, _1_forked
-do
- local _obj_0 = require('importer')
- Importer, import_to_1_from, _1_forked = _obj_0.Importer, _obj_0.import_to_1_from, _obj_0._1_forked
-end
local Files = require("files")
-table.map = function(t, fn)
- return setmetatable((function()
- local _accum_0 = { }
- local _len_0 = 1
- for _, v in ipairs(t) do
- _accum_0[_len_0] = fn(v)
- _len_0 = _len_0 + 1
- end
- return _accum_0
- end)(), getmetatable(t))
-end
local pretty_error = require("pretty_errors")
local compile_error
compile_error = function(source, err_msg, hint)
@@ -68,173 +43,92 @@ compile_error = function(source, err_msg, hint)
})
return error(err_str, 0)
end
+local re = require('re')
local math_expression = re.compile([[ (([*/^+-] / [0-9]+) " ")* [*/^+-] !. ]])
local MAX_LINE = 80
-local compile = setmetatable({
- action = Importer({
- [""] = function(compile, fn, ...)
- local lua = LuaCode()
- local fn_lua = compile(fn)
- lua:add(fn_lua)
- if not (fn_lua:text():match("^%(.*%)$") or fn_lua:text():match("^[_a-zA-Z][_a-zA-Z0-9.]*$")) then
- lua:parenthesize()
- end
- lua:add("(")
- for i = 1, select('#', ...) do
- if i > 1 then
- lua:add(", ")
+local compile
+compile = function(self, tree)
+ local _exp_0 = tree.type
+ if "Action" == _exp_0 then
+ local stub = tree.stub
+ local compile_action = self.COMPILE_RULES[stub]
+ if not compile_action and math_expression:match(stub) then
+ local lua = LuaCode:from(tree.source)
+ for i, tok in ipairs(tree) do
+ if type(tok) == 'string' then
+ lua:add(tok)
+ else
+ local tok_lua = self:compile(tok)
+ if tok.type == "Action" then
+ tok_lua:parenthesize()
+ end
+ lua:add(tok_lua)
+ end
+ if i < #tree then
+ lua:add(" ")
end
- lua:add(compile((select(i, ...))))
end
- lua:add(")")
return lua
- end,
- ["Lua"] = function(compile, code)
- if not code then
- return LuaCode("LuaCode()")
- end
- if code.type ~= "Text" then
- return LuaCode("LuaCode:from(", tostring(code.source):as_lua(), ", ", compile(code), ")")
- end
- local operate_on_text
- operate_on_text = function(text)
- local lua = LuaCode:from(text.source, "LuaCode:from(", tostring(text.source):as_lua())
- for _index_0 = 1, #text do
- local bit = text[_index_0]
- local bit_lua
- if type(bit) == "string" then
- bit_lua = bit:as_lua()
- elseif bit.type == "Text" then
- bit_lua = operate_on_text(bit)
- elseif bit.type == "Block" then
- bit_lua = LuaCode:from(bit.source, "(function()", "\n local _lua = LuaCode:from(", tostring(bit.source):as_lua(), ")", "\n local function add(...) _lua:add(...) end", "\n local function join_with(glue)", "\n local old_bits = _lua.bits", "\n _lua = LuaCode:from(_lua.source)", "\n _lua:concat_add(old_bits, glue)", "\n end", "\n ", compile(bit), "\n return _lua", "\nend)()")
- else
- bit_lua = compile(bit)
+ end
+ if compile_action then
+ local args
+ do
+ local _accum_0 = { }
+ local _len_0 = 1
+ for _index_0 = 1, #tree do
+ local arg = tree[_index_0]
+ if type(arg) ~= "string" then
+ _accum_0[_len_0] = arg
+ _len_0 = _len_0 + 1
end
- local bit_leading_len = #(bit_lua:match("^[^\n]*"))
- lua:add(lua:trailing_line_len() + bit_leading_len > MAX_LINE and ",\n " or ", ")
- lua:add(bit_lua)
end
- lua:add(")")
- return lua
+ args = _accum_0
end
- return operate_on_text(code)
- end,
- ["lua >"] = function(compile, code)
- if code.type ~= "Text" then
- return code
+ local ret = compile_action(self, unpack(args))
+ if ret == nil then
+ local info = debug.getinfo(compile_action, "S")
+ local filename = Source:from_string(info.source).filename
+ compile_error(tree, "The compile-time action here (" .. tostring(stub) .. ") failed to return any value.", "Look at the implementation of (" .. tostring(stub) .. ") in " .. tostring(filename) .. ":" .. tostring(info.linedefined) .. " and make sure it's returning something.")
end
- local operate_on_text
- operate_on_text = function(text)
- local lua = LuaCode:from(text.source)
- for _index_0 = 1, #text do
- local bit = text[_index_0]
- if type(bit) == "string" then
- lua:add(bit)
- elseif bit.type == "Text" then
- lua:add(operate_on_text(bit))
- else
- lua:add(compile(bit))
- end
- end
- return lua
+ if not (SyntaxTree:is_instance(ret)) then
+ ret.source = ret.source or tree.source
+ return ret
end
- return operate_on_text(code)
- end,
- ["= lua"] = function(compile, code)
- return compile.action["lua >"](compile, code)
- end,
- ["use"] = function(compile, path)
- return LuaCode("run_file_1_in(" .. tostring(compile(path)) .. ", _ENV, OPTIMIZATION)")
- end,
- ["use 1 with prefix"] = function(compile, path, prefix)
- return LuaCode("run_file_1_in(" .. tostring(compile(path)) .. ", _ENV, OPTIMIZATION, ", compile(prefix), ")")
- end,
- ["test"] = function(compile, body)
- if not (body.type == 'Block') then
- compile_error(body, "This should be a Block")
+ if ret ~= tree then
+ return self:compile(ret)
end
- local test_nomsu = body:get_source_code():match(":[ ]*(.*)")
- do
- local indent = test_nomsu:match("\n([ ]*)")
- if indent then
- test_nomsu = test_nomsu:gsub("\n" .. indent, "\n")
- end
- end
- local test_text = compile(SyntaxTree({
- type = "Text",
- source = body.source,
- test_nomsu
- }))
- return LuaCode("TESTS[" .. tostring(tostring(body.source):as_lua()) .. "] = ", test_text)
- end,
- ["is jit"] = function(compile, code)
- return LuaCode("jit")
- end,
- ["Lua version"] = function(compile, code)
- return LuaCode("_VERSION")
- end,
- ["nomsu environment"] = function(compile)
- return LuaCode("_ENV")
end
- })
-}, {
- __import = import_to_1_from,
- __call = function(compile, tree)
- local _exp_0 = tree.type
- if "Action" == _exp_0 then
- local stub = tree.stub
- local compile_action = compile.action[stub]
- if not compile_action and math_expression:match(stub) then
- local lua = LuaCode:from(tree.source)
- for i, tok in ipairs(tree) do
- if type(tok) == 'string' then
- lua:add(tok)
- else
- local tok_lua = compile(tok)
- if tok.type == "Action" then
- tok_lua:parenthesize()
- end
- lua:add(tok_lua)
- end
- if i < #tree then
- lua:add(" ")
- end
- end
- return lua
+ local lua = LuaCode:from(tree.source)
+ lua:add((stub):as_lua_id(), "(")
+ for argnum, arg in ipairs(tree:get_args()) do
+ local arg_lua = self:compile(arg)
+ if arg.type == "Block" then
+ arg_lua = LuaCode:from(arg.source, "(function()\n ", arg_lua, "\nend)()")
end
- if compile_action then
- local args
- do
- local _accum_0 = { }
- local _len_0 = 1
- for _index_0 = 1, #tree do
- local arg = tree[_index_0]
- if type(arg) ~= "string" then
- _accum_0[_len_0] = arg
- _len_0 = _len_0 + 1
- end
- end
- args = _accum_0
- end
- local ret = compile_action(compile, unpack(args))
- if ret == nil then
- local info = debug.getinfo(compile_action, "S")
- local filename = Source:from_string(info.source).filename
- compile_error(tree, "The compile-time action here (" .. tostring(stub) .. ") failed to return any value.", "Look at the implementation of (" .. tostring(stub) .. ") in " .. tostring(filename) .. ":" .. tostring(info.linedefined) .. " and make sure it's returning something.")
- end
- if not (SyntaxTree:is_instance(ret)) then
- ret.source = ret.source or tree.source
- return ret
- end
- if ret ~= tree then
- return compile(ret)
- end
+ if lua:trailing_line_len() + #arg_lua:text() > MAX_LINE then
+ lua:add(argnum > 1 and ",\n " or "\n ")
+ elseif argnum > 1 then
+ lua:add(", ")
end
- local lua = LuaCode:from(tree.source)
- lua:add((stub):as_lua_id(), "(")
- for argnum, arg in ipairs(tree:get_args()) do
- local arg_lua = compile(arg)
+ lua:add(arg_lua)
+ end
+ lua:add(")")
+ return lua
+ elseif "MethodCall" == _exp_0 then
+ local lua = LuaCode:from(tree.source)
+ local target_lua = self:compile(tree[1])
+ local target_text = target_lua:text()
+ if not (target_text:match("^%(.*%)$") or target_text:match("^[_a-zA-Z][_a-zA-Z0-9.]*$") or tree[1].type == "IndexChain") then
+ target_lua:parenthesize()
+ end
+ for i = 2, #tree do
+ if i > 2 then
+ lua:add("\n")
+ end
+ lua:add(target_lua, ":")
+ lua:add((tree[i].stub):as_lua_id(), "(")
+ for argnum, arg in ipairs(tree[i]:get_args()) do
+ local arg_lua = self:compile(arg)
if arg.type == "Block" then
arg_lua = LuaCode:from(arg.source, "(function()\n ", arg_lua, "\nend)()")
end
@@ -246,205 +140,193 @@ local compile = setmetatable({
lua:add(arg_lua)
end
lua:add(")")
- return lua
- elseif "MethodCall" == _exp_0 then
- local lua = LuaCode:from(tree.source)
- local target_lua = compile(tree[1])
- local target_text = target_lua:text()
- if not (target_text:match("^%(.*%)$") or target_text:match("^[_a-zA-Z][_a-zA-Z0-9.]*$") or tree[1].type == "IndexChain") then
- target_lua:parenthesize()
+ end
+ return lua
+ elseif "EscapedNomsu" == _exp_0 then
+ local lua = LuaCode:from(tree.source, "SyntaxTree{")
+ local needs_comma, i = false, 1
+ local as_lua
+ as_lua = function(x)
+ if type(x) == 'number' then
+ return tostring(x)
+ elseif SyntaxTree:is_instance(x) then
+ return self:compile(x)
+ elseif Source:is_instance(x) then
+ return tostring(x):as_lua()
+ else
+ return x:as_lua()
end
- for i = 2, #tree do
- if i > 2 then
- lua:add("\n")
- end
- lua:add(target_lua, ":")
- lua:add((tree[i].stub):as_lua_id(), "(")
- for argnum, arg in ipairs(tree[i]:get_args()) do
- local arg_lua = compile(arg)
- if arg.type == "Block" then
- arg_lua = LuaCode:from(arg.source, "(function()\n ", arg_lua, "\nend)()")
- end
- if lua:trailing_line_len() + #arg_lua:text() > MAX_LINE then
- lua:add(argnum > 1 and ",\n " or "\n ")
- elseif argnum > 1 then
- lua:add(", ")
- end
- lua:add(arg_lua)
- end
- lua:add(")")
+ end
+ for k, v in pairs((SyntaxTree:is_instance(tree[1]) and tree[1].type == "EscapedNomsu" and tree) or tree[1]) do
+ local entry_lua = LuaCode()
+ if k == i then
+ i = i + 1
+ elseif type(k) == 'string' and match(k, "[_a-zA-Z][_a-zA-Z0-9]*") then
+ entry_lua:add(k, "= ")
+ else
+ entry_lua:add("[", as_lua(k), "]= ")
end
- return lua
- elseif "EscapedNomsu" == _exp_0 then
- local lua = LuaCode:from(tree.source, "SyntaxTree{")
- local needs_comma, i = false, 1
- local as_lua
- as_lua = function(x)
- if type(x) == 'number' then
- return tostring(x)
- elseif SyntaxTree:is_instance(x) then
- return compile(x)
- elseif Source:is_instance(x) then
- return tostring(x):as_lua()
- else
- return x:as_lua()
- end
+ entry_lua:add(as_lua(v))
+ if needs_comma then
+ lua:add(",")
end
- for k, v in pairs((SyntaxTree:is_instance(tree[1]) and tree[1].type == "EscapedNomsu" and tree) or tree[1]) do
- local entry_lua = LuaCode()
- if k == i then
- i = i + 1
- elseif type(k) == 'string' and match(k, "[_a-zA-Z][_a-zA-Z0-9]*") then
- entry_lua:add(k, "= ")
- else
- entry_lua:add("[", as_lua(k), "]= ")
- end
- entry_lua:add(as_lua(v))
- if needs_comma then
- lua:add(",")
- end
- if lua:trailing_line_len() + #(entry_lua:text():match("^[\n]*")) > MAX_LINE then
- lua:add("\n ")
- elseif needs_comma then
- lua:add(" ")
- end
- lua:add(entry_lua)
- needs_comma = true
+ if lua:trailing_line_len() + #(entry_lua:text():match("^[\n]*")) > MAX_LINE then
+ lua:add("\n ")
+ elseif needs_comma then
+ lua:add(" ")
end
- lua:add("}")
- return lua
- elseif "Block" == _exp_0 then
- local lua = LuaCode:from(tree.source)
- for i, line in ipairs(tree) do
- if i > 1 then
- lua:add("\n")
- end
- lua:add(compile(line))
+ lua:add(entry_lua)
+ needs_comma = true
+ end
+ lua:add("}")
+ return lua
+ elseif "Block" == _exp_0 then
+ local lua = LuaCode:from(tree.source)
+ for i, line in ipairs(tree) do
+ if i > 1 then
+ lua:add("\n")
end
- return lua
- elseif "Text" == _exp_0 then
- local lua = LuaCode:from(tree.source)
- local added = 0
- local string_buffer = ""
- local add_bit
- add_bit = function(bit)
- if added > 0 then
- if lua:trailing_line_len() + #bit > MAX_LINE then
- lua:add("\n ")
- end
- lua:add("..")
+ lua:add(self:compile(line))
+ end
+ return lua
+ elseif "Text" == _exp_0 then
+ local lua = LuaCode:from(tree.source)
+ local added = 0
+ local string_buffer = ""
+ local add_bit
+ add_bit = function(bit)
+ if added > 0 then
+ if lua:trailing_line_len() + #bit > MAX_LINE then
+ lua:add("\n ")
end
- lua:add(bit)
- added = added + 1
+ lua:add("..")
end
- for i, bit in ipairs(tree) do
- local _continue_0 = false
- repeat
- if type(bit) == "string" then
- string_buffer = string_buffer .. bit
- _continue_0 = true
- break
- end
- if string_buffer ~= "" then
- for i = 1, #string_buffer, MAX_LINE do
- add_bit(string_buffer:sub(i, i + MAX_LINE - 1):as_lua())
- end
- string_buffer = ""
- end
- local bit_lua = compile(bit)
- if bit.type == "Block" and #bit == 1 then
- bit = bit[1]
- end
- if bit.type == "Block" then
- bit_lua = LuaCode:from(bit.source, "List(function(add)", "\n ", bit_lua, "\nend):joined()")
- elseif bit.type ~= "Text" then
- bit_lua = LuaCode:from(bit.source, "tostring(", bit_lua, ")")
- end
- add_bit(bit_lua)
+ lua:add(bit)
+ added = added + 1
+ end
+ for i, bit in ipairs(tree) do
+ local _continue_0 = false
+ repeat
+ if type(bit) == "string" then
+ string_buffer = string_buffer .. bit
_continue_0 = true
- until true
- if not _continue_0 then
break
end
- end
- if string_buffer ~= "" then
- for i = 1, #string_buffer, MAX_LINE do
- add_bit(string_buffer:sub(i, i + MAX_LINE - 1):as_lua())
+ if string_buffer ~= "" then
+ for i = 1, #string_buffer, MAX_LINE do
+ add_bit(string_buffer:sub(i, i + MAX_LINE - 1):as_lua())
+ end
+ string_buffer = ""
end
- string_buffer = ""
- end
- if added == 0 then
- add_bit('""')
- end
- if added > 1 then
- lua:parenthesize()
+ local bit_lua = self:compile(bit)
+ if bit.type == "Block" and #bit == 1 then
+ bit = bit[1]
+ end
+ if bit.type == "Block" then
+ bit_lua = LuaCode:from(bit.source, "List(function(add)", "\n ", bit_lua, "\nend):joined()")
+ elseif bit.type ~= "Text" then
+ bit_lua = LuaCode:from(bit.source, "tostring(", bit_lua, ")")
+ end
+ add_bit(bit_lua)
+ _continue_0 = true
+ until true
+ if not _continue_0 then
+ break
end
- return lua
- elseif "List" == _exp_0 or "Dict" == _exp_0 then
- if #tree == 0 then
- return LuaCode:from(tree.source, tree.type, "{}")
+ end
+ if string_buffer ~= "" then
+ for i = 1, #string_buffer, MAX_LINE do
+ add_bit(string_buffer:sub(i, i + MAX_LINE - 1):as_lua())
end
- local lua = LuaCode:from(tree.source)
- local chunks = 0
- local i = 1
- while tree[i] do
- if tree[i].type == 'Block' then
- if chunks > 0 then
- lua:add(" + ")
+ string_buffer = ""
+ end
+ if added == 0 then
+ add_bit('""')
+ end
+ if added > 1 then
+ lua:parenthesize()
+ end
+ return lua
+ elseif "List" == _exp_0 or "Dict" == _exp_0 then
+ if #tree == 0 then
+ return LuaCode:from(tree.source, tree.type, "{}")
+ end
+ local lua = LuaCode:from(tree.source)
+ local chunks = 0
+ local i = 1
+ while tree[i] do
+ if tree[i].type == 'Block' then
+ if chunks > 0 then
+ lua:add(" + ")
+ end
+ lua:add(tree.type, "(function(", (tree.type == 'List' and "add" or ("add, " .. ("add 1 ="):as_lua_id())), ")")
+ lua:add("\n ", self:compile(tree[i]), "\nend)")
+ chunks = chunks + 1
+ i = i + 1
+ else
+ if chunks > 0 then
+ lua:add(" + ")
+ end
+ local sep = ''
+ local items_lua = LuaCode:from(tree[i].source)
+ while tree[i] do
+ if tree[i].type == "Block" then
+ break
end
- lua:add(tree.type, "(function(", (tree.type == 'List' and "add" or ("add, " .. ("add 1 ="):as_lua_id())), ")")
- lua:add("\n ", compile(tree[i]), "\nend)")
- chunks = chunks + 1
- i = i + 1
- else
- if chunks > 0 then
- lua:add(" + ")
+ local item_lua = self:compile(tree[i])
+ if item_lua:text():match("^%.[a-zA-Z_]") then
+ item_lua = item_lua:text():sub(2)
end
- local sep = ''
- local items_lua = LuaCode:from(tree[i].source)
- while tree[i] do
- if tree[i].type == "Block" then
- break
- end
- local item_lua = compile(tree[i])
- if item_lua:text():match("^%.[a-zA-Z_]") then
- item_lua = item_lua:text():sub(2)
- end
- if tree.type == 'Dict' and tree[i].type == 'Index' then
- item_lua = LuaCode:from(tree[i].source, item_lua, "=true")
- end
- items_lua:add(sep, item_lua)
- if tree[i].type == "Comment" then
- items_lua:add("\n")
- sep = ''
- elseif items_lua:trailing_line_len() > MAX_LINE then
- sep = ',\n '
- else
- sep = ', '
- end
- i = i + 1
+ if tree.type == 'Dict' and tree[i].type == 'Index' then
+ item_lua = LuaCode:from(tree[i].source, item_lua, "=true")
end
- if items_lua:is_multiline() then
- lua:add(LuaCode:from(items_lua.source, tree.type, "{\n ", items_lua, "\n}"))
+ items_lua:add(sep, item_lua)
+ if tree[i].type == "Comment" then
+ items_lua:add("\n")
+ sep = ''
+ elseif items_lua:trailing_line_len() > MAX_LINE then
+ sep = ',\n '
else
- lua:add(LuaCode:from(items_lua.source, tree.type, "{", items_lua, "}"))
+ sep = ', '
end
- chunks = chunks + 1
+ i = i + 1
end
+ if items_lua:is_multiline() then
+ lua:add(LuaCode:from(items_lua.source, tree.type, "{\n ", items_lua, "\n}"))
+ else
+ lua:add(LuaCode:from(items_lua.source, tree.type, "{", items_lua, "}"))
+ end
+ chunks = chunks + 1
end
- return lua
- elseif "Index" == _exp_0 then
- local key_lua = compile(tree[1])
- local key_str = match(key_lua:text(), '^"([a-zA-Z_][a-zA-Z0-9_]*)"$')
- if key_str and key_str:is_lua_id() then
- return LuaCode:from(tree.source, ".", key_str)
- elseif sub(key_lua:text(), 1, 1) == "[" then
- return LuaCode:from(tree.source, "[ ", key_lua, "]")
- else
- return LuaCode:from(tree.source, "[", key_lua, "]")
- end
- elseif "DictEntry" == _exp_0 then
- local key = tree[1]
+ end
+ return lua
+ elseif "Index" == _exp_0 then
+ local key_lua = self:compile(tree[1])
+ local key_str = match(key_lua:text(), '^"([a-zA-Z_][a-zA-Z0-9_]*)"$')
+ if key_str and key_str:is_lua_id() then
+ return LuaCode:from(tree.source, ".", key_str)
+ elseif sub(key_lua:text(), 1, 1) == "[" then
+ return LuaCode:from(tree.source, "[ ", key_lua, "]")
+ else
+ return LuaCode:from(tree.source, "[", key_lua, "]")
+ end
+ elseif "DictEntry" == _exp_0 then
+ local key = tree[1]
+ if key.type ~= "Index" then
+ key = SyntaxTree({
+ type = "Index",
+ source = key.source,
+ key
+ })
+ end
+ return LuaCode:from(tree.source, self:compile(key), "=", (tree[2] and self:compile(tree[2]) or "true"))
+ elseif "IndexChain" == _exp_0 then
+ local lua = self:compile(tree[1])
+ if lua:text():match("['\"}]$") or lua:text():match("]=*]$") then
+ lua:parenthesize()
+ end
+ for i = 2, #tree do
+ local key = tree[i]
if key.type ~= "Index" then
key = SyntaxTree({
type = "Index",
@@ -452,39 +334,23 @@ local compile = setmetatable({
key
})
end
- return LuaCode:from(tree.source, compile(key), "=", (tree[2] and compile(tree[2]) or "true"))
- elseif "IndexChain" == _exp_0 then
- local lua = compile(tree[1])
- if lua:text():match("['\"}]$") or lua:text():match("]=*]$") then
- lua:parenthesize()
- end
- for i = 2, #tree do
- local key = tree[i]
- if key.type ~= "Index" then
- key = SyntaxTree({
- type = "Index",
- source = key.source,
- key
- })
- end
- lua:add(compile(key))
- end
- return lua
- elseif "Number" == _exp_0 then
- return LuaCode:from(tree.source, tostring(tree[1]))
- elseif "Var" == _exp_0 then
- return LuaCode:from(tree.source, tree:as_var():as_lua_id())
- elseif "FileChunks" == _exp_0 then
- return error("Can't convert FileChunks to a single block of lua, since each chunk's " .. "compilation depends on the earlier chunks")
- elseif "Comment" == _exp_0 then
- return LuaCode:from(tree.source, "-- ", (tree[1]:gsub('\n', '\n-- ')))
- elseif "Error" == _exp_0 then
- return error("Can't compile errors")
- else
- return error("Unknown type: " .. tostring(tree.type))
+ lua:add(self:compile(key))
end
+ return lua
+ elseif "Number" == _exp_0 then
+ return LuaCode:from(tree.source, tostring(tree[1]))
+ elseif "Var" == _exp_0 then
+ return LuaCode:from(tree.source, tree:as_var():as_lua_id())
+ elseif "FileChunks" == _exp_0 then
+ return error("Can't convert FileChunks to a single block of lua, since each chunk's " .. "compilation depends on the earlier chunks")
+ elseif "Comment" == _exp_0 then
+ return LuaCode:from(tree.source, "-- ", (tree[1]:gsub('\n', '\n-- ')))
+ elseif "Error" == _exp_0 then
+ return error("Can't compile errors")
+ else
+ return error("Unknown type: " .. tostring(tree.type))
end
-})
+end
return {
compile = compile,
compile_error = compile_error
diff --git a/nomsu_compiler.moon b/nomsu_compiler.moon
index 7ab2494..f3530e9 100644
--- a/nomsu_compiler.moon
+++ b/nomsu_compiler.moon
@@ -1,28 +1,13 @@
+--
-- This file contains the source code of the Nomsu compiler.
--- Nomsu is a programming language that cross-compiles to Lua. It was designed to be good
--- at natural-language-like code that is highly self-modifying and flexible.
--- The only dependency is LPEG, which can be installed using "luarocks install lpeg"
--- File usage:
--- Either, in a lua/moonscript file:
--- Nomsu = require "nomsu"
--- nomsu = Nomsu()
--- nomsu:run(your_nomsu_code)
--- Or from the command line:
--- lua nomsu.lua your_file.nom
-lpeg = require 'lpeg'
-{:R,:P,:S} = lpeg
-re = require 're'
+--
{:List, :Dict, :Text} = require 'containers'
-{:insert, :remove, :concat} = table
unpack or= table.unpack
{:match, :sub, :gsub, :format, :byte, :find} = string
{:LuaCode, :Source} = require "code_obj"
SyntaxTree = require "syntax_tree"
-{:Importer, :import_to_1_from, :_1_forked} = require 'importer'
Files = require "files"
-table.map = (t, fn)-> setmetatable([fn(v) for _,v in ipairs(t)], getmetatable(t))
-
-- TODO: de-duplicate this
pretty_error = require("pretty_errors")
compile_error = (source, err_msg, hint=nil)->
@@ -45,137 +30,74 @@ compile_error = (source, err_msg, hint=nil)->
-- This is a bit of a hack, but this code handles arbitrarily complex
-- math expressions like 2*x + 3^2 without having to define a single
-- action for every possibility.
+re = require 're'
math_expression = re.compile [[ (([*/^+-] / [0-9]+) " ")* [*/^+-] !. ]]
MAX_LINE = 80 -- For beautification purposes, try not to make lines much longer than this value
-compile = setmetatable({
- action: Importer{
- [""]: (compile, fn, ...)->
- lua = LuaCode!
- fn_lua = compile(fn)
- lua\add fn_lua
- unless fn_lua\text!\match("^%(.*%)$") or fn_lua\text!\match("^[_a-zA-Z][_a-zA-Z0-9.]*$")
- lua\parenthesize!
- lua\add "("
- for i=1,select('#',...)
- lua\add(", ") if i > 1
- lua\add compile((select(i, ...)))
- lua\add ")"
- return lua
-
- ["Lua"]: (compile, code)->
- if not code
- return LuaCode("LuaCode()")
- if code.type != "Text"
- return LuaCode("LuaCode:from(", tostring(code.source)\as_lua!, ", ", compile(code), ")")
-
- operate_on_text = (text)->
- lua = LuaCode\from(text.source, "LuaCode:from(", tostring(text.source)\as_lua!)
- for bit in *text
- local bit_lua
- if type(bit) == "string"
- bit_lua = bit\as_lua!
- elseif bit.type == "Text"
- bit_lua = operate_on_text(bit)
- elseif bit.type == "Block"
- bit_lua = LuaCode\from bit.source, "(function()",
- "\n local _lua = LuaCode:from(", tostring(bit.source)\as_lua!, ")",
- "\n local function add(...) _lua:add(...) end",
- "\n local function join_with(glue)",
- "\n local old_bits = _lua.bits",
- "\n _lua = LuaCode:from(_lua.source)",
- "\n _lua:concat_add(old_bits, glue)",
- "\n end",
- "\n ", compile(bit),
- "\n return _lua",
- "\nend)()"
- else
- bit_lua = compile(bit)
-
- bit_leading_len = #(bit_lua\match("^[^\n]*"))
- lua\add(lua\trailing_line_len! + bit_leading_len > MAX_LINE and ",\n " or ", ")
- lua\add(bit_lua)
- lua\add ")"
- return lua
-
- return operate_on_text code
-
- ["lua >"]: (compile, code)->
- if code.type != "Text"
- return code
- operate_on_text = (text)->
- lua = LuaCode\from(text.source)
- for bit in *text
- if type(bit) == "string"
- lua\add bit
- elseif bit.type == "Text"
- lua\add(operate_on_text(bit))
+compile = (tree)=>
+ switch tree.type
+ when "Action"
+ stub = tree.stub
+ compile_action = @COMPILE_RULES[stub]
+ if not compile_action and math_expression\match(stub)
+ lua = LuaCode\from(tree.source)
+ for i,tok in ipairs tree
+ if type(tok) == 'string'
+ lua\add tok
else
- lua\add compile(bit)
+ tok_lua = @compile(tok)
+ -- TODO: this is overly eager, should be less aggressive
+ tok_lua\parenthesize! if tok.type == "Action"
+ lua\add tok_lua
+ lua\add " " if i < #tree
return lua
- return operate_on_text code
-
- ["= lua"]: (compile, code)-> compile.action["lua >"](compile, code)
-
- ["use"]: (compile, path)-> LuaCode("run_file_1_in(#{compile(path)}, _ENV, OPTIMIZATION)")
- ["use 1 with prefix"]: (compile, path, prefix)->
- LuaCode("run_file_1_in(#{compile(path)}, _ENV, OPTIMIZATION, ", compile(prefix), ")")
-
- ["test"]: (compile, body)->
- unless body.type == 'Block'
- compile_error(body, "This should be a Block")
- test_nomsu = body\get_source_code!\match(":[ ]*(.*)")
- if indent = test_nomsu\match("\n([ ]*)")
- test_nomsu = test_nomsu\gsub("\n"..indent, "\n")
- test_text = compile(SyntaxTree{type:"Text", source:body.source, test_nomsu})
- return LuaCode "TESTS[#{tostring(body.source)\as_lua!}] = ", test_text
-
- ["is jit"]: (compile, code)-> LuaCode("jit")
- ["Lua version"]: (compile, code)-> LuaCode("_VERSION")
- ["nomsu environment"]: (compile)-> LuaCode("_ENV")
- }
-}, {
- __import: import_to_1_from
- __call: (compile, tree)->
- switch tree.type
- when "Action"
- stub = tree.stub
- compile_action = compile.action[stub]
- if not compile_action and math_expression\match(stub)
- lua = LuaCode\from(tree.source)
- for i,tok in ipairs tree
- if type(tok) == 'string'
- lua\add tok
- else
- tok_lua = compile(tok)
- -- TODO: this is overly eager, should be less aggressive
- tok_lua\parenthesize! if tok.type == "Action"
- lua\add tok_lua
- lua\add " " if i < #tree
- return lua
-
- if compile_action
- args = [arg for arg in *tree when type(arg) != "string"]
- -- Force Lua to avoid tail call optimization for debugging purposes
- -- TODO: use tail call?
- ret = compile_action(compile, unpack(args))
- if ret == nil
- info = debug.getinfo(compile_action, "S")
- filename = Source\from_string(info.source).filename
- compile_error tree,
- "The compile-time action here (#{stub}) failed to return any value.",
- "Look at the implementation of (#{stub}) in #{filename}:#{info.linedefined} and make sure it's returning something."
- unless SyntaxTree\is_instance(ret)
- ret.source or= tree.source
- return ret
- if ret != tree
- return compile(ret)
+ if compile_action
+ args = [arg for arg in *tree when type(arg) != "string"]
+ -- Force Lua to avoid tail call optimization for debugging purposes
+ -- TODO: use tail call?
+ ret = compile_action(@, unpack(args))
+ if ret == nil
+ info = debug.getinfo(compile_action, "S")
+ filename = Source\from_string(info.source).filename
+ compile_error tree,
+ "The compile-time action here (#{stub}) failed to return any value.",
+ "Look at the implementation of (#{stub}) in #{filename}:#{info.linedefined} and make sure it's returning something."
+ unless SyntaxTree\is_instance(ret)
+ ret.source or= tree.source
+ return ret
+ if ret != tree
+ return @compile(ret)
+
+ lua = LuaCode\from(tree.source)
+ lua\add((stub)\as_lua_id!,"(")
+ for argnum, arg in ipairs tree\get_args!
+ arg_lua = @compile(arg)
+ if arg.type == "Block"
+ arg_lua = LuaCode\from(arg.source, "(function()\n ", arg_lua, "\nend)()")
+ if lua\trailing_line_len! + #arg_lua\text! > MAX_LINE
+ lua\add(argnum > 1 and ",\n " or "\n ")
+ elseif argnum > 1
+ lua\add ", "
+ lua\add arg_lua
+ lua\add ")"
+ return lua
- lua = LuaCode\from(tree.source)
- lua\add((stub)\as_lua_id!,"(")
- for argnum, arg in ipairs tree\get_args!
- arg_lua = compile(arg)
+ when "MethodCall"
+ lua = LuaCode\from tree.source
+ target_lua = @compile tree[1]
+ target_text = target_lua\text!
+ -- TODO: this parenthesizing is maybe overly conservative
+ if not (target_text\match("^%(.*%)$") or target_text\match("^[_a-zA-Z][_a-zA-Z0-9.]*$") or
+ tree[1].type == "IndexChain")
+ target_lua\parenthesize!
+
+ for i=2,#tree
+ lua\add "\n" if i > 2
+ lua\add target_lua, ":"
+ lua\add((tree[i].stub)\as_lua_id!,"(")
+ for argnum, arg in ipairs tree[i]\get_args!
+ arg_lua = @compile(arg)
if arg.type == "Block"
arg_lua = LuaCode\from(arg.source, "(function()\n ", arg_lua, "\nend)()")
if lua\trailing_line_len! + #arg_lua\text! > MAX_LINE
@@ -184,207 +106,180 @@ compile = setmetatable({
lua\add ", "
lua\add arg_lua
lua\add ")"
- return lua
-
- when "MethodCall"
- lua = LuaCode\from tree.source
- target_lua = compile tree[1]
- target_text = target_lua\text!
- -- TODO: this parenthesizing is maybe overly conservative
- if not (target_text\match("^%(.*%)$") or target_text\match("^[_a-zA-Z][_a-zA-Z0-9.]*$") or
- tree[1].type == "IndexChain")
- target_lua\parenthesize!
-
- for i=2,#tree
- lua\add "\n" if i > 2
- lua\add target_lua, ":"
- lua\add((tree[i].stub)\as_lua_id!,"(")
- for argnum, arg in ipairs tree[i]\get_args!
- arg_lua = compile(arg)
- if arg.type == "Block"
- arg_lua = LuaCode\from(arg.source, "(function()\n ", arg_lua, "\nend)()")
- if lua\trailing_line_len! + #arg_lua\text! > MAX_LINE
- lua\add(argnum > 1 and ",\n " or "\n ")
- elseif argnum > 1
- lua\add ", "
- lua\add arg_lua
- lua\add ")"
- return lua
-
- when "EscapedNomsu"
- lua = LuaCode\from tree.source, "SyntaxTree{"
- needs_comma, i = false, 1
- as_lua = (x)->
- if type(x) == 'number'
- tostring(x)
- elseif SyntaxTree\is_instance(x)
- compile(x)
- elseif Source\is_instance(x)
- tostring(x)\as_lua!
- else x\as_lua!
-
- for k,v in pairs((SyntaxTree\is_instance(tree[1]) and tree[1].type == "EscapedNomsu" and tree) or tree[1])
- entry_lua = LuaCode!
- if k == i
- i += 1
- elseif type(k) == 'string' and match(k,"[_a-zA-Z][_a-zA-Z0-9]*")
- entry_lua\add(k, "= ")
- else
- entry_lua\add("[", as_lua(k), "]= ")
- entry_lua\add as_lua(v)
- if needs_comma then lua\add ","
- if lua\trailing_line_len! + #(entry_lua\text!\match("^[\n]*")) > MAX_LINE
- lua\add "\n "
- elseif needs_comma
- lua\add " "
- lua\add entry_lua
- needs_comma = true
- lua\add "}"
- return lua
-
- when "Block"
- lua = LuaCode\from(tree.source)
- for i, line in ipairs tree
- if i > 1 then lua\add "\n"
- lua\add compile(line)
- return lua
-
- when "Text"
- lua = LuaCode\from(tree.source)
- added = 0
- string_buffer = ""
- add_bit = (bit)->
- if added > 0
- if lua\trailing_line_len! + #bit > MAX_LINE
- lua\add "\n "
- lua\add ".."
- lua\add bit
- added += 1
-
- for i, bit in ipairs tree
- if type(bit) == "string"
- string_buffer ..= bit
- continue
- if string_buffer != ""
- for i=1,#string_buffer,MAX_LINE
- add_bit string_buffer\sub(i, i+MAX_LINE-1)\as_lua!
- string_buffer = ""
+ return lua
- bit_lua = compile(bit)
- if bit.type == "Block" and #bit == 1
- bit = bit[1]
- if bit.type == "Block"
- bit_lua = LuaCode\from bit.source, "List(function(add)",
- "\n ", bit_lua,
- "\nend):joined()"
- elseif bit.type != "Text"
- bit_lua = LuaCode\from(bit.source, "tostring(",bit_lua,")")
- add_bit bit_lua
+ when "EscapedNomsu"
+ lua = LuaCode\from tree.source, "SyntaxTree{"
+ needs_comma, i = false, 1
+ as_lua = (x)->
+ if type(x) == 'number'
+ tostring(x)
+ elseif SyntaxTree\is_instance(x)
+ @compile(x)
+ elseif Source\is_instance(x)
+ tostring(x)\as_lua!
+ else x\as_lua!
+
+ for k,v in pairs((SyntaxTree\is_instance(tree[1]) and tree[1].type == "EscapedNomsu" and tree) or tree[1])
+ entry_lua = LuaCode!
+ if k == i
+ i += 1
+ elseif type(k) == 'string' and match(k,"[_a-zA-Z][_a-zA-Z0-9]*")
+ entry_lua\add(k, "= ")
+ else
+ entry_lua\add("[", as_lua(k), "]= ")
+ entry_lua\add as_lua(v)
+ if needs_comma then lua\add ","
+ if lua\trailing_line_len! + #(entry_lua\text!\match("^[\n]*")) > MAX_LINE
+ lua\add "\n "
+ elseif needs_comma
+ lua\add " "
+ lua\add entry_lua
+ needs_comma = true
+ lua\add "}"
+ return lua
+
+ when "Block"
+ lua = LuaCode\from(tree.source)
+ for i, line in ipairs tree
+ if i > 1 then lua\add "\n"
+ lua\add @compile(line)
+ return lua
+ when "Text"
+ lua = LuaCode\from(tree.source)
+ added = 0
+ string_buffer = ""
+ add_bit = (bit)->
+ if added > 0
+ if lua\trailing_line_len! + #bit > MAX_LINE
+ lua\add "\n "
+ lua\add ".."
+ lua\add bit
+ added += 1
+
+ for i, bit in ipairs tree
+ if type(bit) == "string"
+ string_buffer ..= bit
+ continue
if string_buffer != ""
for i=1,#string_buffer,MAX_LINE
add_bit string_buffer\sub(i, i+MAX_LINE-1)\as_lua!
string_buffer = ""
- if added == 0
- add_bit '""'
- if added > 1
- lua\parenthesize!
- return lua
+ bit_lua = @compile(bit)
+ if bit.type == "Block" and #bit == 1
+ bit = bit[1]
+ if bit.type == "Block"
+ bit_lua = LuaCode\from bit.source, "List(function(add)",
+ "\n ", bit_lua,
+ "\nend):joined()"
+ elseif bit.type != "Text"
+ bit_lua = LuaCode\from(bit.source, "tostring(",bit_lua,")")
+ add_bit bit_lua
+
+ if string_buffer != ""
+ for i=1,#string_buffer,MAX_LINE
+ add_bit string_buffer\sub(i, i+MAX_LINE-1)\as_lua!
+ string_buffer = ""
- when "List", "Dict"
- if #tree == 0
- return LuaCode\from tree.source, tree.type, "{}"
+ if added == 0
+ add_bit '""'
+ if added > 1
+ lua\parenthesize!
+ return lua
- lua = LuaCode\from tree.source
- chunks = 0
- i = 1
- while tree[i]
- if tree[i].type == 'Block'
- lua\add " + " if chunks > 0
- lua\add tree.type, "(function(", (tree.type == 'List' and "add" or ("add, "..("add 1 =")\as_lua_id!)), ")"
- lua\add "\n ", compile(tree[i]), "\nend)"
- chunks += 1
+ when "List", "Dict"
+ if #tree == 0
+ return LuaCode\from tree.source, tree.type, "{}"
+
+ lua = LuaCode\from tree.source
+ chunks = 0
+ i = 1
+ while tree[i]
+ if tree[i].type == 'Block'
+ lua\add " + " if chunks > 0
+ lua\add tree.type, "(function(", (tree.type == 'List' and "add" or ("add, "..("add 1 =")\as_lua_id!)), ")"
+ lua\add "\n ", @compile(tree[i]), "\nend)"
+ chunks += 1
+ i += 1
+ else
+ lua\add " + " if chunks > 0
+ sep = ''
+ items_lua = LuaCode\from tree[i].source
+ while tree[i]
+ if tree[i].type == "Block"
+ break
+ item_lua = @compile tree[i]
+ if item_lua\text!\match("^%.[a-zA-Z_]")
+ item_lua = item_lua\text!\sub(2)
+ if tree.type == 'Dict' and tree[i].type == 'Index'
+ item_lua = LuaCode\from tree[i].source, item_lua, "=true"
+ items_lua\add sep, item_lua
+ if tree[i].type == "Comment"
+ items_lua\add "\n"
+ sep = ''
+ elseif items_lua\trailing_line_len! > MAX_LINE
+ sep = ',\n '
+ else
+ sep = ', '
i += 1
+ if items_lua\is_multiline!
+ lua\add LuaCode\from items_lua.source, tree.type, "{\n ", items_lua, "\n}"
else
- lua\add " + " if chunks > 0
- sep = ''
- items_lua = LuaCode\from tree[i].source
- while tree[i]
- if tree[i].type == "Block"
- break
- item_lua = compile tree[i]
- if item_lua\text!\match("^%.[a-zA-Z_]")
- item_lua = item_lua\text!\sub(2)
- if tree.type == 'Dict' and tree[i].type == 'Index'
- item_lua = LuaCode\from tree[i].source, item_lua, "=true"
- items_lua\add sep, item_lua
- if tree[i].type == "Comment"
- items_lua\add "\n"
- sep = ''
- elseif items_lua\trailing_line_len! > MAX_LINE
- sep = ',\n '
- else
- sep = ', '
- i += 1
- if items_lua\is_multiline!
- lua\add LuaCode\from items_lua.source, tree.type, "{\n ", items_lua, "\n}"
- else
- lua\add LuaCode\from items_lua.source, tree.type, "{", items_lua, "}"
- chunks += 1
-
- return lua
-
- when "Index"
- key_lua = compile(tree[1])
- key_str = match(key_lua\text!, '^"([a-zA-Z_][a-zA-Z0-9_]*)"$')
- return if key_str and key_str\is_lua_id!
- LuaCode\from tree.source, ".", key_str
- elseif sub(key_lua\text!,1,1) == "["
- -- NOTE: this *must* use a space after the [ to avoid freaking out
- -- Lua's parser if the inner expression is a long string. Lua
- -- parses x[[[y]]] as x("[y]"), not as x["y"]
- LuaCode\from tree.source, "[ ",key_lua,"]"
- else
- LuaCode\from tree.source, "[",key_lua,"]"
+ lua\add LuaCode\from items_lua.source, tree.type, "{", items_lua, "}"
+ chunks += 1
+
+ return lua
- when "DictEntry"
- key = tree[1]
+ when "Index"
+ key_lua = @compile(tree[1])
+ key_str = match(key_lua\text!, '^"([a-zA-Z_][a-zA-Z0-9_]*)"$')
+ return if key_str and key_str\is_lua_id!
+ LuaCode\from tree.source, ".", key_str
+ elseif sub(key_lua\text!,1,1) == "["
+ -- NOTE: this *must* use a space after the [ to avoid freaking out
+ -- Lua's parser if the inner expression is a long string. Lua
+ -- parses x[[[y]]] as x("[y]"), not as x["y"]
+ LuaCode\from tree.source, "[ ",key_lua,"]"
+ else
+ LuaCode\from tree.source, "[",key_lua,"]"
+
+ when "DictEntry"
+ key = tree[1]
+ if key.type != "Index"
+ key = SyntaxTree{type:"Index", source:key.source, key}
+ return LuaCode\from tree.source, @compile(key),"=",(tree[2] and @compile(tree[2]) or "true")
+
+ when "IndexChain"
+ lua = @compile(tree[1])
+ if lua\text!\match("['\"}]$") or lua\text!\match("]=*]$")
+ lua\parenthesize!
+ for i=2,#tree
+ key = tree[i]
+ -- TODO: remove this shim
if key.type != "Index"
key = SyntaxTree{type:"Index", source:key.source, key}
- return LuaCode\from tree.source, compile(key),"=",(tree[2] and compile(tree[2]) or "true")
-
- when "IndexChain"
- lua = compile(tree[1])
- if lua\text!\match("['\"}]$") or lua\text!\match("]=*]$")
- lua\parenthesize!
- for i=2,#tree
- key = tree[i]
- -- TODO: remove this shim
- if key.type != "Index"
- key = SyntaxTree{type:"Index", source:key.source, key}
- lua\add compile(key)
- return lua
-
- when "Number"
- return LuaCode\from(tree.source, tostring(tree[1]))
+ lua\add @compile(key)
+ return lua
- when "Var"
- return LuaCode\from(tree.source, tree\as_var!\as_lua_id!)
+ when "Number"
+ return LuaCode\from(tree.source, tostring(tree[1]))
- when "FileChunks"
- error("Can't convert FileChunks to a single block of lua, since each chunk's "..
- "compilation depends on the earlier chunks")
-
- when "Comment"
- return LuaCode\from(tree.source, "-- ", (tree[1]\gsub('\n', '\n-- ')))
-
- when "Error"
- error("Can't compile errors")
+ when "Var"
+ return LuaCode\from(tree.source, tree\as_var!\as_lua_id!)
- else
- error("Unknown type: #{tree.type}")
+ when "FileChunks"
+ error("Can't convert FileChunks to a single block of lua, since each chunk's "..
+ "compilation depends on the earlier chunks")
+
+ when "Comment"
+ return LuaCode\from(tree.source, "-- ", (tree[1]\gsub('\n', '\n-- ')))
+
+ when "Error"
+ error("Can't compile errors")
-})
+ else
+ error("Unknown type: #{tree.type}")
return {:compile, :compile_error}
diff --git a/nomsu_decompiler.lua b/nomsu_decompiler.lua
index 472be27..be71c48 100644
--- a/nomsu_decompiler.lua
+++ b/nomsu_decompiler.lua
@@ -130,7 +130,7 @@ tree_to_inline_nomsu = function(tree)
local interp_nomsu = tree_to_inline_nomsu(bit)
if bit.type ~= "Var" and bit.type ~= "List" and bit.type ~= "Dict" then
interp_nomsu:parenthesize()
- elseif bit.type == "Var" and type(tree[i + 1]) == 'string' and not match(tree[i + 1], "^[ \n\t,.:;#(){}[%]]") then
+ elseif bit.type == "Var" and type(bit[1]) == 'string' and type(tree[i + 1]) == 'string' and not match(tree[i + 1], "^[ \n\t,.:;#(){}[%]]") then
interp_nomsu:parenthesize()
end
nomsu:add("\\", interp_nomsu)
diff --git a/nomsu_decompiler.moon b/nomsu_decompiler.moon
index 03e9956..090e9b2 100644
--- a/nomsu_decompiler.moon
+++ b/nomsu_decompiler.moon
@@ -95,7 +95,8 @@ tree_to_inline_nomsu = (tree)->
interp_nomsu = tree_to_inline_nomsu(bit)
if bit.type != "Var" and bit.type != "List" and bit.type != "Dict"
interp_nomsu\parenthesize!
- elseif bit.type == "Var" and type(tree[i+1]) == 'string' and not match(tree[i+1], "^[ \n\t,.:;#(){}[%]]")
+ elseif bit.type == "Var" and type(bit[1]) == 'string' and
+ type(tree[i+1]) == 'string' and not match(tree[i+1], "^[ \n\t,.:;#(){}[%]]")
interp_nomsu\parenthesize!
nomsu\add "\\", interp_nomsu
nomsu = NomsuCode\from(tree.source)
diff --git a/nomsu_environment.lua b/nomsu_environment.lua
index 13225c0..7295676 100644
--- a/nomsu_environment.lua
+++ b/nomsu_environment.lua
@@ -3,11 +3,6 @@ do
local _obj_0 = require("code_obj")
NomsuCode, LuaCode, Source = _obj_0.NomsuCode, _obj_0.LuaCode, _obj_0.Source
end
-local Importer, import_to_1_from, _1_forked
-do
- local _obj_0 = require('importer')
- Importer, import_to_1_from, _1_forked = _obj_0.Importer, _obj_0.import_to_1_from, _obj_0._1_forked
-end
local List, Dict, Text
do
local _obj_0 = require('containers')
@@ -24,26 +19,27 @@ make_tree = function(tree, userdata)
tree = SyntaxTree(tree)
return tree
end
+table.map = function(t, fn)
+ return setmetatable((function()
+ local _accum_0 = { }
+ local _len_0 = 1
+ for _, v in ipairs(t) do
+ _accum_0[_len_0] = fn(v)
+ _len_0 = _len_0 + 1
+ end
+ return _accum_0
+ end)(), getmetatable(t))
+end
local Parsers = { }
local max_parser_version = 0
for version = 1, 999 do
local peg_file
if package.nomsupath then
- for path in package.nomsupath:gmatch("[^;]+") do
- local _continue_0 = false
- repeat
- if path == "." and package.nomsupath ~= "." then
- _continue_0 = true
- break
- end
- peg_file = io.open(path .. "/nomsu." .. tostring(version) .. ".peg")
- if peg_file then
- break
- end
- _continue_0 = true
- until true
- if not _continue_0 then
- break
+ local pegpath = package.nomsupath:gsub("%.nom", ".peg")
+ do
+ local path = package.searchpath("nomsu." .. tostring(version), pegpath, "/")
+ if path then
+ peg_file = io.open(path)
end
end
else
@@ -68,8 +64,10 @@ do
compile, compile_error = _obj_0.compile, _obj_0.compile_error
end
local _currently_running_files = List({ })
-local nomsu_environment = Importer({
- NOMSU_COMPILER_VERSION = 12,
+local nomsu_environment
+local _module_imports = { }
+nomsu_environment = setmetatable({
+ NOMSU_COMPILER_VERSION = 13,
NOMSU_SYNTAX_VERSION = max_parser_version,
next = next,
unpack = unpack or table.unpack,
@@ -129,14 +127,12 @@ local nomsu_environment = Importer({
NomsuCode_from = (function(src, ...)
return NomsuCode:from(src, ...)
end),
- SOURCE_MAP = Importer({ }),
+ SOURCE_MAP = { },
+ getfenv = getfenv,
_1_as_nomsu = tree_to_nomsu,
_1_as_inline_nomsu = tree_to_inline_nomsu,
compile = compile,
- _1_as_lua = compile,
compile_error_at = compile_error,
- _1_forked = _1_forked,
- import_to_1_from = import_to_1_from,
exit = os.exit,
quit = os.exit,
_1_parsed = function(nomsu_code, syntax_version)
@@ -208,19 +204,87 @@ local nomsu_environment = Importer({
end
return tree
end,
- run_1_in = function(to_run, environment)
+ load_module = function(self, package_name)
+ local path
+ if package_name:match("%.nom$") or package_name:match("%.lua") then
+ path = package_name
+ else
+ local err
+ path, err = package.searchpath(package_name, package.nomsupath, "/")
+ if not path then
+ error(err)
+ end
+ end
+ path = path:gsub("^%./", "")
+ do
+ local ret = package.loaded[package_name] or package.loaded[path]
+ if ret then
+ return ret
+ end
+ end
+ if _currently_running_files:has(path) then
+ local i = _currently_running_files:index_of(path)
+ _currently_running_files:add(path)
+ local circle = _currently_running_files:from_1_to(i, -1)
+ error("Circular import detected:\n " .. circle:joined_with("\n..imports "))
+ 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)
+ else
+ code = NomsuCode:from(Source(path, 1, #code), code)
+ end
+ _currently_running_files:add(path)
+ assert(mod[jit and "_G" or "_ENV"] == mod)
+ mod:run(code)
+ assert(mod[jit and "_G" or "_ENV"] == mod)
+ _currently_running_files:pop()
+ package.loaded[package_name] = mod
+ package.loaded[path] = mod
+ return mod
+ end,
+ use = function(self, package_name)
+ local mod = self:load_module(package_name)
+ assert(mod[jit and "_G" or "_ENV"] == mod)
+ local imports = assert(_module_imports[self])
+ for k, v in pairs(mod) do
+ imports[k] = v
+ end
+ assert(mod[jit and "_G" or "_ENV"] == mod)
+ return mod
+ end,
+ export = function(self, package_name)
+ local mod = self:load_module(package_name)
+ assert(mod[jit and "_G" or "_ENV"] == mod)
+ local imports = assert(_module_imports[self])
+ for k, v in pairs(_module_imports[mod]) do
+ imports[k] = v
+ end
+ for k, v in pairs(mod) do
+ if k ~= "_G" and k ~= "_ENV" then
+ self[k] = v
+ end
+ end
+ assert(mod[jit and "_G" or "_ENV"] == mod)
+ return mod
+ end,
+ run = function(self, to_run)
+ if not to_run then
+ error("Need both something to run and an environment")
+ end
if type(to_run) == 'string' then
local filename = Files.spoof(to_run)
to_run = NomsuCode:from(Source(filename, 1, #to_run), to_run)
- local ret = environment.run_1_in(to_run, environment)
- return ret
+ return self:run(to_run)
elseif NomsuCode:is_instance(to_run) then
- local tree = environment._1_parsed(to_run)
+ local tree = self._1_parsed(to_run)
if tree == nil then
return nil
end
- local ret = environment.run_1_in(tree, environment)
- return ret
+ return self:run(tree)
elseif SyntaxTree:is_instance(to_run) then
local filename = to_run.source.filename:gsub("\n.*", "...")
if to_run.type ~= "FileChunks" then
@@ -230,16 +294,16 @@ local nomsu_environment = Importer({
end
local ret = nil
for chunk_no, chunk in ipairs(to_run) do
- local lua = environment.compile(chunk)
+ local lua = self:compile(chunk)
lua:declare_locals()
lua:prepend("-- File: " .. tostring(filename) .. " chunk #" .. tostring(chunk_no) .. "\n")
- ret = environment.run_1_in(lua, environment)
+ ret = self:run(lua)
end
return ret
elseif LuaCode:is_instance(to_run) then
local source = to_run.source
local lua_string = to_run:text()
- local run_lua_fn, err = load(lua_string, tostring(source), "t", environment)
+ local run_lua_fn, err = load(lua_string, tostring(source), "t", self)
if not run_lua_fn then
local lines
do
@@ -255,7 +319,7 @@ local nomsu_environment = Importer({
error("Failed to compile generated code:\n\027[1;34m" .. tostring(line_numbered_lua) .. "\027[0m\n\n" .. tostring(err), 0)
end
local source_key = tostring(source)
- if not (environment.SOURCE_MAP[source_key] or environment.OPTIMIZATION >= 2) then
+ if not (self.SOURCE_MAP[source_key] or self.OPTIMIZATION >= 2) then
local map = { }
local file = Files.read(source.filename)
if not file then
@@ -285,87 +349,33 @@ local nomsu_environment = Importer({
map_sources(to_run)
map[lua_line] = map[lua_line] or nomsu_line
map[0] = 0
- environment.SOURCE_MAP[source_key] = map
+ self.SOURCE_MAP[source_key] = map
end
return run_lua_fn()
else
return error("Attempt to run unknown thing: " .. tostring(to_run))
end
end,
- FILE_CACHE = { },
- run_file_1_in = function(path, environment, optimization, prefix)
- if prefix == nil then
- prefix = nil
- end
- if not optimization then
- optimization = environment.OPTIMIZATION
- end
- if environment.FILE_CACHE[path] then
- import_to_1_from(environment, environment.FILE_CACHE[path], prefix)
- return
- end
- if _currently_running_files:has(path) then
- local i = _currently_running_files:index_of(path)
- _currently_running_files:add(path)
- local circle = _currently_running_files:from_1_to(i, -1)
- error("Circular import detected:\n " .. circle:joined_with("\n..imports "))
- end
- _currently_running_files:add(path)
- local mod = _1_forked(environment)
- local did_anything = false
- for nomsupath in package.nomsupath:gmatch("[^;]+") do
- local _continue_0 = false
- repeat
- do
- local full_path = nomsupath == "." and path or nomsupath .. "/" .. path
- local files = Files.list(full_path)
- if not (files) then
- _continue_0 = true
- break
- end
- for _index_0 = 1, #files do
- local _continue_1 = false
- repeat
- local filename = files[_index_0]
- local lua_filename = filename:gsub("%.nom$", ".lua")
- if environment.FILE_CACHE[filename] then
- import_to_1_from(environment, environment.FILE_CACHE[filename], prefix)
- did_anything = true
- _continue_1 = true
- break
- end
- local code
- if optimization ~= 0 and Files.exists(lua_filename) then
- local file = Files.read(lua_filename)
- code = LuaCode:from(Source(filename, 1, #file), file)
- else
- local file = Files.read(filename)
- code = NomsuCode:from(Source(filename, 1, #file), file)
- end
- environment.run_1_in(code, mod)
- did_anything = true
- _continue_1 = true
- until true
- if not _continue_1 then
- break
- end
- end
- break
- end
- _continue_0 = true
- until true
- if not _continue_0 then
- break
+ new_environment = function()
+ local env = { }
+ do
+ local _tbl_0 = { }
+ for k, v in pairs(nomsu_environment) do
+ _tbl_0[k] = v
end
+ _module_imports[env] = _tbl_0
end
- if not (did_anything) then
- error("File not found: " .. tostring(path) .. "\n(searched in " .. tostring(package.nomsupath) .. ")", 0)
- end
- import_to_1_from(environment, mod, prefix)
- environment.FILE_CACHE[path] = mod
- return _currently_running_files:remove()
+ env[jit and "_G" or "_ENV"] = env
+ setmetatable(env, getmetatable(nomsu_environment))
+ return env
+ end
+}, {
+ __index = function(self, k)
+ return _module_imports[self][k]
end
})
-nomsu_environment._ENV = nomsu_environment
+nomsu_environment[jit and "_G" or "_ENV"] = nomsu_environment
+nomsu_environment.COMPILE_RULES = require('bootstrap')
+_module_imports[nomsu_environment] = { }
SOURCE_MAP = nomsu_environment.SOURCE_MAP
return nomsu_environment
diff --git a/nomsu_environment.moon b/nomsu_environment.moon
index 6ae57d2..70f2848 100644
--- a/nomsu_environment.moon
+++ b/nomsu_environment.moon
@@ -1,7 +1,6 @@
-- This file defines the environment in which Nomsu code runs, including some
-- basic bootstrapping functionality.
{:NomsuCode, :LuaCode, :Source} = require "code_obj"
-{:Importer, :import_to_1_from, :_1_forked} = require 'importer'
{:List, :Dict, :Text} = require 'containers'
SyntaxTree = require "syntax_tree"
Files = require "files"
@@ -14,15 +13,16 @@ make_tree = (tree, userdata)->
tree = SyntaxTree(tree)
return tree
+table.map = (t, fn)-> setmetatable([fn(v) for _,v in ipairs(t)], getmetatable(t))
+
Parsers = {}
max_parser_version = 0
for version=1,999
local peg_file
if package.nomsupath
- for path in package.nomsupath\gmatch("[^;]+")
- continue if path == "." and package.nomsupath != "."
- peg_file = io.open(path.."/nomsu.#{version}.peg")
- break if peg_file
+ pegpath = package.nomsupath\gsub("%.nom", ".peg")
+ if path = package.searchpath("nomsu.#{version}", pegpath, "/")
+ peg_file = io.open(path)
else
peg_file = io.open("nomsu.#{version}.peg")
break unless peg_file
@@ -34,8 +34,10 @@ 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
-nomsu_environment = Importer{
- NOMSU_COMPILER_VERSION: 12, NOMSU_SYNTAX_VERSION: max_parser_version
+local nomsu_environment
+_module_imports = {}
+nomsu_environment = setmetatable({
+ NOMSU_COMPILER_VERSION: 13, NOMSU_SYNTAX_VERSION: max_parser_version
-- Lua stuff:
:next, unpack: unpack or table.unpack, :setmetatable, :rawequal, :getmetatable, :pcall,
yield:coroutine.yield, resume:coroutine.resume, coroutine_status_of:coroutine.status,
@@ -53,12 +55,13 @@ nomsu_environment = Importer{
:LuaCode, :NomsuCode, :Source
LuaCode_from: ((src, ...)-> LuaCode\from(src, ...)),
NomsuCode_from: ((src, ...)-> NomsuCode\from(src, ...)),
- SOURCE_MAP: Importer({})
+ SOURCE_MAP: {},
+ getfenv:getfenv,
-- Nomsu functions:
_1_as_nomsu:tree_to_nomsu, _1_as_inline_nomsu:tree_to_inline_nomsu,
- compile: compile, _1_as_lua: compile, compile_error_at:compile_error,
- :_1_forked, :import_to_1_from, exit:os.exit, quit:os.exit,
+ compile: compile, compile_error_at:compile_error,
+ exit:os.exit, quit:os.exit,
_1_parsed: (nomsu_code, syntax_version)->
if type(nomsu_code) == 'string'
@@ -96,17 +99,72 @@ nomsu_environment = Importer{
return tree
- run_1_in: (to_run, environment)->
+ load_module: (package_name)=>
+ local path
+ if package_name\match("%.nom$") or package_name\match("%.lua")
+ path = package_name
+ else
+ path, err = package.searchpath(package_name, package.nomsupath, "/")
+ if not path then error(err)
+ path = path\gsub("^%./", "")
+
+ if ret = package.loaded[package_name] or package.loaded[path]
+ return ret
+
+ if _currently_running_files\has(path)
+ i = _currently_running_files\index_of(path)
+ _currently_running_files\add path
+ circle = _currently_running_files\from_1_to(i, -1)
+ 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)
+ else
+ code = NomsuCode\from(Source(path, 1, #code), code)
+ _currently_running_files\add path
+ assert(mod[jit and "_G" or "_ENV"] == mod)
+ mod\run(code)
+ assert(mod[jit and "_G" or "_ENV"] == mod)
+ _currently_running_files\pop!
+ package.loaded[package_name] = mod
+ package.loaded[path] = mod
+ return mod
+
+ use: (package_name)=>
+ mod = @load_module(package_name)
+ assert(mod[jit and "_G" or "_ENV"] == mod)
+ imports = assert _module_imports[@]
+ for k,v in pairs(mod)
+ imports[k] = v
+ assert(mod[jit and "_G" or "_ENV"] == mod)
+ return mod
+
+ export: (package_name)=>
+ mod = @load_module(package_name)
+ assert(mod[jit and "_G" or "_ENV"] == mod)
+ imports = assert _module_imports[@]
+ for k,v in pairs(_module_imports[mod])
+ imports[k] = v
+ for k,v in pairs(mod)
+ if k != "_G" and k != "_ENV"
+ @[k] = v
+ assert(mod[jit and "_G" or "_ENV"] == mod)
+ return mod
+
+ run: (to_run)=>
+ if not to_run
+ error("Need both something to run and an environment")
if type(to_run) == 'string'
filename = Files.spoof(to_run)
to_run = NomsuCode\from(Source(filename, 1, #to_run), to_run)
- ret = environment.run_1_in(to_run, environment)
- return ret
+ return @run(to_run)
elseif NomsuCode\is_instance(to_run)
- tree = environment._1_parsed(to_run)
+ tree = @._1_parsed(to_run)
return nil if tree == nil
- ret = environment.run_1_in(tree, environment)
- return ret
+ return @run(tree)
elseif SyntaxTree\is_instance(to_run)
filename = to_run.source.filename\gsub("\n.*", "...")
if to_run.type != "FileChunks"
@@ -116,22 +174,22 @@ nomsu_environment = Importer{
-- compiles.
ret = nil
for chunk_no, chunk in ipairs to_run
- lua = environment.compile(chunk)
+ lua = @compile(chunk)
lua\declare_locals!
lua\prepend "-- File: #{filename} chunk ##{chunk_no}\n"
- ret = environment.run_1_in(lua, environment)
+ ret = @run(lua)
return ret
elseif LuaCode\is_instance(to_run)
source = to_run.source
lua_string = to_run\text!
-- If you replace tostring(source) with "nil", source mapping won't happen
- run_lua_fn, err = load(lua_string, tostring(source), "t", environment)
+ 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)]
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)
- unless environment.SOURCE_MAP[source_key] or environment.OPTIMIZATION >= 2
+ unless @SOURCE_MAP[source_key] or @OPTIMIZATION >= 2
map = {}
file = Files.read(source.filename)
if not file
@@ -152,56 +210,23 @@ nomsu_environment = Importer{
map[lua_line] or= nomsu_line
map[0] = 0
-- Mapping from lua line number to nomsu line numbers
- environment.SOURCE_MAP[source_key] = map
+ @SOURCE_MAP[source_key] = map
return run_lua_fn!
else
error("Attempt to run unknown thing: "..tostring(to_run))
-
- FILE_CACHE: {}
- run_file_1_in: (path, environment, optimization, prefix=nil)->
- if not optimization
- optimization = environment.OPTIMIZATION
- if environment.FILE_CACHE[path]
- import_to_1_from(environment, environment.FILE_CACHE[path], prefix)
- return
- if _currently_running_files\has(path)
- i = _currently_running_files\index_of(path)
- _currently_running_files\add path
- circle = _currently_running_files\from_1_to(i, -1)
- error("Circular import detected:\n "..circle\joined_with("\n..imports "))
- _currently_running_files\add path
- mod = _1_forked(environment)
- did_anything = false
- for nomsupath in package.nomsupath\gmatch("[^;]+")
- full_path = nomsupath == "." and path or nomsupath.."/"..path
- files = Files.list(full_path)
- continue unless files
- for filename in *files
- lua_filename = filename\gsub("%.nom$", ".lua")
- -- Need to check here to prevent re-running files
- if environment.FILE_CACHE[filename]
- import_to_1_from(environment, environment.FILE_CACHE[filename], prefix)
- did_anything = true
- continue
- -- TODO: don't automatically use precompiled version?
- code = if optimization != 0 and Files.exists(lua_filename)
- -- TODO: use a checksum?
- file = Files.read(lua_filename)
- LuaCode\from(Source(filename, 1, #file), file)
- else
- file = Files.read(filename)
- NomsuCode\from(Source(filename, 1, #file), file)
- environment.run_1_in(code, mod)
- did_anything = true
- break
- unless did_anything
- error("File not found: #{path}\n(searched in #{package.nomsupath})", 0)
- import_to_1_from(environment, mod, prefix)
- environment.FILE_CACHE[path] = mod
- _currently_running_files\remove!
-}
-nomsu_environment._ENV = nomsu_environment
+ new_environment: ->
+ env = {}
+ _module_imports[env] = {k,v for k,v in pairs(nomsu_environment)}
+ env[jit and "_G" or "_ENV"] = env
+ setmetatable(env, getmetatable(nomsu_environment))
+ return env
+}, {
+ __index: (k)=> _module_imports[@][k]
+})
+nomsu_environment[jit and "_G" or "_ENV"] = nomsu_environment
+nomsu_environment.COMPILE_RULES = require('bootstrap')
+_module_imports[nomsu_environment] = {}
-- Hacky use of globals:
export SOURCE_MAP
diff --git a/tools/find.nom b/tools/find.nom
index 8f2bc9f..f9a63b9 100755
--- a/tools/find.nom
+++ b/tools/find.nom
@@ -16,8 +16,8 @@
<filename>:<line number>:
<matching lines>
-use "lib/os.nom"
-use "lib/consolecolor.nom"
+use "lib/os"
+use "lib/consolecolor"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/tools/format.nom b/tools/format.nom
index 4915e46..07f7980 100755
--- a/tools/format.nom
+++ b/tools/format.nom
@@ -7,7 +7,7 @@
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.nom"
+use "lib/os"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/tools/parse.nom b/tools/parse.nom
index ab2c583..22bfdc3 100755
--- a/tools/parse.nom
+++ b/tools/parse.nom
@@ -3,7 +3,7 @@
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.nom"
+use "lib/os"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/tools/repl.nom b/tools/repl.nom
index 58a24d3..175d068 100755
--- a/tools/repl.nom
+++ b/tools/repl.nom
@@ -2,8 +2,8 @@
#
This file defines a Read-Evaluate-Print-Loop (REPL) for Nomsu
-use "lib/consolecolor.nom"
-use "lib/os.nom"
+use "lib/consolecolor"
+use "lib/os"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -44,7 +44,7 @@ repeat:
spoof file $buff
try:
$tree = ($buff parsed)
- ..if it fails $err:
+ ..if it fails with $err:
say $err
do next
@@ -54,7 +54,7 @@ repeat:
for $chunk in $tree:
try:
$lua = ($chunk as lua)
- ..if it fails $err: say $err
+ ..if it fails with $err: say $err
unless $lua:
do next
@@ -65,7 +65,7 @@ repeat:
$lua, remove free vars
try:
$ret = (run $lua)
- ..if it fails $err: say $err
+ ..if it fails with $err: say $err
..if it succeeds:
if (type of $ret) is:
"nil":
diff --git a/tools/replace.nom b/tools/replace.nom
index aa5d08c..f4df0e4 100755
--- a/tools/replace.nom
+++ b/tools/replace.nom
@@ -15,8 +15,8 @@
contents will be output.
If no files are passed in, this will read from stdin.
-use "lib/os.nom"
-use "lib/consolecolor.nom"
+use "lib/os"
+use "lib/consolecolor"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/tools/test.nom b/tools/test.nom
index f8373d8..44d783b 100755
--- a/tools/test.nom
+++ b/tools/test.nom
@@ -3,15 +3,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.nom"
-use "lib/consolecolor.nom"
+use "lib/os"
+use "lib/consolecolor"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-# Make sure all the files get run
-for $filename in $(COMMAND LINE ARGS).extras: use $filename
-$tests = {: for $s = $t in $TESTS: add (=lua "Source:from_string(\$s)") = $t}
for $filename in $(COMMAND LINE ARGS).extras:
+ $(test environment) = (new environment)
+ $(test environment), use $filename
$file = (read file $filename)
$version =
$file, matching ("
@@ -20,14 +19,13 @@ for $filename in $(COMMAND LINE ARGS).extras:
]*)
")
$file_tests = []
- for $src = $test in $tests:
- if ($src.filename == $filename):
- if $version:
- $test = ("
- #!/usr/bin/env nomsu -V\$version
- \$test
- ")
- $file_tests, add {.test = $test, .source = $src}
+ 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
@@ -38,7 +36,7 @@ for $filename in $(COMMAND LINE ARGS).extras:
for $ in $file_tests:
if (command line args).v:
say " \(yellow ($.test, with "\n" -> "\n "))"
- run $.test
+ $(test environment), run $.test
if (command line args).v:
say (green "PASS")
diff --git a/tools/upgrade.nom b/tools/upgrade.nom
index 01040c8..b9b8255 100755
--- a/tools/upgrade.nom
+++ b/tools/upgrade.nom
@@ -6,8 +6,8 @@
upgraded code will be printed.
use "compatibility"
-use "lib/os.nom"
-use "lib/consolecolor.nom"
+use "lib/os"
+use "lib/consolecolor"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~