diff --git a/README.md b/README.md index 46e62e8..9d0f569 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ All `.moon` files have been precompiled into corresponding `.lua` files, so you * `nomsu` - A shell script that selects between different installed versions of Nomsu (using the `-V` flag). You can use this script to, for example, run `nomsu -V 1.2 your_script.nom` to run with the latest version of Nomsu that matches `1.2.?.?`. All flags and arguments are passed along to whichever Nomsu compiler is chosen. * `nomsu.moon` - The source code for the Nomsu command line runner. This handles launching the compiler and running the REPL. -* `nomsu.peg` - The [Parsing Expression Grammar](https://en.wikipedia.org/wiki/Parsing_expression_grammar) used to define Nomsu's syntax. The format of this file is a slightly modified version of the format accepted by LPEG's `re` module. +* `nomsu.*.peg` - The [Parsing Expression Grammar](https://en.wikipedia.org/wiki/Parsing_expression_grammar) used to define each version of Nomsu's syntax. The format of this file is a slightly modified version of the format accepted by LPEG's `re` module. * `nomsu_compiler.moon` - **The actual Nomsu compiler**. This file can be imported and used without going through the regular command line interface (e.g. for applications that want to embed the compiler). * `parser.moon` - The Nomsu parser. This file can also be imported and used directly for applications that only need to *parse* Nomsu, not compile it. * `syntax_tree.moon` - Datastructures used for Nomsu Abstract Syntax Trees. diff --git a/code_obj.lua b/code_obj.lua index 11f78b2..686cc7f 100644 --- a/code_obj.lua +++ b/code_obj.lua @@ -132,13 +132,13 @@ do _continue_0 = true break end - bits[#bits + 1] = b if b.is_code then b.dirty = error end if type(b) ~= 'string' and not (type(b) == 'table' and b.is_code) then b = repr(b) end + bits[#bits + 1] = b _continue_0 = true until true if not _continue_0 then @@ -210,10 +210,13 @@ do end for i = 1, n do local b = select(i, ...) - bits[i] = b if b.is_code then b.dirty = error end + if type(b) ~= 'string' and not (type(b) == 'table' and b.is_code) then + b = repr(b) + end + bits[i] = b end return self:dirty() end, diff --git a/code_obj.moon b/code_obj.moon index 996a228..7752de6 100644 --- a/code_obj.moon +++ b/code_obj.moon @@ -86,10 +86,10 @@ class Code assert(b, "code bit is nil") assert(not Source\is_instance(b), "code bit is a Source") if b == '' then continue - bits[#bits+1] = b b.dirty = error if b.is_code if type(b) != 'string' and not (type(b) == 'table' and b.is_code) b = repr(b) + bits[#bits+1] = b @dirty! trailing_line_len: => @@ -141,8 +141,10 @@ class Code bits[i] = bits[i-n] for i=1,n b = select(i, ...) - bits[i] = b b.dirty = error if b.is_code + if type(b) != 'string' and not (type(b) == 'table' and b.is_code) + b = repr(b) + bits[i] = b @dirty! parenthesize: => diff --git a/compatibility/2.4.nom b/compatibility/2.4.nom index 2c5cc8e..088e320 100644 --- a/compatibility/2.4.nom +++ b/compatibility/2.4.nom @@ -55,7 +55,7 @@ upgrade %tree to "2.4" as: add %line.2 to %values %action = %line.3 unless (%action is "Block" syntax tree): - %action = (=lua "Block(\%action.source, \%action)") + %action = \(: %action) add %action to %values add (=lua "Action(\%values[1].source, unpack(\%values))") to %new_lines %values = [] diff --git a/compatibility/2.nom b/compatibility/2.nom index 399d485..53d9988 100644 --- a/compatibility/2.nom +++ b/compatibility/2.nom @@ -9,7 +9,7 @@ upgrade %tree to "2" as: if (%tree.stub is "if % % else %"): %true_body = (%tree.3 upgraded) unless (%true_body is "Block" syntax tree): - %true_body = (=lua "Block(\%true_body.source, \%true_body)") + %true_body = \(: %true_body) %false_body = (%tree.5 upgraded) unless (%false_body is "Block" syntax tree): %false_body = (=lua "Block(\%false_body.source, \%false_body)") diff --git a/core/collections.nom b/core/collections.nom index 8553d66..8270f62 100644 --- a/core/collections.nom +++ b/core/collections.nom @@ -191,11 +191,16 @@ test: assume (({} with fallback % -> (% + 1)).10 == 11) compile [%dict with fallback %key -> %value] to (..) Lua value ".." - setmetatable(\(%dict as lua expr), {__index=function(self, \(%key as lua expr)) - local value = \(%value as lua expr) - self[\(%key as lua expr)] = value - return value - end}) + (function(d) + local mt = {} + for k,v in pairs(getmetatable(d) or {}) do mt[k] = v end + mt.__index = function(self, \(%key as lua expr)) + local value = \(%value as lua expr) + self[\(%key as lua expr)] = value + return value + end + return setmetatable(d, mt) + end)(\(%dict as lua expr)) # Sorting test: diff --git a/core/control_flow.nom b/core/control_flow.nom index 703c438..5210519 100644 --- a/core/control_flow.nom +++ b/core/control_flow.nom @@ -206,10 +206,10 @@ compile [..] if (%body has subtree \(do next)): to %lua write "\n ::continue::" - if (%body has subtree (\(do next %v) with vars {v:%var})): + if (%body has subtree \(do next %var)): to %lua write "\n \(compile as (===next %var ===))" to %lua write "\nend --numeric for-loop" - if (%body has subtree (\(stop %v) with vars {v:%var})): + if (%body has subtree \(stop %var)): %lua = (..) Lua ".." do -- scope for stopping for-loop @@ -249,10 +249,10 @@ compile [for %var in %iterable %body] to: if (%body has subtree \(do next)): to %lua write "\n ::continue::" - if (%body has subtree (\(do next %v) with vars {v:%var})): + if (%body has subtree \(do next %var)): to %lua write (Lua "\n\(compile as (===next %var ===))") to %lua write "\nend --foreach-loop" - if (%body has subtree (\(stop %v) with vars {v:%var})): + if (%body has subtree \(stop %var)): %lua = (..) Lua ".." do -- scope for stopping for-loop @@ -290,15 +290,15 @@ compile [..] if (%body has subtree \(do next)): to %lua write "\n ::continue::" - if (%body has subtree (\(do next %v) with vars {v:%key})): + if (%body has subtree \(do next %key)): to %lua write (Lua "\n\(compile as (===next %key ===))") - if (%body has subtree (\(do next %v) with vars {v:%value})): + if (%body has subtree \(do next %value)): to %lua write (Lua "\n\(compile as (===next %value ===))") to %lua write "\nend --foreach-loop" %stop_labels = (Lua "") - if (%body has subtree (\(stop %v) with vars {v:%key})): + if (%body has subtree \(stop %key)): to %stop_labels write "\n\(compile as (===stop %key ===))" - if (%body has subtree (\(stop %v) with vars {v:%value})): + if (%body has subtree \(stop %value)): to %stop_labels write "\n\(compile as (===stop %value ===))" if ((length of "\%stop_labels") > 0): %lua = (..) @@ -505,10 +505,10 @@ compile [for %var in recursive %structure %body] to (..) if (%body has subtree \(do next)): to %lua write "\n ::continue::" - if (%body has subtree (\(do next %v) with vars {v:%var})): + if (%body has subtree \(do next %var)): to %lua write "\n \(compile as (===next %var ===))" to %lua write "\n end -- Recursive loop" - if (%body has subtree (\(stop %v) with vars {v:%var})): + if (%body has subtree \(stop %var)): to %lua write "\n \(compile as (===stop %var ===))" to %lua write "\nend -- Recursive scope" return %lua diff --git a/core/errors.nom b/core/errors.nom index d8c23b8..899b30b 100644 --- a/core/errors.nom +++ b/core/errors.nom @@ -7,11 +7,11 @@ use "core/metaprogramming.nom" compile [barf] to (Lua "error(nil, 0);") compile [barf %msg] to (Lua "error(\(%msg as lua expr), 0);") compile [compile error at %source %msg] to (..) - Lua "nomsu:compile_error(\(%source as lua expr), \(%msg as lua expr))" + Lua "_ENV:compile_error(\(%source as lua expr), \(%msg as lua expr))" compile [assume %condition] to: lua> ".." - local \%assumption = 'Assumption failed: '..tostring(nomsu:tree_to_nomsu(\%condition)) + local \%assumption = 'Assumption failed: '..tostring(_ENV:tree_to_nomsu(\%condition)) return (..) Lua ".." if not \(%condition as lua expr) then diff --git a/core/metaprogramming.nom b/core/metaprogramming.nom index 153a0bf..968ed39 100644 --- a/core/metaprogramming.nom +++ b/core/metaprogramming.nom @@ -5,12 +5,12 @@ lua> "NOMSU_CORE_VERSION = 5" lua> ".." - nomsu.COMPILE_ACTIONS["% -> %"] = function(nomsu, tree, \%args, \%body) + COMPILE_ACTIONS["% -> %"] = function(nomsu, tree, \%args, \%body) local lua = LuaCode.Value(tree.source, "(function(") if AST.is_syntax_tree(\%args, "Action") then \%args = \%args:get_args() end - local lua_args = table.map(\%args, function(a) return AST.is_syntax_tree(a) and tostring(nomsu:compile(a)) or a end) + local lua_args = table.map(\%args, function(a) return AST.is_syntax_tree(a) and tostring(_ENV:compile(a)) or a end) lua:concat_append(lua_args, ", ") - local body_lua = AST.is_syntax_tree(\%body) and nomsu:compile(\%body):as_statements("return ") or \%body + local body_lua = AST.is_syntax_tree(\%body) and _ENV:compile(\%body):as_statements("return ") or \%body body_lua:remove_free_vars(lua_args) body_lua:declare_locals() lua:append(")\\n ", body_lua, "\\nend)") @@ -18,9 +18,9 @@ lua> ".." end lua> ".." - nomsu.COMPILE_ACTIONS["compile as %"] = function(nomsu, tree, \%action) - local lua = LuaCode.Value(tree.source, "nomsu.COMPILE_ACTIONS[", repr(\%action.stub), "](") - local lua_args = table.map(\%action:get_args(), function(a) return nomsu:compile(a) end) + COMPILE_ACTIONS["compile as %"] = function(nomsu, tree, \%action) + local lua = LuaCode.Value(tree.source, "COMPILE_ACTIONS[", repr(\%action.stub), "](") + local lua_args = table.map(\%action:get_args(), function(a) return _ENV:compile(a) end) table.insert(lua_args, 1, "nomsu") table.insert(lua_args, 2, "tree") lua:concat_append(lua_args, ", ") @@ -48,22 +48,22 @@ test: asdf assume (%tmp is (nil)) or barf "compile to is leaking variables" lua> ".." - nomsu.COMPILE_ACTIONS["compile % to %"] = function(nomsu, tree, \%actions, \%body) - local \%args = {"nomsu", "tree", unpack(table.map(\%actions[1]:get_args(), function(a) return tostring(nomsu:compile(\ + COMPILE_ACTIONS["compile % to %"] = function(nomsu, tree, \%actions, \%body) + local \%args = {"nomsu", "tree", unpack(table.map(\%actions[1]:get_args(), function(a) return tostring(_ENV:compile(\ ..a)) end))} - local lua = LuaCode(tree.source, "nomsu.COMPILE_ACTIONS[", repr(\%actions[1].stub), + local lua = LuaCode(tree.source, "COMPILE_ACTIONS[", repr(\%actions[1].stub), "] = ", \(compile as (%args -> %body))) for i=2,#\%actions do local alias = \%actions[i] - local \%alias_args = {"nomsu", "tree", unpack(table.map(alias:get_args(), function(a) return tostring(nomsu:compile(\ + local \%alias_args = {"nomsu", "tree", unpack(table.map(alias:get_args(), function(a) return tostring(_ENV:compile(\ ..a)) end))} - lua:append("\\nnomsu.COMPILE_ACTIONS[", repr(alias.stub), "] = ") + lua:append("\\nCOMPILE_ACTIONS[", repr(alias.stub), "] = ") if utils.equivalent(\%args, \%alias_args) then - lua:append("nomsu.COMPILE_ACTIONS[", repr(\%actions[1].stub), "]") + lua:append("COMPILE_ACTIONS[", repr(\%actions[1].stub), "]") else lua:append("function(") lua:concat_append(\%alias_args, ", ") - lua:append(")\\n return nomsu.COMPILE_ACTIONS[", repr(\%actions[1].stub), "](") + lua:append(")\\n return COMPILE_ACTIONS[", repr(\%actions[1].stub), "](") lua:concat_append(\%args, ", ") lua:append(")\\nend") end @@ -75,8 +75,8 @@ lua> ".." compile [call %fn with %args] to (..) lua> ".." - local lua = LuaCode.Value(tree.source, nomsu:compile(\%fn), "(") - lua:concat_append(table.map(\%args, function(a) return nomsu:compile(a) end), ", ") + local lua = LuaCode.Value(tree.source, _ENV:compile(\%fn), "(") + lua:concat_append(table.map(\%args, function(a) return _ENV:compile(a) end), ", ") lua:append(")") return lua @@ -95,14 +95,14 @@ test: compile [local action %actions %body] to (..) lua> ".." local fn_name = "A"..string.as_lua_id(\%actions[1].stub) - local \%args = table.map(\%actions[1]:get_args(), function(a) return tostring(nomsu:compile(a)) end) + local \%args = table.map(\%actions[1]:get_args(), function(a) return tostring(_ENV:compile(a)) end) local lua = LuaCode(tree.source, fn_name, " = ", \(compile as (%args -> %body))) lua:add_free_vars({fn_name}) for i=2,#\%actions do local alias = \%actions[i] local alias_name = "A"..string.as_lua_id(alias.stub) lua:add_free_vars({alias_name}) - local \%alias_args = table.map(alias:get_args(), function(a) return tostring(nomsu:compile(a)) end) + local \%alias_args = table.map(alias:get_args(), function(a) return tostring(_ENV:compile(a)) end) lua:append("\\n", alias_name, " = ") if utils.equivalent(\%args, \%alias_args) then lua:append(fn_name) @@ -151,7 +151,7 @@ compile [parse %actions as %body] to (..) lua> ".." local replacements = {} for i,arg in ipairs(\%actions[1]:get_args()) do - replacements[arg[1]] = tostring(nomsu:compile(arg)) + replacements[arg[1]] = tostring(_ENV:compile(arg)) end local function make_tree(t) if not AST.is_syntax_tree(t) then @@ -168,7 +168,7 @@ compile [parse %actions as %body] to (..) local \%new_body = LuaCode(\%body.source, "__MANGLE_INDEX = (__MANGLE_INDEX or 0) + 1", "\\nlocal tree = ", make_tree(\%body), - "\\nlocal lua = nomsu:compile(tree); return lua") + "\\nlocal lua = _ENV:compile(tree); return lua") local ret = \(compile as (compile %actions to %new_body)) return ret @@ -176,33 +176,33 @@ compile [parse %actions as %body] to (..) action [%tree as lua expr]: lua> ".." - \%tree_lua = nomsu:compile(\%tree) + \%tree_lua = _ENV:compile(\%tree) if not \%tree_lua.is_value then - nomsu:compile_error(\%tree.source, "Could not convert %s to a Lua expression", - nomsu:tree_to_nomsu(\%tree)) + _ENV:compile_error(\%tree.source, "Could not convert %s to a Lua expression", + _ENV:tree_to_nomsu(\%tree)) end return \%tree_lua ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -compile [%tree as lua] to (Lua value "nomsu:compile(\(%tree as lua expr))") +compile [%tree as lua] to (Lua value "_ENV:compile(\(%tree as lua expr))") compile [%tree as lua statements] to (..) - Lua value "nomsu:compile(\(%tree as lua expr)):as_statements()" + Lua value "_ENV:compile(\(%tree as lua expr)):as_statements()" compile [%tree as lua return] to (..) - Lua value "nomsu:compile(\(%tree as lua expr)):as_statements('return ')" + Lua value "_ENV:compile(\(%tree as lua expr)):as_statements('return ')" compile [remove action %action] to (..) Lua "A\(=lua "string.as_lua_id(\(%action.stub))") = nil" test: - assume ("\(\(foo %x) as nomsu)" == "foo %x") or barf ".." + assume ("\(\(foo \%x) as nomsu)" == "foo %x") or barf ".." action source code failed. compile [%tree as nomsu] to (..) - Lua value "nomsu:tree_to_nomsu(\(%tree as lua expr))" + Lua value "_ENV:tree_to_nomsu(\(%tree as lua expr))" compile [%tree as inline nomsu] to (..) - Lua value "nomsu:tree_to_nomsu(\(%tree as lua expr), true)" + Lua value "_ENV:tree_to_nomsu(\(%tree as lua expr), true)" action [%var as lua identifier, %var as lua id] (..) lua> ".." @@ -231,6 +231,14 @@ action [%tree with vars %replacements] (..) end end) +compile [tree %tree with vars %replacements] to (..) + Lua value ".." + \(=lua "repr(\%tree)"):map(function(t) + if t.type == "Var" then + return \(%replacements as lua expr)[t[1]] + end + end) + compile [%tree has subtree %match_tree] to (..) Lua value ".." (function() @@ -240,6 +248,39 @@ compile [%tree has subtree %match_tree] to (..) end end)() +action [match %tree with %patt]: + lua> ".." + if \%patt.type == "Var" then return dict{[\%patt[1]]=\%tree} end + if \%patt.type == "Action" and \%patt.stub ~= \%tree.stub then return nil end + if #\%patt ~= #\%tree then return nil end + local matches = dict{} + for \%i=1,#\%patt do + if AST.is_syntax_tree(\%tree[\%i]) then + local submatch = \(match %tree.%i with %patt.%i) + if not submatch then return nil end + for k,v in pairs(submatch) do + if matches[k] and matches[k] ~= v then return nil end + matches[k] = v + end + end + end + return matches + +action [%tree with %patt ~> %replacement]: + lua> ".." + return \%tree:map(function(\%t) + local \%vars = \(match %t with %patt) + if not \%vars then return nil end + for \%k,\%v in pairs(\%vars) do + \%vars[\%k] = \(%v with %patt ~> %replacement) + end + return \%replacement:map(function(\%t) + if \%t.type == "Var" then + return \%vars[\%t[1]] + end + end) + end) + compile [declare locals in %code] to (..) Lua value "\(%code as lua expr):declare_locals()" @@ -275,11 +316,12 @@ compile [type of %obj] to (Lua value "type(\(%obj as lua expr))") ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ test: - assume ((parse "foo %") == \(foo %)) -compile [parse %text] to (Lua value "nomsu:parse(\(%text as lua expr))") + assume ((parse "foo %") == \(foo \%)) + assume ((parse "\\1") == \\1) +compile [parse %text] to (Lua value "_ENV:parse(\(%text as lua expr))") compile [parse %text from %filename] to (..) Lua value ".." - nomsu:parse(NomsuCode(Source(\(%filename as lua expr), 1, #\(%text as lua expr)), \(..) + _ENV:parse(NomsuCode(Source(\(%filename as lua expr), 1, #\(%text as lua expr)), \(..) %text as lua expr ..)) @@ -287,19 +329,19 @@ test: assume ((run "return (2 + 99)") == 101) external %passed = (no) run \: - external %passed = (yes) + \(external \%passed = \(yes)) assume %passed compile [run %nomsu_code] to (..) Lua value ".." - nomsu:run(\(%nomsu_code as lua expr), \(..) + _ENV:run(\(%nomsu_code as lua expr), \(..) =lua "repr(tostring(\(%nomsu_code.source)))" ..) test: - assume ((\(5 + 5) as value) == 10) or barf "%tree as value failed." -action [run tree %tree, %tree as value] (lua> "return nomsu:run(\%tree)") + assume ((\(\5 + \5) as value) == 10) or barf "%tree as value failed." +action [run tree %tree, %tree as value] (lua> "return _ENV:run(\%tree)") compile [compile %block, compiled %block, %block compiled] to (..) - Lua value "nomsu:compile(\(%block as lua))" + Lua value "_ENV:compile(\(%block as lua))" # 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. @@ -322,7 +364,7 @@ compile [command line args] to (Lua value "arg") compile [with local compile actions %body] to (..) Lua ".." do - local nomsu = table.fork(nomsu, {COMPILE_ACTIONS=table.fork(nomsu.COMPILE_ACTIONS)}) + local nomsu = table.fork(nomsu, {COMPILE_ACTIONS=table.fork(COMPILE_ACTIONS)}) \(%body as lua statements) end diff --git a/core/text.nom b/core/text.nom index 701b1cd..a82e9df 100644 --- a/core/text.nom +++ b/core/text.nom @@ -124,7 +124,7 @@ lua> ".." }; for name, e in pairs(escapes) do local lua = "'"..e.."'" - nomsu.COMPILE_ACTIONS[name] = function(nomsu, tree) + COMPILE_ACTIONS[name] = function(nomsu, tree) return LuaCode.Value(tree.source, lua) end end diff --git a/lib/object.nom b/lib/object.nom index dd99109..ddbb2b5 100644 --- a/lib/object.nom +++ b/lib/object.nom @@ -35,23 +35,34 @@ test: assume ((me).barks == 101) or barf ".." Error in nested 'as % %' failed to properly reset 'self' - object "Corgi" extends (class Dog) (method [sploot] "splooted") + object "Corgi" extends (class Dog): + method [sploot] "splooted" + method [bark, woof]: + %barks = ("Yip!" for % in 1 to (me).barks) + return (%barks joined with " ") + %corg = (new Corgi) assume (%corg.barks == 0) as (new Corgi {barks:1}): assume ((sploot) == "splooted") or barf "subclass method failed" - assume ((bark) == "Bark!") or barf "inheritance failed" - assume ((woof) == "Bark!") + assume ((bark) == "Yip!") or barf "inheritance failed" + assume ((woof) == "Yip!") + + as (new Dog {barks:2}): + assume ((bark) == "Bark! Bark!") + compile [@, me] to (Lua value "self") compile [method %actions %body] to: - %lua = (compile as (local action %actions %body)) + %lua = (\(local action \[%actions.1] %body) as lua) + declare locals in %lua for % in %actions: - to %lua write "\nclass.\(% as lua id) = \(% as lua id)" - return (..) + to %lua write "\n\(\%class as lua id).\(% as lua id) = \(%actions.1 as lua id)" + %lua = (..) Lua ".." do -- Method: \(%actions.(1).stub) \%lua end + return %lua ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -64,33 +75,35 @@ parse [as %instance %body] as (..) barf %msg ..or if it succeeds: (me) = %old_self -compile [object %classname extends %parent %class_body] to (..) - Lua ".." - do - local class = {name=\(%classname as lua expr)} - setmetatable(class, { - __index=\(%parent as lua expr), - __tostring=function(cls) return cls.name end, - __call=function(cls, inst) - inst = setmetatable(inst or {}, cls) - if cls.A_initialize_1 then - cls.A_initialize_1(inst) - end - return inst - end, - }) - _ENV["A"..string.as_lua_id("new "..class.name)] = class - _ENV["A"..string.as_lua_id("new "..class.name.." 1")] = class - _ENV["A"..string.as_lua_id("class "..class.name)] = function() return class end - class.__index = class - class.class = class - - \(%class_body as lua statements) - - class.__tostring = class["A"..string.as_lua_id("as text")] or function(inst) - return inst.name..getmetatable(dict{}).__tostring(inst) +compile [object %classname extends %parent %class_body] to: + %class = (\%class as lua id) + return (..) + Lua ".." + do + local \%class = {name=\(%classname as lua expr)} + setmetatable(\%class, { + __index=\(%parent as lua expr), + __tostring=function(cls) return cls.name end, + __call=function(cls, inst) + inst = setmetatable(inst or {}, cls) + if cls.A_initialize_1 then + cls.A_initialize_1(inst) + end + return inst + end, + }) + _ENV["A"..string.as_lua_id("new "..\%class.name)] = \%class + _ENV["A"..string.as_lua_id("new "..\%class.name.." 1")] = \%class + _ENV["A"..string.as_lua_id("class "..\%class.name)] = function() return \%class end + \%class.__index = \%class + \%class.class = \%class + + \(%class_body as lua statements) + + \%class.__tostring = \%class["A"..string.as_lua_id("as text")] or function(inst) + return inst.name..getmetatable(dict{}).__tostring(inst) + end end - end ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/lib/os.nom b/lib/os.nom index 8bbc7c5..03d9657 100644 --- a/lib/os.nom +++ b/lib/os.nom @@ -43,6 +43,7 @@ action [..] write to file %filename %text, to file %filename write %text write %text to file %filename ..: + assume (%filename != "stdin") or barf "Cannot write to stdin" lua> ".." local file = io.open(\%filename, 'w') file:write(\%text) diff --git a/nomsu.2.peg b/nomsu.2.peg index 4f9c4c4..ce4d2d7 100644 --- a/nomsu.2.peg +++ b/nomsu.2.peg @@ -5,7 +5,7 @@ file: / file_chunks / empty_block) %ws* (!! .+ -> "Parse error" !!)? -shebang: "#!" (!"nomsu" [^%nl])* "nomsu" %ws+ "-V" %ws* {:version: [0-9.]+ :} [^%nl]* +shebang: {:shebang: "#!" (!"nomsu" [^%nl])* "nomsu" %ws+ "-V" %ws* {:version: [0-9.]+ :} [^%nl]* :} file_chunks (FileChunks): {:curr_indent: ' '* :} diff --git a/nomsu_compiler.lua b/nomsu_compiler.lua index 6692fe3..c3c21af 100644 --- a/nomsu_compiler.lua +++ b/nomsu_compiler.lua @@ -145,7 +145,9 @@ dict = function(t) return setmetatable(t, _dict_mt) end local MAX_LINE = 80 -local NomsuCompiler = setmetatable({ }, { +local NomsuCompiler = setmetatable({ + name = "Nomsu" +}, { __index = function(self, k) do local _self = rawget(self, "self") @@ -155,13 +157,14 @@ local NomsuCompiler = setmetatable({ }, { return nil end end + end, + __tostring = function(self) + return self.name end }) do NomsuCompiler.NOMSU_COMPILER_VERSION = 5 NomsuCompiler.NOMSU_SYNTAX_VERSION = Parser.version - NomsuCompiler._ENV = NomsuCompiler - NomsuCompiler.nomsu = NomsuCompiler NomsuCompiler.parse = function(self, ...) return Parser.parse(...) end @@ -226,9 +229,6 @@ do NomsuCompiler.LuaCode = LuaCode NomsuCompiler.NomsuCode = NomsuCode NomsuCompiler.Source = Source - NomsuCompiler.ALIASES = setmetatable({ }, { - __mode = "k" - }) NomsuCompiler.LOADED = { } NomsuCompiler.TESTS = { } NomsuCompiler.AST = AST @@ -335,13 +335,13 @@ do end, ["lua > %"] = function(self, tree, _code) if _code.type ~= "Text" then - return LuaCode(tree.source, "nomsu:run_lua(", self:compile(_code), ");") + return LuaCode(tree.source, "_ENV:run_lua(", self:compile(_code), ");") end return add_lua_bits(self, "statements", _code) end, ["= lua %"] = function(self, tree, _code) if _code.type ~= "Text" then - return LuaCode.Value(tree.source, "nomsu:run_lua(", self:compile(_code), ":as_statements('return '))") + return LuaCode.Value(tree.source, "_ENV:run_lua(", self:compile(_code), ":as_statements('return '))") end return add_lua_bits(self, "value", _code) end, @@ -352,7 +352,7 @@ do self:run_file(f) end end - return LuaCode(tree.source, "for i,f in Files.walk(", self:compile(_path), ") do nomsu:run_file(f) end") + return LuaCode(tree.source, "for i,f in Files.walk(", self:compile(_path), ") do _ENV:run_file(f) end") end, ["tests"] = function(self, tree) return LuaCode.Value(tree.source, "TESTS") @@ -581,7 +581,11 @@ do end local arg_lua = self:compile(tok) if not (arg_lua.is_value) then - self:compile_error(tok.source, "Cannot use:\n%s\nas an argument to %s, since it's not an expression, it produces: %s", stub, repr(arg_lua)) + if tok.type == "Block" then + self:compile_error(tok.source, ("Cannot compile action '" .. tostring(stub) .. "' with a Block as an argument.\n" .. "Maybe there should be a compile-time action with that name that isn't being found?")) + else + self:compile_error(tok.source, "Cannot use:\n%s\nas an argument to '%s', since it's not an expression, it produces: %s", stub, repr(arg_lua)) + end end insert(args, arg_lua) _continue_0 = true @@ -594,26 +598,29 @@ do lua:append(")") return lua elseif "EscapedNomsu" == _exp_0 then - local make_tree - make_tree = function(t) - if not (AST.is_syntax_tree(t)) then - return repr(t) - end - local bits + local lua = LuaCode.Value(tree.source, tree[1].type, "(") + local bits + if tree[1].type == "EscapedNomsu" then + bits = { + self:compile(tree[1]) + } + else do local _accum_0 = { } local _len_0 = 1 - for _index_0 = 1, #t do - local bit = t[_index_0] - _accum_0[_len_0] = make_tree(bit) + local _list_0 = tree[1] + for _index_0 = 1, #_list_0 do + local bit = _list_0[_index_0] + _accum_0[_len_0] = AST.is_syntax_tree(bit) and self:compile(bit) or repr(bit) _len_0 = _len_0 + 1 end bits = _accum_0 end - insert(bits, 1, repr(tostring(t.source))) - return t.type .. "(" .. concat(bits, ", ") .. ")" end - return LuaCode.Value(tree.source, make_tree(tree[1])) + insert(bits, 1, repr(tostring(tree[1].source))) + lua:concat_append(bits, ", ") + lua:append(")") + return lua elseif "Block" == _exp_0 then local lua = LuaCode(tree.source) lua:concat_append((function() @@ -647,7 +654,7 @@ do end local bit_lua = self:compile(bit) if not (bit_lua.is_value) then - local src = ' ' .. gsub(tostring(recurse(bit)), '\n', '\n ') + local src = ' ' .. gsub(tostring(self:compile(bit)), '\n', '\n ') local line = tostring(bit.source.filename) .. ":" .. tostring(Files.get_line_number(Files.read(bit.source.filename), bit.source.start)) self:compile_error(bit.source, "Cannot use:\n%s\nas a string interpolation value, since it's not an expression.") end diff --git a/nomsu_compiler.moon b/nomsu_compiler.moon index 0b3ae7c..dada050 100644 --- a/nomsu_compiler.moon +++ b/nomsu_compiler.moon @@ -93,12 +93,12 @@ _dict_mt = dict = (t)-> setmetatable(t, _dict_mt) MAX_LINE = 80 -- For beautification purposes, try not to make lines much longer than this value -NomsuCompiler = setmetatable({}, {__index: (k)=> if _self = rawget(@, "self") then _self[k] else nil}) +NomsuCompiler = setmetatable {name:"Nomsu"}, + __index: (k)=> if _self = rawget(@, "self") then _self[k] else nil + __tostring: => @name with NomsuCompiler .NOMSU_COMPILER_VERSION = 5 .NOMSU_SYNTAX_VERSION = Parser.version - ._ENV = NomsuCompiler - .nomsu = NomsuCompiler .parse = (...)=> Parser.parse(...) .can_optimize = -> false @@ -121,7 +121,6 @@ with NomsuCompiler .LuaCode = LuaCode .NomsuCode = NomsuCode .Source = Source - .ALIASES = setmetatable({}, {__mode:"k"}) .LOADED = {} .TESTS = {} .AST = AST @@ -213,12 +212,12 @@ with NomsuCompiler ["lua > %"]: (tree, _code)=> if _code.type != "Text" - return LuaCode tree.source, "nomsu:run_lua(", @compile(_code), ");" + return LuaCode tree.source, "_ENV:run_lua(", @compile(_code), ");" return add_lua_bits(@, "statements", _code) ["= lua %"]: (tree, _code)=> if _code.type != "Text" - return LuaCode.Value tree.source, "nomsu:run_lua(", @compile(_code), ":as_statements('return '))" + return LuaCode.Value tree.source, "_ENV:run_lua(", @compile(_code), ":as_statements('return '))" return add_lua_bits(@, "value", _code) ["use %"]: (tree, _path)=> @@ -226,7 +225,7 @@ with NomsuCompiler path = _path[1] for _,f in Files.walk(path) @run_file(f) - return LuaCode(tree.source, "for i,f in Files.walk(", @compile(_path), ") do nomsu:run_file(f) end") + return LuaCode(tree.source, "for i,f in Files.walk(", @compile(_path), ") do _ENV:run_file(f) end") ["tests"]: (tree)=> LuaCode.Value(tree.source, "TESTS") ["test %"]: (tree, _body)=> @@ -362,22 +361,28 @@ with NomsuCompiler if type(tok) == "string" then continue arg_lua = @compile(tok) unless arg_lua.is_value - @compile_error tok.source, - "Cannot use:\n%s\nas an argument to %s, since it's not an expression, it produces: %s", - stub, repr arg_lua + if tok.type == "Block" + @compile_error tok.source, + ("Cannot compile action '#{stub}' with a Block as an argument.\n".. + "Maybe there should be a compile-time action with that name that isn't being found?") + + else + @compile_error tok.source, + "Cannot use:\n%s\nas an argument to '%s', since it's not an expression, it produces: %s", + stub, repr arg_lua insert args, arg_lua lua\concat_append args, ", " lua\append ")" return lua when "EscapedNomsu" - make_tree = (t)-> - unless AST.is_syntax_tree(t) - return repr(t) - bits = [make_tree(bit) for bit in *t] - insert bits, 1, repr(tostring t.source) - return t.type.."("..concat(bits, ", ")..")" - return LuaCode.Value tree.source, make_tree(tree[1]) + lua = LuaCode.Value tree.source, tree[1].type, "(" + bits = if tree[1].type == "EscapedNomsu" then {@compile(tree[1])} + else [AST.is_syntax_tree(bit) and @compile(bit) or repr(bit) for bit in *tree[1]] + insert bits, 1, repr(tostring tree[1].source) + lua\concat_append bits, ", " + lua\append ")" + return lua when "Block" lua = LuaCode(tree.source) @@ -397,7 +402,7 @@ with NomsuCompiler string_buffer = "" bit_lua = @compile(bit) unless bit_lua.is_value - src = ' '..gsub(tostring(recurse(bit)), '\n','\n ') + src = ' '..gsub(tostring(@compile(bit)), '\n','\n ') line = "#{bit.source.filename}:#{Files.get_line_number(Files.read(bit.source.filename), bit.source.start)}" @compile_error bit.source, "Cannot use:\n%s\nas a string interpolation value, since it's not an expression." diff --git a/syntax_tree.lua b/syntax_tree.lua index 64b4efc..9b47123 100644 --- a/syntax_tree.lua +++ b/syntax_tree.lua @@ -40,11 +40,15 @@ for _index_0 = 1, #types do return getmetatable(x) == self end cls.__tostring = function(self) - return tostring(self.type) .. "(" .. tostring(repr(tostring(self.source))) .. ", " .. tostring(concat((function() + local args = { + tostring(self.source), + unpack(self) + } + return tostring(self.type) .. "(" .. tostring(concat((function() local _accum_0 = { } local _len_0 = 1 - for _index_1 = 1, #self do - local v = self[_index_1] + for _index_1 = 1, #args do + local v = args[_index_1] _accum_0[_len_0] = repr(v) _len_0 = _len_0 + 1 end @@ -114,7 +118,7 @@ for _index_0 = 1, #types do end AST[name] = setmetatable(cls, { __tostring = function(self) - return self.name + return self.__name end, __call = function(self, source, ...) if type(source) == 'string' then diff --git a/syntax_tree.moon b/syntax_tree.moon index 885892f..7132c64 100644 --- a/syntax_tree.moon +++ b/syntax_tree.moon @@ -19,7 +19,9 @@ for name in *types .__name = name .type = name .is_instance = (x)=> getmetatable(x) == @ - .__tostring = => "#{@type}(#{repr tostring(@source)}, #{concat([repr(v) for v in *@], ', ')})" + .__tostring = => + args = {tostring(@source), unpack(@)} + "#{@type}(#{concat([repr(v) for v in *args], ', ')})" .map = (fn)=> replacement = fn(@) if replacement == false then return nil @@ -47,7 +49,7 @@ for name in *types return true AST[name] = setmetatable cls, - __tostring: => @name + __tostring: => @__name __call: (source, ...)=> if type(source) == 'string' source = Source\from_string(source) diff --git a/tools/find_action.nom b/tools/find_action.nom index 2ddc89f..720899b 100755 --- a/tools/find_action.nom +++ b/tools/find_action.nom @@ -16,7 +16,7 @@ for %path in %files: %file = (read file %filename) %tree = (parse %file from %filename) for %t in recursive %tree: - if (%t is "Action" syntax tree) (..) + if (%t is "Action" syntax tree): if (%t.stub is %stub): %line_num = (line number of %t.source.start in %file) say (blue "\%filename:\%line_num:") diff --git a/tools/upgrade.nom b/tools/upgrade.nom index 490a58e..6cc2d2c 100755 --- a/tools/upgrade.nom +++ b/tools/upgrade.nom @@ -20,7 +20,6 @@ if (%args.1 is "-t"): remove index 1 from %args for %path in %args: - if (%path is "-i"): %inplace = (yes) for file %filename in %path: unless (%filename matches "%.nom$"): do next %filename %tree = (parse (read file %filename) from %filename)