Map<K,V> and MapIterator<K,V> for ZScript
This commit is contained in:
parent
1e5e65546d
commit
8b6a714d41
23 changed files with 2354 additions and 28 deletions
|
|
@ -8205,6 +8205,8 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
|
|||
|
||||
PContainerType *ccls = nullptr;
|
||||
|
||||
PFunction * afd_override = nullptr;
|
||||
|
||||
if (ctx.Class == nullptr)
|
||||
{
|
||||
// There's no way that a member function call can resolve to a constant so abort right away.
|
||||
|
|
@ -8278,7 +8280,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
|
|||
if (Self->ValueType->isRealPointer())
|
||||
{
|
||||
auto pointedType = Self->ValueType->toPointer()->PointedType;
|
||||
if (pointedType && pointedType->isDynArray())
|
||||
if (pointedType && (pointedType->isDynArray() || pointedType->isMap() || pointedType->isMapIterator()))
|
||||
{
|
||||
Self = new FxOutVarDereference(Self, Self->ScriptPosition);
|
||||
SAFE_RESOLVE(Self, ctx);
|
||||
|
|
@ -8454,7 +8456,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
|
|||
if (a->ValueType->isRealPointer())
|
||||
{
|
||||
auto pointedType = a->ValueType->toPointer()->PointedType;
|
||||
if (pointedType && pointedType->isDynArray())
|
||||
if (pointedType && (pointedType->isDynArray() || pointedType->isMap() || pointedType->isMapIterator()))
|
||||
{
|
||||
a = new FxOutVarDereference(a, a->ScriptPosition);
|
||||
SAFE_RESOLVE(a, ctx);
|
||||
|
|
@ -8561,6 +8563,193 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
|
|||
}
|
||||
}
|
||||
}
|
||||
else if(Self->IsMap())
|
||||
{
|
||||
PMap * m = static_cast<PMap*>(Self->ValueType);
|
||||
Self->ValueType = m->BackingType;
|
||||
|
||||
auto mapKeyType = m->KeyType;
|
||||
auto mapValueType = m->ValueType;
|
||||
|
||||
bool isObjMap = mapValueType->isObjectPointer();
|
||||
|
||||
if (PFunction **Override; (Override = m->FnOverrides.CheckKey(MethodName)))
|
||||
{
|
||||
afd_override = *Override;
|
||||
}
|
||||
|
||||
// Adapted from DynArray codegen
|
||||
|
||||
int idx = 0;
|
||||
for (auto &a : ArgList)
|
||||
{
|
||||
a = a->Resolve(ctx);
|
||||
if (a == nullptr)
|
||||
{
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
if (a->ValueType->isRealPointer())
|
||||
{
|
||||
auto pointedType = a->ValueType->toPointer()->PointedType;
|
||||
if (pointedType && (pointedType->isDynArray() || pointedType->isMap() || pointedType->isMapIterator()))
|
||||
{
|
||||
a = new FxOutVarDereference(a, a->ScriptPosition);
|
||||
SAFE_RESOLVE(a, ctx);
|
||||
}
|
||||
}
|
||||
if (isObjMap && (MethodName == NAME_Insert && idx == 1))
|
||||
{
|
||||
// Null pointers are always valid.
|
||||
if (!a->isConstant() || static_cast<FxConstant*>(a)->GetValue().GetPointer() != nullptr)
|
||||
{
|
||||
if (!a->ValueType->isObjectPointer() ||
|
||||
!static_cast<PObjectPointer*>(mapValueType)->PointedClass()->IsAncestorOf(static_cast<PObjectPointer*>(a->ValueType)->PointedClass()))
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "Type mismatch in function argument");
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (a->IsMap())
|
||||
{
|
||||
// Copy and Move must turn their parameter into a pointer to the backing struct type.
|
||||
auto o = static_cast<PMap*>(a->ValueType);
|
||||
auto backingtype = o->BackingType;
|
||||
if (mapKeyType != o->KeyType || mapValueType != o->ValueType)
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "Type mismatch in function argument");
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
bool writable;
|
||||
if (!a->RequestAddress(ctx, &writable))
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "Unable to dereference map variable");
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
a->ValueType = NewPointer(backingtype);
|
||||
|
||||
// Also change the field's type so the code generator can work with this (actually this requires swapping out the entire field.)
|
||||
if (Self->ExprType == EFX_StructMember || Self->ExprType == EFX_ClassMember || Self->ExprType == EFX_StackVariable)
|
||||
{
|
||||
auto member = static_cast<FxMemberBase*>(Self);
|
||||
auto newfield = Create<PField>(NAME_None, backingtype, 0, member->membervar->Offset);
|
||||
member->membervar = newfield;
|
||||
}
|
||||
}
|
||||
else if (a->IsPointer() && Self->ValueType->isPointer())
|
||||
{
|
||||
// the only case which must be checked up front is for pointer arrays receiving a new element.
|
||||
// Since there is only one native backing class it uses a neutral void pointer as its argument,
|
||||
// meaning that FxMemberFunctionCall is unable to do a proper check. So we have to do it here.
|
||||
if (a->ValueType != mapValueType)
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "Type mismatch in function argument. Got %s, expected %s", a->ValueType->DescriptiveName(), mapValueType->DescriptiveName());
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
idx++;
|
||||
|
||||
}
|
||||
}
|
||||
else if(Self->IsMapIterator())
|
||||
{
|
||||
PMapIterator * mi = static_cast<PMapIterator*>(Self->ValueType);
|
||||
Self->ValueType = mi->BackingType;
|
||||
|
||||
auto mapKeyType = mi->KeyType;
|
||||
auto mapValueType = mi->ValueType;
|
||||
|
||||
bool isObjMap = mapValueType->isObjectPointer();
|
||||
|
||||
if (PFunction **Override; (Override = mi->FnOverrides.CheckKey(MethodName)))
|
||||
{
|
||||
afd_override = *Override;
|
||||
}
|
||||
|
||||
// Adapted from DynArray codegen
|
||||
|
||||
int idx = 0;
|
||||
for (auto &a : ArgList)
|
||||
{
|
||||
a = a->Resolve(ctx);
|
||||
if (a == nullptr)
|
||||
{
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
if (a->ValueType->isRealPointer())
|
||||
{
|
||||
auto pointedType = a->ValueType->toPointer()->PointedType;
|
||||
if (pointedType && (pointedType->isDynArray() || pointedType->isMap() || pointedType->isMapIterator()))
|
||||
{
|
||||
a = new FxOutVarDereference(a, a->ScriptPosition);
|
||||
SAFE_RESOLVE(a, ctx);
|
||||
}
|
||||
}
|
||||
if (isObjMap && (MethodName == NAME_SetValue && idx == 0))
|
||||
{
|
||||
// Null pointers are always valid.
|
||||
if (!a->isConstant() || static_cast<FxConstant*>(a)->GetValue().GetPointer() != nullptr)
|
||||
{
|
||||
if (!a->ValueType->isObjectPointer() ||
|
||||
!static_cast<PObjectPointer*>(mapValueType)->PointedClass()->IsAncestorOf(static_cast<PObjectPointer*>(a->ValueType)->PointedClass()))
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "Type mismatch in function argument");
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (a->IsMap())
|
||||
{
|
||||
// Copy and Move must turn their parameter into a pointer to the backing struct type.
|
||||
auto o = static_cast<PMapIterator*>(a->ValueType);
|
||||
auto backingtype = o->BackingType;
|
||||
if (mapKeyType != o->KeyType || mapValueType != o->ValueType)
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "Type mismatch in function argument");
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
bool writable;
|
||||
if (!a->RequestAddress(ctx, &writable))
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "Unable to dereference map variable");
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
a->ValueType = NewPointer(backingtype);
|
||||
|
||||
// Also change the field's type so the code generator can work with this (actually this requires swapping out the entire field.)
|
||||
if (Self->ExprType == EFX_StructMember || Self->ExprType == EFX_ClassMember || Self->ExprType == EFX_StackVariable)
|
||||
{
|
||||
auto member = static_cast<FxMemberBase*>(Self);
|
||||
auto newfield = Create<PField>(NAME_None, backingtype, 0, member->membervar->Offset);
|
||||
member->membervar = newfield;
|
||||
}
|
||||
}
|
||||
else if (a->IsPointer() && Self->ValueType->isPointer())
|
||||
{
|
||||
// the only case which must be checked up front is for pointer arrays receiving a new element.
|
||||
// Since there is only one native backing class it uses a neutral void pointer as its argument,
|
||||
// meaning that FxMemberFunctionCall is unable to do a proper check. So we have to do it here.
|
||||
if (a->ValueType != mapValueType)
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "Type mismatch in function argument. Got %s, expected %s", a->ValueType->DescriptiveName(), mapValueType->DescriptiveName());
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (MethodName == NAME_GetParentClass &&
|
||||
|
|
@ -8635,7 +8824,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
|
|||
|
||||
isresolved:
|
||||
bool error = false;
|
||||
PFunction *afd = FindClassMemberFunction(cls, ctx.Class, MethodName, ScriptPosition, &error, ctx.Version, !ctx.FromDecorate);
|
||||
PFunction *afd = afd_override ? afd_override : FindClassMemberFunction(cls, ctx.Class, MethodName, ScriptPosition, &error, ctx.Version, !ctx.FromDecorate);
|
||||
if (error)
|
||||
{
|
||||
delete this;
|
||||
|
|
@ -9034,7 +9223,7 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx)
|
|||
if (ArgList[i] && ArgList[i]->ValueType->isRealPointer())
|
||||
{
|
||||
auto pointedType = ArgList[i]->ValueType->toPointer()->PointedType;
|
||||
if (pointedType && pointedType->isDynArray())
|
||||
if (pointedType && (pointedType->isDynArray() || pointedType->isMap() || pointedType->isMapIterator()))
|
||||
{
|
||||
ArgList[i] = new FxOutVarDereference(ArgList[i], ArgList[i]->ScriptPosition);
|
||||
SAFE_RESOLVE(ArgList[i], ctx);
|
||||
|
|
@ -11806,7 +11995,7 @@ FxExpression *FxOutVarDereference::Resolve(FCompileContext &ctx)
|
|||
SelfType = Self->ValueType->toPointer()->PointedType;
|
||||
ValueType = SelfType;
|
||||
|
||||
if (SelfType->GetRegType() == REGT_NIL && !SelfType->isRealPointer() && !SelfType->isDynArray())
|
||||
if (SelfType->GetRegType() == REGT_NIL && !SelfType->isRealPointer() && !SelfType->isDynArray() && !SelfType->isMap() && !SelfType->isMapIterator())
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "Cannot dereference pointer");
|
||||
delete this;
|
||||
|
|
@ -11835,7 +12024,7 @@ ExpEmit FxOutVarDereference::Emit(VMFunctionBuilder *build)
|
|||
regType = REGT_POINTER;
|
||||
loadOp = OP_LP;
|
||||
}
|
||||
else if (SelfType->isDynArray())
|
||||
else if (SelfType->isDynArray() || SelfType->isMap() || SelfType->isMapIterator())
|
||||
{
|
||||
regType = REGT_POINTER;
|
||||
loadOp = OP_MOVEA;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue