diff options
Diffstat (limited to 'nomsu_tree.lua')
| -rw-r--r-- | nomsu_tree.lua | 339 |
1 files changed, 177 insertions, 162 deletions
diff --git a/nomsu_tree.lua b/nomsu_tree.lua index 68475f6..4d30f38 100644 --- a/nomsu_tree.lua +++ b/nomsu_tree.lua @@ -18,59 +18,92 @@ Types.is_node = function(n) return type(n) == 'userdata' and getmetatable(n) and Types[n.type] == getmetatable(n) end local Tree -Tree = function(name, methods) +Tree = function(name, kind, methods) + assert((kind == 'single') or (kind == 'multi')) + local is_multi = (kind == 'multi') do - methods.__tostring = function(self) - return tostring(self.name) .. "(" .. tostring(repr(self.value)) .. ", " .. tostring(repr(self.source)) .. ")" - end methods.with_value = function(self, value) - return getmetatable(self)(value, self.source) + return getmetatable(self)(value) end methods.type = name methods.name = name - methods.original_nomsu = function(self) - local leading_space = 0 - local src_file = FILE_CACHE[self.source.filename] - while src_file:sub(self.source.start - leading_space - 1, self.source.start - leading_space - 1) == " " do - leading_space = leading_space + 1 - end - if src_file:sub(self.source.start - leading_space - 1, self.source.start - leading_space - 1) ~= "\n" then - leading_space = 0 + methods.is_multi = is_multi + if is_multi then + methods.__tostring = function(self) + return tostring(self.name) .. "(" .. tostring(table.concat((function() + local _accum_0 = { } + local _len_0 = 1 + for _index_0 = 1, #self do + local v = self[_index_0] + _accum_0[_len_0] = repr(v) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)(), ', ')) .. ")" end - local ret = tostring(self.source:get_text()):gsub("\n" .. ((" "):rep(leading_space)), "\n") - return ret - end - methods.map = function(self, fn) - do - local mapped = fn(self) - if mapped then - return mapped + methods.map = function(self, fn) + do + local ret = fn(self) + if ret then + return ret + end end - end - if Tuple:is_instance(self.value) then - return self:with_value(Tuple(unpack((function() + local new_vals + do local _accum_0 = { } local _len_0 = 1 - local _list_0 = self.value - for _index_0 = 1, #_list_0 do - local v = _list_0[_index_0] + for _index_0 = 1, #self do + local v = self[_index_0] _accum_0[_len_0] = v.map and v:map(fn) or v _len_0 = _len_0 + 1 end - return _accum_0 - end)()))) + new_vals = _accum_0 + end + local ret = getmetatable(self)(unpack(new_vals)) + return ret + end + else + methods.__tostring = function(self) + return tostring(self.name) .. "(" .. tostring(repr(self.value)) .. ")" + end + methods.map = function(self, fn) + return fn(self) or self end - return self end end - Types[name] = immutable({ - "value", - "source" - }, methods) + if is_multi then + Types[name] = immutable(nil, methods) + else + Types[name] = immutable({ + "value" + }, methods) + end end -Tree("Nomsu", { +Tree("EscapedNomsu", 'single', { as_lua = function(self, nomsu) - return Lua.Value(self.source, "nomsu:parse(Nomsu(", repr(self.value.source), ", ", repr(tostring(self.value:as_nomsu(true))), "))") + 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(self.value)) end, as_nomsu = function(self, inline) if inline == nil then @@ -79,15 +112,18 @@ Tree("Nomsu", { local nomsu = self.value:as_nomsu(true) if nomsu == nil and not inline then nomsu = self.value:as_nomsu() - return nomsu and Nomsu(self.source, "\\:\n ", nomsu) + return nomsu and Nomsu(nil, "\\:\n ", nomsu) end - return nomsu and Nomsu(self.source, "\\(", nomsu, ")") + return nomsu and Nomsu(nil, "\\(", nomsu, ")") + end, + map = function(self, fn) + return fn(self) or self:map(fn) end }) -Tree("Block", { +Tree("Block", 'multi', { as_lua = function(self, nomsu) - local lua = Lua(self.source) - for i, line in ipairs(self.value) do + local lua = Lua() + for i, line in ipairs(self) do local line_lua = line:as_lua(nomsu) if i > 1 then lua:append("\n") @@ -101,8 +137,8 @@ Tree("Block", { inline = false end if inline then - local nomsu = Nomsu(self.source) - for i, line in ipairs(self.value) do + local nomsu = Nomsu() + for i, line in ipairs(self) do if i > 1 then nomsu:append("; ") end @@ -114,11 +150,11 @@ Tree("Block", { end return nomsu end - local nomsu = Nomsu(self.source) - for i, line in ipairs(self.value) do + local nomsu = Nomsu() + for i, line in ipairs(self) do line = assert(line:as_nomsu(nil, true), "Could not convert line to nomsu") nomsu:append(line) - if i < #self.value then + if i < #self then nomsu:append("\n") if tostring(line):match("\n") then nomsu:append("\n") @@ -129,7 +165,7 @@ Tree("Block", { end }) local math_expression = re.compile([[ ([+-] " ")* "%" (" " [*/^+-] (" " [+-])* " %")+ !. ]]) -Tree("Action", { +Tree("Action", 'multi', { as_lua = function(self, nomsu) local stub = self:get_stub() local compile_action = nomsu.environment.COMPILE_ACTIONS[stub] @@ -138,9 +174,8 @@ Tree("Action", { do local _accum_0 = { } local _len_0 = 1 - local _list_0 = self.value - for _index_0 = 1, #_list_0 do - local arg = _list_0[_index_0] + for _index_0 = 1, #self do + local arg = self[_index_0] if arg.type ~= "Word" then _accum_0[_len_0] = arg _len_0 = _len_0 + 1 @@ -166,30 +201,29 @@ Tree("Action", { return ret end local action = rawget(nomsu.environment.ACTIONS, stub) - local lua = Lua.Value(self.source) + local lua = Lua.Value() if not action and math_expression:match(stub) then - for i, tok in ipairs(self.value) do + for i, tok in ipairs(self) do if tok.type == "Word" then lua:append(tok.value) else local tok_lua = tok:as_lua(nomsu) if not (tok_lua.is_value) then - local src = tok.source:get_text() - error("non-expression value inside math expression: " .. tostring(colored.yellow(src))) + 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 < #self.value then + if i < #self then lua:append(" ") end end return lua end local args = { } - for i, tok in ipairs(self.value) do + for i, tok in ipairs(self) do local _continue_0 = false repeat if tok.type == "Word" then @@ -198,8 +232,7 @@ Tree("Action", { end local arg_lua = tok:as_lua(nomsu) if not (arg_lua.is_value) then - local line, src = tok.source:get_line(), tok.source:get_text() - error(tostring(line) .. ": Cannot use:\n" .. tostring(colored.yellow(src)) .. "\nas an argument to " .. tostring(stub) .. ", since it's not an expression, it produces: " .. tostring(repr(arg_lua)), 0) + 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 @@ -240,9 +273,8 @@ Tree("Action", { do local _accum_0 = { } local _len_0 = 1 - local _list_0 = self.value - for _index_0 = 1, #_list_0 do - local t = _list_0[_index_0] + for _index_0 = 1, #self do + local t = self[_index_0] _accum_0[_len_0] = (t.type == "Word" and t.value or "%" .. tostring(t.value)) _len_0 = _len_0 + 1 end @@ -252,9 +284,8 @@ Tree("Action", { do local _accum_0 = { } local _len_0 = 1 - local _list_0 = self.value - for _index_0 = 1, #_list_0 do - local t = _list_0[_index_0] + for _index_0 = 1, #self do + local t = self[_index_0] _accum_0[_len_0] = (t.type == "Word" and t.value or "%") _len_0 = _len_0 + 1 end @@ -271,8 +302,8 @@ Tree("Action", { can_use_colon = false end if inline then - local nomsu = Nomsu(self.source) - for i, bit in ipairs(self.value) do + local nomsu = Nomsu() + for i, bit in ipairs(self) do if bit.type == "Word" then if i > 1 then nomsu:append(" ") @@ -294,10 +325,10 @@ Tree("Action", { end return nomsu else - local nomsu = Nomsu(self.source) + local nomsu = Nomsu() local next_space = "" local last_colon = nil - for i, bit in ipairs(self.value) do + for i, bit in ipairs(self) do if bit.type == "Word" then nomsu:append(next_space, bit.value) next_space = " " @@ -331,9 +362,9 @@ Tree("Action", { end if bit.type ~= "List" and bit.type ~= "Dict" and bit.type ~= "Text" then if i == 1 then - arg_nomsu = Nomsu(bit.source, "(..)\n ", arg_nomsu) + arg_nomsu = Nomsu(nil, "(..)\n ", arg_nomsu) else - arg_nomsu = Nomsu(bit.source, "\n ", arg_nomsu) + arg_nomsu = Nomsu(nil, "\n ", arg_nomsu) end end if last_colon == i - 1 and (bit.type == "Action" or bit.type == "Block") then @@ -351,15 +382,14 @@ Tree("Action", { end end }) -Tree("Text", { +Tree("Text", 'multi', { as_lua = function(self, nomsu) - local lua = Lua.Value(self.source) + local lua = Lua.Value() local string_buffer = "" - local _list_0 = self.value - for _index_0 = 1, #_list_0 do + for _index_0 = 1, #self do local _continue_0 = false repeat - local bit = _list_0[_index_0] + local bit = self[_index_0] if type(bit) == "string" then string_buffer = string_buffer .. bit _continue_0 = true @@ -374,14 +404,13 @@ Tree("Text", { end local bit_lua = bit:as_lua(nomsu) if not (bit_lua.is_value) then - local line, src = bit.source:get_line(), bit.source:get_text() - error(tostring(line) .. ": Cannot use " .. tostring(colored.yellow(bit)) .. " as a string interpolation value, since it's not an expression.", 0) + 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(bit.source, "stringify(", bit_lua, ")") + bit_lua = Lua.Value(nil, "stringify(", bit_lua, ")") end lua:append(bit_lua) _continue_0 = true @@ -406,10 +435,9 @@ Tree("Text", { inline = false end if inline then - local nomsu = Nomsu(self.source, '"') - local _list_0 = self.value - for _index_0 = 1, #_list_0 do - local bit = _list_0[_index_0] + local nomsu = Nomsu(nil, '"') + for _index_0 = 1, #self do + local bit = self[_index_0] if type(bit) == 'string' then nomsu:append((bit:gsub("\\", "\\\\"):gsub("\n", "\\n"))) else @@ -431,8 +459,8 @@ Tree("Text", { if inline_version and #inline_version <= MAX_LINE then return inline_version end - local nomsu = Nomsu(self.source, '".."\n ') - for i, bit in ipairs(self.value) do + 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 @@ -448,7 +476,7 @@ Tree("Text", { return nil end nomsu:append("\\\n ", interp_nomsu) - if i < #self.value then + if i < #self then nomsu:append("\n ..") end end @@ -458,15 +486,14 @@ Tree("Text", { end end }) -Tree("List", { +Tree("List", 'multi', { as_lua = function(self, nomsu) - local lua = Lua.Value(self.source, "{") + local lua = Lua.Value(nil, "{") local line_length = 0 - for i, item in ipairs(self.value) do + for i, item in ipairs(self) do local item_lua = item:as_lua(nomsu) if not (item_lua.is_value) then - local line, src = item.source:get_line(), item.source:get_text() - error(tostring(line) .. ": Cannot use " .. tostring(colored.yellow(src)) .. " as a list item, since it's not an expression.", 0) + 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) @@ -476,7 +503,7 @@ Tree("List", { else line_length = line_length + #last_line end - if i < #self.value then + if i < #self then if line_length >= MAX_LINE then lua:append(",\n ") line_length = 0 @@ -494,8 +521,8 @@ Tree("List", { inline = false end if inline then - local nomsu = Nomsu(self.source, "[") - for i, item in ipairs(self.value) do + local nomsu = Nomsu(nil, "[") + for i, item in ipairs(self) do local item_nomsu = item:as_nomsu(true) if not (item_nomsu) then return nil @@ -512,11 +539,10 @@ Tree("List", { if inline_version and #inline_version <= MAX_LINE then return inline_version end - local nomsu = Nomsu(self.source, "[..]") - local line = Nomsu(self.source, "\n ") - local _list_0 = self.value - for _index_0 = 1, #_list_0 do - local item = _list_0[_index_0] + local nomsu = Nomsu(nil, "[..]") + local line = Nomsu(nil, "\n ") + for _index_0 = 1, #self do + local item = self[_index_0] local item_nomsu = item:as_nomsu(true) if item_nomsu and #line + #", " + #item_nomsu <= MAX_LINE then if #line.bits > 1 then @@ -532,7 +558,7 @@ Tree("List", { end if #line.bits > 1 then nomsu:append(line) - line = Nomsu(item.source, "\n ") + line = Nomsu(nil, "\n ") end line:append(item_nomsu) end @@ -544,11 +570,11 @@ Tree("List", { end end }) -Tree("Dict", { +Tree("Dict", 'multi', { as_lua = function(self, nomsu) - local lua = Lua.Value(self.source, "{") + local lua = Lua.Value(nil, "{") local line_length = 0 - for i, entry in ipairs(self.value) do + for i, entry in ipairs(self) do local entry_lua = entry:as_lua(nomsu) lua:append(entry_lua) local entry_lua_str = tostring(entry_lua) @@ -558,7 +584,7 @@ Tree("Dict", { else line_length = line_length + #entry_lua_str end - if i < #self.value then + if i < #self then if line_length >= MAX_LINE then lua:append(",\n ") line_length = 0 @@ -576,8 +602,8 @@ Tree("Dict", { inline = false end if inline then - local nomsu = Nomsu(self.source, "{") - for i, entry in ipairs(self.value) do + local nomsu = Nomsu(nil, "{") + for i, entry in ipairs(self) do local entry_nomsu = entry:as_nomsu(true) if not (entry_nomsu) then return nil @@ -594,11 +620,10 @@ Tree("Dict", { if inline_version then return inline_version end - local nomsu = Nomsu(self.source, "{..}") - local line = Nomsu(self.source, "\n ") - local _list_0 = self.value - for _index_0 = 1, #_list_0 do - local entry = _list_0[_index_0] + local nomsu = Nomsu(nil, "{..}") + local line = Nomsu(nil, "\n ") + for _index_0 = 1, #self do + local entry = self[_index_0] local entry_nomsu = entry:as_nomsu() if not (entry_nomsu) then return nil @@ -611,7 +636,7 @@ Tree("Dict", { else if #line.bits > 1 then nomsu:append(line) - line = Nomsu(bit.source, "\n ") + line = Nomsu(nil, "\n ") end line:append(entry_nomsu) end @@ -623,33 +648,31 @@ Tree("Dict", { end end }) -Tree("DictEntry", { +Tree("DictEntry", 'multi', { as_lua = function(self, nomsu) - local key, value = self.value[1], self.value[2] + local key, value = self[1], self[2] local key_lua = key:as_lua(nomsu) if not (key_lua.is_value) then - local line, src = key.source:get_line(), key.source:get_text() - error(tostring(line) .. ": Cannot use " .. tostring(colored.yellow(src)) .. " as a dict key, since it's not an expression.", 0) + 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 value:as_lua(nomsu) or Lua.Value(key.source, "true") + local value_lua = value and value:as_lua(nomsu) or Lua.Value(nil, "true") if not (value_lua.is_value) then - local line, src = value.source:get_line(), value.source:get_text() - error(tostring(line) .. ": Cannot use " .. tostring(colored.yellow(src)) .. " as a dict value, since it's not an expression.", 0) + 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(key.source, key_str, "=", value_lua) + return Lua(nil, key_str, "=", value_lua) elseif tostring(key_lua):sub(1, 1) == "[" then - return Lua(key.source, "[ ", key_lua, "]=", value_lua) + return Lua(nil, "[ ", key_lua, "]=", value_lua) else - return Lua(key.source, "[", key_lua, "]=", value_lua) + return Lua(nil, "[", key_lua, "]=", value_lua) end end, as_nomsu = function(self, inline) if inline == nil then inline = true end - local key, value = self.value[1], self.value[2] + local key, value = self[1], self[2] local key_nomsu = key:as_nomsu(true) if not (key_nomsu) then return nil @@ -661,7 +684,7 @@ Tree("DictEntry", { if value then value_nomsu = value:as_nomsu(true) else - value_nomsu = Nomsu(key.source, "") + value_nomsu = Nomsu(nil, "") end if inline and not value_nomsu then return nil @@ -675,43 +698,35 @@ Tree("DictEntry", { return nil end end - return Nomsu(key.source, key_nomsu, ":", value_nomsu) + return Nomsu(nil, key_nomsu, ":", value_nomsu) end }) -Tree("IndexChain", { +Tree("IndexChain", 'multi', { as_lua = function(self, nomsu) - local lua = self.value[1]:as_lua(nomsu) + local lua = self[1]:as_lua(nomsu) if not (lua.is_value) then - local line, src = self.value[1].source:get_line(), self.value[1].source:get_text() - error(tostring(line) .. ": Cannot index " .. tostring(colored.yellow(src)) .. ", since it's not an expression.", 0) + error("Cannot index " .. tostring(colored.yellow(repr(self[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, #self.value do - local _continue_0 = false - repeat - local key = self.value[i] - if key.type == 'Text' and #key.value == 1 and type(key.value[1]) == 'string' and key.value[1]:match("^[a-zA-Z_][a-zA-Z0-9_]*$") then - lua:append("." .. tostring(key.value[1])) - _continue_0 = true - break - end - local key_lua = key:as_lua(nomsu) - if not (key_lua.is_value) then - local line, src = key.source:get_line(), key.source:get_text() - error(tostring(line) .. ": Cannot use " .. tostring(colored.yellow(src)) .. " as an index, since it's not an expression.", 0) - end - if tostring(key_lua):sub(1, 1) == '[' then - lua:append("[ ", key_lua, "]") + for i = 2, #self do + local key = self[i] + local key_lua = key:as_lua(nomsu) + 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 - _continue_0 = true - until true - if not _continue_0 then - break end end return lua @@ -720,8 +735,8 @@ Tree("IndexChain", { if inline == nil then inline = false end - local nomsu = Nomsu(self.source) - for i, bit in ipairs(self.value) do + local nomsu = Nomsu() + for i, bit in ipairs(self) do if i > 1 then nomsu:append(".") end @@ -737,18 +752,18 @@ Tree("IndexChain", { return nomsu end }) -Tree("Number", { +Tree("Number", 'single', { as_lua = function(self, nomsu) - return Lua.Value(self.source, tostring(self.value)) + return Lua.Value(nil, tostring(self.value)) end, as_nomsu = function(self, inline) if inline == nil then inline = false end - return Nomsu(self.source, tostring(self.value)) + return Nomsu(nil, tostring(self.value)) end }) -Tree("Var", { +Tree("Var", 'single', { as_lua_id = function(v) return "_" .. (v:gsub("%W", function(c) if c == "_" then @@ -759,16 +774,16 @@ Tree("Var", { end)) end, as_lua = function(self, nomsu) - return Lua.Value(self.source, self.as_lua_id(self.value)) + return Lua.Value(nil, self.as_lua_id(self.value)) end, as_nomsu = function(self, inline) if inline == nil then inline = false end - return Nomsu(self.source, "%", self.value) + return Nomsu(nil, "%", self.value) end }) -Tree("Word", { +Tree("Word", 'single', { as_lua = function(self, nomsu) return error("Attempt to convert Word to lua") end, @@ -776,12 +791,12 @@ Tree("Word", { if inline == nil then inline = false end - return Nomsu(self.source, self.value) + return Nomsu(nil, self.value) end }) -Tree("Comment", { +Tree("Comment", 'single', { as_lua = function(self, nomsu) - return Lua(self.source, "--" .. self.value:gsub("\n", "\n--") .. "\n") + return Lua(nil, "--" .. self.value:gsub("\n", "\n--") .. "\n") end, as_nomsu = function(self, inline) if inline == nil then @@ -791,9 +806,9 @@ Tree("Comment", { return nil end if self.value:match("\n") then - return Nomsu(self.source, "#..", self.value:gsub("\n", "\n ")) + return Nomsu(nil, "#..", self.value:gsub("\n", "\n ")) else - return Nomsu(self.source, "#", self.value) + return Nomsu(nil, "#", self.value) end end }) |
