diff options
| author | Bruce Hill <bitbucket@bruce-hill.com> | 2018-05-16 19:08:16 -0700 |
|---|---|---|
| committer | Bruce Hill <bitbucket@bruce-hill.com> | 2018-05-16 19:08:59 -0700 |
| commit | ad94ed3653e2b7a9f68855670a32617aa80a637c (patch) | |
| tree | bfde4d9e82635aea25336bfda4bf73e819347a93 /nomsu.lua | |
| parent | 6f6c4377b236902566794c3d06820f3fdd7ec28c (diff) | |
Moved all the tree->lua and tree->nomsu code back into single functions
in nomsu.moon, and cleaned up how Vars are treated, since they are not
atomic.
Diffstat (limited to 'nomsu.lua')
| -rw-r--r-- | nomsu.lua | 663 |
1 files changed, 630 insertions, 33 deletions
@@ -249,7 +249,7 @@ end local NomsuCompiler do local _class_0 - local stub_defs, stub_pattern, var_pattern, _nomsu_chunk_counter, _running_files + local stub_defs, stub_pattern, var_pattern, _nomsu_chunk_counter, _running_files, MAX_LINE, math_expression local _base_0 = { define_action = function(self, signature, fn, is_compile_action) if is_compile_action == nil then @@ -284,7 +284,7 @@ do local _len_0 = 1 for _index_1 = 1, #stub_args do local a = stub_args[_index_1] - _accum_0[_len_0] = fn_arg_positions[Types.Var.as_lua_id(a)] + _accum_0[_len_0] = fn_arg_positions[Types.Var(a):as_lua_id()] _len_0 = _len_0 + 1 end arg_orders[stub] = _accum_0 @@ -341,7 +341,7 @@ do end local tree = self:parse(nomsu_code) assert(tree, "Failed to parse: " .. tostring(nomsu_code)) - local lua = tree:as_lua(self):as_statements() + local lua = self:tree_to_lua(tree):as_statements() lua:declare_locals() lua:prepend("-- File: " .. tostring(nomsu_code.source or "") .. "\n") if compile_fn then @@ -432,11 +432,628 @@ do end return run_lua_fn() end, + tree_to_lua = function(self, tree) + local _exp_0 = tree.type + if "Action" == _exp_0 then + local stub = tree:get_stub() + local compile_action = self.environment.COMPILE_ACTIONS[stub] + if compile_action then + local args + do + local _accum_0 = { } + local _len_0 = 1 + for _index_0 = 1, #tree do + local arg = tree[_index_0] + if arg.type ~= "Word" then + _accum_0[_len_0] = arg + _len_0 = _len_0 + 1 + end + end + args = _accum_0 + end + do + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = self.environment.ARG_ORDERS[compile_action][stub] + for _index_0 = 1, #_list_0 do + local p = _list_0[_index_0] + _accum_0[_len_0] = args[p - 1] + _len_0 = _len_0 + 1 + end + args = _accum_0 + end + local ret = compile_action(tree, unpack(args)) + if not ret then + error("Failed to produce any Lua") + end + return ret + end + local action = rawget(self.environment.ACTIONS, stub) + local lua = Lua.Value() + if not action and math_expression:match(stub) then + for i, tok in ipairs(tree) do + if tok.type == "Word" then + lua:append(tok.value) + else + local tok_lua = self:tree_to_lua(tok) + if not (tok_lua.is_value) then + error("non-expression value inside math expression: " .. tostring(colored.yellow(repr(tok)))) + end + if tok.type == "Action" then + tok_lua:parenthesize() + end + lua:append(tok_lua) + end + if i < #tree then + lua:append(" ") + end + end + return lua + end + local args = { } + for i, tok in ipairs(tree) do + local _continue_0 = false + repeat + if tok.type == "Word" then + _continue_0 = true + break + end + local arg_lua = self:tree_to_lua(tok) + if not (arg_lua.is_value) then + error("Cannot use:\n" .. tostring(colored.yellow(repr(tok))) .. "\nas an argument to " .. tostring(stub) .. ", since it's not an expression, it produces: " .. tostring(repr(arg_lua)), 0) + end + insert(args, arg_lua) + _continue_0 = true + until true + if not _continue_0 then + break + end + end + if action then + do + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = self.environment.ARG_ORDERS[action][stub] + for _index_0 = 1, #_list_0 do + local p = _list_0[_index_0] + _accum_0[_len_0] = args[p] + _len_0 = _len_0 + 1 + end + args = _accum_0 + end + end + lua:append("ACTIONS[", repr(stub), "](") + for i, arg in ipairs(args) do + lua:append(arg) + if i < #args then + lua:append(", ") + end + end + lua:append(")") + return lua + elseif "EscapedNomsu" == _exp_0 then + local make_tree + make_tree = function(t) + if type(t) ~= 'userdata' then + return repr(t) + end + if t.is_multi then + local bits + 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) + _len_0 = _len_0 + 1 + end + bits = _accum_0 + end + return t.type .. "(" .. table.concat(bits, ", ") .. ")" + else + return t.type .. "(" .. make_tree(t.value) .. ")" + end + end + return Lua.Value(nil, make_tree(tree.value)) + elseif "Block" == _exp_0 then + local lua = Lua() + for i, line in ipairs(tree) do + local line_lua = self:tree_to_lua(line) + if i > 1 then + lua:append("\n") + end + lua:append(line_lua:as_statements()) + end + return lua + elseif "Text" == _exp_0 then + local lua = Lua.Value() + local string_buffer = "" + for _index_0 = 1, #tree do + local _continue_0 = false + repeat + local bit = tree[_index_0] + if type(bit) == "string" then + string_buffer = string_buffer .. bit + _continue_0 = true + break + end + if string_buffer ~= "" then + if #lua.bits > 0 then + lua:append("..") + end + lua:append(repr(string_buffer)) + string_buffer = "" + end + local bit_lua = self:tree_to_lua(bit) + if not (bit_lua.is_value) then + error("Cannot use " .. tostring(colored.yellow(repr(bit))) .. " as a string interpolation value, since it's not an expression.", 0) + end + if #lua.bits > 0 then + lua:append("..") + end + if bit.type ~= "Text" then + bit_lua = Lua.Value(nil, "stringify(", bit_lua, ")") + end + lua:append(bit_lua) + _continue_0 = true + until true + if not _continue_0 then + break + end + end + if string_buffer ~= "" or #lua.bits == 0 then + if #lua.bits > 0 then + lua:append("..") + end + lua:append(repr(string_buffer)) + end + if #lua.bits > 1 then + lua:parenthesize() + end + return lua + elseif "List" == _exp_0 then + local lua = Lua.Value(nil, "{") + local line_length = 0 + for i, item in ipairs(tree) do + local item_lua = self:tree_to_lua(item) + if not (item_lua.is_value) then + error("Cannot use " .. tostring(colored.yellow(repr(item))) .. " as a list item, since it's not an expression.", 0) + end + lua:append(item_lua) + local item_string = tostring(item_lua) + local last_line = item_string:match("[^\n]*$") + if item_string:match("\n") then + line_length = #last_line + else + line_length = line_length + #last_line + end + if i < #tree then + if line_length >= MAX_LINE then + lua:append(",\n ") + line_length = 0 + else + lua:append(", ") + line_length = line_length + 2 + end + end + end + lua:append("}") + return lua + elseif "Dict" == _exp_0 then + local lua = Lua.Value(nil, "{") + local line_length = 0 + for i, entry in ipairs(tree) do + local entry_lua = self:tree_to_lua(entry) + lua:append(entry_lua) + local entry_lua_str = tostring(entry_lua) + local last_line = entry_lua_str:match("\n([^\n]*)$") + if last_line then + line_length = #last_line + else + line_length = line_length + #entry_lua_str + end + if i < #tree then + if line_length >= MAX_LINE then + lua:append(",\n ") + line_length = 0 + else + lua:append(", ") + line_length = line_length + 2 + end + end + end + lua:append("}") + return lua + elseif "DictEntry" == _exp_0 then + local key, value = tree[1], tree[2] + local key_lua = self:tree_to_lua(key) + if not (key_lua.is_value) then + error("Cannot use " .. tostring(colored.yellow(repr(key))) .. " as a dict key, since it's not an expression.", 0) + end + local value_lua = value and self:tree_to_lua(value) or Lua.Value(nil, "true") + if not (value_lua.is_value) then + error("Cannot use " .. tostring(colored.yellow(repr(value))) .. " as a dict value, since it's not an expression.", 0) + end + local key_str = tostring(key_lua):match([=[["']([a-zA-Z_][a-zA-Z0-9_]*)['"]]=]) + if key_str then + return Lua(nil, key_str, "=", value_lua) + elseif tostring(key_lua):sub(1, 1) == "[" then + return Lua(nil, "[ ", key_lua, "]=", value_lua) + else + return Lua(nil, "[", key_lua, "]=", value_lua) + end + elseif "IndexChain" == _exp_0 then + local lua = self:tree_to_lua(tree[1]) + if not (lua.is_value) then + error("Cannot index " .. tostring(colored.yellow(repr(tree[1]))) .. ", since it's not an expression.", 0) + end + local first_char = tostring(lua):sub(1, 1) + if first_char == "{" or first_char == '"' or first_char == "[" then + lua:parenthesize() + end + for i = 2, #tree do + local key = tree[i] + local key_lua = self:tree_to_lua(key) + if not (key_lua.is_value) then + error("Cannot use " .. tostring(colored.yellow(repr(key))) .. " as an index, since it's not an expression.", 0) + end + local key_lua_str = tostring(key_lua) + do + local lua_id = key_lua_str:match("^['\"]([a-zA-Z_][a-zA-Z0-9_]*)['\"]$") + if lua_id then + lua:append("." .. tostring(lua_id)) + elseif key_lua_str:sub(1, 1) == '[' then + lua:append("[ ", key_lua, " ]") + else + lua:append("[", key_lua, "]") + end + end + end + return lua + elseif "Number" == _exp_0 then + return Lua.Value(nil, tostring(tree.value)) + elseif "Var" == _exp_0 then + return Lua.Value(nil, tree:as_lua_id()) + elseif "Word" == _exp_0 then + return error("Cannot convert a Word to lua") + elseif "Comment" == _exp_0 then + return Lua(nil, "--" .. tree.value:gsub("\n", "\n--") .. "\n") + else + return error("Unknown type: " .. tostring(tree.type)) + end + end, + tree_to_nomsu = function(self, tree, inline, can_use_colon) + if inline == nil then + inline = false + end + if can_use_colon == nil then + can_use_colon = false + end + local _exp_0 = tree.type + if "Action" == _exp_0 then + if inline then + local nomsu = Nomsu() + for i, bit in ipairs(tree) do + if bit.type == "Word" then + if i > 1 then + nomsu:append(" ") + end + nomsu:append(bit.value) + else + local arg_nomsu = self:tree_to_nomsu(bit, true) + if not (arg_nomsu) then + return nil + end + if not (i == 1) then + nomsu:append(" ") + end + if bit.type == "Action" or bit.type == "Block" then + arg_nomsu:parenthesize() + end + nomsu:append(arg_nomsu) + end + end + return nomsu + else + local nomsu = Nomsu() + local next_space = "" + local last_colon = nil + for i, bit in ipairs(tree) do + if bit.type == "Word" then + nomsu:append(next_space, bit.value) + next_space = " " + else + local arg_nomsu + if last_colon == i - 1 and bit.type == "Action" then + arg_nomsu = nil + elseif bit.type == "Block" then + arg_nomsu = nil + else + arg_nomsu = self:tree_to_nomsu(bit, true) + end + if arg_nomsu and #arg_nomsu < MAX_LINE then + if bit.type == "Action" then + if can_use_colon and i > 1 then + nomsu:append(next_space:match("[^ ]*"), ": ", arg_nomsu) + next_space = "\n.." + last_colon = i + else + nomsu:append(next_space, "(", arg_nomsu, ")") + next_space = " " + end + else + nomsu:append(next_space, arg_nomsu) + next_space = " " + end + else + arg_nomsu = self:tree_to_nomsu(bit, nil, true) + if not (nomsu) then + return nil + end + if bit.type ~= "List" and bit.type ~= "Dict" and bit.type ~= "Text" then + if i == 1 then + arg_nomsu = Nomsu(nil, "(..)\n ", arg_nomsu) + else + arg_nomsu = Nomsu(nil, "\n ", arg_nomsu) + end + end + if last_colon == i - 1 and (bit.type == "Action" or bit.type == "Block") then + next_space = "" + end + nomsu:append(next_space, arg_nomsu) + next_space = "\n.." + end + if next_space == " " and #(tostring(nomsu):match("[^\n]*$")) > MAX_LINE then + next_space = "\n.." + end + end + end + return nomsu + end + elseif "EscapedNomsu" == _exp_0 then + local nomsu = self:tree_to_nomsu(tree.value, true) + if nomsu == nil and not inline then + nomsu = self:tree_to_nomsu(tree.value) + return nomsu and Nomsu(nil, "\\:\n ", nomsu) + end + return nomsu and Nomsu(nil, "\\(", nomsu, ")") + elseif "Block" == _exp_0 then + if inline then + local nomsu = Nomsu() + for i, line in ipairs(self) do + if i > 1 then + nomsu:append("; ") + end + local line_nomsu = self:tree_to_nomsu(line, true) + if not (line_nomsu) then + return nil + end + nomsu:append(line_nomsu) + end + return nomsu + end + local nomsu = Nomsu() + for i, line in ipairs(self) do + line = assert(self:tree_to_nomsu(line, nil, true), "Could not convert line to nomsu") + nomsu:append(line) + if i < #self then + nomsu:append("\n") + if tostring(line):match("\n") then + nomsu:append("\n") + end + end + end + return nomsu + elseif "Text" == _exp_0 then + if inline then + local nomsu = Nomsu(nil, '"') + for _index_0 = 1, #tree do + local bit = tree[_index_0] + if type(bit) == 'string' then + nomsu:append((bit:gsub("\\", "\\\\"):gsub("\n", "\\n"))) + else + local interp_nomsu = self:tree_to_nomsu(bit, true) + if interp_nomsu then + if bit.type ~= "Word" and bit.type ~= "List" and bit.type ~= "Dict" and bit.type ~= "Text" then + interp_nomsu:parenthesize() + end + nomsu:append("\\", interp_nomsu) + else + return nil + end + end + end + nomsu:append('"') + return nomsu + else + local inline_version = self:tree_to_nomsu(tree, true) + if inline_version and #inline_version <= MAX_LINE then + return inline_version + end + local nomsu = Nomsu(nil, '".."\n ') + for i, bit in ipairs(self) do + if type(bit) == 'string' then + nomsu:append((bit:gsub("\\", "\\\\"):gsub("\n", "\n "))) + else + local interp_nomsu = self:tree_to_nomsu(bit, true) + if interp_nomsu then + if bit.type ~= "Word" and bit.type ~= "List" and bit.type ~= "Dict" and bit.type ~= "Text" then + interp_nomsu:parenthesize() + end + nomsu:append("\\", interp_nomsu) + else + interp_nomsu = self:tree_to_nomsu(bit) + if not (interp_nomsu) then + return nil + end + nomsu:append("\\\n ", interp_nomsu) + if i < #self then + nomsu:append("\n ..") + end + end + end + end + return nomsu + end + elseif "List" == _exp_0 then + if inline then + local nomsu = Nomsu(nil, "[") + for i, item in ipairs(tree) do + local item_nomsu = self:tree_to_nomsu(item, true) + if not (item_nomsu) then + return nil + end + if i > 1 then + nomsu:append(", ") + end + nomsu:append(item_nomsu) + end + nomsu:append("]") + return nomsu + else + local inline_version = self:tree_to_nomsu(tree, true) + if inline_version and #inline_version <= MAX_LINE then + return inline_version + end + local nomsu = Nomsu(nil, "[..]") + local line = Nomsu(nil, "\n ") + for _index_0 = 1, #tree do + local item = tree[_index_0] + local item_nomsu = self:tree_to_nomsu(item, true) + if item_nomsu and #line + #", " + #item_nomsu <= MAX_LINE then + if #line.bits > 1 then + line:append(", ") + end + line:append(item_nomsu) + else + if not (item_nomsu) then + item_nomsu = self:tree_to_nomsu(item) + if not (item_nomsu) then + return nil + end + end + if #line.bits > 1 then + nomsu:append(line) + line = Nomsu(nil, "\n ") + end + line:append(item_nomsu) + end + end + if #line.bits > 1 then + nomsu:append(line) + end + return nomsu + end + elseif "Dict" == _exp_0 then + if inline then + local nomsu = Nomsu(nil, "{") + for i, entry in ipairs(tree) do + local entry_nomsu = self:tree_to_nomsu(entry, true) + if not (entry_nomsu) then + return nil + end + if i > 1 then + nomsu:append(", ") + end + nomsu:append(entry_nomsu) + end + nomsu:append("}") + return nomsu + else + local inline_version = self:tree_to_nomsu(tree, true) + if inline_version then + return inline_version + end + local nomsu = Nomsu(nil, "{..}") + local line = Nomsu(nil, "\n ") + for _index_0 = 1, #tree do + local entry = tree[_index_0] + local entry_nomsu = self:tree_to_nomsu(entry) + if not (entry_nomsu) then + return nil + end + if #line + #tostring(entry_nomsu) <= MAX_LINE then + if #line.bits > 1 then + line:append(", ") + end + line:append(entry_nomsu) + else + if #line.bits > 1 then + nomsu:append(line) + line = Nomsu(nil, "\n ") + end + line:append(entry_nomsu) + end + end + if #line.bits > 1 then + nomsu:append(line) + end + return nomsu + end + elseif "DictEntry" == _exp_0 then + local key, value = tree[1], tree[2] + local key_nomsu = self:tree_to_nomsu(key, true) + if not (key_nomsu) then + return nil + end + if key.type == "Action" or key.type == "Block" then + key_nomsu:parenthesize() + end + local value_nomsu + if value then + value_nomsu = self:tree_to_nomsu(value, true) + else + value_nomsu = Nomsu(nil, "") + end + if inline and not value_nomsu then + return nil + end + if not value_nomsu then + if inline then + return nil + end + value_nomsu = self:tree_to_nomsu(value) + if not (value_nomsu) then + return nil + end + end + return Nomsu(nil, key_nomsu, ":", value_nomsu) + elseif "IndexChain" == _exp_0 then + local nomsu = Nomsu() + for i, bit in ipairs(tree) do + if i > 1 then + nomsu:append(".") + end + local bit_nomsu = self:tree_to_nomsu(bit, true) + if not (bit_nomsu) then + return nil + end + if bit.type == "Action" or bit.type == "Block" then + bit_nomsu:parenthesize() + end + nomsu:append(bit_nomsu) + end + return nomsu + elseif "Number" == _exp_0 then + return Nomsu(nil, tostring(tree.value)) + elseif "Var" == _exp_0 then + return Nomsu(nil, "%", tree.value) + elseif "Word" == _exp_0 then + return Nomsu(nil, tree.value) + elseif "Comment" == _exp_0 then + if inline then + return nil + end + return Nomsu(nil, "#", tree.value:gsub("\n", "\n ")) + else + return error("Unknown type: " .. tostring(tree.type)) + end + end, tree_to_value = function(self, tree) if tree.type == 'Text' and #tree == 1 and type(tree[1]) == 'string' then return tree[1] end - local lua = Lua(nil, "return ", tree:as_lua(self), ";") + local lua = Lua(nil, "return ", self:tree_to_lua(tree), ";") return self:run_lua(lua) end, walk_tree = function(self, tree, depth) @@ -456,32 +1073,10 @@ do return self:walk_tree(v, depth + 1) end end, - tree_with_replacements = function(self, tree, replacements) - if not (next(replacements)) then - return tree - end - if next(replacements).type == "Var" then - do - local _tbl_0 = { } - for k, v in pairs(replacements) do - _tbl_0[tostring(k:as_lua(self))] = v - end - replacements = _tbl_0 - end - end - return tree:map(function(t) - if t.type == "Var" then - local id = tostring(t:as_lua(self)) - if replacements[id] ~= nil then - return replacements[id] - end - end - end) - end, initialize_core = function(self) local nomsu = self self:define_compile_action("immediately %block", function(self, _block) - local lua = _block:as_lua(nomsu):as_statements() + local lua = nomsu:tree_to_lua(_block):as_statements() lua:declare_locals() nomsu:run_lua(lua) return Lua(nil, "if IMMEDIATE then\n ", lua, "\nend") @@ -489,7 +1084,7 @@ do local add_lua_string_bits add_lua_string_bits = function(lua, code) if code.type ~= "Text" then - lua:append(", ", code:as_lua(nomsu)) + lua:append(", ", nomsu:tree_to_lua(code)) return end for _index_0 = 1, #code do @@ -498,7 +1093,7 @@ do if type(bit) == "string" then lua:append(repr(bit)) else - local bit_lua = bit:as_lua(nomsu) + local bit_lua = nomsu:tree_to_lua(bit) if not (bit_lua.is_value) then error("Cannot use " .. tostring(colored.yellow(repr(bit))) .. " as a string interpolation value, since it's not an expression.") end @@ -525,7 +1120,7 @@ do if type(bit) == "string" then lua:append(bit) else - local bit_lua = bit:as_lua(nomsu) + local bit_lua = nomsu:tree_to_lua(bit) if not (bit_lua.is_value) then error("Cannot use " .. tostring(colored.yellow(repr(bit))) .. " as a string interpolation value, since it's not an expression.", 0) end @@ -536,13 +1131,13 @@ do end self:define_compile_action("lua> %code", function(self, _code) if _code.type ~= "Text" then - return Lua(nil, "nomsu:run_lua(", _code:as_lua(nomsu), ");") + return Lua(nil, "nomsu:run_lua(", nomsu:tree_to_lua(_code), ");") end return add_lua_bits(Lua(), _code) end) self:define_compile_action("=lua %code", function(self, _code) if _code.type ~= "Text" then - return Lua.Value(nil, "nomsu:run_lua(", _code:as_lua(nomsu), ":as_statements('return '))") + return Lua.Value(nil, "nomsu:run_lua(", nomsu:tree_to_lua(_code), ":as_statements('return '))") end return add_lua_bits(Lua.Value(), _code) end) @@ -715,6 +1310,8 @@ do var_pattern = re.compile("{| %space ((('%' {%varname}) / %word) %space)+ |}", stub_defs) _nomsu_chunk_counter = 0 _running_files = { } + MAX_LINE = 80 + math_expression = re.compile([[ ([+-] " ")* "%" (" " [*/^+-] (" " [+-])* " %")+ !. ]]) NomsuCompiler = _class_0 end if arg and debug_getinfo(2).func ~= require then @@ -953,7 +1550,7 @@ OPTIONS elseif args.format then for input_file in all_files(input) do local tree = nomsu:parse(io.open(input_file):read("*a")) - local formatted = tostring(tree:as_nomsu()) + local formatted = tostring(self:tree_to_nomsu(tree)) if output_file then output_file:write(formatted, "\n") output_file:flush() |
