diff --git a/patchwork.md b/patchwork.md index 04a7fec16..1f628cf6a 100644 --- a/patchwork.md +++ b/patchwork.md @@ -244,3 +244,15 @@ Tesselator, but this'll do for now. Fixes Zundrel/cc-tweaked-fabric#20. ``` + +``` +c58441b29c3715f092e7f3747bb3ec65ae5a3d29 +Various SNBT parsing improvements + +Correctly handle: + - Typed arrays ([I; 1, 2, 3]) + - All suffixed numbers (1.2d) + - Single-quoted strings + +Fixes #559 +``` diff --git a/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua b/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua index 576c6755e..d7aeb9e67 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua @@ -453,13 +453,13 @@ do error_at(pos, "Unexpected %s, expected %s.", actual, exp) end - local function parse_string(str, pos) + local function parse_string(str, pos, terminate) local buf, n = {}, 1 while true do local c = sub(str, pos, pos) if c == "" then error_at(pos, "Unexpected end of input, expected '\"'.") end - if c == '"' then break end + if c == terminate then break end if c == '\\' then -- Handle the various escapes @@ -485,13 +485,13 @@ do return concat(buf, "", 1, n - 1), pos + 1 end - local valid = { b = true, B = true, s = true, S = true, l = true, L = true, f = true, F = true, d = true, D = true } + local num_types = { b = true, B = true, s = true, S = true, l = true, L = true, f = true, F = true, d = true, D = true } local function parse_number(str, pos, opts) local _, last, num_str = find(str, '^(-?%d+%.?%d*[eE]?[+-]?%d*)', pos) local val = tonumber(num_str) if not val then error_at(pos, "Malformed number %q.", num_str) end - if opts.nbt_style and valid[sub(str, pos + 1, pos + 1)] then return val, last + 2 end + if opts.nbt_style and num_types[sub(str, last + 1, last + 1)] then return val, last + 2 end return val, last + 1 end @@ -501,9 +501,11 @@ do return val, last + 1 end + local arr_types = { I = true, L = true, B = true } local function decode_impl(str, pos, opts) local c = sub(str, pos, pos) - if c == '"' then return parse_string(str, pos + 1) + if c == '"' then return parse_string(str, pos + 1, '"') + elseif c == "'" and opts.nbt_style then return parse_string(str, pos + 1, "\'") elseif c == "-" or c >= "0" and c <= "9" then return parse_number(str, pos, opts) elseif c == "t" then if sub(str, pos + 1, pos + 3) == "rue" then return true, pos + 4 end @@ -560,6 +562,11 @@ do pos = skip(str, pos + 1) c = sub(str, pos, pos) + if arr_types[c] and sub(str, pos + 1, pos + 1) == ";" and opts.nbt_style then + pos = skip(str, pos + 2) + c = sub(str, pos, pos) + end + if c == "" then return expected(pos, c, "']'") end if c == "]" then return empty_json_array, pos + 1 end @@ -712,7 +719,7 @@ function urlEncode(str) else -- Non-ASCII (encode as UTF-8) return - string.format("%%%02X", 192 + bit32.band(bit32.arshift(n, 6), 31)) .. + string.format("%%%02X", 192 + bit32.band(bit32.arshift(n, 6), 31)) .. string.format("%%%02X", 128 + bit32.band(n, 63)) end end)