aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2018-11-17 14:38:05 -0800
committerBruce Hill <bruce@bruce-hill.com>2018-11-17 14:39:08 -0800
commit7f47d4204039258cec78c767f489b7809b4257ff (patch)
treec8533068b75ab453accfe1f688705e9e94c9e279
parent34a3dd22a4e132bd4e0fe3ce89831c3fe761d3d9 (diff)
In-progress (but working) overhaul of some elements including: function
calls, lib/thing.nom API, multi-assignments, varargs, etc.
-rw-r--r--code_obj.lua7
-rw-r--r--code_obj.moon11
-rw-r--r--compatibility/2.3.nom2
-rw-r--r--compatibility/3.5.5.6.nom4
-rw-r--r--compatibility/3.nom2
-rw-r--r--compatibility/4.10.12.7.nom38
-rw-r--r--compatibility/4.11.nom24
-rw-r--r--compatibility/4.8.10.nom8
-rw-r--r--compatibility/4.9.nom2
-rw-r--r--compatibility/compatibility.nom4
-rw-r--r--containers.lua18
-rw-r--r--containers.moon11
-rw-r--r--core/collections.nom2
-rw-r--r--core/control_flow.nom2
-rw-r--r--core/coroutines.nom33
-rw-r--r--core/id.nom2
-rw-r--r--core/math.nom8
-rw-r--r--core/metaprogramming.nom109
-rw-r--r--core/operators.nom120
-rw-r--r--core/text.nom2
-rw-r--r--examples/how_do_i.nom8
-rw-r--r--importer.lua37
-rw-r--r--importer.moon26
-rw-r--r--lib/base64.nom28
-rw-r--r--lib/consolecolor.nom2
-rw-r--r--lib/things.nom163
-rw-r--r--lib/version.nom3
-rw-r--r--nomsu.4.peg4
-rw-r--r--nomsu.lua16
-rwxr-xr-xnomsu.moon13
-rw-r--r--nomsu_compiler.lua83
-rw-r--r--nomsu_compiler.moon74
-rw-r--r--nomsu_decompiler.lua10
-rw-r--r--nomsu_decompiler.moon7
-rw-r--r--nomsu_environment.lua54
-rw-r--r--nomsu_environment.moon32
-rw-r--r--syntax_tree.lua13
-rw-r--r--syntax_tree.moon17
-rwxr-xr-xtools/autoformat.nom5
-rwxr-xr-xtools/find_action.nom2
40 files changed, 550 insertions, 456 deletions
diff --git a/code_obj.lua b/code_obj.lua
index 376ee0c..69b7976 100644
--- a/code_obj.lua
+++ b/code_obj.lua
@@ -77,7 +77,6 @@ local Code
do
local _class_0
local _base_0 = {
- is_code = true,
text = function(self)
if self.__str == nil then
local buff, indent = { }, 0
@@ -169,7 +168,7 @@ do
_continue_0 = true
break
end
- if b.is_code then
+ if type(b) ~= 'string' then
b.dirty = error
end
bits[#bits + 1] = b
@@ -223,7 +222,7 @@ do
end
end
bits[#bits + 1] = b
- if b.is_code then
+ if type(b) ~= 'string' then
b.dirty = error
end
if not (type(b) == 'string') then
@@ -246,7 +245,7 @@ do
end
for i = 1, n do
local b = select(i, ...)
- if b.is_code then
+ if type(b) ~= 'string' then
b.dirty = error
end
bits[i] = b
diff --git a/code_obj.moon b/code_obj.moon
index e7fb5f3..4fcfd42 100644
--- a/code_obj.moon
+++ b/code_obj.moon
@@ -42,7 +42,6 @@ class Source
return Source(@filename, @start+offset, @stop)
class Code
- is_code: true
new: (...)=>
@bits = {}
@append(...)
@@ -101,9 +100,7 @@ class Code
assert(b, "code bit is nil")
assert(not Source\is_instance(b), "code bit is a Source")
if b == '' then continue
- b.dirty = error if b.is_code
- --if type(b) != 'string' and not (type(b) == 'table' and b.is_code)
- -- b = b\as_lua!
+ b.dirty = error if type(b) != 'string'
bits[#bits+1] = b
@dirty!
@@ -140,7 +137,7 @@ class Code
else
bits[#bits+1] = joiner
bits[#bits+1] = b
- b.dirty = error if b.is_code
+ b.dirty = error if type(b) != 'string'
unless type(b) == 'string'
b = b\text!
line = match(b, "\n([^\n]*)$")
@@ -157,9 +154,7 @@ class Code
bits[i] = bits[i-n]
for i=1,n
b = select(i, ...)
- b.dirty = error if b.is_code
- --if type(b) != 'string' and not (type(b) == 'table' and b.is_code)
- -- b = b\as_lua!
+ b.dirty = error if type(b) != 'string'
bits[i] = b
@dirty!
diff --git a/compatibility/2.3.nom b/compatibility/2.3.nom
index 7d8fae0..a07729c 100644
--- a/compatibility/2.3.nom
+++ b/compatibility/2.3.nom
@@ -1,4 +1,4 @@
-#!/usr/bin/env nomsu -V4.10.12.7
+#!/usr/bin/env nomsu -V4.11
#
This file defines upgrades from Nomsu <2.3 to Nomsu 2.3
diff --git a/compatibility/3.5.5.6.nom b/compatibility/3.5.5.6.nom
index db7b3a0..aebd0a5 100644
--- a/compatibility/3.5.5.6.nom
+++ b/compatibility/3.5.5.6.nom
@@ -7,7 +7,7 @@ use "compatibility/compatibility.nom"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
upgrade action "traceback" to "3.5.5.6" via (..)
- [%] -> (barf "'traceback' has been deprecated")
+ -> (barf "'traceback' has been deprecated")
upgrade action "traceback 1" to "3.5.5.6" via (..)
- [%] -> (barf "'traceback 1' has been deprecated")
+ -> (barf "'traceback 1' has been deprecated")
diff --git a/compatibility/3.nom b/compatibility/3.nom
index 1f23897..69f8d25 100644
--- a/compatibility/3.nom
+++ b/compatibility/3.nom
@@ -10,4 +10,4 @@ upgrade action (method %spec %body) to "3" as (my action %spec %body)
upgrade action (me) to "3" as %me
upgrade action (@) to "3" as %me
upgrade action "as" to "3" via (..)
- [] -> (barf "Object API has changed. Use (%obj::action ...) instead of (as %obj: action ...)")
+ -> (barf "Object API has changed. Use (%obj::action ...) instead of (as %obj: action ...)")
diff --git a/compatibility/4.10.12.7.nom b/compatibility/4.10.12.7.nom
index 56cdb1e..2e42bdc 100644
--- a/compatibility/4.10.12.7.nom
+++ b/compatibility/4.10.12.7.nom
@@ -44,24 +44,32 @@ upgrade action (% as lua statements) to "4.10.12.7" as (% as lua)
upgrade action (compile error at %pos %err hint %hint) to "4.10.12.7" as (..)
compile error at %pos %err %hint
+# In old code, it was okay to have imports at the top of the file in the same chunk,
+ but changes to the API now require imports to be in their own file chunk in order
+ for compilation to work properly.
upgrade %tree to "4.10.12.7" as:
if (%tree.type == "FileChunks"):
%first_chunk = %tree.1
- %first_has_use = (no)
%i = 1
- repeat while (%i < (size of %first_chunk)):
- if %first_has_use:
- if ((%first_chunk.%i.type != "Action") or (%first_chunk.%i.stub != "use")):
- %chunk2 = (%SyntaxTree {type: "Block"})
- for %j in %i to (size of %first_chunk.%i):
- %chunk2.((size of %chunk2) + 1) = %first_chunk.%i.%j
-
- for %j in %i to (size of %first_chunk.%i):
- %first_chunk.%i.%j = (nil)
-
- %table.insert %tree 2 %chunk2
- return %tree
+ %has_use = (no)
+ repeat while (%i <= (size of %first_chunk)):
+ if ((%first_chunk.%i.type == "Action") and (%first_chunk.%i.stub == "use")):
+ %has_use = (yes)
..else:
- if ((%first_chunk.type == "Action") and (%first_chunk.stub == "use")):
- %first_has_use = (yes)
+ if %has_use: go to (insert chunk)
%i += 1
+ return
+
+ === (insert chunk) ===
+ [%chunk1, %chunk2] = [..]
+ SyntaxTree {type: "Block", source: %first_chunk.source}
+ SyntaxTree {type: "Block", source: %first_chunk.source}
+ for %j in 1 to (%i - 1):
+ %chunk1.%j = %first_chunk.%j
+ for %j in %i to (size of %first_chunk):
+ %chunk2.(%j - %i + 1) = %first_chunk.%j
+
+ %new_tree = (SyntaxTree {source: %tree.source, type: "FileChunks", 1: %chunk1, 2: %chunk2})
+ for %i in 2 to (size of %tree):
+ %new_tree.(%i + 1) = %tree.%i
+ return %new_tree
diff --git a/compatibility/4.11.nom b/compatibility/4.11.nom
index 320fe5e..fdf6660 100644
--- a/compatibility/4.11.nom
+++ b/compatibility/4.11.nom
@@ -1,12 +1,34 @@
#!/usr/bin/env nomsu -V4.11
#
This file defines upgrades from Nomsu <4.11 to Nomsu 4.11
- (deleting (if all of ...), etc. shorthand)
+ (overhaul of function literals, deleting (if all of ...), etc. shorthand)
use "compatibility/compatibility.nom"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+# Overhaul of function literals:
+upgrade action "call 1 with" to "4.11" via (..)
+ for (%tree %end_version):
+ %tree2 = {type: "Action", source: %tree.source, 1: %tree.2}
+ for %arg in %tree.4 at %i:
+ %tree2.(%i + 1) = %arg
+ return (SyntaxTree %tree2)
+
+upgrade action (-> %yield_value) to "4.11" as (yield %yield_value)
+
+# Replace set {%x:1, %y:2} with [%x, %y] = [1, 2]
+upgrade action "set" to "4.11" via (..)
+ for (%tree %end_version):
+ [%lhs, %rhs] = [\[], \[]]
+ %lhs.source = %tree.(2).source
+ %rhs.source = %tree.(2).source
+ for %entry in %tree.2 at %i:
+ %lhs.%i = %entry.1
+ %rhs.%i = %entry.2
+ return (SyntaxTree {type: "Action", source: %tree.source, 1: %lhs, 2: "=", 3: %rhs})
+
+# Deprecating shorthand functions:
upgrade action [if all of %items %body, if all of %items then %body] to "4.11" as (..)
if (all of %items) %body
diff --git a/compatibility/4.8.10.nom b/compatibility/4.8.10.nom
index c0c17dc..9049830 100644
--- a/compatibility/4.8.10.nom
+++ b/compatibility/4.8.10.nom
@@ -6,7 +6,7 @@ use "compatibility/compatibility.nom"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
upgrade action "local action" to "4.8.10" via (..)
- [%tree, %end_version] ->:
+ for (%tree %end_version):
%spec = %tree.3
%body = %tree.4
if %spec.type is:
@@ -20,7 +20,7 @@ upgrade action "local action" to "4.8.10" via (..)
return \(%spec means %body)
upgrade action "action" to "4.8.10" via (..)
- [%tree, %end_version] ->:
+ for (%tree %end_version):
%spec = %tree.2
%body = %tree.3
if %body:
@@ -37,7 +37,7 @@ upgrade action "action" to "4.8.10" via (..)
return \(%spec's meaning)
upgrade action "compile 1 to" to "4.8.10" via (..)
- [%tree, %end_version] ->:
+ for (%tree %end_version):
%spec = %tree.2
%body = %tree.4
if %spec.type is:
@@ -51,7 +51,7 @@ upgrade action "compile 1 to" to "4.8.10" via (..)
return \(%spec compiles to %body)
upgrade action "parse 1 as" to "4.8.10" via (..)
- [%tree, %end_version] ->:
+ for (%tree %end_version):
%spec = %tree.2
%body = %tree.4
if %spec.type is:
diff --git a/compatibility/4.9.nom b/compatibility/4.9.nom
index e72b159..ab58a86 100644
--- a/compatibility/4.9.nom
+++ b/compatibility/4.9.nom
@@ -6,6 +6,6 @@ use "compatibility/compatibility.nom"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
upgrade action "if" to "4.9" via (..)
- [%tree, %end_version] ->:
+ for (%tree %end_version):
if ((size of %tree) > 2): return %tree
return \(when %tree.2)
diff --git a/compatibility/compatibility.nom b/compatibility/compatibility.nom
index 65e75fc..c7895e0 100644
--- a/compatibility/compatibility.nom
+++ b/compatibility/compatibility.nom
@@ -15,7 +15,7 @@ externally (upgrade action %stub to %version via %upgrade_fn) means:
%ACTION_UPGRADES.%version.%stub = %upgrade_fn
(upgrade %tree to %version as %body) parses as (..)
- upgrade to %version via ([%, %end_version] -> (% with %tree -> %body))
+ upgrade to %version via ((% %end_version) -> (% with %tree -> %body))
(upgrade action %actions to %version as %body) compiles to:
if (%actions is "Action" syntax tree):
@@ -91,7 +91,7 @@ externally [..]
for %k = %v in %tree:
add %k = (%v upgraded from %start_version to %end_version)
set %with_upgraded_args's metatable to (%tree's metatable)
- %tree = (call %UPGRADES.%ver with [%with_upgraded_args, %end_version])
+ %tree = (%UPGRADES.%ver %with_upgraded_args %end_version)
%tree.shebang = "#!/usr/bin/env nomsu -V\%end_version\n"
return %tree
diff --git a/containers.lua b/containers.lua
index f33c2ff..6417f2e 100644
--- a/containers.lua
+++ b/containers.lua
@@ -491,21 +491,21 @@ do
result[#result + 1] = tmp
end
return List(result)
+ end,
+ from_1_to = sub,
+ from = sub,
+ character = function(self, i)
+ return sub(self, i, i)
end
}
setmetatable(text_methods, {
__index = string2
})
+ setmetatable(string2, {
+ __index = error
+ })
getmetatable("").__methods = text_methods
- getmetatable("").__index = function(self, i)
- if type(i) == 'number' then
- return sub(self, i, i)
- elseif type(i) == 'table' then
- return sub(self, i[1], i[2])
- else
- return text_methods[i]
- end
- end
+ getmetatable("").__index = text_methods
getmetatable("").__add = function(self, x)
return tostring(self) .. tostring(x)
end
diff --git a/containers.moon b/containers.moon
index 990a741..0c881cd 100644
--- a/containers.moon
+++ b/containers.moon
@@ -196,16 +196,13 @@ do
i = tmp[1]
result[#result+1] = tmp
return List(result)
+ from_1_to: sub, from: sub,
+ character: (i)=> sub(@, i, i)
setmetatable(text_methods, {__index:string2})
-
+ setmetatable(string2, {__index:error})
getmetatable("").__methods = text_methods
- getmetatable("").__index = (i)=>
- -- Use [] for accessing text characters, or s[{3,4}] for s:sub(3,4)
- if type(i) == 'number' then return sub(@, i, i)
- elseif type(i) == 'table' then return sub(@, i[1], i[2])
- else return text_methods[i]
-
+ getmetatable("").__index = text_methods
getmetatable("").__add = (x)=> tostring(@)..tostring(x)
return {:List, :Dict}
diff --git a/core/collections.nom b/core/collections.nom
index 82b5dfb..a586882 100644
--- a/core/collections.nom
+++ b/core/collections.nom
@@ -72,7 +72,7 @@ test:
# Metatable stuff
test:
%t = {}
- set %t's metatable to {__tostring: [%] -> "XXX"}
+ set %t's metatable to {__tostring: % -> "XXX"}
assume ("\%t" == "XXX")
(set %dict's metatable to %metatable) compiles to "\
diff --git a/core/control_flow.nom b/core/control_flow.nom
index 964250e..9432a92 100644
--- a/core/control_flow.nom
+++ b/core/control_flow.nom
@@ -506,7 +506,7 @@ test:
assume ((result of: return 99) == 99)
# Inline thunk:
-(result of %body) compiles to "\(what ([] -> %body) compiles to)()"
+(result of %body) compiles to "\(what (-> %body) compiles to)()"
test:
%t = [1, [2, [[3], 4], 5, [[[6]]]]]
%flat = []
diff --git a/core/coroutines.nom b/core/coroutines.nom
index 7d17d63..0a625c2 100644
--- a/core/coroutines.nom
+++ b/core/coroutines.nom
@@ -3,29 +3,40 @@
This file defines the code that creates and manipulates coroutines
use "core/metaprogramming.nom"
+use "core/operators.nom"
+use "core/control_flow.nom"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test:
- %nums = []
%co = (..)
- coroutine:
- -> 4
- -> 5
- repeat 3 times: -> 6
+ ->:
+ yield 4
+ yield 5
+ repeat 3 times: yield 6
+ %nums = []
for % in coroutine %co:
%nums::add %
assume (%nums == [4, 5, 6, 6, 6]) or barf "Coroutine iteration failed"
-[coroutine %body, generator %body] all compile to "\
- ..(function()
- \(%body as lua)
- end)"
-(-> %) compiles to "coroutine.yield(true, \((% as lua expr) if % else "nil"))"
+ %d = {x:0}
+ %co2 = (..)
+ coroutine:
+ %d.x += 1
+ yield 1
+ %d.x += 1
+ yield
+ %d.x += 1
+ repeat while ((coroutine status of %co2) != "dead"):
+ resume %co2
+ assume %d.x == 3
+
+(coroutine %body) parses as (coroutine from (-> %body))
+
(for % in coroutine %co %body) compiles to "\
- ..for _junk,\(% as lua expr) in coroutine.wrap(\(%co as lua expr)) do
+ ..for \(% as lua expr) in coroutine_wrap(\(%co as lua expr)) do
\(%body as lua)
end"
diff --git a/core/id.nom b/core/id.nom
index 9cf5820..7de38f9 100644
--- a/core/id.nom
+++ b/core/id.nom
@@ -16,7 +16,7 @@ use "core/control_flow.nom"
set %obj_by_id's metatable to {__mode: "v"}
%id_by_obj = {}
set %id_by_obj's metatable to {..}
- __mode: "k", __index: [%self, %key] ->:
+ __mode: "k", __index: for (%self %key):
if (%key == (nil)):
return %self.%nil_surrogate
diff --git a/core/math.nom b/core/math.nom
index aa1d200..38fb984 100644
--- a/core/math.nom
+++ b/core/math.nom
@@ -70,7 +70,7 @@ externally [all of %items, all %items] all mean:
return (no)
return (yes)
-[all of %items, all %items] all compile to:
+#[all of %items, all %items] all compile to:
unless (%items.type is "List"):
return \(all of %items)
@@ -89,7 +89,7 @@ externally [any of %items, any %items] all mean:
return (yes)
return (no)
-[any of %items, any %items] all compile to:
+#[any of %items, any %items] all compile to:
unless (%items.type is "List"):
return \(any of %items)
@@ -110,7 +110,7 @@ externally [sum of %items, sum %items] all mean:
%total += %
return %total
-[sum of %items, sum %items] all compile to:
+#[sum of %items, sum %items] all compile to:
unless (%items.type is "List"):
return \(sum of %items)
@@ -128,7 +128,7 @@ externally [product of %items, product %items] all mean:
%prod *= %
return %prod
-[product of %items, product %items] all compile to:
+#[product of %items, product %items] all compile to:
unless (%items.type is "List"):
return \(product of %items)
diff --git a/core/metaprogramming.nom b/core/metaprogramming.nom
index 944dc34..165a814 100644
--- a/core/metaprogramming.nom
+++ b/core/metaprogramming.nom
@@ -3,7 +3,8 @@
This File contains actions for making actions and compile-time actions and some helper
functions to make that easier.
-lua> "NOMSU_CORE_VERSION = 10\nNOMSU_LIB_VERSION = 7"
+lua> "NOMSU_CORE_VERSION = 11"
+lua> "NOMSU_LIB_VERSION = 8"
lua> "\
..do
local mangle_index = 0
@@ -21,23 +22,38 @@ lua> "\
lua> "\
..compile.action["1 ->"] = function(compile, \%args, \%body)
- local lua = LuaCode("(function(")
- if SyntaxTree:is_instance(\%args) and \%args.type == "Action" then \%args = \%args:get_args() end
- local lua_args = table.map(\%args, function(a) return SyntaxTree:is_instance(a) and compile(a):text(\
- ..) or a end)
- lua:concat_append(lua_args, ", ")
+ if \%args and not \%body then \%args, \%body = {}, \%args end
local body_lua = SyntaxTree:is_instance(\%body) and compile(\%body) or \%body
if SyntaxTree:is_instance(\%body) and \%body.type ~= "Block" then body_lua:prepend("return ") end
- body_lua:remove_free_vars(lua_args)
+ local lua = LuaCode("(function(")
+ if SyntaxTree:is_instance(\%args) and \%args.type == "Action" then \%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
+ if arg_lua == "..." then
+ if i < #\%args then
+ compile_error_at(SyntaxTree:is_instance(arg) and arg or nil,
+ "Extra arguments must come last.", "Try removing any arguments after (*extra arguments*)")
+ end
+ elseif not arg_lua:is_lua_id() then
+ compile_error_at(SyntaxTree:is_instance(arg) and arg or nil,
+ "This does not compile to a Lua identifier, so it can't be used as a function argument.",
+ "This should probably be a Nomsu variable instead (like %x).")
+ end
+ lua:append(i > 1 and ", " or "", arg_lua)
+ body_lua:remove_free_vars({arg_lua})
+ end
body_lua:declare_locals()
lua:append(")\\n ", body_lua, "\\nend)")
return lua
- end"
+ end
+ compile.action["->"] = compile.action["1 ->"]
+ compile.action["for"] = compile.action["1 ->"]"
lua> "\
..compile.action["what 1 compiles to"] = function(compile, \%action)
local lua = LuaCode("compile.action[", \%action.stub:as_lua(), "](")
- local lua_args = table.map(\%action:get_args(), function(a) return compile(a) end)
+ local lua_args = table.map(\%action:get_args(), compile)
table.insert(lua_args, 1, "compile")
lua:concat_append(lua_args, ", ")
lua:append(")")
@@ -100,17 +116,6 @@ lua> "\
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-(call %fn with %args) compiles to:
- lua> "\
- ..local lua = LuaCode(compile(\%fn), "(")
- if \%args.type == 'List' then
- lua:concat_append(table.map(\%args, function(a) return compile(a) end), ", ")
- else
- lua:append('unpack(', compile(\%args), ')')
- end
- lua:append(")")
- return lua"
-
test:
(foo %x) means "outer"
with local [(foo %)'s meaning]:
@@ -124,27 +129,36 @@ test:
(%action means %body) compiles to:
lua> "\
- ..local fn_name = \%action.stub:as_lua_id()
- local \%args = \%action:get_args()
- local lua = LuaCode(fn_name, " = ", \(what (%args -> %body) compiles to))
- lua:add_free_vars({fn_name})
+ ..
+ local lua = LuaCode()
+ local fn_name = \%action.stub:as_lua_id()
+ if \%action.target then lua:append(compile(\%action.target), ".")
+ else lua:add_free_vars({fn_name}) end
+ lua:append(fn_name, " = ", \(what (%action -> %body) compiles to), ";")
return lua"
(%actions all mean %body) compiles to:
lua> "\
..local fn_name = \%actions[1].stub:as_lua_id()
+ local target = \%actions[1].target and compile(\%actions[1].target) or nil
local \%args = List(\%actions[1]:get_args())
local lua = \(what (%actions.1 means %body) compiles to)
for i=2,#\%actions do
local alias = \%actions[i]
local alias_name = alias.stub:as_lua_id()
- lua:add_free_vars({alias_name})
local \%alias_args = List(alias:get_args())
- lua:append("\\n", alias_name, " = ")
+ lua:append("\\n")
+ if alias.target then
+ lua:append(compile(alias.target), ".")
+ else
+ lua:add_free_vars({alias_name})
+ end
+ lua:append(alias_name, " = ")
if \%args == \%alias_args then
- lua:append(fn_name)
+ if target then lua:append(target, ".") end
+ lua:append(fn_name, ";")
else
- lua:append(\(what (%alias_args -> %actions.1) compiles to))
+ lua:append(\(what (%alias_args -> %actions.1) compiles to), ";")
end
end
return lua"
@@ -182,11 +196,11 @@ test:
%y = %tmp
test:
- set {%1: 1, %2: 2}
+ [%1, %2] = [1, 2]
swap %1 and %2
assume ((%1 == 2) and (%2 == 1)) or barf "\
..'parse % as %' failed on 'swap % and %'"
- set {%tmp: 1, %tmp2: 2}
+ [%tmp, %tmp2] = [1, 2]
swap %tmp and %tmp2
assume ((%tmp == 2) and (%tmp2 == 1)) or barf "\
..'parse % as %' variable mangling failed."
@@ -239,9 +253,15 @@ test:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[%action parses as %body] all parse as ([%action] all parse as %body)
-(%tree as lua expr) compiles to "compile(\(=lua "compile(\%tree, true)"), true)"
+#(%tree as lua expr) compiles to "compile(\(=lua "compile(\%tree, true)"), true)"
+externally (%tree as lua expr) means:
+ lua> "\
+ ..local tree_lua = compile(\%tree)
+ if \%tree.type == 'Block' then
+ tree_lua = LuaCode:from(\%tree.source, '(function()\n ', tree_lua, '\nend)()')
+ end
+ return tree_lua"
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
externally [%var as lua identifier, %var as lua id] all mean:
lua> "\
@@ -256,7 +276,14 @@ externally [%var as lua identifier, %var as lua id] all mean:
else error("Unknown type: "..tostring(\%var))
end"
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+test:
+ (num args (*extra arguments*)) means (select "#" (*extra arguments*))
+ assume (num args 1 2 3) == 3
+ (extra args (*extra arguments*)) means [*extra arguments*]
+ assume (extra args 1 2 3) == [1, 2, 3]
+ (third arg (*extra arguments*)) means (select 3 (*extra arguments*))
+ assume (third arg 5 6 7 8) == 7
+(*extra arguments*) compiles to "..."
(% is syntax tree) compiles to "SyntaxTree:is_instance(\(% as lua expr))"
externally (% is %kind syntax tree) means (..)
@@ -288,7 +315,7 @@ externally (%tree with vars %replacements) means (..)
(%tree has subtree %match_tree) compiles to "\
..(function()
local match_tree = \(%match_tree as lua expr)
- for subtree in coroutine.wrap(function() \(%tree as lua expr):map(coroutine.yield) end) do
+ for subtree in coroutine_wrap(function() \(%tree as lua expr):map(yield) end) do
if subtree == match_tree then return true end
end
end)()"
@@ -366,10 +393,20 @@ test:
[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
# Return statement is wrapped in a do..end block because Lua is unhappy if you
put code after a return statement, unless you wrap it in a block.
-(return %return_value) compiles to "\
- ..do return \(=lua "\%return_value and \(%return_value as lua expr) or ''") end"
+(return (*extra arguments*)) compiles to:
+ lua> "\
+ ..local lua = \(Lua "do return ")
+ for i=1,select('#',...) do
+ if i > 1 then lua:append(", ") end
+ lua:append(_1_as_lua((select(i, ...))))
+ end
+ lua:append(" end")
+ return lua"
# Literals
(yes) compiles to "true"
diff --git a/core/operators.nom b/core/operators.nom
index cc86398..a7cb116 100644
--- a/core/operators.nom
+++ b/core/operators.nom
@@ -24,57 +24,58 @@ test:
test:
%x = 10
assume (%x == 10)
-
-# Variable assignment operator
-(%var = %value) compiles to:
- lua> "\
- ..local \%var_lua = \(%var as lua expr)
- local \%value_lua = \(%value as lua expr)
- local lua = LuaCode(\%var_lua, ' = ', \%value_lua, ';')
- if \%var.type == 'Var' then
- lua:add_free_vars({compile(\%var):text()})
- end
- return lua"
-
-test:
- set {%x: 10, %y: 20}
+ [%x, %y] = [10, 20]
assume ((%x == 10) and (%y == 20)) or barf "mutli-assignment failed."
- set {%x: %y, %y: %x}
+ [%x, %y] = [%y, %x]
assume ((%y == 10) and (%x == 20)) or barf "swapping vars failed."
+ %vals = [4, 5]
+ [%x, %y] = (unpack %vals)
+ assume ((%x == 4) and (%y == 5)) or barf "unpacking failed"
-# Simultaneous mutli-assignments like: x,y,z = 1,x,3;
-# TODO: deprecate?
-(set %assignments) compiles to:
- assume (%assignments.type is "Dict") or barf "\
- ..Expected a Dict for the assignments part of '<- %' statement, not \%assignments"
-
+# Variable assignment operator
+(%var = %value) compiles to:
lua> "\
- ..local lhs, rhs = LuaCode(), LuaCode()
- for i, item in ipairs(\%assignments) do
- local \%target, \%value = item[1], item[2]
- \%value = \%value:map(function(t)
- if SyntaxTree:is_instance(t) and t.type == "Action" and t.stub == "?" then
- return \%target
+ ..
+ local lua = LuaCode()
+ if \%var.type == "List" then
+ for i, \%assignment in ipairs(\%var) do
+ if i > 1 then lua:append(", ") end
+ local assignment_lua = \(%assignment as lua expr)
+ lua:append(assignment_lua)
+ if \%assignment.type == 'Var' then
+ lua:add_free_vars({assignment_lua:text()})
end
- end)
- local target_lua = \(%target as lua)
- local value_lua = \(%value as lua)
- if \%target.type == "Var" then
- lhs:add_free_vars({target_lua:text()})
end
- if i > 1 then
- lhs:append(", ")
- rhs:append(", ")
+ lua:append(' = ')
+ if \%value.type == "List" then
+ if #\%value ~= #\%var then
+ compile_error_at(\%value,
+ "This assignment has too "..(#\%value > #\%var and "many" or "few").." values.",
+ "Make sure it has the same number of values on the left and right hand side of the '=' operator.")
+ end
+ for i, \%val in ipairs(\%value) do
+ if i > 1 then lua:append(", ") end
+ local val_lua = \(%val as lua expr)
+ lua:append(val_lua)
+ end
+ lua:append(";")
+ else
+ lua:append(\(%value as lua expr), ';')
end
- lhs:append(target_lua)
- rhs:append(value_lua)
+ else
+ local var_lua = \(%var as lua expr)
+ lua:append(var_lua)
+ if \%var.type == 'Var' then
+ lua:add_free_vars({var_lua:text()})
+ end
+ lua:append(' = ', \(%value as lua expr), ';')
end
- return LuaCode(lhs, " = ", rhs, ";")"
+ return lua"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test:
- set {%foozle: "outer", %y: "outer"}
+ [%foozle, %y] = ["outer", "outer"]
externally (set global x local y) means:
external %foozle = "inner"
%y = "inner"
@@ -82,7 +83,7 @@ test:
assume ((%foozle == "inner") and (%y == "outer")) or barf "external failed."
(external %var = %value) compiles to "\(%var as lua) = \(%value as lua)"
test:
- set {%foozle: "outer", %y: "outer"}
+ [%foozle, %y] = ["outer", "outer"]
externally (set global x local y) means:
with external [%foozle]:
%foozle = "inner"
@@ -97,7 +98,7 @@ test:
return %body_lua
test:
- set {%x: 1, %y: 2}
+ [%x, %y] = [1, 2]
with {%z: nil, %x: 999}:
%z = 999
assume (%z == 999) or barf "'with' failed."
@@ -149,29 +150,14 @@ test:
assume (%calls == 1) or barf "\
..Three-way comparison evaluated middle value multiple times"
-(%x < %y < %z) parses as (..)
- call ([%a, %b, %c] -> ((%a < %b) and (%b < %c))) with [%x, %y, %z]
-
-(%x <= %y < %z) parses as (..)
- call ([%a, %b, %c] -> ((%a <= %b) and (%b < %c))) with [%x, %y, %z]
-
-(%x < %y <= %z) parses as (..)
- call ([%a, %b, %c] -> ((%a < %b) and (%b <= %c))) with [%x, %y, %z]
-
-(%x <= %y <= %z) parses as (..)
- call ([%a, %b, %c] -> ((%a <= %b) and (%b <= %c))) with [%x, %y, %z]
-
-(%x > %y > %z) parses as (..)
- call ([%a, %b, %c] -> ((%a > %b) and (%b > %c))) with [%x, %y, %z]
-
-(%x >= %y > %z) parses as (..)
- call ([%a, %b, %c] -> ((%a >= %b) and (%b > %c))) with [%x, %y, %z]
-
-(%x > %y >= %z) parses as (..)
- call ([%a, %b, %c] -> ((%a > %b) and (%b >= %c))) with [%x, %y, %z]
-
-(%x >= %y >= %z) parses as (..)
- call ([%a, %b, %c] -> ((%a >= %b) and (%b >= %c))) with [%x, %y, %z]
+(%x < %y < %z) parses as (((%a %b %c) -> ((%a < %b) and (%b < %c))) %x %y %z)
+(%x <= %y < %z) parses as (((%a %b %c) -> ((%a <= %b) and (%b < %c))) %x %y %z)
+(%x < %y <= %z) parses as (((%a %b %c) -> ((%a < %b) and (%b <= %c))) %x %y %z)
+(%x <= %y <= %z) parses as (((%a %b %c) -> ((%a <= %b) and (%b <= %c))) %x %y %z)
+(%x > %y > %z) parses as (((%a %b %c) -> ((%a > %b) and (%b > %c))) %x %y %z)
+(%x >= %y > %z) parses as (((%a %b %c) -> ((%a >= %b) and (%b > %c))) %x %y %z)
+(%x > %y >= %z) parses as (((%a %b %c) -> ((%a > %b) and (%b >= %c))) %x %y %z)
+(%x >= %y >= %z) parses as (((%a %b %c) -> ((%a >= %b) and (%b >= %c))) %x %y %z)
# TODO: optimize for common case where x,y,z are all either variables or number literals
# Boolean Operators
@@ -249,9 +235,9 @@ test:
assume (%x == 4) or barf "*= failed"
wrap %x around 3
assume (%x == 1) or barf "wrap around failed"
-(%var += %) parses as (%var = (%var + %))
-(%var -= %) parses as (%var = (%var - %))
-(%var *= %) parses as (%var = (%var * %))
+(%var += %) parses as (%var = ((%var or 0) + %))
+(%var -= %) parses as (%var = ((%var or 0) - %))
+(%var *= %) parses as (%var = ((%var or 1) * %))
(%var /= %) parses as (%var = (%var / %))
(%var ^= %) parses as (%var = (%var ^ %))
(%var and= %) parses as (%var = (%var and %))
diff --git a/core/text.nom b/core/text.nom
index 50a0ab5..62b6656 100644
--- a/core/text.nom
+++ b/core/text.nom
@@ -63,4 +63,4 @@ externally (%num as hex) means:
for %name = %str in %escapes:
with {%lua: Lua (quote %str)}:
- %compile.action.%name = ([] -> %lua)
+ %compile.action.%name = (-> %lua)
diff --git a/examples/how_do_i.nom b/examples/how_do_i.nom
index e26103b..bae1379 100644
--- a/examples/how_do_i.nom
+++ b/examples/how_do_i.nom
@@ -219,11 +219,11 @@ I think "chihuahuas" are worse than "corgis"
# The language only reserves []{}().,:;%#\ as special characters, so actions
can have really funky names!
-(>> %foo_bar $@&' --> % @&_~-^-~_~-^ %1 !) means:
+(>> %foo_bar $@&' -->< % @&_~-^-~_~-^ %1 !) means:
say %foo_bar
say %
say %1
->> "wow" $@&' --> "so flexible!" @&_~-^-~_~-^ "even numbers can be variables!" !
+>> "wow" $@&' -->< "so flexible!" @&_~-^-~_~-^ "even numbers can be variables!" !
# There's also full unicode support
%こんにちは = "こんにちは"
@@ -305,8 +305,8 @@ debug only:
%best_key = %key
return %best
-# Function literals look like: [%x] -> (%x * %x)
-say (best of [2, -3, 4, -8] according to ([%x] -> (%x * %x)))
+# Function literals look like: %x -> (%x * %x)
+say (best of [2, -3, 4, -8] according to (%x -> (%x * %x)))
# Or, you can use ((foo %)'s meaning) to access the function that gets called by (foo %)
(%x squared) means (%x * %x)
diff --git a/importer.lua b/importer.lua
index 9b2c936..0d45db8 100644
--- a/importer.lua
+++ b/importer.lua
@@ -1,15 +1,27 @@
local import_to_1_from
-import_to_1_from = function(host, to_import)
+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)
+ 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
@@ -20,19 +32,30 @@ local Importer = setmetatable({
__index = function(self, key)
return _imports[self][key]
end,
- __import = function(self, to_import)
+ __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]
- if type(conflict) == 'table' then
- import_to_1_from(conflict, v)
+ 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
@@ -49,8 +72,8 @@ local Importer = setmetatable({
end
})
local _1_forked
-_1_forked = function(self)
- local f = Importer({ })
+_1_forked = function(self, t)
+ local f = Importer(t or { })
_imports[f] = assert(_imports[self])
import_to_1_from(f, self)
return f
diff --git a/importer.moon b/importer.moon
index 48a3800..26b78f7 100644
--- a/importer.moon
+++ b/importer.moon
@@ -1,22 +1,36 @@
-- This file defines Importer, which is a type of table that can import from other tables
-import_to_1_from = (host, to_import)->
+import_to_1_from = (host, to_import, prefix=nil)->
if host_mt = getmetatable(host)
if host_mt.__import
- host_mt.__import(host, to_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)=>
+ __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]
- import_to_1_from(conflict, v) if type(conflict) == 'table'
+ 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] = {}
@@ -24,8 +38,8 @@ Importer = setmetatable({
return t
})
-_1_forked = =>
- f = Importer{}
+_1_forked = (t)=>
+ f = Importer(t or {})
_imports[f] = assert _imports[@]
import_to_1_from(f, @)
return f
diff --git a/lib/base64.nom b/lib/base64.nom
index 01d4f2f..ea951c8 100644
--- a/lib/base64.nom
+++ b/lib/base64.nom
@@ -4,12 +4,14 @@
https://tools.ietf.org/html/rfc4648
%b64_str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
-%reverse_b64 = {: for %i in 1 to (size of %b64_str): add %b64_str.%i = (%i - 1)}
-%reverse_b64."=" = 0
+%b64_chars = [: for % in 1 to (size of %b64_str): add (%b64_str::character %)]
+%reverse_b64 = {: for %c in %b64_chars at %i: add %c = (%i - 1)}
+%reverse_b64."=" = 64
+set %reverse_b64's metatable to {__index: -> 0}
test:
%cases = ["", "Zg==", "Zm8=", "Zm9v", "Zm9vYg==", "Zm9vYmE=", "Zm9vYmFy"]
for %len = %encoded in %cases:
- %plain = "foobar".[1, %len - 1]
+ %plain = ("foobar"::from 1 to (%len - 1))
assume (base64 %plain) == %encoded
assume (base64 decode %encoded) == %plain
@@ -17,20 +19,20 @@ externally [base64 %str, base64 encode %str, %str base64] all mean:
%chars = []
for %i in 1 to (size of %str) via 3:
%bytes = [=lua "\%str:byte(\%i, \(%i + 2))"]
- %chars::add %b64_str.(((%bytes.1 & 252) >> 2) + 1)
+ %chars::add %b64_chars.(((%bytes.1 & 252) >> 2) + 1)
if (size of %bytes) is:
3:
- %chars::add %b64_str.(((%bytes.1 & 3) << 4) + ((%bytes.2 & 240) >> 4) + 1)
- %chars::add %b64_str.(((%bytes.2 & 15) << 2) + ((%bytes.3 & 192) >> 6) + 1)
- %chars::add %b64_str.((%bytes.3 & 63) + 1)
+ %chars::add %b64_chars.(((%bytes.1 & 3) << 4) + ((%bytes.2 & 240) >> 4) + 1)
+ %chars::add %b64_chars.(((%bytes.2 & 15) << 2) + ((%bytes.3 & 192) >> 6) + 1)
+ %chars::add %b64_chars.((%bytes.3 & 63) + 1)
2:
- %chars::add %b64_str.(((%bytes.1 & 3) << 4) + ((%bytes.2 & 240) >> 4) + 1)
- %chars::add %b64_str.(((%bytes.2 & 15) << 2) + 1)
+ %chars::add %b64_chars.(((%bytes.1 & 3) << 4) + ((%bytes.2 & 240) >> 4) + 1)
+ %chars::add %b64_chars.(((%bytes.2 & 15) << 2) + 1)
%chars::add "="
1:
- %chars::add %b64_str.(((%bytes.1 & 3) << 4) + 1)
+ %chars::add %b64_chars.(((%bytes.1 & 3) << 4) + 1)
%chars::add "="
%chars::add "="
return (%chars::joined)
@@ -39,10 +41,10 @@ externally (chr %) means (=lua "string.char(\%)")
externally [decode base64 %str, %str base64 decoded, base64 decode %str] all mean:
%chars = []
for %i in 1 to (size of %str) via 4:
- %indices = [: for % in %i to (%i + 3): add %reverse_b64.(%str.%)]
+ %indices = [: for %j in %i to (%i + 3): add %reverse_b64.(%str::character %j)]
%chars::add (chr ((%indices.1 << 2) + ((%indices.2 & 48) >> 4)))
- if (%str.(%i + 2) == "="): stop
+ if ((%str::character (%i + 2)) == "="): stop
%chars::add (chr (((%indices.2 & 15) << 4) + ((%indices.3 & 60) >> 2)))
- if (%str.(%i + 3) == "="): stop
+ if ((%str::character (%i + 3)) == "="): stop
%chars::add (chr (((%indices.3 & 3) << 6) + %indices.4))
return (%chars::joined)
diff --git a/lib/consolecolor.nom b/lib/consolecolor.nom
index aabb740..0114d01 100644
--- a/lib/consolecolor.nom
+++ b/lib/consolecolor.nom
@@ -19,7 +19,7 @@ for %name = %colornum in %colors:
#(=lua "COMPILE_ACTIONS").%name = (..)
[%nomsu, %tree] -> (Lua "'\\027[\(%colornum)m'")
%compile.action.%name = (..)
- [%nomsu, %text] ->:
+ for (%compile %text):
if %text:
return (Lua "('\\027[\(%colornum)m'..\(%text as lua expr)..'\\027[0m')")
..else:
diff --git a/lib/things.nom b/lib/things.nom
index 998db47..731c206 100644
--- a/lib/things.nom
+++ b/lib/things.nom
@@ -2,32 +2,28 @@
#
A library for simple object oriented programming.
-%globals.METAMETHOD_MAP = {..}
- "as text": "__tostring", "clean up": "__gc", "+": "__add", "-": "__sub"
- "*": "__mul", "/": "__div", negative: "__unm", "//": "__idiv", mod: "__mod"
- "^": "__pow", "&": "__band", "|": "__bor", "~": "__bxor", "~": "__bnot"
- "<<": "__bshl", ">>": "__bshr", "==": "__eq", "<": "__lt", "<=": "__le"
- "set 1 =": "__newindex", size: "__len", iterate: "__ipairs", "iterate all": "__pairs"
-
test:
an (Empty) is a thing
a (Dog) is a thing:
- that can (set up) by:
+ [%it, %its] = [Dog, Dog]
+ (%its::set up) means:
%its.barks or= 0
- whose [bark, woof] all mean:
+ [%its::bark, %its::woof] all mean:
%barks = [: for % in 1 to %its.barks: add "Bark!"]
return (%barks::joined with " ")
- that can (get pissed off) by: %its.barks += 1
+ (%it::gets pissed off) means:
+ %it.barks += 1
(Dog).genus = "Canus"
%d = (a Dog with {barks: 2})
+ assume "\%d" == "Dog {barks: 2}"
assume (type of %d) == "Dog"
assume (%d is a "Dog")
assume %d.barks == 2
assume ((%d::bark) == "Bark! Bark!")
assume ((%d::woof) == "Bark! Bark!")
- %d::get pissed off
+ %d::gets pissed off
assume (%d.barks == 3)
assume ((%d::bark) == "Bark! Bark! Bark!")
assume (%d.genus == "Canus")
@@ -40,112 +36,101 @@ test:
assume ((%d::bark) == "Bark!")
a (Corgi) is a thing:
- that can [set up, get pissed off] like a (Dog)
- whose (sploot) means "splooted"
- whose [bark, woof] all mean:
+ [%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"
+ [%its::bark, %its::woof] all mean:
%barks = [: for % in 1 to %its.barks: add "Yip!"]
return (%barks::joined with " ")
%corg = (a Corgi)
assume (%corg.barks == 0)
+ assume "\%corg" == "Dogloaf {barks: 0}"
with {%d: a Corgi with {barks: 1}}:
- assume ((%d::sploot) == "splooted") or barf "subclass method failed"
+ assume ((%d::sploot) == "sploooot") or barf "subclass method failed"
assume ((%d::bark) == "Yip!") or barf "inheritance failed"
assume ((%d::woof) == "Yip!")
with {%d: a Dog with {barks: 2}}:
assume ((%d::bark) == "Bark! Bark!")
-[..]
- that can %actions by %body, whose %actions means %body
- whose %actions all mean %body
-..all compile to:
- unless (%actions.type == "List"):
- %actions = [%actions]
+ a (Vec) is a thing with {x, y}:
+ %its = (Vec)
+ (%its::+ %other) means (Vec {x: %its.x + %other.x, y: %its.y + %other.y})
- lua> "\
- ..local fn_name = \%actions[1].stub:as_lua_id()
- local \%args = List{\(\%its), unpack(\%actions[1]:get_args())}
- local lua = LuaCode("class.", fn_name, " = ", \(what (%args -> %body) compiles to))
- for i=2,#\%actions do
- local alias = \%actions[i]
- local alias_name = alias.stub:as_lua_id()
- local \%alias_args = List{\(\%its), unpack(alias:get_args())}
- lua:append("\\nclass.", alias_name, " = ")
- if \%alias_args == \%args then
- lua:append("class.", fn_name)
- else
- lua:append("function(")
- lua:concat_append(table.map(\%alias_args, function(a) return compile(a) end), ", ")
- lua:append(")\\n return class.", fn_name, "(")
- lua:concat_append(table.map(\%args, function(a) return compile(a) end), ", ")
- lua:append(")\\nend")
- end
- end
- return lua"
-
+ assume ((Vec {x: 1, y:2 }) + (Vec {x: 10, y: 10})) == (Vec {x: 11, y: 12})
+ assume (((Vec {x: 1, y:2 }) + (Vec {x: 10, y: 10})) != (Vec {x: 0, y: 0}))
[..]
- that can %actions like a %class, that can %actions like an %class
- that has %actions like a %class, that has %actions like an %class
+ %it can %actions like a %class, %it can %actions like an %class
+ %it has %actions like a %class, %it has %actions like an %class
+ %it %actions like a %class, %it %actions like an %class
..all compile to:
%lua = (Lua "")
%class_expr = (%class as lua expr)
%lines = []
for %a in %actions:
- %lines::add "class.\(%a.stub::as lua id) = \%class_expr.\(%a.stub::as lua id)"
+ %lines::add "\(%it as lua expr).\(%a.stub::as lua id) = \%class_expr.\(%a.stub::as lua id)"
%lua::add %lines joined with "\n"
return %lua
+%METAMETHOD_MAP = {..}
+ "as text": "__tostring", "clean up": "__gc", "+": "__add", "-": "__sub"
+ "*": "__mul", "/": "__div", negative: "__unm", "//": "__idiv", mod: "__mod"
+ "^": "__pow", "&": "__band", "|": "__bor", "~": "__bxor", "~": "__bnot"
+ "<<": "__bshl", ">>": "__bshr", "==": "__eq", "<": "__lt", "<=": "__le"
+ "set 1 =": "__newindex", size: "__len", iterate: "__ipairs", "iterate all": "__pairs"
+
+((% as text like a dict)'s meaning) = ({}'s metatable).__tostring
+
+externally (..)
+ a class named %classname with %members ((initialize %it)'s meaning)
+..means:
+ %class = {__type: %classname}
+ %class.__index = %class
+ %class.class = %class
+ %class.__tostring = (% -> "\(%.__type) \(% as text like a dict)")
+ %class.__eq = ({}'s metatable).__eq
+ %class.__len = ({}'s metatable).__len
+ if %members:
+ %class.__members = %members
+ %class.__newindex = (..)
+ for (%its %key = %value):
+ if %members.%key:
+ rawset %its %key %value
+ ..else:
+ barf "Cannot set \%key, it's not one of the allowed member fields."
+ set %class's metatable to {..}
+ __tostring: (%class) -> %class.__type
+ __call: for (%class with %initial_values):
+ if (%initial_values == (nil)): return %class
+ set %initial_values's metatable to %class
+ if %initial_values.set_up: %initial_values::set up
+ return %initial_values
+ if ((initialize)'s meaning):
+ initialize %class
+ for %stub = %metamethod in %METAMETHOD_MAP:
+ if %class.(%stub::as lua id):
+ %class.%metamethod = %class.(%stub::as lua id)
+ return %class
+
[..]
a %classname is a thing with %members %class_body
an %classname is a thing with %members %class_body
..all compile to:
- unless (%classname.type == "Action"):
- compile error at %classname "\
- ..Expected this to be an action, not a \%classname.type"
-
- for % in %classname:
- unless (% is text):
- compile error at % "Class names should not have arguments."
-
+ %class_id = (%classname.stub::as lua id)
+ if %class_body:
+ %body_lua = (%class_body as lua)
+ %body_lua::remove free vars [%class_id]
+ %body_lua::declare locals
return (..)
Lua "\
- ..do
- local class = {name=\(quote %classname.stub)}
- class.__type = class.name
- setmetatable(class, {
- __tostring=function(cls) return cls.name end,
- __call=function(cls, inst)
- inst = setmetatable(inst or {}, cls)
- if inst.set_up then inst:set_up() end
- return inst
- end,
- })
- class.__members = \(%members as lua expr)
- _ENV[("a "..class.name):as_lua_id()] = class
- _ENV[("an "..class.name):as_lua_id()] = class
- _ENV[("a "..class.name.." with"):as_lua_id()] = class
- _ENV[("an "..class.name.." with"):as_lua_id()] = class
- _ENV[class.name:as_lua_id()] = function() return class end
- class.__index = class
- class.class = class
- local dict_tostring = getmetatable(Dict{}).__tostring
- class.__tostring = function(inst)
- return inst.name..dict_tostring(inst)
- end
- \((%class_body as lua) if %class_body else "")
- for stub,metamethod in pairs(globals.METAMETHOD_MAP) do
- class[metamethod] = class[stub:as_lua_id()]
- end
- if class.__members then
- assert(select(2, next(class.__members)) == true)
- getmetatable(class).__newindex = function(its, key, value)
- if class.__members[key] then
- rawset(its, key, value)
- else error("Not a valid member: "..tostring(key)) end
- end
- end
- end"
+ ..\%class_id = a_class_named_1_with(\(quote %classname.stub), \(%members as lua)\(..)
+ (Lua ", function(\%class_id)\n \%body_lua\nend") if %class_body else ""
+ ..)
+ a_\%class_id = function(initial_values) return \(%classname.stub::as lua id)(initial_values or {}) end
+ an_\%class_id, a_\(%class_id)_with, an_\(%class_id)_with = \
+ ..a_\%class_id, a_\%class_id, a_\%class_id"
[a %classname is a thing %class_body, an %classname is a thing] all parse as (..)
a %classname is a thing with (nil) %class_body
diff --git a/lib/version.nom b/lib/version.nom
deleted file mode 100644
index e4a29e4..0000000
--- a/lib/version.nom
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/usr/bin/env nomsu -V4.10.12.7
-# This file sets the current library version.
-lua> "NOMSU_LIB_VERSION = 7"
diff --git a/nomsu.4.peg b/nomsu.4.peg
index b2e636f..7ca8423 100644
--- a/nomsu.4.peg
+++ b/nomsu.4.peg
@@ -118,14 +118,14 @@ inline_action (Action):
( (inline_arg (ws* (inline_arg / word))+)
/ (word (ws* (inline_arg / word))*))
(ws* inline_block)?
-inline_arg: inline_expression / inline_block
+inline_arg: inline_expression / inline_block / "(" ws* ")"
action (Action):
!section_division
({:target: (expression / "(" inline_block ")" / indented_block) :}
((ws* "\")? eol nl_nodent "..")? ws* "::" ((ws* "\")? eol nl_nodent "..")? ws*)?
( (arg (((ws* "\")? eol nl_nodent "..")? ws* (arg / word))+)
/ (word (((ws* "\")? eol nl_nodent "..")? ws* (arg / word))*))
-arg: expression / inline_block / indented_block
+arg: expression / inline_block / indented_block / "(" ws* ")"
word: !number { operator_char+ / ident_char+ }
diff --git a/nomsu.lua b/nomsu.lua
index 4cbaf7c..b4e031b 100644
--- a/nomsu.lua
+++ b/nomsu.lua
@@ -202,12 +202,12 @@ run = function()
for chunk_no, chunk in ipairs(tree) do
local lua = nomsu_environment.compile(chunk)
lua:declare_locals()
- nomsu_environment.run_1_in(chunk, nomsu_environment)
- output:write((chunk_no > 1) and '\n' or '', "-- File " .. tostring(filename) .. " chunk #" .. tostring(chunk_no) .. "\n")
- output:write(tostring(lua), "\n")
+ lua:prepend((chunk_no > 1) and '\n' or '', "-- File " .. tostring(filename) .. " chunk #" .. tostring(chunk_no) .. "\n")
if args.verbose then
- print(tostring(lua))
+ print(lua:text())
end
+ nomsu_environment.run_1_in(chunk, nomsu_environment)
+ output:write(lua:text(), "\n")
end
print(("Compiled %-25s -> %s"):format(filename, filename:gsub("%.nom$", ".lua")))
output:close()
@@ -221,12 +221,12 @@ run = function()
tree
}
end
- for _index_1 = 1, #tree do
- local chunk = tree[_index_1]
+ for chunk_no, chunk in ipairs(tree) do
local lua = nomsu_environment.compile(chunk)
lua:declare_locals()
- nomsu_environment.run_1_in(chunk, nomsu_environment)
- print(tostring(lua))
+ 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)
end
else
nomsu_environment.run_file_1_in(filename, nomsu_environment, 0)
diff --git a/nomsu.moon b/nomsu.moon
index dd37034..62deada 100755
--- a/nomsu.moon
+++ b/nomsu.moon
@@ -131,10 +131,10 @@ run = ->
for chunk_no, chunk in ipairs tree
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)
- output\write((chunk_no > 1) and '\n' or '', "-- File #{filename} chunk ##{chunk_no}\n")
- output\write(tostring(lua), "\n")
- if args.verbose then print(tostring(lua))
+ output\write(lua\text!, "\n")
print ("Compiled %-25s -> %s")\format(filename, filename\gsub("%.nom$", ".lua"))
output\close!
elseif args.verbose
@@ -143,11 +143,12 @@ run = ->
code = NomsuCode\from(source, code)
tree = nomsu_environment._1_parsed(code)
tree = {tree} unless tree.type == 'FileChunks'
- for chunk in *tree
+ for chunk_no, chunk in ipairs tree
lua = nomsu_environment.compile(chunk)
lua\declare_locals!
- nomsu_environment.run_1_in(chunk, nomsu_environment)
- print(tostring(lua))
+ 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)
else
-- Just run the file
nomsu_environment.run_file_1_in(filename, nomsu_environment, 0)
diff --git a/nomsu_compiler.lua b/nomsu_compiler.lua
index 0ea2079..a1eadd8 100644
--- a/nomsu_compiler.lua
+++ b/nomsu_compiler.lua
@@ -29,6 +29,7 @@ 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 = { }
@@ -42,18 +43,28 @@ table.map = function(t, fn)
end
local pretty_error = require("pretty_errors")
local compile_error
-compile_error = function(tree, err_msg, hint)
+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 = tree:get_source_file(),
- start = tree.source.start,
- stop = tree.source.stop,
- filename = tree.source.filename
+ source = file,
+ start = source.start,
+ stop = source.stop,
+ filename = source.filename
})
return error(err_str, 0)
end
@@ -78,7 +89,7 @@ local compile = setmetatable({
if i > 1 then
lua:append(", ")
end
- lua:append(compile(select(i, ...)))
+ lua:append(compile((select(i, ...))))
end
lua:append(")")
return lua
@@ -138,6 +149,9 @@ local compile = setmetatable({
["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,
["tests"] = function(compile)
return LuaCode("TESTS")
end,
@@ -165,18 +179,13 @@ local compile = setmetatable({
end
})
}, {
- __import = function(self, other)
- import_to_1_from(self.action, other.action)
- end,
- __call = function(compile, tree, force_value)
- if force_value == nil then
- force_value = false
- 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
+ if not compile_action and not tree.target and math_expression:match(stub) then
local lua = LuaCode:from(tree.source)
for i, tok in ipairs(tree) do
if type(tok) == 'string' then
@@ -226,7 +235,7 @@ local compile = setmetatable({
if tree.target then
local target_lua = compile(tree.target)
local target_text = target_lua:text()
- if target_text:match("^%(.*%)$") or target_text:match("^[_a-zA-Z][_a-zA-Z0-9.]*$") then
+ if target_text:match("^%(.*%)$") or target_text:match("^[_a-zA-Z][_a-zA-Z0-9.]*$") or tree.target.type == "IndexChain" then
lua:append(target_lua, ":")
else
lua:append("(", target_lua, "):")
@@ -241,7 +250,10 @@ local compile = setmetatable({
_continue_0 = true
break
end
- local arg_lua = compile(tok, true)
+ local arg_lua = compile(tok)
+ if tok.type == "Block" then
+ arg_lua = LuaCode:from(tok.source, "(function()\n ", arg_lua, "\nend)()")
+ end
insert(args, arg_lua)
_continue_0 = true
until true
@@ -287,28 +299,14 @@ local compile = setmetatable({
lua:append("}")
return lua
elseif "Block" == _exp_0 then
- if not force_value then
- local lua = LuaCode:from(tree.source)
- lua:concat_append((function()
- local _accum_0 = { }
- local _len_0 = 1
- for _index_0 = 1, #tree do
- local line = tree[_index_0]
- _accum_0[_len_0] = compile(line)
- _len_0 = _len_0 + 1
- end
- return _accum_0
- end)(), "\n")
- return lua
- else
- local lua = LuaCode:from(tree.source)
- lua:append("((function()")
- for i, line in ipairs(tree) do
- lua:append("\n ", compile(line))
+ local lua = LuaCode:from(tree.source)
+ for i, line in ipairs(tree) do
+ if i > 1 then
+ lua:append("\n")
end
- lua:append("\nend)())")
- return lua
+ lua:append(compile(line))
end
+ return lua
elseif "Text" == _exp_0 then
local lua = LuaCode:from(tree.source)
local string_buffer = ""
@@ -352,7 +350,7 @@ local compile = setmetatable({
end
return lua
elseif "List" == _exp_0 or "Dict" == _exp_0 then
- local lua = LuaCode:from(tree.source, tostring(tree.type) .. "{")
+ local lua = LuaCode:from(tree.source)
local i = 1
local sep = ''
while i <= #tree do
@@ -371,7 +369,11 @@ local compile = setmetatable({
end
i = i + 1
end
- lua:append("}")
+ if lua:is_multiline() then
+ lua = LuaCode:from(tree.source, tostring(tree.type) .. "{\n ", lua, "\n}")
+ else
+ lua = LuaCode:from(tree.source, tostring(tree.type) .. "{", lua, "}")
+ end
if i <= #tree then
lua = LuaCode:from(tree.source, "(function()\n local comprehension = ", lua)
if tree.type == "List" then
@@ -441,4 +443,7 @@ local compile = setmetatable({
end
end
})
-return compile
+return {
+ compile = compile,
+ compile_error = compile_error
+}
diff --git a/nomsu_compiler.moon b/nomsu_compiler.moon
index 497d210..3ddf74b 100644
--- a/nomsu_compiler.moon
+++ b/nomsu_compiler.moon
@@ -19,19 +19,26 @@ unpack or= table.unpack
{: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:
--- Re-implement nomsu-to-lua comment translation?
-
-- TODO: de-duplicate this
pretty_error = require("pretty_errors")
-compile_error = (tree, err_msg, hint=nil)->
+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:tree\get_source_file!
- start:tree.source.start, stop:tree.source.stop, filename:tree.source.filename
+ error:err_msg, hint:hint, source:file
+ start:source.start, stop:source.stop, filename:source.filename
}
error(err_str, 0)
{:tree_to_nomsu, :tree_to_inline_nomsu} = require "nomsu_decompiler"
@@ -53,7 +60,7 @@ compile = setmetatable({
lua\append "("
for i=1,select('#',...)
lua\append(", ") if i > 1
- lua\append compile(select(i, ...))
+ lua\append compile((select(i, ...)))
lua\append ")"
return lua
@@ -94,11 +101,10 @@ compile = setmetatable({
["= lua"]: (compile, code)-> compile.action["lua >"](compile, code)
- ["use"]: (compile, path)->
- --if path.type == 'Text' and #path == 1 and type(path[1]) == 'string'
- -- unless import_to_1_from(compile, path[1])
- -- compile_error tree, "Could not find anything to import for #{path}"
- return LuaCode("run_file_1_in(#{compile(path)}, _ENV, OPTIMIZATION)")
+ ["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), ")")
["tests"]: (compile)-> LuaCode("TESTS")
["test"]: (compile, body)->
@@ -114,15 +120,13 @@ compile = setmetatable({
["nomsu environment"]: (compile)-> LuaCode("_ENV")
}
}, {
- __import: (other)=>
- import_to_1_from(@action, other.action)
- return
- __call: (compile, tree, force_value=false)->
+ __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)
+ if not compile_action and not tree.target and math_expression\match(stub)
lua = LuaCode\from(tree.source)
for i,tok in ipairs tree
if type(tok) == 'string'
@@ -155,7 +159,9 @@ compile = setmetatable({
if tree.target -- Method call
target_lua = compile tree.target
target_text = target_lua\text!
- if target_text\match("^%(.*%)$") or target_text\match("^[_a-zA-Z][_a-zA-Z0-9.]*$")
+ -- TODO: this parenthesizing is maybe overly conservative
+ if target_text\match("^%(.*%)$") or target_text\match("^[_a-zA-Z][_a-zA-Z0-9.]*$") or
+ tree.target.type == "IndexChain"
lua\append target_lua, ":"
else
lua\append "(", target_lua, "):"
@@ -163,7 +169,9 @@ compile = setmetatable({
args = {}
for i, tok in ipairs tree
if type(tok) == "string" then continue
- arg_lua = compile(tok, true)
+ arg_lua = compile(tok)
+ if tok.type == "Block"
+ arg_lua = LuaCode\from(tok.source, "(function()\n ", arg_lua, "\nend)()")
insert args, arg_lua
lua\concat_append args, ", "
lua\append ")"
@@ -196,17 +204,11 @@ compile = setmetatable({
return lua
when "Block"
- if not force_value
- lua = LuaCode\from(tree.source)
- lua\concat_append([compile(line) for line in *tree], "\n")
- return lua
- else
- lua = LuaCode\from(tree.source)
- lua\append("((function()")
- for i, line in ipairs(tree)
- lua\append "\n ", compile(line)
- lua\append("\nend)())")
- return lua
+ lua = LuaCode\from(tree.source)
+ for i, line in ipairs tree
+ if i > 1 then lua\append "\n"
+ lua\append compile(line)
+ return lua
when "Text"
lua = LuaCode\from(tree.source)
@@ -234,7 +236,7 @@ compile = setmetatable({
return lua
when "List", "Dict"
- lua = LuaCode\from tree.source, "#{tree.type}{"
+ lua = LuaCode\from tree.source
i = 1
sep = ''
while i <= #tree
@@ -250,7 +252,12 @@ compile = setmetatable({
lua\append item_lua
sep = ', '
i += 1
- lua\append "}"
+
+ if lua\is_multiline!
+ lua = LuaCode\from tree.source, "#{tree.type}{\n ", lua, "\n}"
+ else
+ lua = LuaCode\from tree.source, "#{tree.type}{", lua, "}"
+
-- List/dict comprehenstion
if i <= #tree
lua = LuaCode\from tree.source, "(function()\n local comprehension = ", lua
@@ -269,6 +276,7 @@ compile = setmetatable({
lua\append "comprehension[#comprehension+1] = ", compile(tree[i])
i += 1
lua\append "\n return comprehension\nend)()"
+
return lua
when "DictEntry"
@@ -329,4 +337,4 @@ compile = setmetatable({
})
-return compile
+return {:compile, :compile_error}
diff --git a/nomsu_decompiler.lua b/nomsu_decompiler.lua
index 46316d1..19ede3c 100644
--- a/nomsu_decompiler.lua
+++ b/nomsu_decompiler.lua
@@ -88,6 +88,9 @@ tree_to_inline_nomsu = function(tree)
nomsu:append(arg_nomsu)
end
end
+ if #tree == 1 and type(tree[1]) ~= "string" then
+ nomsu:append("()")
+ end
return nomsu
elseif "EscapedNomsu" == _exp_0 then
local inner_nomsu = tree_to_inline_nomsu(tree[1])
@@ -326,6 +329,13 @@ tree_to_nomsu = function(tree)
end
end
nomsu:append(next_space, words)
+ next_space = " "
+ end
+ if #tree == 1 and type(tree[1]) ~= "string" then
+ if next_space == " " then
+ next_space = ""
+ end
+ nomsu:append(next_space, "()")
end
return nomsu
elseif "EscapedNomsu" == _exp_0 then
diff --git a/nomsu_decompiler.moon b/nomsu_decompiler.moon
index 5b6c89e..31647aa 100644
--- a/nomsu_decompiler.moon
+++ b/nomsu_decompiler.moon
@@ -58,6 +58,8 @@ tree_to_inline_nomsu = (tree)->
if bit.type == "Action"
arg_nomsu\parenthesize!
nomsu\append arg_nomsu
+ if #tree == 1 and type(tree[1]) != "string"
+ nomsu\append "()"
return nomsu
when "EscapedNomsu"
@@ -251,6 +253,11 @@ tree_to_nomsu = (tree)->
elseif word_buffer[1] == "'"
next_space = ""
nomsu\append next_space, words
+ next_space = " "
+
+ if #tree == 1 and type(tree[1]) != "string"
+ if next_space == " " then next_space = ""
+ nomsu\append next_space, "()"
return nomsu
diff --git a/nomsu_environment.lua b/nomsu_environment.lua
index 4d2a95b..74a5bc1 100644
--- a/nomsu_environment.lua
+++ b/nomsu_environment.lua
@@ -51,7 +51,11 @@ do
local _obj_0 = require("nomsu_decompiler")
tree_to_nomsu, tree_to_inline_nomsu = _obj_0.tree_to_nomsu, _obj_0.tree_to_inline_nomsu
end
-local compile = require('nomsu_compiler')
+local compile, compile_error
+do
+ local _obj_0 = require('nomsu_compiler')
+ compile, compile_error = _obj_0.compile, _obj_0.compile_error
+end
local _currently_running_files = List({ })
local nomsu_environment = Importer({
NOMSU_COMPILER_VERSION = 12,
@@ -59,10 +63,14 @@ local nomsu_environment = Importer({
next = next,
unpack = unpack or table.unpack,
setmetatable = setmetatable,
- coroutine = coroutine,
rawequal = rawequal,
getmetatable = getmetatable,
pcall = pcall,
+ yield = coroutine.yield,
+ resume = coroutine.resume,
+ coroutine_status_of = coroutine.status,
+ coroutine_wrap = coroutine.wrap,
+ coroutine_from = coroutine.create,
error = error,
package = package,
os = os,
@@ -115,6 +123,7 @@ local nomsu_environment = Importer({
_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,
_1_parsed = function(nomsu_code)
@@ -131,10 +140,11 @@ local nomsu_environment = Importer({
if tree.shebang then
tree.version = tree.shebang:match("nomsu %-V[ ]*([%d.]*)")
end
+ local errs = { }
local find_errors
find_errors = function(t)
if t.type == "Error" then
- return coroutine.yield(t)
+ errs[#errs + 1] = t
else
for k, v in pairs(t) do
local _continue_0 = false
@@ -152,18 +162,7 @@ local nomsu_environment = Importer({
end
end
end
- local errs
- do
- local _accum_0 = { }
- local _len_0 = 1
- for err in coroutine.wrap(function()
- return find_errors(tree)
- end) do
- _accum_0[_len_0] = err
- _len_0 = _len_0 + 1
- end
- errs = _accum_0
- end
+ find_errors(tree)
local num_errs = #errs
if num_errs > 0 then
local err_strings
@@ -278,12 +277,15 @@ local nomsu_environment = Importer({
end
end,
FILE_CACHE = { },
- run_file_1_in = function(path, environment, optimization)
+ 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])
+ import_to_1_from(environment, environment.FILE_CACHE[path], prefix)
return
end
if _currently_running_files:has(path) then
@@ -294,7 +296,6 @@ local nomsu_environment = Importer({
end
_currently_running_files:add(path)
local mod = _1_forked(environment)
- mod._ENV = mod
for _, filename in Files.walk(path) do
local _continue_0 = false
repeat
@@ -318,24 +319,9 @@ local nomsu_environment = Importer({
break
end
end
- import_to_1_from(environment, mod)
+ import_to_1_from(environment, mod, prefix)
environment.FILE_CACHE[path] = mod
return _currently_running_files:remove()
- end,
- compile_error_at = function(tree, err_msg, hint)
- if hint == nil then
- hint = nil
- end
- local err_str = pretty_error({
- title = "Compile error",
- error = err_msg,
- hint = hint,
- source = tree:get_source_file(),
- start = tree.source.start,
- stop = tree.source.stop,
- filename = tree.source.filename
- })
- return error(err_str, 0)
end
})
nomsu_environment._ENV = nomsu_environment
diff --git a/nomsu_environment.moon b/nomsu_environment.moon
index 1046004..cfcb15f 100644
--- a/nomsu_environment.moon
+++ b/nomsu_environment.moon
@@ -31,12 +31,14 @@ for version=1,999
Parsers[version] = make_parser(peg_contents, make_tree)
{:tree_to_nomsu, :tree_to_inline_nomsu} = require "nomsu_decompiler"
-compile = require('nomsu_compiler')
+{: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
-- Lua stuff:
- :next, unpack: unpack or table.unpack, :setmetatable, :coroutine, :rawequal, :getmetatable, :pcall,
+ :next, unpack: unpack or table.unpack, :setmetatable, :rawequal, :getmetatable, :pcall,
+ yield:coroutine.yield, resume:coroutine.resume, coroutine_status_of:coroutine.status,
+ coroutine_wrap:coroutine.wrap, coroutine_from: coroutine.create,
:error, :package, :os, :require, :tonumber, :tostring, :string, :xpcall, :module,
say:print, :loadfile, :rawset, :_VERSION, :collectgarbage, :rawget, :rawlen,
:table, :assert, :dofile, :loadstring, lua_type_of:type, :select, :math, :io, :load,
@@ -53,9 +55,9 @@ nomsu_environment = Importer{
SOURCE_MAP: Importer({})
-- Nomsu functions:
- _1_as_nomsu:tree_to_nomsu, _1_as_inline_nomsu:tree_to_inline_nomsu
- compile: compile, _1_as_lua: compile,
- :_1_forked, :import_to_1_from
+ _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,
_1_parsed: (nomsu_code)->
if type(nomsu_code) == 'string'
@@ -69,14 +71,15 @@ nomsu_environment = Importer{
tree = parse(nomsu_code, source.filename)
if tree.shebang
tree.version = tree.shebang\match("nomsu %-V[ ]*([%d.]*)")
+ errs = {}
find_errors = (t)->
if t.type == "Error"
- coroutine.yield t
+ errs[#errs+1] = t
else
for k,v in pairs(t)
continue unless SyntaxTree\is_instance(v)
find_errors(v)
- errs = [err for err in coroutine.wrap(-> find_errors(tree))]
+ find_errors(tree)
num_errs = #errs
if num_errs > 0
err_strings = [pretty_error{
@@ -152,11 +155,11 @@ nomsu_environment = Importer{
error("Attempt to run unknown thing: "..tostring(to_run))
FILE_CACHE: {}
- run_file_1_in: (path, environment, optimization)->
+ 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])
+ import_to_1_from(environment, environment.FILE_CACHE[path], prefix)
return
if _currently_running_files\has(path)
i = _currently_running_files\index_of(path)
@@ -165,7 +168,6 @@ nomsu_environment = Importer{
error("Circular import detected:\n "..circle\joined_with("\n..imports "))
_currently_running_files\add path
mod = _1_forked(environment)
- mod._ENV = mod
for _,filename in Files.walk(path)
continue unless filename == "stdin" or filename\match("%.nom$")
lua_filename = filename\gsub("%.nom$", ".lua")
@@ -177,17 +179,9 @@ nomsu_environment = Importer{
file = Files.read(filename)
NomsuCode\from(Source(filename, 1, #file), file)
environment.run_1_in(code, mod)
- import_to_1_from(environment, mod)
+ import_to_1_from(environment, mod, prefix)
environment.FILE_CACHE[path] = mod
_currently_running_files\remove!
-
- compile_error_at: (tree, err_msg, hint=nil)->
- err_str = pretty_error{
- title: "Compile error"
- error:err_msg, hint:hint, source:tree\get_source_file!
- start:tree.source.start, stop:tree.source.stop, filename:tree.source.filename
- }
- error(err_str, 0)
}
nomsu_environment._ENV = nomsu_environment
diff --git a/syntax_tree.lua b/syntax_tree.lua
index 098dbce..ddd607c 100644
--- a/syntax_tree.lua
+++ b/syntax_tree.lua
@@ -147,16 +147,16 @@ do
end,
get_args = function(self)
assert(self.type == "Action", "Only actions have arguments")
- local _accum_0 = { }
- local _len_0 = 1
+ local args = {
+ self.target
+ }
for _index_0 = 1, #self do
local tok = self[_index_0]
if type(tok) ~= 'string' then
- _accum_0[_len_0] = tok
- _len_0 = _len_0 + 1
+ args[#args + 1] = tok
end
end
- return _accum_0
+ return args
end,
get_stub = function(self)
local stub_bits = { }
@@ -198,7 +198,8 @@ do
local Files = require('files')
local f = Files.read(s.filename)
return f
- end
+ end,
+ __mode = "k"
})
self.is_instance = function(self, t)
return type(t) == 'table' and getmetatable(t) == self.__base
diff --git a/syntax_tree.moon b/syntax_tree.moon
index dd10d77..71b9bac 100644
--- a/syntax_tree.moon
+++ b/syntax_tree.moon
@@ -39,11 +39,13 @@ class SyntaxTree
table.insert(bits, "[ #{as_lua(k)}]=#{as_lua(v)}")
return "SyntaxTree{#{table.concat(bits, ", ")}}"
- @source_code_for_tree: setmetatable({}, {__index:(t)=>
- s = t.source
- Files = require 'files'
- f = Files.read(s.filename)
- return f
+ @source_code_for_tree: setmetatable({}, {
+ __index:(t)=>
+ s = t.source
+ Files = require 'files'
+ f = Files.read(s.filename)
+ return f
+ __mode: "k"
})
get_source_file: => @@source_code_for_tree[@]
get_source_code: => @@source_code_for_tree[@]\sub(@source.start, @source.stop)
@@ -73,7 +75,10 @@ class SyntaxTree
get_args: =>
assert(@type == "Action", "Only actions have arguments")
- return [tok for tok in *@ when type(tok) != 'string']
+ args = {@target}
+ for tok in *@
+ if type(tok) != 'string' then args[#args+1] = tok
+ return args
get_stub: =>
stub_bits = {}
diff --git a/tools/autoformat.nom b/tools/autoformat.nom
index 3082a9e..8626c91 100755
--- a/tools/autoformat.nom
+++ b/tools/autoformat.nom
@@ -16,8 +16,9 @@ if (%args.1 is "-i"):
%args::remove index 1
for %path in %args:
+ if (%path == "-"): %path = "stdin"
for file %filename in %path:
- unless (%filename::matches "%.nom$"): do next %filename
+ unless ((%filename::matches "%.nom$") or (%filename == "stdin")): do next %filename
%contents = (read file %filename)
%code = (NomsuCode from (Source %filename 1 (size of %contents)) %contents)
%tree = (%code parsed)
@@ -25,4 +26,4 @@ for %path in %args:
if %inplace:
write %formatted to file %filename
..else:
- say %formatted
+ say %formatted inline
diff --git a/tools/find_action.nom b/tools/find_action.nom
index 21482d3..c51a144 100755
--- a/tools/find_action.nom
+++ b/tools/find_action.nom
@@ -11,7 +11,7 @@ use "lib/consolecolor.nom"
%stub = (command line args).1
say "Looking for stub: \%stub..."
-%files = ((command line args).% for % in 2 to (size of (command line args)))
+%files = [: for % in 2 to (size of (command line args)): add (command line args).%]
for %path in %files:
for file %filename in %path:
unless (%filename::matches "%.nom$"): do next %filename