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, " = ") - if \%args == \%alias_args then - lua:append(fn_name) + lua:append("\\n") + if alias.target then + lua:append(compile(alias.target), ".") else - lua:append(\(what (%alias_args -> %actions.1) compiles to)) + lua:add_free_vars({alias_name}) + end + lua:append(alias_name, " = ") + if \%args == \%alias_args then + if target then lua:append(target, ".") end + lua:append(fn_name, ";") + else + 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) + [%x, %y] = [10, 20] + assume ((%x == 10) and (%y == 20)) or barf "mutli-assignment failed." + [%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" # 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()}) + .. + 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 + 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 + 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 lua" -test: - set {%x: 10, %y: 20} - assume ((%x == 10) and (%y == 20)) or barf "mutli-assignment failed." - set {%x: %y, %y: %x} - assume ((%y == 10) and (%x == 20)) or barf "swapping vars 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" - - 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 - 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(", ") - end - lhs:append(target_lua) - rhs:append(value_lua) - end - return LuaCode(lhs, " = ", rhs, ";")" - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 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