diff options
Diffstat (limited to 'nomsu_compiler.lua')
| -rw-r--r-- | nomsu_compiler.lua | 368 |
1 files changed, 164 insertions, 204 deletions
diff --git a/nomsu_compiler.lua b/nomsu_compiler.lua index b56fde8..57ed5c1 100644 --- a/nomsu_compiler.lua +++ b/nomsu_compiler.lua @@ -350,10 +350,13 @@ do end end }) - NomsuCompiler.run = function(self, to_run, source) + NomsuCompiler.run = function(self, to_run, source, version) if source == nil then source = nil end + if version == nil then + version = nil + end source = source or (to_run.source or Source(to_run, 1, #to_run)) if type(source) == 'string' then source = Source:from_string(source) @@ -365,29 +368,27 @@ do if AST.is_syntax_tree(to_run) then tree = to_run else - tree = self:parse(to_run, source) + tree = self:parse(to_run, source, version) end if tree == nil then return nil end - if tree.type == "File" then - local ret = nil - local all_lua = { } - for _index_0 = 1, #tree do - local chunk = tree[_index_0] - local lua = self:compile(chunk):as_statements("return ") - lua:declare_locals() - lua:prepend("-- File: " .. tostring(source.filename:gsub("\n.*", "...")) .. "\n") - insert(all_lua, tostring(lua)) - ret = self:run_lua(lua) - end - return ret - else - local lua = self:compile(tree):as_statements("return ") + if tree.type ~= "FileChunks" then + tree = { + tree + } + end + local ret = nil + local all_lua = { } + for _index_0 = 1, #tree do + local chunk = tree[_index_0] + local lua = self:compile(chunk):as_statements("return ") lua:declare_locals() lua:prepend("-- File: " .. tostring(source.filename:gsub("\n.*", "...")) .. "\n") - return self:run_lua(lua) + insert(all_lua, tostring(lua)) + ret = self:run_lua(lua) end + return ret end local _running_files = { } NomsuCompiler.run_file = function(self, filename) @@ -571,7 +572,8 @@ do end bits = _accum_0 end - return t.type .. "(" .. repr(tostring(t.source)) .. ", " .. table.concat(bits, ", ") .. ")" + insert(bits, 1, repr(tostring(t.source))) + return t.type .. "(" .. concat(bits, ", ") .. ")" end return LuaCode.Value(tree.source, make_tree(tree[1])) elseif "Block" == _exp_0 then @@ -711,13 +713,13 @@ do return LuaCode.Value(tree.source, tostring(tree[1])) elseif "Var" == _exp_0 then return LuaCode.Value(tree.source, string.as_lua_id(tree[1])) - elseif "File" == _exp_0 then - return error("Cannot convert File to a single block of lua, since each chunk's " .. "compilation depends on the earlier chunks") + elseif "FileChunks" == _exp_0 then + return error("Cannot convert FileChunks to a single block of lua, since each chunk's " .. "compilation depends on the earlier chunks") else return error("Unknown type: " .. tostring(tree.type)) end end - local MIN_COLON_LEN = 25 + local MIN_COLON_LEN = 20 NomsuCompiler.tree_to_nomsu = function(self, tree, options) options = options or { } if not (options.pop_comments) then @@ -740,7 +742,10 @@ do return a.pos < b.pos end) local comment_i = 1 - options.pop_comments = function(pos) + options.pop_comments = function(pos, prefix) + if prefix == nil then + prefix = '' + end local nomsu = NomsuCode(tree.source) while comments[comment_i] and comments[comment_i].pos <= pos do local comment = comments[comment_i].comment @@ -750,7 +755,11 @@ do end comment_i = comment_i + 1 end - return #nomsu.bits == 0 and '' or nomsu + if #nomsu.bits == 0 then + return '' + end + nomsu:prepend(prefix) + return nomsu end end local recurse @@ -759,12 +768,12 @@ do opts.pop_comments = options.pop_comments return self:tree_to_nomsu(t, opts) end - local inline, can_use_colon, pop_comments - inline, can_use_colon, pop_comments = options.inline, options.can_use_colon, options.pop_comments + local inline, pop_comments + inline, pop_comments = options.inline, options.pop_comments local _exp_0 = tree.type - if "File" == _exp_0 then + if "FileChunks" == _exp_0 then if inline then - return nil + error("Cannot inline a FileChunks") end local nomsu = NomsuCode(tree.source) for i, chunk in ipairs(tree) do @@ -772,7 +781,9 @@ do nomsu:append("\n\n" .. tostring(("~"):rep(80)) .. "\n\n") end nomsu:append(pop_comments(chunk.source.start)) - nomsu:append(recurse(chunk)) + nomsu:append(recurse(chunk, { + top = true + })) end nomsu:append(pop_comments(tree.source.stop)) return nomsu @@ -792,16 +803,12 @@ do if not (arg_nomsu) then return nil end - if bit.type == "Action" or bit.type == "Block" then - if bit.type == "Action" and i == #tree and #tostring(arg_nomsu) >= MIN_COLON_LEN then - nomsu:append(":") - else - arg_nomsu:parenthesize() - end - end if not (i == 1) then nomsu:append(" ") end + if bit.type == "Action" or (bit.type == "Block" and (#bit > 1 or i < #tree)) then + arg_nomsu:parenthesize() + end nomsu:append(arg_nomsu) end end @@ -809,100 +816,79 @@ do else local nomsu = NomsuCode(tree.source) local next_space = "" - local line_len, last_colon = 0, nil for i, bit in ipairs(tree) do if type(bit) == "string" then - line_len = line_len + #next_space + #bit nomsu:append(next_space, bit) next_space = " " else local arg_nomsu - if last_colon == i - 1 and bit.type == "Action" then - arg_nomsu = nil - elseif bit.type == "Block" then + if bit.type == "Block" and #bit > 1 then arg_nomsu = nil else - arg_nomsu = recurse(bit, { + arg_nomsu = assert(recurse(bit, { inline = true - }) + })) end - if arg_nomsu and line_len + #tostring(arg_nomsu) < MAX_LINE then - if bit.type == "Action" then - if can_use_colon and i > 1 and #tostring(arg_nomsu) >= MIN_COLON_LEN then - nomsu:append(match(next_space, "[^ ]*"), ": ", arg_nomsu) - next_space = "\n.." - line_len = 2 - last_colon = i - else - nomsu:append(next_space, "(", arg_nomsu, ")") - line_len = line_len + #next_space + 2 + #tostring(arg_nomsu) - next_space = " " - end + if bit.type == "Block" then + next_space = match(next_space, "[^ ]*") + end + nomsu:append(next_space) + if arg_nomsu and nomsu.trailing_line_len + #tostring(arg_nomsu) < MAX_LINE then + if bit.type == "Block" then + nomsu:append(arg_nomsu) + next_space = "\n.." else - nomsu:append(next_space, arg_nomsu) - line_len = line_len + #next_space + #tostring(arg_nomsu) + if bit.type == "Action" then + arg_nomsu:parenthesize() + end + nomsu:append(arg_nomsu) next_space = " " end else - arg_nomsu = recurse(bit, { - can_use_colon = true - }) - if not (arg_nomsu) then - return nil - end - if bit.type ~= "List" and bit.type ~= "Dict" and bit.type ~= "Text" then - if i == 1 then - arg_nomsu = NomsuCode(bit.source, "(..)\n ", pop_comments(bit.source.start), arg_nomsu) - else - arg_nomsu = NomsuCode(bit.source, "\n ", pop_comments(bit.source.start), arg_nomsu) - end - end - if last_colon == i - 1 and (bit.type == "Action" or bit.type == "Block") then - next_space = "" + arg_nomsu = assert(recurse(bit)) + if bit.type ~= "List" and bit.type ~= "Dict" and bit.type ~= "Text" and bit.type ~= "Block" then + nomsu:append(NomsuCode(bit.source, "(..)\n ", pop_comments(bit.source.start), arg_nomsu)) + else + nomsu:append(arg_nomsu) end - nomsu:append(next_space, arg_nomsu) - next_space = "\n.." - line_len = 2 - end - if next_space == " " and #(match(tostring(nomsu), "[^\n]*$")) > MAX_LINE then next_space = "\n.." end end + if next_space == " " and nomsu.trailing_line_len > MAX_LINE then + next_space = "\n.." + end end return nomsu end elseif "EscapedNomsu" == _exp_0 then - local nomsu = recurse(tree[1], { + local nomsu = NomsuCode(tree.source, "\\(", assert(recurse(tree[1], { inline = true - }) - if nomsu == nil and not inline then - nomsu = recurse(tree[1]) - return nomsu and NomsuCode(tree.source, "\\:\n ", pop_comments(tree.source.start), nomsu) + })), ")") + if inline or #tostring(nomsu) <= MAX_LINE then + return nomsu + end + nomsu = assert(recurse(tree[1])) + local _exp_1 = tree[1].type + if "List" == _exp_1 or "Dict" == _exp_1 or "Text" == _exp_1 or "Block" == _exp_1 then + return NomsuCode(tree.source, "\\", nomsu) + else + return NomsuCode(tree.source, "\\(..)\n ", pop_comments(tree.source.start), nomsu) end - return nomsu and NomsuCode(tree.source, "\\(", nomsu, ")") elseif "Block" == _exp_0 then if inline then - local nomsu = NomsuCode(tree.source) + local nomsu = NomsuCode(tree.source, ":") for i, line in ipairs(tree) do - if i > 1 then - nomsu:append("; ") - end - local line_nomsu = recurse(line, { + nomsu:append(i == 1 and " " or "; ") + nomsu:append(assert(recurse(line, { inline = true - }) - if not (line_nomsu) then - return nil - end - nomsu:append(line_nomsu) + }))) end return nomsu end local nomsu = NomsuCode(tree.source) for i, line in ipairs(tree) do nomsu:append(pop_comments(line.source.start)) - line = assert(recurse(line, { - can_use_colon = true - }), "Could not convert line to nomsu") + line = assert(recurse(line), "Could not convert line to nomsu") nomsu:append(line) if i < #tree then nomsu:append("\n") @@ -911,7 +897,7 @@ do end end end - return nomsu + return options.top and nomsu or NomsuCode(tree.source, ":\n ", nomsu) elseif "Text" == _exp_0 then if inline then local make_text @@ -927,7 +913,7 @@ do local interp_nomsu = assert(recurse(bit, { inline = true })) - if bit.type ~= "Var" and bit.type ~= "List" and bit.type ~= "Dict" and bit.type ~= "Text" then + if bit.type ~= "Var" and bit.type ~= "List" and bit.type ~= "Dict" then interp_nomsu:parenthesize() end nomsu:append("\\", interp_nomsu) @@ -985,7 +971,7 @@ do inline = true }) if interp_nomsu then - if bit.type ~= "Var" and bit.type ~= "List" and bit.type ~= "Dict" and bit.type ~= "Text" then + if bit.type ~= "Var" and bit.type ~= "List" and bit.type ~= "Dict" then interp_nomsu:parenthesize() end nomsu:append("\\", interp_nomsu) @@ -1009,16 +995,12 @@ do if inline then local nomsu = NomsuCode(tree.source, "[") for i, item in ipairs(tree) do - local item_nomsu = recurse(item, { - inline = true - }) - if not (item_nomsu) then - return nil - end if i > 1 then nomsu:append(", ") end - nomsu:append(item_nomsu) + nomsu:append(assert(recurse(item, { + inline = true + }))) end nomsu:append("]") return nomsu @@ -1026,67 +1008,56 @@ do local inline_version = recurse(tree, { inline = true }) - if inline_version and #inline_version <= MAX_LINE then + if inline_version and #tostring(inline_version) <= MAX_LINE then return inline_version end - local nomsu = NomsuCode(tree.source, "[..]") - local line = NomsuCode(tree.source, "\n ") - local line_comments - if #tree > 0 then - line_comments = pop_comments(tree[1].source.start) - else - line_comments = '' - end + assert(#tree > 0) + local nomsu = NomsuCode(tree.source, pop_comments(tree[1].source.start)) for i, item in ipairs(tree) do - local item_nomsu = recurse(item, { + local item_nomsu = assert(recurse(item, { inline = true - }) - if item_nomsu and #tostring(line) + #", " + #item_nomsu <= MAX_LINE then - if #line.bits > 1 then - line:append(", ") + })) + if item.type == "Block" then + item_nomsu:parenthesize() + end + if nomsu.trailing_line_len + #tostring(item_nomsu) <= MAX_LINE then + if nomsu.trailing_line_len > 0 then + nomsu:append(", ") end - line:append(item_nomsu) + nomsu:append(item_nomsu) else - if not (item_nomsu) then + if #tostring(item_nomsu) > MAX_LINE then item_nomsu = recurse(item) - if not (item_nomsu) then - return nil - end - end - if #line.bits > 1 then - if #tostring(line_comments) > 0 then - nomsu:append('\n ', line_comments) + local _exp_1 = item.type + if "List" == _exp_1 or "Dict" == _exp_1 or "Text" == _exp_1 or "Block" == _exp_1 then + nomsu:append(item_nomsu) + else + nomsu:append("(..)\n ", item_nomsu) end - nomsu:append(line) - line = NomsuCode(line.source, "\n ") if i < #tree then - line_comments = pop_comments(tree[i + 1].source.start) - else - line_comments = '' + nomsu:append("\n") + end + else + if nomsu.trailing_line_len > 0 then + nomsu:append('\n') end + nomsu:append(pop_comments(item.source.start), item_nomsu) end - line:append(item_nomsu) end end - if #line.bits > 1 then - nomsu:append(line) - end - return nomsu + nomsu:append(pop_comments(tree.source.stop, '\n')) + return NomsuCode(tree.source, "[..]\n ", nomsu) end elseif "Dict" == _exp_0 then if inline then local nomsu = NomsuCode(tree.source, "{") for i, entry in ipairs(tree) do - local entry_nomsu = recurse(entry, { - inline = true - }) - if not (entry_nomsu) then - return nil - end if i > 1 then nomsu:append(", ") end - nomsu:append(entry_nomsu) + nomsu:append(assert(recurse(entry, { + inline = true + }))) end nomsu:append("}") return nomsu @@ -1094,80 +1065,75 @@ do local inline_version = recurse(tree, { inline = true }) - if inline_version then + if inline_version and #tostring(inline_version) <= MAX_LINE then return inline_version end - local nomsu = NomsuCode(tree.source, "{..}") - local line = NomsuCode(tree.source, "\n ") - local line_comments - if #tree > 0 then - line_comments = pop_comments(tree[1].source.start) - else - line_comments = '' - end - for i, entry in ipairs(tree) do - local entry_nomsu = recurse(entry) - if not (entry_nomsu) then - return nil + assert(#tree > 0) + local nomsu = NomsuCode(tree.source, pop_comments(tree[1].source.start)) + for i, item in ipairs(tree) do + local item_nomsu = assert(recurse(item, { + inline = true + })) + if item.type == "Block" then + item_nomsu:parenthesize() end - if #line + #tostring(entry_nomsu) <= MAX_LINE then - if #line.bits > 1 then - line:append(", ") + if nomsu.trailing_line_len + #tostring(item_nomsu) <= MAX_LINE then + if nomsu.trailing_line_len > 0 then + nomsu:append(", ") end - line:append(entry_nomsu) + nomsu:append(item_nomsu) else - if #line.bits > 1 then - if #tostring(line_comments) > 0 then - nomsu:append("\n ", line_comments) + if #tostring(item_nomsu) > MAX_LINE then + item_nomsu = recurse(item) + local _exp_1 = item.type + if "List" == _exp_1 or "Dict" == _exp_1 or "Text" == _exp_1 or "Block" == _exp_1 then + nomsu:append(item_nomsu) + else + nomsu:append("(..)\n ", item_nomsu) end - nomsu:append(line) - line = NomsuCode(line.source, "\n ") if i < #tree then - line_comments = pop_comments(tree[1].source.start) - else - line_comments = '' + nomsu:append("\n") + end + else + if nomsu.trailing_line_len > 0 then + nomsu:append('\n') end + nomsu:append(pop_comments(item.source.start), item_nomsu) end - line:append(entry_nomsu) end end - if #line.bits > 1 then - nomsu:append(line) - end - return nomsu + nomsu:append(pop_comments(tree.source.stop, '\n')) + return NomsuCode(tree.source, "{..}\n ", nomsu) end elseif "DictEntry" == _exp_0 then local key, value = tree[1], tree[2] - local key_nomsu = recurse(key, { + local key_nomsu = assert(recurse(key, { inline = 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 = recurse(value, { + value_nomsu = assert(recurse(value, { inline = true - }) + })) else value_nomsu = NomsuCode(tree.source, "") end - if inline and not value_nomsu then - return nil + assert(value.type ~= "Block", "Didn't expect to find a Block as a value in a dict") + if value.type == "Block" then + value_nomsu:parenthesize() end - if not value_nomsu then - if inline then - return nil - end - value_nomsu = recurse(value) - if not (value_nomsu) then - return nil - end + if inline or #tostring(key_nomsu) + 2 + #tostring(value_nomsu) <= MAX_LINE then + return NomsuCode(tree.source, key_nomsu, ": ", value_nomsu) + end + value_nomsu = recurse(value) + if value.type == "List" or value.type == "Dict" or value.type == "Text" then + return NomsuCode(tree.source, key_nomsu, ": ", value_nomsu) + else + return NomsuCode(tree.source, key_nomsu, ": (..)\n ", value_nomsu) end - return NomsuCode(tree.source, key_nomsu, ":", value_nomsu) elseif "IndexChain" == _exp_0 then local nomsu = NomsuCode(tree.source) for i, bit in ipairs(tree) do @@ -1175,18 +1141,12 @@ do nomsu:append(".") end local bit_nomsu - if bit.type == "Text" and #bit == 1 and type(bit[1]) == 'string' then - if bit[1]:match("[_a-zA-Z][_a-zA-Z0-9]*") then - bit_nomsu = bit[1] - end - end - if not (bit_nomsu) then - bit_nomsu = recurse(bit, { + if bit.type == "Text" and #bit == 1 and type(bit[1]) == 'string' and bit[1]:match("[_a-zA-Z][_a-zA-Z0-9]*") then + bit_nomsu = bit[1] + else + bit_nomsu = assert(recurse(bit, { inline = true - }) - end - if not (bit_nomsu) then - return nil + })) end local _exp_1 = bit.type if "Action" == _exp_1 or "Block" == _exp_1 or "IndexChain" == _exp_1 then |
