| 3 | // *********************************************************************** |
| 4 | |
| 5 | void SerializeTextRecursive(lua_State* L, StringBuilder& builder, bool isMetadata = false) { |
| 6 | // TODO: |
| 7 | // Need to error if we encounter a cyclic table reference |
| 8 | |
| 9 | if (lua_istable(L, -1)) { |
| 10 | if (isMetadata) { |
| 11 | builder.Append("--[[poly,"); |
| 12 | } |
| 13 | else { |
| 14 | builder.Append("{"); |
| 15 | } |
| 16 | lua_pushnil(L); |
| 17 | i32 arrayCounter = 0; // we'll set this to -1 if the sequence of indices breaks and we're in the hash part of the table |
| 18 | while (lua_next(L, -2)) { |
| 19 | lua_pushvalue(L, -2); |
| 20 | |
| 21 | // first decide if we're dealing with an array element or not |
| 22 | if (arrayCounter >= 0 && lua_isnumber(L, -1)) { |
| 23 | f32 key = (f32)lua_tonumber(L, -1); |
| 24 | if (key != (i32)key || (i32)key != ++arrayCounter) { |
| 25 | arrayCounter = -1; |
| 26 | } |
| 27 | } else { |
| 28 | arrayCounter = -1; |
| 29 | } |
| 30 | |
| 31 | // array element |
| 32 | if (arrayCounter > 0) { |
| 33 | lua_pop(L, 1); // pop key copy |
| 34 | SerializeTextRecursive(L, builder); |
| 35 | } |
| 36 | // dictionary element |
| 37 | else { |
| 38 | const char *key = lua_tostring(L, -1); |
| 39 | if (lua_isnumber(L, -1)) { |
| 40 | f32 key = (f32)lua_tonumber(L, -1); |
| 41 | if (key == (i32)key) { |
| 42 | builder.AppendFormat("[%i]=", (i32)key); |
| 43 | } |
| 44 | else { |
| 45 | builder.AppendFormat("[%.17g]=", key); |
| 46 | } |
| 47 | } |
| 48 | else { |
| 49 | const char *key = lua_tostring(L, -1); |
| 50 | // if this string has an equal character in it, we must escape it |
| 51 | bool needsEscape = false; |
| 52 | char* c = (char*)key; |
| 53 | while (*c != 0) { |
| 54 | if (*c == '=' || *c == '.') |
| 55 | needsEscape = true; |
| 56 | c++; |
| 57 | } |
| 58 | if (needsEscape) |
| 59 | builder.AppendFormat("[\"%s\"]=", key); |
| 60 | else |
| 61 | builder.AppendFormat("%s=", key); |
| 62 | } |