Skip to content

Commit

Permalink
Turn Map/Array assignments into Copy
Browse files Browse the repository at this point in the history
Better error checking for struct assignment

Lock assignments behind version, don't break or "fix" existing code using older ZScript versions
  • Loading branch information
RicardoLuis0 committed Oct 7, 2023
1 parent eea573a commit 7955c8c
Showing 1 changed file with 98 additions and 19 deletions.
117 changes: 98 additions & 19 deletions src/common/scripting/backend/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2454,36 +2454,115 @@ FxExpression *FxAssign::Resolve(FCompileContext &ctx)
SAFE_RESOLVE(Right, ctx);
}
}
else if (Base->ValueType == Right->ValueType)
else if (Right->IsNativeStruct() && Base->ValueType->isRealPointer() && Base->ValueType->toPointer()->PointedType == Right->ValueType)
{
// allow conversion of native structs to pointers of the same type. This is necessary to assign elements from global arrays like players, sectors, etc. to local pointers.
// For all other types this is not needed. Structs are not assignable and classes can only exist as references.
Right->RequestAddress(ctx, nullptr);
Right->ValueType = Base->ValueType;
}
else if ( Base->ValueType == Right->ValueType
|| (Base->ValueType->isRealPointer() && Base->ValueType->toPointer()->PointedType == Right->ValueType)
|| (Right->ValueType->isRealPointer() && Right->ValueType->toPointer()->PointedType == Base->ValueType)
)
{
if (Base->ValueType->isArray())
{
ScriptPosition.Message(MSG_ERROR, "Cannot assign arrays");
delete this;
return nullptr;
}
else if (Base->IsDynamicArray())
else if(!Base->IsVector() && !Base->IsQuaternion())
{
ScriptPosition.Message(MSG_ERROR, "Cannot assign dynamic arrays, use Copy() or Move() function instead");
delete this;
return nullptr;
}
if (!Base->IsVector() && !Base->IsQuaternion() && Base->ValueType->isStruct())
{
ScriptPosition.Message(MSG_ERROR, "Struct assignment not implemented yet");
delete this;
return nullptr;
PType * btype = Base->ValueType;

if(btype->isRealPointer())
{
PType * p = static_cast<PPointer *>(btype)->PointedType;
if( p->isDynArray() || p->isMap()
|| (p->isStruct() && !static_cast<PStruct*>(p)->isNative)
)
{ //un-pointer dynarrays, maps and non-native structs for assignment checking
btype = p;
}
}

if (btype->isDynArray())
{
if(ctx.Version >= MakeVersion(4, 11, 0))
{
FArgumentList args;
args.Push(Right);
auto call = new FxMemberFunctionCall(Base, NAME_Copy, args, ScriptPosition);
Right = Base = nullptr;
delete this;
return call->Resolve(ctx);
}
else
{
if(Base->ValueType->isRealPointer() && Right->ValueType->isRealPointer())
{
ScriptPosition.Message(MSG_WARNING, "Dynamic Array assignments not allowed in ZScript versions below 4.11, use the Copy() or Move() functions instead\n"
TEXTCOLOR_RED "!! Assigning an out array pointer to another out array pointer does not alter either of the underlying arrays' values below ZScript version 4.11 !!");
}
else
{
ScriptPosition.Message(MSG_ERROR, "Dynamic Array assignments not allowed in ZScript versions below 4.11, use the Copy() or Move() functions instead");
delete this;
return nullptr;
}
}
}
else if (btype->isMap())
{
if(ctx.Version >= MakeVersion(4, 11, 0))
{
FArgumentList args;
args.Push(Right);
auto call = new FxMemberFunctionCall(Base, NAME_Copy, args, ScriptPosition);
Right = Base = nullptr;
delete this;
return call->Resolve(ctx);
}
else
{
if(Base->ValueType->isRealPointer() && Right->ValueType->isRealPointer())
{ // don't break existing code, but warn that it's a no-op
ScriptPosition.Message(MSG_WARNING, "Map assignments not allowed in ZScript versions below 4.11, use the Copy() or Move() functions instead\n"
TEXTCOLOR_RED "!! Assigning an out map pointer to another out map pointer does not alter either of the underlying maps' values below ZScript version 4.11 !!");
}
else
{
ScriptPosition.Message(MSG_ERROR, "Map assignments not allowed in ZScript versions below 4.11, use the Copy() or Move() functions instead");
delete this;
return nullptr;
}
}
}
else if (btype->isMapIterator())
{
ScriptPosition.Message(MSG_ERROR, "Cannot assign map iterators");
delete this;
return nullptr;
}
else if (btype->isStruct())
{
if(Base->ValueType->isRealPointer() && Right->ValueType->isRealPointer())
{ // don't break existing code, but warn that it's a no-op
ScriptPosition.Message(MSG_WARNING, "Struct assignment not implemented yet\n"
TEXTCOLOR_RED "!! Assigning an out struct pointer to another out struct pointer does not alter either of the underlying structs' values !!");
}
else
{
ScriptPosition.Message(MSG_ERROR, "Struct assignment not implemented yet");
delete this;
return nullptr;
}
}
}

// Both types are the same so this is ok.
}
else if (Right->IsNativeStruct() && Base->ValueType->isRealPointer() && Base->ValueType->toPointer()->PointedType == Right->ValueType)
{
// allow conversion of native structs to pointers of the same type. This is necessary to assign elements from global arrays like players, sectors, etc. to local pointers.
// For all other types this is not needed. Structs are not assignable and classes can only exist as references.
bool writable;
Right->RequestAddress(ctx, &writable);
Right->ValueType = Base->ValueType;
}
else
{
// pass it to FxTypeCast for complete handling.
Expand Down

0 comments on commit 7955c8c

Please sign in to comment.