I've been working on lua machine json object system. But I've hit a snag with the json object merger(You can see the functions code used below). When I try to iterate through a table using a while loop and IterateTable function, and then ether call Next or a function containing Next it causes an infinite loop that leads to a stack overflow crash.
Loops through the map elements of a user data object
void UJsonMergetFunctionLibrary::MergeLuaJsonObject(UMyDynamicObject* Origional, UMyDynamicObject* ToMerge, bool Override)
{
//Get all user data object keys
for (TPair<FString, FLuaValue>& P: ToMerge->GetTableContent())
{
//Holds the value of current key
FLuaValue Hold;
if (Origional->hasField(P.Key))
{
if ((P.Value.Type == ELuaValueType::Table) || (P.Value.Type == ELuaValueType::UObject))
{
Hold = Origional->LuaGetField(P.Key);
MergeLuaJsonObject(Hold, P.Value, Override);
}
else if (Override)
{
Origional->LuaSetField(P.Key, P.Value);
}
}
else
{
Origional->LuaSetField(P.Key, P.Value);
}
}
}
Loops through the elements of ether a lua table or user data object
void UJsonMergetFunctionLibrary::MergeLuaJsonObject(FLuaValue& Origional, FLuaValue& ToMerge, bool Override)
{
if (Origional.Type != ToMerge.Type) {
if (Override)
{
Origional = ToMerge;
return;
}
else
{
return;
}
}
//Table
if ((Origional.Type == ELuaValueType::Table) || (ToMerge.Type == ELuaValueType::Table)) {
TPair<FLuaValue, FLuaValue> Pair;
int32 MaxDex = MaxTableIndex(Origional);
while (IterateTable(ToMerge, Pair)) {
if (Pair.Key.Type == ELuaValueType::Integer)
{
MaxDex += 1;
Origional.SetFieldByIndex(MaxDex, Pair.Value);
}
else if (HasTableField(Origional, Pair.Key.ToString()))
{
FLuaValue Hold = Origional.GetField(Pair.Key.ToString());
if ((Pair.Value.Type == ELuaValueType::Table) && (Hold.Type == ELuaValueType::Table))
{
//Hold = OrigionalObj->LuaGetField(P.Key);
MergeLuaJsonObject(Hold, Pair.Value, Override);
}
else if((Pair.Value.Type == ELuaValueType::UObject) && (Hold.Type == ELuaValueType::UObject))
{
MergeLuaJsonObject(Hold, Pair.Value, Override);
}
else if (Override) {
Origional.SetField(Pair.Key.ToString(), Pair.Value);
}
}
else
{
Origional.SetField(Pair.Key.ToString(), Pair.Value);
}
}
}
//Object
else if ((Origional.Type == ELuaValueType::UObject) || (ToMerge.Type == ELuaValueType::UObject)) {
UMyDynamicObject* ToMergeObj = Cast<UMyDynamicObject>(ULuaBlueprintFunctionLibrary::Conv_LuaValueToObject(ToMerge));
UMyDynamicObject* OrigionalObj = Cast<UMyDynamicObject>(ULuaBlueprintFunctionLibrary::Conv_LuaValueToObject(Origional));
TMap<FString, FLuaValue> Keys = ToMergeObj->GetTableContent();
for (TPair<FString, FLuaValue>& P: Keys)
{
FLuaValue Hold;
if (OrigionalObj->hasField(P.Key))
{
if ((P.Value.Type == ELuaValueType::Table) || (P.Value.Type == ELuaValueType::UObject))
{
Hold = OrigionalObj->LuaGetField(P.Key);
MergeLuaJsonObject(Hold, P.Value, Override);
}
else if (Override)
{
OrigionalObj->LuaSetField(P.Key, P.Value);
}
}
else
{
OrigionalObj->LuaSetField(P.Key, P.Value);
}
//OrigionalObj->LuaSetField(P.Key, P)
}
Origional = FLuaValue(OrigionalObj);
}
}
Iterates and retrieves the next key in a table
bool UJsonMergetFunctionLibrary::IterateTable(FLuaValue Table, TPair<FLuaValue, FLuaValue>& Pair)
{
if (Table.Type != ELuaValueType::Table)
return false;
ULuaState* L = Table.LuaState;
if (!L)
return false;
if (Pair.Key.IsNil())
{
L->FromLuaValue(Table);
L->PushNil(); // first key
}
if (L->Next(-2))
{
Pair.Key = L->ToLuaValue(-2);
Pair.Value = L->ToLuaValue(-1);
if (GEngine)
GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Yellow, Pair.Key.ToString());
L->Pop(); // pop the value
return true;
}
else
{
L->Pop(); // pop the table
return false;
}
}
Checks if the table contains a key
bool UJsonMergetFunctionLibrary::HasTableField(FLuaValue Table, FString FieldName)
{
if (Table.Type != ELuaValueType::Table)
return false;
ULuaState* L = Table.LuaState;
if (!L)
return false;
L->FromLuaValue(Table);
L->PushNil(); // first key
while (L->Next(-2))
{
FLuaValue Key = L->ToLuaValue(-2);
if (Key.ToString() == FieldName)
{
L->Pop(); // pop the value
L->Pop(); // pop the table
return true;
}
else {
L->Pop(); // pop the value
}
}
L->Pop(); // pop the table
return false;
}
1.I have tried poping both the value and the key when calling next within the loop, and than reassigning the old key once the internal next call ends. 2.I have tried googling it and Wasn't able to find anything. 3.I added a limit to how many times the loop can execute, to test if a infinite loops is causing the crash. 4.I tried making a function in pure lua that loops through a table and calls next within it(Didn't work, but do note I'm new to lua).
None of what I've tried has worked. What I want to happen is that when both Original and ToMerge have the same key, and the value assigned to that key is table I want it to perform recursion and merge those two tables than once thats done return to the execution on the original loop. Any help would be appreciated.