This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
SilentPro's profile picture

[Lua][Error] Different results from string.find() in API call and lua prompt (with WORKAROUND)

Started by SilentPro, 09 August 2012 - 04:35 PM
SilentPro #1
Posted 09 August 2012 - 06:35 PM
Hi,

although I think of myself as a descent programmer I'm struggling with a strange Lua-Error at the moment.
I implemented my one "Serializer - Deserializer - Combo" to turn any of the major lua objects into strings for storage.

Everything's working fine except both uses of the find method from the string API return always wrong values.
In the screenshot you see a simple test of my api functions in the lua interpreter.
The error or wrong result occurs only within my deserializer function, but not on it's own when directly tested on a string literal. I looked at the code multiple times and checked if variable "p2" gets changed at any point, but it has the wrong value (very often 7 or 8 regardless of the length of "ms", but sometimes the same or near that) directly after the API call.
I have no clue what else to look for. There aren't any parallel processes, so I can't think of any side effects.

Anyone a clue?

Screenshot from test
[attachment=377:Bug - Deserialize.gif]

– SEE WORKAROUND IN POST 4 –

You can look at all the relevant code and maybe test it on system as well. Maybe it's a memory issue?! I don't know…
Useful code would be:


os.unloadAPI("move")
os.loadAPI("move")
move.serialize(move.deserialize(move.serialize({m="asd"})))
(the code is included in an API for turtle movement, so the file is called move atm)

This tests both methods (serializer should work fine!) and should output the readable serialized result.
In my last test case I skipped the last serialization as the error stops the code in the deserialization step anyways.
If you need more information to understand the code feel free to ask. I just don't want to explain everything in advance.
The test works fine with any other object (number, string, boolean) except tables.
Tables (with unlimited nesting, except empty tables) should work,
if the statement "p2 = ms:find("=",1,true);" results in a correct value for the position of the equal sign (others chars already tested!). Also tested "p2 = string.find(ms,"=",1,true);" as an alternative, but with same result!


Serializer - Function:
Spoiler

function serialize(obj)
local s = "";

if type(obj) == "string" then
  return "s"..":"..tostring(#obj)..":"..obj;
elseif type(obj) == "number" then
  s = tostring(obj);
  return "n"..":"..tostring(#s)..":"..s;
elseif type(obj) == "boolean" then
  s = tostring(obj);
  return "b"..":"..tostring(#s)..":"..s;
elseif type(obj) == "table" then
  if next(obj) == nil then
   error("serialize - cannot convert empty table");
  end;
  local k,v;
  for k,v in pairs(obj) do
	local m = k.."="..serialize(v);
	s = s..",m"..":"..tostring(#m)..":"..m;
  end;
  return "t"..":"..tostring(#s-1)..":"..s:sub(2);
else
  error("serialize - cannot convert function, thread or userdata to string");
end;
end;

Deserializer - Function
Spoiler

function deserialize(s)
local p, p2, p3;
local t,os,ms,mn,mos,obj;
local success;
local function dechunk(c,from)
  local p = from;
  local t,sz,os,p2;
  t = c:sub(p,p);
  p = p + 1;
  if c:sub(p,p) ~= ":" then return false; end;
  p = p + 1;
  p2 = c:find(":",p,true);
  if p2 == nil then return false; end;
  sz = tonumber(c:sub(p,p2-1));
  if sz == nil then return false; end;
  os = c:sub(p2+1,p2+sz);
  p = p2+sz;
  if p > #c then return false; end;
  p = p + 1
  return true,t,os,p;
end;
success, t, os = dechunk(s,1);
if not success then
  error("deserialize - unable to dechunk input string:"..s:sub(1,10).."...");
end;

if t == "s" then
  obj = os;
elseif t == "n" then
  obj = tonumber(os);
  if type(obj) ~= "number" then
   error("deserialize - not a valid number format:"..os);
  end;
elseif t == "b" then
  if #os ~= 4 and #os ~= 5 then
   error("deserialize - not a valid boolean format:"..os);
  end;
  obj = (os == "true");
elseif t == "t" then
  obj = {};
  os = ","..os;
  p = 1;
  repeat
   if os:sub(p,p) ~= "," then
	error("deserialize - comma-leaded member expected:"..os:sub(p,10).."...");
   end;
   p = p + 1;
   success, t, ms, p2 = dechunk(os,p);
   if not success or t ~= "m" then
	error("deserialize - unable to dechunk table member:"..os:sub(p,p+15).."...");
   end;
   p = p2;
   p2 = ms:find("=",1,true);
   if p2 == nil then
	error("deserialize - invalid member string:"..ms);
   end;
   mn = ms:sub(1,p2-1);
   mos = ms:sub(p2+1);
   term.write("ms="..ms..", p2="..p2..", mn="..mn..", mos="..mos);
   obj[mn] = deserialize(mos);  
  until p > #s;
else
  error("deserialize - unknown chunk type:"..t);
end;

return obj;
end;
Cranium #2
Posted 09 August 2012 - 06:42 PM
If you are using the lua prompt to test it, then you may want to just edit your mod folder… Easier, and works better. Otherwise, just ignore me. ;)/>/>
SilentPro #3
Posted 09 August 2012 - 06:47 PM
As with v1.41 the mod gets installed from the zip archive I haven't found any "computercraft"-folder to work in yet.
Atm I work within the home directory of a turtle. The test calls of my api functions are easily typed into the prompt or chosen from input history.
SilentPro #4
Posted 09 August 2012 - 07:54 PM
I found a workaround:

string.find works (more) reliably, when I wrap the string in some useless crap ;)/>/> like

p2 = (""..c..""):find(":",p,true);
p2, p3 = (""..ms..""):find("=",1,true);

Why this is, I don't know, but my functions do work as expected now.
I checked the type of ms to be a string and the syntax I used wouldn't allow to use the method on an wrong object.
Maybe someone can explain this? I might not even have found a bug in Lua?
Cloudy #5
Posted 09 August 2012 - 08:07 PM
It's a bug in LuaJ - but no matter. We are probably moving away from that in the next version.

FYI you only have to concactenate at the end.
Cranium #6
Posted 09 August 2012 - 08:22 PM
It's a bug in LuaJ - but no matter. We are probably moving away from that in the next version.

FYI you only have to concactenate at the end.
Wow, just released this version, and already looking to the next super awesome version! I love coding, can't wait!
SilentPro #7
Posted 10 August 2012 - 04:20 PM
@Cloudy: Thanks for the answer!! Great to know!

Someone should write that into the CC Wiki (here). It's not mentioned there yet.
Maybe I'll do it myself.