mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-13 07:57:52 +00:00
- first stage of simplifying the type system.
Let's use inline checkers in PType instead of constantly having to do clumsy IsKindOf checks etc. Once complete this also means that the types can be taken out of the class hierarchy, freeing up some common names.
This commit is contained in:
parent
522ce59be2
commit
b2d944974e
16 changed files with 153 additions and 138 deletions
|
@ -205,7 +205,6 @@ void PClass::StaticInit ()
|
||||||
{
|
{
|
||||||
atterm (StaticShutdown);
|
atterm (StaticShutdown);
|
||||||
|
|
||||||
StaticBootstrap();
|
|
||||||
Namespaces.GlobalNamespace = Namespaces.NewNamespace(0);
|
Namespaces.GlobalNamespace = Namespaces.NewNamespace(0);
|
||||||
|
|
||||||
FAutoSegIterator probe(CRegHead, CRegTail);
|
FAutoSegIterator probe(CRegHead, CRegTail);
|
||||||
|
@ -265,6 +264,7 @@ void PClass::StaticShutdown ()
|
||||||
ClassDataAllocator.FreeAllBlocks();
|
ClassDataAllocator.FreeAllBlocks();
|
||||||
AllClasses.Clear();
|
AllClasses.Clear();
|
||||||
PClassActor::AllActorClasses.Clear();
|
PClassActor::AllActorClasses.Clear();
|
||||||
|
ClassMap.Clear();
|
||||||
|
|
||||||
FAutoSegIterator probe(CRegHead, CRegTail);
|
FAutoSegIterator probe(CRegHead, CRegTail);
|
||||||
|
|
||||||
|
@ -276,16 +276,6 @@ void PClass::StaticShutdown ()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// PClass :: StaticBootstrap STATIC
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
void PClass::StaticBootstrap()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// PClass Constructor
|
// PClass Constructor
|
||||||
|
@ -363,7 +353,6 @@ void ClassReg::SetupClass(PClass *cls)
|
||||||
cls->Size = SizeOf;
|
cls->Size = SizeOf;
|
||||||
cls->Pointers = Pointers;
|
cls->Pointers = Pointers;
|
||||||
cls->ConstructNative = ConstructNative;
|
cls->ConstructNative = ConstructNative;
|
||||||
//cls->mDescriptiveName.Format("Class<%s>", cls->TypeName.GetChars());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
|
@ -52,7 +52,6 @@ public:
|
||||||
|
|
||||||
static void StaticInit();
|
static void StaticInit();
|
||||||
static void StaticShutdown();
|
static void StaticShutdown();
|
||||||
static void StaticBootstrap();
|
|
||||||
|
|
||||||
// Per-class information -------------------------------------
|
// Per-class information -------------------------------------
|
||||||
PClass *ParentClass = nullptr; // the class this class derives from
|
PClass *ParentClass = nullptr; // the class this class derives from
|
||||||
|
|
|
@ -75,12 +75,12 @@ cycle_t ActionCycles;
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
class PActorInfo : public PBasicType
|
class PActorInfo : public PCompoundType
|
||||||
{
|
{
|
||||||
DECLARE_CLASS(PActorInfo, PBasicType);
|
DECLARE_CLASS(PActorInfo, PCompoundType);
|
||||||
public:
|
public:
|
||||||
PActorInfo()
|
PActorInfo()
|
||||||
:PBasicType(sizeof(FActorInfo), alignof(FActorInfo))
|
:PCompoundType(sizeof(FActorInfo), alignof(FActorInfo))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -424,7 +424,7 @@ static void ParseListMenuBody(FScanner &sc, DListMenuDescriptor *desc)
|
||||||
}
|
}
|
||||||
params.Push(f.GetIndex());
|
params.Push(f.GetIndex());
|
||||||
}
|
}
|
||||||
else if (args[i]->IsKindOf(RUNTIME_CLASS(PInt)))
|
else if (args[i]->isIntCompatible())
|
||||||
{
|
{
|
||||||
char *endp;
|
char *endp;
|
||||||
int v = (int)strtoll(sc.String, &endp, 0);
|
int v = (int)strtoll(sc.String, &endp, 0);
|
||||||
|
@ -441,7 +441,7 @@ static void ParseListMenuBody(FScanner &sc, DListMenuDescriptor *desc)
|
||||||
if (args[i] == TypeBool) v = !!v;
|
if (args[i] == TypeBool) v = !!v;
|
||||||
params.Push(v);
|
params.Push(v);
|
||||||
}
|
}
|
||||||
else if (args[i]->IsKindOf(RUNTIME_CLASS(PFloat)))
|
else if (args[i]->isFloat())
|
||||||
{
|
{
|
||||||
char *endp;
|
char *endp;
|
||||||
double v = strtod(sc.String, &endp);
|
double v = strtod(sc.String, &endp);
|
||||||
|
@ -775,7 +775,7 @@ static void ParseOptionMenuBody(FScanner &sc, DOptionMenuDescriptor *desc)
|
||||||
{
|
{
|
||||||
params.Push(V_GetColor(nullptr, sc));
|
params.Push(V_GetColor(nullptr, sc));
|
||||||
}
|
}
|
||||||
else if (args[i]->IsKindOf(RUNTIME_CLASS(PInt)))
|
else if (args[i]->isIntCompatible())
|
||||||
{
|
{
|
||||||
char *endp;
|
char *endp;
|
||||||
int v = (int)strtoll(sc.String, &endp, 0);
|
int v = (int)strtoll(sc.String, &endp, 0);
|
||||||
|
@ -794,7 +794,7 @@ static void ParseOptionMenuBody(FScanner &sc, DOptionMenuDescriptor *desc)
|
||||||
if (args[i] == TypeBool) v = !!v;
|
if (args[i] == TypeBool) v = !!v;
|
||||||
params.Push(v);
|
params.Push(v);
|
||||||
}
|
}
|
||||||
else if (args[i]->IsKindOf(RUNTIME_CLASS(PFloat)))
|
else if (args[i]->isFloat())
|
||||||
{
|
{
|
||||||
char *endp;
|
char *endp;
|
||||||
double v = strtod(sc.String, &endp);
|
double v = strtod(sc.String, &endp);
|
||||||
|
|
|
@ -5040,12 +5040,11 @@ bool GetVarAddrType(AActor *self, FName varname, int index, void *&addr, PType *
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
addr = baddr;
|
addr = baddr;
|
||||||
// We don't want Int subclasses like Name or Color to be accessible,
|
// We don't want Int subclasses like Name or Color to be accessible here.
|
||||||
// but we do want to support Float subclasses like Fixed.
|
if (!type->isInt() && !type->isFloat())
|
||||||
if (!type->IsA(RUNTIME_CLASS(PInt)) && !type->IsKindOf(RUNTIME_CLASS(PFloat)))
|
|
||||||
{
|
{
|
||||||
// For reading, we also support Name and String types.
|
// For reading, we also support Name and String types.
|
||||||
if (readonly && (type->IsA(RUNTIME_CLASS(PName)) || type->IsA(RUNTIME_CLASS(PString))))
|
if (readonly && (type == TypeName || type == TypeString))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -5061,7 +5060,7 @@ static void SetUserVariable(AActor *self, FName varname, int index, int value)
|
||||||
|
|
||||||
if (GetVarAddrType(self, varname, index, addr, type, false))
|
if (GetVarAddrType(self, varname, index, addr, type, false))
|
||||||
{
|
{
|
||||||
if (!type->IsKindOf(RUNTIME_CLASS(PFloat)))
|
if (!type->isFloat())
|
||||||
{
|
{
|
||||||
type->SetValue(addr, value);
|
type->SetValue(addr, value);
|
||||||
}
|
}
|
||||||
|
@ -5079,15 +5078,15 @@ static int GetUserVariable(AActor *self, FName varname, int index)
|
||||||
|
|
||||||
if (GetVarAddrType(self, varname, index, addr, type, true))
|
if (GetVarAddrType(self, varname, index, addr, type, true))
|
||||||
{
|
{
|
||||||
if (type->IsKindOf(RUNTIME_CLASS(PFloat)))
|
if (type->isFloat())
|
||||||
{
|
{
|
||||||
return DoubleToACS(type->GetValueFloat(addr));
|
return DoubleToACS(type->GetValueFloat(addr));
|
||||||
}
|
}
|
||||||
else if (type->IsA(RUNTIME_CLASS(PName)))
|
else if (type == TypeName)
|
||||||
{
|
{
|
||||||
return GlobalACSStrings.AddString(FName(ENamedName(type->GetValueInt(addr))).GetChars());
|
return GlobalACSStrings.AddString(FName(ENamedName(type->GetValueInt(addr))).GetChars());
|
||||||
}
|
}
|
||||||
else if (type->IsA(RUNTIME_CLASS(PString)))
|
else if (type == TypeString)
|
||||||
{
|
{
|
||||||
return GlobalACSStrings.AddString(*(FString *)addr);
|
return GlobalACSStrings.AddString(*(FString *)addr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4753,7 +4753,7 @@ static PField *GetVar(DObject *self, FName varname)
|
||||||
{
|
{
|
||||||
PField *var = dyn_cast<PField>(self->GetClass()->FindSymbol(varname, true));
|
PField *var = dyn_cast<PField>(self->GetClass()->FindSymbol(varname, true));
|
||||||
|
|
||||||
if (var == NULL || (var->Flags & (VARF_Native | VARF_Private | VARF_Protected | VARF_Static)) || !var->Type->IsKindOf(RUNTIME_CLASS(PBasicType)))
|
if (var == NULL || (var->Flags & (VARF_Native | VARF_Private | VARF_Protected | VARF_Static)) || !var->Type->isScalar())
|
||||||
{
|
{
|
||||||
Printf("%s is not a user variable in class %s\n", varname.GetChars(),
|
Printf("%s is not a user variable in class %s\n", varname.GetChars(),
|
||||||
self->GetClass()->TypeName.GetChars());
|
self->GetClass()->TypeName.GetChars());
|
||||||
|
@ -4803,8 +4803,7 @@ static PField *GetArrayVar(DObject *self, FName varname, int pos)
|
||||||
PField *var = dyn_cast<PField>(self->GetClass()->FindSymbol(varname, true));
|
PField *var = dyn_cast<PField>(self->GetClass()->FindSymbol(varname, true));
|
||||||
|
|
||||||
if (var == NULL || (var->Flags & (VARF_Native | VARF_Private | VARF_Protected | VARF_Static)) ||
|
if (var == NULL || (var->Flags & (VARF_Native | VARF_Private | VARF_Protected | VARF_Static)) ||
|
||||||
!var->Type->IsKindOf(RUNTIME_CLASS(PArray)) ||
|
!var->Type->IsKindOf(RUNTIME_CLASS(PArray)) || !static_cast<PArray *>(var->Type)->ElementType->isScalar())
|
||||||
!static_cast<PArray *>(var->Type)->ElementType->IsKindOf(RUNTIME_CLASS(PBasicType)))
|
|
||||||
{
|
{
|
||||||
Printf("%s is not a user array in class %s\n", varname.GetChars(),
|
Printf("%s is not a user array in class %s\n", varname.GetChars(),
|
||||||
self->GetClass()->TypeName.GetChars());
|
self->GetClass()->TypeName.GetChars());
|
||||||
|
|
|
@ -1621,7 +1621,7 @@ static void SetMapThingUserData(AActor *actor, unsigned udi)
|
||||||
|
|
||||||
udi++;
|
udi++;
|
||||||
|
|
||||||
if (var == NULL || (var->Flags & (VARF_Native|VARF_Private|VARF_Protected|VARF_Static)) || !var->Type->IsKindOf(RUNTIME_CLASS(PBasicType)))
|
if (var == NULL || (var->Flags & (VARF_Native|VARF_Private|VARF_Protected|VARF_Static)) || !var->Type->isScalar())
|
||||||
{
|
{
|
||||||
DPrintf(DMSG_WARNING, "%s is not a user variable in class %s\n", varname.GetChars(),
|
DPrintf(DMSG_WARNING, "%s is not a user variable in class %s\n", varname.GetChars(),
|
||||||
actor->GetClass()->TypeName.GetChars());
|
actor->GetClass()->TypeName.GetChars());
|
||||||
|
|
|
@ -207,7 +207,7 @@ static PContainerType *FindContainerType(FName name, FCompileContext &ctx)
|
||||||
if (sym && sym->IsKindOf(RUNTIME_CLASS(PSymbolType)))
|
if (sym && sym->IsKindOf(RUNTIME_CLASS(PSymbolType)))
|
||||||
{
|
{
|
||||||
auto type = static_cast<PSymbolType*>(sym);
|
auto type = static_cast<PSymbolType*>(sym);
|
||||||
return dyn_cast<PContainerType>(type->Type);
|
return type->Type->toContainer();
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -292,10 +292,10 @@ static PSymbol *FindBuiltinFunction(FName funcname, VMNativeFunction::NativeCall
|
||||||
|
|
||||||
static bool AreCompatiblePointerTypes(PType *dest, PType *source, bool forcompare = false)
|
static bool AreCompatiblePointerTypes(PType *dest, PType *source, bool forcompare = false)
|
||||||
{
|
{
|
||||||
if (dest->IsKindOf(RUNTIME_CLASS(PPointer)) && source->IsKindOf(RUNTIME_CLASS(PPointer)))
|
if (dest->isPointer() && source->isPointer())
|
||||||
{
|
{
|
||||||
auto fromtype = static_cast<PPointer *>(source);
|
auto fromtype = source->toPointer();
|
||||||
auto totype = static_cast<PPointer *>(dest);
|
auto totype = dest->toPointer();
|
||||||
// null pointers can be assigned to everything, everything can be assigned to void pointers.
|
// null pointers can be assigned to everything, everything can be assigned to void pointers.
|
||||||
if (fromtype == nullptr || totype == TypeVoidPtr) return true;
|
if (fromtype == nullptr || totype == TypeVoidPtr) return true;
|
||||||
// when comparing const-ness does not matter.
|
// when comparing const-ness does not matter.
|
||||||
|
@ -557,11 +557,11 @@ FxExpression *FxConstant::MakeConstant(PSymbol *sym, const FScriptPosition &pos)
|
||||||
PSymbolConstNumeric *csym = dyn_cast<PSymbolConstNumeric>(sym);
|
PSymbolConstNumeric *csym = dyn_cast<PSymbolConstNumeric>(sym);
|
||||||
if (csym != nullptr)
|
if (csym != nullptr)
|
||||||
{
|
{
|
||||||
if (csym->ValueType->IsA(RUNTIME_CLASS(PInt)))
|
if (csym->ValueType->isInt())
|
||||||
{
|
{
|
||||||
x = new FxConstant(csym->Value, pos);
|
x = new FxConstant(csym->Value, pos);
|
||||||
}
|
}
|
||||||
else if (csym->ValueType->IsA(RUNTIME_CLASS(PFloat)))
|
else if (csym->ValueType->isFloat())
|
||||||
{
|
{
|
||||||
x = new FxConstant(csym->Float, pos);
|
x = new FxConstant(csym->Float, pos);
|
||||||
}
|
}
|
||||||
|
@ -1356,7 +1356,7 @@ FxExpression *FxColorCast::Resolve(FCompileContext &ctx)
|
||||||
CHECKRESOLVED();
|
CHECKRESOLVED();
|
||||||
SAFE_RESOLVE(basex, ctx);
|
SAFE_RESOLVE(basex, ctx);
|
||||||
|
|
||||||
if (basex->ValueType == TypeColor || basex->ValueType->GetClass() == RUNTIME_CLASS(PInt))
|
if (basex->ValueType == TypeColor || basex->ValueType->isInt())
|
||||||
{
|
{
|
||||||
FxExpression *x = basex;
|
FxExpression *x = basex;
|
||||||
x->ValueType = TypeColor;
|
x->ValueType = TypeColor;
|
||||||
|
@ -1445,7 +1445,7 @@ FxExpression *FxSoundCast::Resolve(FCompileContext &ctx)
|
||||||
CHECKRESOLVED();
|
CHECKRESOLVED();
|
||||||
SAFE_RESOLVE(basex, ctx);
|
SAFE_RESOLVE(basex, ctx);
|
||||||
|
|
||||||
if (basex->ValueType == TypeSound || basex->ValueType->GetClass() == RUNTIME_CLASS(PInt))
|
if (basex->ValueType == TypeSound || basex->ValueType->isInt())
|
||||||
{
|
{
|
||||||
FxExpression *x = basex;
|
FxExpression *x = basex;
|
||||||
x->ValueType = TypeSound;
|
x->ValueType = TypeSound;
|
||||||
|
@ -1617,7 +1617,7 @@ FxExpression *FxTypeCast::Resolve(FCompileContext &ctx)
|
||||||
// don't go through the entire list if the types are the same.
|
// don't go through the entire list if the types are the same.
|
||||||
goto basereturn;
|
goto basereturn;
|
||||||
}
|
}
|
||||||
else if (basex->ValueType == TypeNullPtr && (ValueType == TypeState || ValueType->IsKindOf(RUNTIME_CLASS(PPointer))))
|
else if (basex->ValueType == TypeNullPtr && ValueType->isPointer())
|
||||||
{
|
{
|
||||||
goto basereturn;
|
goto basereturn;
|
||||||
}
|
}
|
||||||
|
@ -1629,7 +1629,7 @@ FxExpression *FxTypeCast::Resolve(FCompileContext &ctx)
|
||||||
delete this;
|
delete this;
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
else if (ValueType->IsA(RUNTIME_CLASS(PInt)))
|
else if (ValueType->isInt())
|
||||||
{
|
{
|
||||||
// This is only for casting to actual ints. Subtypes representing an int will be handled elsewhere.
|
// This is only for casting to actual ints. Subtypes representing an int will be handled elsewhere.
|
||||||
FxExpression *x = new FxIntCast(basex, NoWarn, Explicit);
|
FxExpression *x = new FxIntCast(basex, NoWarn, Explicit);
|
||||||
|
@ -1773,7 +1773,7 @@ FxExpression *FxTypeCast::Resolve(FCompileContext &ctx)
|
||||||
if (fromtype->IsDescendantOf(totype)) goto basereturn;
|
if (fromtype->IsDescendantOf(totype)) goto basereturn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (basex->IsNativeStruct() && ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast<PPointer*>(ValueType)->PointedType == basex->ValueType)
|
else if (basex->IsNativeStruct() && ValueType->isRealPointer() && ValueType->toPointer()->PointedType == basex->ValueType)
|
||||||
{
|
{
|
||||||
bool writable;
|
bool writable;
|
||||||
basex->RequestAddress(ctx, &writable);
|
basex->RequestAddress(ctx, &writable);
|
||||||
|
@ -2494,7 +2494,7 @@ FxExpression *FxAssign::Resolve(FCompileContext &ctx)
|
||||||
}
|
}
|
||||||
// Both types are the same so this is ok.
|
// Both types are the same so this is ok.
|
||||||
}
|
}
|
||||||
else if (Right->IsNativeStruct() && Base->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast<PPointer*>(Base->ValueType)->PointedType == 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.
|
// 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.
|
// For all other types this is not needed. Structs are not assignable and classes can only exist as references.
|
||||||
|
@ -3649,12 +3649,12 @@ FxExpression *FxCompareEq::Resolve(FCompileContext& ctx)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (left->IsPointer() && static_cast<PPointer*>(left->ValueType)->PointedType == right->ValueType)
|
else if (left->IsPointer() && left->ValueType->toPointer()->PointedType == right->ValueType)
|
||||||
{
|
{
|
||||||
bool writable;
|
bool writable;
|
||||||
if (!right->RequestAddress(ctx, &writable)) goto error;
|
if (!right->RequestAddress(ctx, &writable)) goto error;
|
||||||
}
|
}
|
||||||
else if (right->IsPointer() && static_cast<PPointer*>(right->ValueType)->PointedType == left->ValueType)
|
else if (right->IsPointer() && right->ValueType->toPointer()->PointedType == left->ValueType)
|
||||||
{
|
{
|
||||||
bool writable;
|
bool writable;
|
||||||
if (!left->RequestAddress(ctx, &writable)) goto error;
|
if (!left->RequestAddress(ctx, &writable)) goto error;
|
||||||
|
@ -4684,7 +4684,7 @@ FxExpression *FxDynamicCast::Resolve(FCompileContext& ctx)
|
||||||
{
|
{
|
||||||
CHECKRESOLVED();
|
CHECKRESOLVED();
|
||||||
SAFE_RESOLVE(expr, ctx);
|
SAFE_RESOLVE(expr, ctx);
|
||||||
bool constflag = expr->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast<PPointer *>(expr->ValueType)->IsConst;
|
bool constflag = expr->ValueType->isPointer() && expr->ValueType->toPointer()->IsConst;
|
||||||
if (constflag)
|
if (constflag)
|
||||||
{
|
{
|
||||||
// readonly pointers are normally only used for class defaults which lack type information to be cast properly, so we have to error out here.
|
// readonly pointers are normally only used for class defaults which lack type information to be cast properly, so we have to error out here.
|
||||||
|
@ -6342,7 +6342,7 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx)
|
||||||
auto sn = static_cast<PSymbolConstNumeric*>(sym);
|
auto sn = static_cast<PSymbolConstNumeric*>(sym);
|
||||||
|
|
||||||
VMValue vmv;
|
VMValue vmv;
|
||||||
if (sn->ValueType->IsKindOf(RUNTIME_CLASS(PInt))) vmv = sn->Value;
|
if (sn->ValueType->isIntCompatible()) vmv = sn->Value;
|
||||||
else vmv = sn->Float;
|
else vmv = sn->Float;
|
||||||
auto x = new FxConstant(sn->ValueType, vmv, ScriptPosition);
|
auto x = new FxConstant(sn->ValueType, vmv, ScriptPosition);
|
||||||
delete this;
|
delete this;
|
||||||
|
@ -6393,10 +6393,10 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx)
|
||||||
{
|
{
|
||||||
Object->ValueType = TypeColorStruct;
|
Object->ValueType = TypeColorStruct;
|
||||||
}
|
}
|
||||||
if (Object->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)))
|
if (Object->ValueType->isRealPointer())
|
||||||
{
|
{
|
||||||
auto ptype = static_cast<PPointer *>(Object->ValueType)->PointedType;
|
auto ptype = Object->ValueType->toPointer()->PointedType;
|
||||||
if (ptype->IsKindOf(RUNTIME_CLASS(PContainerType)))
|
if (ptype->isContainer())
|
||||||
{
|
{
|
||||||
auto ret = ResolveMember(ctx, ctx.Class, Object, static_cast<PContainerType *>(ptype));
|
auto ret = ResolveMember(ctx, ctx.Class, Object, static_cast<PContainerType *>(ptype));
|
||||||
delete this;
|
delete this;
|
||||||
|
@ -6603,8 +6603,8 @@ FxExpression *FxClassDefaults::Resolve(FCompileContext& ctx)
|
||||||
{
|
{
|
||||||
CHECKRESOLVED();
|
CHECKRESOLVED();
|
||||||
SAFE_RESOLVE(obj, ctx);
|
SAFE_RESOLVE(obj, ctx);
|
||||||
assert(obj->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)));
|
assert(obj->ValueType->isRealPointer());
|
||||||
ValueType = NewPointer(static_cast<PPointer*>(obj->ValueType)->PointedType, true);
|
ValueType = NewPointer(obj->ValueType->toPointer()->PointedType, true);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6938,7 +6938,7 @@ bool FxStructMember::RequestAddress(FCompileContext &ctx, bool *writable)
|
||||||
{
|
{
|
||||||
// [ZZ] original check.
|
// [ZZ] original check.
|
||||||
bool bWritable = (AddressWritable && !ctx.CheckWritable(membervar->Flags) &&
|
bool bWritable = (AddressWritable && !ctx.CheckWritable(membervar->Flags) &&
|
||||||
(!classx->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) || !static_cast<PPointer*>(classx->ValueType)->IsConst));
|
(!classx->ValueType->isPointer() || !classx->ValueType->toPointer()->IsConst));
|
||||||
// [ZZ] implement write barrier between different scopes
|
// [ZZ] implement write barrier between different scopes
|
||||||
if (bWritable)
|
if (bWritable)
|
||||||
{
|
{
|
||||||
|
@ -7018,10 +7018,10 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx)
|
||||||
return x->Resolve(ctx);
|
return x->Resolve(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (classx->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)))
|
if (classx->ValueType->isPointer())
|
||||||
{
|
{
|
||||||
PPointer *ptrtype = dyn_cast<PPointer>(classx->ValueType);
|
PPointer *ptrtype = classx->ValueType->toPointer();
|
||||||
if (ptrtype == nullptr || !ptrtype->PointedType->IsKindOf(RUNTIME_CLASS(PContainerType)))
|
if (ptrtype == nullptr || !ptrtype->PointedType->isContainer())
|
||||||
{
|
{
|
||||||
ScriptPosition.Message(MSG_ERROR, "Member variable requires a struct or class object");
|
ScriptPosition.Message(MSG_ERROR, "Member variable requires a struct or class object");
|
||||||
delete this;
|
delete this;
|
||||||
|
@ -7241,7 +7241,7 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx)
|
||||||
if (arraytype == nullptr)
|
if (arraytype == nullptr)
|
||||||
{
|
{
|
||||||
// Check if we got a pointer to an array. Some native data structures (like the line list in sectors) use this.
|
// Check if we got a pointer to an array. Some native data structures (like the line list in sectors) use this.
|
||||||
PPointer *ptype = dyn_cast<PPointer>(Array->ValueType);
|
PPointer *ptype = Array->ValueType->toPointer();
|
||||||
if (ptype == nullptr || !ptype->PointedType->IsKindOf(RUNTIME_CLASS(PArray)))
|
if (ptype == nullptr || !ptype->PointedType->IsKindOf(RUNTIME_CLASS(PArray)))
|
||||||
{
|
{
|
||||||
ScriptPosition.Message(MSG_ERROR, "'[]' can only be used with arrays.");
|
ScriptPosition.Message(MSG_ERROR, "'[]' can only be used with arrays.");
|
||||||
|
@ -7316,7 +7316,7 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build)
|
||||||
|
|
||||||
if (arrayispointer)
|
if (arrayispointer)
|
||||||
{
|
{
|
||||||
arraytype = static_cast<PArray*>(static_cast<PPointer*>(Array->ValueType)->PointedType);
|
arraytype = static_cast<PArray*>(Array->ValueType->toPointer()->PointedType);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -8150,7 +8150,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
|
||||||
member->membervar = newfield;
|
member->membervar = newfield;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (a->IsPointer() && Self->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)))
|
else if (a->IsPointer() && Self->ValueType->isPointer())
|
||||||
{
|
{
|
||||||
// the only case which must be checked up front is for pointer arrays receiving a new element.
|
// 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,
|
// Since there is only one native backing class it uses a neutral void pointer as its argument,
|
||||||
|
@ -8178,7 +8178,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
|
||||||
if (!Self->IsResizableArray())
|
if (!Self->IsResizableArray())
|
||||||
{
|
{
|
||||||
auto atype = Self->ValueType;
|
auto atype = Self->ValueType;
|
||||||
if (Self->ValueType->IsKindOf(RUNTIME_CLASS(PPointer))) atype = static_cast<PPointer*>(ValueType)->PointedType;
|
if (Self->ValueType->isPointer()) atype = ValueType->toPointer()->PointedType;
|
||||||
auto size = static_cast<PArray*>(atype)->ElementCount;
|
auto size = static_cast<PArray*>(atype)->ElementCount;
|
||||||
auto x = new FxConstant(size, ScriptPosition);
|
auto x = new FxConstant(size, ScriptPosition);
|
||||||
delete this;
|
delete this;
|
||||||
|
@ -8222,10 +8222,11 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
|
||||||
return x->Resolve(ctx);
|
return x->Resolve(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Self->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && !Self->ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)))
|
if (Self->ValueType->isRealPointer())
|
||||||
{
|
{
|
||||||
auto ptype = static_cast<PPointer *>(Self->ValueType)->PointedType;
|
auto ptype = Self->ValueType->toPointer()->PointedType;
|
||||||
if (ptype->IsKindOf(RUNTIME_CLASS(PContainerType)))
|
cls = ptype->toContainer();
|
||||||
|
if (cls != nullptr)
|
||||||
{
|
{
|
||||||
if (ptype->IsKindOf(RUNTIME_CLASS(PClassType)) && MethodName == NAME_GetClass)
|
if (ptype->IsKindOf(RUNTIME_CLASS(PClassType)) && MethodName == NAME_GetClass)
|
||||||
{
|
{
|
||||||
|
@ -8238,9 +8239,6 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
|
||||||
auto x = new FxGetClass(Self);
|
auto x = new FxGetClass(Self);
|
||||||
return x->Resolve(ctx);
|
return x->Resolve(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
cls = static_cast<PContainerType *>(ptype);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -8759,7 +8757,7 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx)
|
||||||
// If this is a reference argument, the pointer type must be undone because the code below expects the pointed type as value type.
|
// If this is a reference argument, the pointer type must be undone because the code below expects the pointed type as value type.
|
||||||
if (argflags[i + k + implicit] & VARF_Ref)
|
if (argflags[i + k + implicit] & VARF_Ref)
|
||||||
{
|
{
|
||||||
assert(ntype->IsKindOf(RUNTIME_CLASS(PPointer)));
|
assert(ntype->isPointer());
|
||||||
ntype = TypeNullPtr; // the default of a reference type can only be a null pointer
|
ntype = TypeNullPtr; // the default of a reference type can only be a null pointer
|
||||||
}
|
}
|
||||||
if (ntype->GetRegCount() == 1)
|
if (ntype->GetRegCount() == 1)
|
||||||
|
@ -8822,7 +8820,7 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx)
|
||||||
ArgList[i] = ArgList[i]->Resolve(ctx); // nust be resolved before the address is requested.
|
ArgList[i] = ArgList[i]->Resolve(ctx); // nust be resolved before the address is requested.
|
||||||
if (ArgList[i] != nullptr && ArgList[i]->ValueType != TypeNullPtr)
|
if (ArgList[i] != nullptr && ArgList[i]->ValueType != TypeNullPtr)
|
||||||
{
|
{
|
||||||
if (type == ArgList[i]->ValueType && type->IsA(RUNTIME_CLASS(PPointer)) && static_cast<PPointer*>(type)->PointedType->IsA(RUNTIME_CLASS(PStruct)))
|
if (type == ArgList[i]->ValueType && type->isRealPointer() && type->toPointer()->PointedType->IsA(RUNTIME_CLASS(PStruct)))
|
||||||
{
|
{
|
||||||
// trying to pass a struct reference as a struct reference. This must preserve the type.
|
// trying to pass a struct reference as a struct reference. This must preserve the type.
|
||||||
}
|
}
|
||||||
|
@ -8937,7 +8935,7 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
|
||||||
|
|
||||||
if (innerside == FScopeBarrier::Side_Virtual)
|
if (innerside == FScopeBarrier::Side_Virtual)
|
||||||
{
|
{
|
||||||
auto selfside = FScopeBarrier::SideFromObjectFlags(static_cast<PPointer*>(Self->ValueType)->PointedType->ObjectFlags);
|
auto selfside = FScopeBarrier::SideFromObjectFlags(Self->ValueType->toPointer()->PointedType->ObjectFlags);
|
||||||
|
|
||||||
int outerside = FScopeBarrier::SideFromFlags(CallingFunction->Variants[0].Flags);
|
int outerside = FScopeBarrier::SideFromFlags(CallingFunction->Variants[0].Flags);
|
||||||
if (outerside == FScopeBarrier::Side_Virtual)
|
if (outerside == FScopeBarrier::Side_Virtual)
|
||||||
|
@ -9300,7 +9298,7 @@ FxExpression *FxGetClass::Resolve(FCompileContext &ctx)
|
||||||
delete this;
|
delete this;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
ValueType = NewClassPointer(static_cast<PClassType*>(static_cast<PPointer*>(Self->ValueType)->PointedType)->Descriptor);
|
ValueType = NewClassPointer(static_cast<PClassType*>(Self->ValueType->toPointer()->PointedType)->Descriptor);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -330,14 +330,14 @@ public:
|
||||||
virtual bool CheckReturn() { return false; }
|
virtual bool CheckReturn() { return false; }
|
||||||
virtual int GetBitValue() { return -1; }
|
virtual int GetBitValue() { return -1; }
|
||||||
bool IsNumeric() const { return ValueType->isNumeric(); }
|
bool IsNumeric() const { return ValueType->isNumeric(); }
|
||||||
bool IsFloat() const { return ValueType->GetRegType() == REGT_FLOAT && ValueType->GetRegCount() == 1; }
|
bool IsFloat() const { return ValueType->isFloat(); }
|
||||||
bool IsInteger() const { return ValueType->isNumeric() && (ValueType->GetRegType() == REGT_INT); }
|
bool IsInteger() const { return ValueType->isNumeric() && ValueType->isIntCompatible(); }
|
||||||
bool IsPointer() const { return ValueType->GetRegType() == REGT_POINTER; }
|
bool IsPointer() const { return ValueType->isPointer(); }
|
||||||
bool IsVector() const { return ValueType == TypeVector2 || ValueType == TypeVector3; };
|
bool IsVector() const { return ValueType == TypeVector2 || ValueType == TypeVector3; };
|
||||||
bool IsBoolCompat() const { return ValueType->GetRegCount() == 1 && (ValueType->GetRegType() == REGT_INT || ValueType->GetRegType() == REGT_FLOAT || ValueType->GetRegType() == REGT_POINTER); }
|
bool IsBoolCompat() const { return ValueType->isScalar(); }
|
||||||
bool IsObject() const { return ValueType->IsKindOf(RUNTIME_CLASS(PObjectPointer)); }
|
bool IsObject() const { return ValueType->IsKindOf(RUNTIME_CLASS(PObjectPointer)); }
|
||||||
bool IsArray() const { return ValueType->IsKindOf(RUNTIME_CLASS(PArray)) || (ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast<PPointer*>(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PArray))); }
|
bool IsArray() const { return ValueType->IsKindOf(RUNTIME_CLASS(PArray)) || (ValueType->isPointer() && ValueType->toPointer()->PointedType->IsKindOf(RUNTIME_CLASS(PArray))); }
|
||||||
bool IsResizableArray() const { return (ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast<PPointer*>(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PStaticArray))); } // can only exist in pointer form.
|
bool IsResizableArray() const { return (ValueType->isPointer() && ValueType->toPointer()->PointedType->IsKindOf(RUNTIME_CLASS(PStaticArray))); } // can only exist in pointer form.
|
||||||
bool IsDynamicArray() const { return (ValueType->IsKindOf(RUNTIME_CLASS(PDynArray))); }
|
bool IsDynamicArray() const { return (ValueType->IsKindOf(RUNTIME_CLASS(PDynArray))); }
|
||||||
bool IsNativeStruct() const { return (ValueType->IsA(RUNTIME_CLASS(PStruct)) && static_cast<PStruct*>(ValueType)->isNative); }
|
bool IsNativeStruct() const { return (ValueType->IsA(RUNTIME_CLASS(PStruct)) && static_cast<PStruct*>(ValueType)->isNative); }
|
||||||
|
|
||||||
|
|
|
@ -866,17 +866,17 @@ static void DispatchScriptProperty(FScanner &sc, PProperty *prop, AActor *defaul
|
||||||
if (sc.CheckNumber()) *(int*)addr = sc.Number;
|
if (sc.CheckNumber()) *(int*)addr = sc.Number;
|
||||||
else *(PalEntry*)addr = V_GetColor(nullptr, sc);
|
else *(PalEntry*)addr = V_GetColor(nullptr, sc);
|
||||||
}
|
}
|
||||||
else if (f->Type->IsKindOf(RUNTIME_CLASS(PInt)))
|
else if (f->Type->isIntCompatible())
|
||||||
{
|
{
|
||||||
sc.MustGetNumber();
|
sc.MustGetNumber();
|
||||||
static_cast<PInt*>(f->Type)->SetValue(addr, sc.Number);
|
static_cast<PInt*>(f->Type)->SetValue(addr, sc.Number);
|
||||||
}
|
}
|
||||||
else if (f->Type->IsKindOf(RUNTIME_CLASS(PFloat)))
|
else if (f->Type->isFloat())
|
||||||
{
|
{
|
||||||
sc.MustGetFloat();
|
sc.MustGetFloat();
|
||||||
static_cast<PFloat*>(f->Type)->SetValue(addr, sc.Float);
|
static_cast<PFloat*>(f->Type)->SetValue(addr, sc.Float);
|
||||||
}
|
}
|
||||||
else if (f->Type->IsKindOf(RUNTIME_CLASS(PString)))
|
else if (f->Type == TypeString)
|
||||||
{
|
{
|
||||||
sc.MustGetString();
|
sc.MustGetString();
|
||||||
*(FString*)addr = strbin1(sc.String);
|
*(FString*)addr = strbin1(sc.String);
|
||||||
|
|
|
@ -104,9 +104,9 @@ unsigned PFunction::AddVariant(PPrototype *proto, TArray<uint32_t> &argflags, TA
|
||||||
if (flags & VARF_Method)
|
if (flags & VARF_Method)
|
||||||
{
|
{
|
||||||
assert(proto->ArgumentTypes.Size() > 0);
|
assert(proto->ArgumentTypes.Size() > 0);
|
||||||
auto selftypeptr = dyn_cast<PPointer>(proto->ArgumentTypes[0]);
|
auto selftypeptr = proto->ArgumentTypes[0]->toPointer();
|
||||||
assert(selftypeptr != nullptr);
|
assert(selftypeptr != nullptr);
|
||||||
variant.SelfClass = dyn_cast<PContainerType>(selftypeptr->PointedType);
|
variant.SelfClass = selftypeptr->PointedType->toContainer();
|
||||||
assert(variant.SelfClass != nullptr);
|
assert(variant.SelfClass != nullptr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -155,7 +155,7 @@ PField::PField(FName name, PType *type, uint32_t flags, size_t offset, int bitva
|
||||||
unsigned val = bitvalue;
|
unsigned val = bitvalue;
|
||||||
while ((val >>= 1)) BitValue++;
|
while ((val >>= 1)) BitValue++;
|
||||||
|
|
||||||
if (type->IsA(RUNTIME_CLASS(PInt)) && unsigned(BitValue) < 8u * type->Size)
|
if (type->isInt() && unsigned(BitValue) < 8u * type->Size)
|
||||||
{
|
{
|
||||||
// map to the single bytes in the actual variable. The internal bit instructions operate on 8 bit values.
|
// map to the single bytes in the actual variable. The internal bit instructions operate on 8 bit values.
|
||||||
#ifndef __BIG_ENDIAN__
|
#ifndef __BIG_ENDIAN__
|
||||||
|
@ -582,7 +582,7 @@ void RemoveUnusedSymbols()
|
||||||
{
|
{
|
||||||
for (PType *ty = TypeTable.TypeHash[i]; ty != nullptr; ty = ty->HashNext)
|
for (PType *ty = TypeTable.TypeHash[i]; ty != nullptr; ty = ty->HashNext)
|
||||||
{
|
{
|
||||||
if (ty->IsKindOf(RUNTIME_CLASS(PContainerType)))
|
if (ty->isContainer())
|
||||||
{
|
{
|
||||||
auto it = ty->Symbols.GetIterator();
|
auto it = ty->Symbols.GetIterator();
|
||||||
PSymbolTable::MapType::Pair *pair;
|
PSymbolTable::MapType::Pair *pair;
|
||||||
|
|
|
@ -377,16 +377,6 @@ void PType::StaticInit()
|
||||||
|
|
||||||
IMPLEMENT_CLASS(PBasicType, true, false)
|
IMPLEMENT_CLASS(PBasicType, true, false)
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// PBasicType Default Constructor
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
PBasicType::PBasicType()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// PBasicType Parameterized Constructor
|
// PBasicType Parameterized Constructor
|
||||||
|
@ -397,12 +387,25 @@ PBasicType::PBasicType(unsigned int size, unsigned int align)
|
||||||
: PType(size, align)
|
: PType(size, align)
|
||||||
{
|
{
|
||||||
mDescriptiveName = "BasicType";
|
mDescriptiveName = "BasicType";
|
||||||
|
Flags |= TYPE_Scalar;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* PCompoundType **********************************************************/
|
/* PCompoundType **********************************************************/
|
||||||
|
|
||||||
IMPLEMENT_CLASS(PCompoundType, true, false)
|
IMPLEMENT_CLASS(PCompoundType, true, false)
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// PBasicType Parameterized Constructor
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
PCompoundType::PCompoundType(unsigned int size, unsigned int align)
|
||||||
|
: PType(size, align)
|
||||||
|
{
|
||||||
|
mDescriptiveName = "CompoundType";
|
||||||
|
}
|
||||||
|
|
||||||
/* PContainerType *************************************************************/
|
/* PContainerType *************************************************************/
|
||||||
|
|
||||||
IMPLEMENT_CLASS(PContainerType, true, false)
|
IMPLEMENT_CLASS(PContainerType, true, false)
|
||||||
|
@ -462,6 +465,7 @@ PInt::PInt(unsigned int size, bool unsign, bool compatible)
|
||||||
: PBasicType(size, size), Unsigned(unsign), IntCompatible(compatible)
|
: PBasicType(size, size), Unsigned(unsign), IntCompatible(compatible)
|
||||||
{
|
{
|
||||||
mDescriptiveName.Format("%cInt%d", unsign? 'U':'S', size);
|
mDescriptiveName.Format("%cInt%d", unsign? 'U':'S', size);
|
||||||
|
Flags |= TYPE_Int;
|
||||||
|
|
||||||
MemberOnly = (size < 4);
|
MemberOnly = (size < 4);
|
||||||
if (!unsign)
|
if (!unsign)
|
||||||
|
@ -713,26 +717,13 @@ PBool::PBool()
|
||||||
{
|
{
|
||||||
mDescriptiveName = "Bool";
|
mDescriptiveName = "Bool";
|
||||||
MemberOnly = false;
|
MemberOnly = false;
|
||||||
|
Flags |= TYPE_IntNotInt;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* PFloat *****************************************************************/
|
/* PFloat *****************************************************************/
|
||||||
|
|
||||||
IMPLEMENT_CLASS(PFloat, false, false)
|
IMPLEMENT_CLASS(PFloat, false, false)
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// PFloat Default Constructor
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
PFloat::PFloat()
|
|
||||||
: PBasicType(8, 8)
|
|
||||||
{
|
|
||||||
mDescriptiveName = "Float";
|
|
||||||
SetDoubleSymbols();
|
|
||||||
SetOps();
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// PFloat Parameterized Constructor
|
// PFloat Parameterized Constructor
|
||||||
|
@ -743,6 +734,7 @@ PFloat::PFloat(unsigned int size)
|
||||||
: PBasicType(size, size)
|
: PBasicType(size, size)
|
||||||
{
|
{
|
||||||
mDescriptiveName.Format("Float%d", size);
|
mDescriptiveName.Format("Float%d", size);
|
||||||
|
Flags |= TYPE_Float;
|
||||||
if (size == 8)
|
if (size == 8)
|
||||||
{
|
{
|
||||||
#ifdef __i386__
|
#ifdef __i386__
|
||||||
|
@ -1085,6 +1077,7 @@ PName::PName()
|
||||||
: PInt(sizeof(FName), true, false)
|
: PInt(sizeof(FName), true, false)
|
||||||
{
|
{
|
||||||
mDescriptiveName = "Name";
|
mDescriptiveName = "Name";
|
||||||
|
Flags |= TYPE_IntNotInt;
|
||||||
assert(sizeof(FName) == alignof(FName));
|
assert(sizeof(FName) == alignof(FName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1134,6 +1127,7 @@ IMPLEMENT_CLASS(PSpriteID, false, false)
|
||||||
PSpriteID::PSpriteID()
|
PSpriteID::PSpriteID()
|
||||||
: PInt(sizeof(int), true, true)
|
: PInt(sizeof(int), true, true)
|
||||||
{
|
{
|
||||||
|
Flags |= TYPE_IntNotInt;
|
||||||
mDescriptiveName = "SpriteID";
|
mDescriptiveName = "SpriteID";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1177,6 +1171,7 @@ PTextureID::PTextureID()
|
||||||
: PInt(sizeof(FTextureID), true, false)
|
: PInt(sizeof(FTextureID), true, false)
|
||||||
{
|
{
|
||||||
mDescriptiveName = "TextureID";
|
mDescriptiveName = "TextureID";
|
||||||
|
Flags |= TYPE_IntNotInt;
|
||||||
assert(sizeof(FTextureID) == alignof(FTextureID));
|
assert(sizeof(FTextureID) == alignof(FTextureID));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1220,6 +1215,7 @@ PSound::PSound()
|
||||||
: PInt(sizeof(FSoundID), true)
|
: PInt(sizeof(FSoundID), true)
|
||||||
{
|
{
|
||||||
mDescriptiveName = "Sound";
|
mDescriptiveName = "Sound";
|
||||||
|
Flags |= TYPE_IntNotInt;
|
||||||
assert(sizeof(FSoundID) == alignof(FSoundID));
|
assert(sizeof(FSoundID) == alignof(FSoundID));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1270,6 +1266,7 @@ PColor::PColor()
|
||||||
: PInt(sizeof(PalEntry), true)
|
: PInt(sizeof(PalEntry), true)
|
||||||
{
|
{
|
||||||
mDescriptiveName = "Color";
|
mDescriptiveName = "Color";
|
||||||
|
Flags |= TYPE_IntNotInt;
|
||||||
assert(sizeof(PalEntry) == alignof(PalEntry));
|
assert(sizeof(PalEntry) == alignof(PalEntry));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1286,6 +1283,7 @@ IMPLEMENT_CLASS(PStateLabel, false, false)
|
||||||
PStateLabel::PStateLabel()
|
PStateLabel::PStateLabel()
|
||||||
: PInt(sizeof(int), false, false)
|
: PInt(sizeof(int), false, false)
|
||||||
{
|
{
|
||||||
|
Flags |= TYPE_IntNotInt;
|
||||||
mDescriptiveName = "StateLabel";
|
mDescriptiveName = "StateLabel";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1307,6 +1305,7 @@ PPointer::PPointer()
|
||||||
storeOp = OP_SP;
|
storeOp = OP_SP;
|
||||||
moveOp = OP_MOVEA;
|
moveOp = OP_MOVEA;
|
||||||
RegType = REGT_POINTER;
|
RegType = REGT_POINTER;
|
||||||
|
Flags |= TYPE_Pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -1332,6 +1331,7 @@ PPointer::PPointer(PType *pointsat, bool isconst)
|
||||||
storeOp = OP_SP;
|
storeOp = OP_SP;
|
||||||
moveOp = OP_MOVEA;
|
moveOp = OP_MOVEA;
|
||||||
RegType = REGT_POINTER;
|
RegType = REGT_POINTER;
|
||||||
|
Flags |= TYPE_Pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
|
@ -61,6 +61,21 @@ enum
|
||||||
// Map * *
|
// Map * *
|
||||||
// Prototype *+ *+
|
// Prototype *+ *+
|
||||||
|
|
||||||
|
enum ETypeFlags
|
||||||
|
{
|
||||||
|
TYPE_Scalar = 1,
|
||||||
|
TYPE_Container = 2,
|
||||||
|
TYPE_Int = 4,
|
||||||
|
TYPE_IntNotInt = 8, // catch-all for subtypes that are not being checked by type directly.
|
||||||
|
TYPE_Float = 16,
|
||||||
|
TYPE_Pointer = 32,
|
||||||
|
|
||||||
|
TYPE_IntCompatible = TYPE_Int | TYPE_IntNotInt, // must be the combination of all flags that are subtypes of int and can be cast to an int.
|
||||||
|
};
|
||||||
|
|
||||||
|
class PContainerType;
|
||||||
|
class PPointer;
|
||||||
|
|
||||||
struct ZCC_ExprConstant;
|
struct ZCC_ExprConstant;
|
||||||
class PType : public PTypeBase
|
class PType : public PTypeBase
|
||||||
{
|
{
|
||||||
|
@ -71,6 +86,7 @@ public:
|
||||||
PClass *TypeTableType; // The type to use for hashing into the type table
|
PClass *TypeTableType; // The type to use for hashing into the type table
|
||||||
unsigned int Size; // this type's size
|
unsigned int Size; // this type's size
|
||||||
unsigned int Align; // this type's preferred alignment
|
unsigned int Align; // this type's preferred alignment
|
||||||
|
unsigned int Flags = 0; // What is this type?
|
||||||
PType *HashNext; // next type in this type table
|
PType *HashNext; // next type in this type table
|
||||||
PSymbolTable Symbols;
|
PSymbolTable Symbols;
|
||||||
bool MemberOnly = false; // type may only be used as a struct/class member but not as a local variable or function argument.
|
bool MemberOnly = false; // type may only be used as a struct/class member but not as a local variable or function argument.
|
||||||
|
@ -160,6 +176,17 @@ public:
|
||||||
const char *DescriptiveName() const;
|
const char *DescriptiveName() const;
|
||||||
|
|
||||||
static void StaticInit();
|
static void StaticInit();
|
||||||
|
|
||||||
|
bool isScalar() const { return !!(Flags & TYPE_Scalar); }
|
||||||
|
bool isContainer() const { return !!(Flags & TYPE_Container); }
|
||||||
|
bool isInt() const { return (Flags & TYPE_IntCompatible) == TYPE_Int; }
|
||||||
|
bool isIntCompatible() const { return !!(Flags & TYPE_IntCompatible); }
|
||||||
|
bool isFloat() const { return !!(Flags & TYPE_Float); }
|
||||||
|
bool isPointer() const { return !!(Flags & TYPE_Pointer); }
|
||||||
|
bool isRealPointer() const { return !!(Flags & TYPE_Pointer); } // This excludes class pointers which use their PointedType differently
|
||||||
|
|
||||||
|
PContainerType *toContainer() { return isContainer() ? (PContainerType*)this : nullptr; }
|
||||||
|
PPointer *toPointer() { return isPointer() ? (PPointer*)this : nullptr; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Not-really-a-type types --------------------------------------------------
|
// Not-really-a-type types --------------------------------------------------
|
||||||
|
@ -183,14 +210,15 @@ public:
|
||||||
class PBasicType : public PType
|
class PBasicType : public PType
|
||||||
{
|
{
|
||||||
DECLARE_ABSTRACT_CLASS(PBasicType, PType);
|
DECLARE_ABSTRACT_CLASS(PBasicType, PType);
|
||||||
public:
|
protected:
|
||||||
PBasicType();
|
PBasicType(unsigned int size = 1, unsigned int align = 1);
|
||||||
PBasicType(unsigned int size, unsigned int align);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class PCompoundType : public PType
|
class PCompoundType : public PType
|
||||||
{
|
{
|
||||||
DECLARE_ABSTRACT_CLASS(PCompoundType, PType);
|
DECLARE_ABSTRACT_CLASS(PCompoundType, PType);
|
||||||
|
protected:
|
||||||
|
PCompoundType(unsigned int size = 1, unsigned int align = 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
class PContainerType : public PCompoundType
|
class PContainerType : public PCompoundType
|
||||||
|
@ -200,11 +228,15 @@ public:
|
||||||
PTypeBase *Outer; // object this type is contained within
|
PTypeBase *Outer; // object this type is contained within
|
||||||
FName TypeName; // this type's name
|
FName TypeName; // this type's name
|
||||||
|
|
||||||
PContainerType() : Outer(NULL) {
|
PContainerType() : Outer(NULL)
|
||||||
mDescriptiveName = "NamedType";
|
{
|
||||||
|
mDescriptiveName = "ContainerType";
|
||||||
|
Flags |= TYPE_Container;
|
||||||
}
|
}
|
||||||
PContainerType(FName name, PTypeBase *outer) : Outer(outer), TypeName(name) {
|
PContainerType(FName name, PTypeBase *outer) : Outer(outer), TypeName(name)
|
||||||
|
{
|
||||||
mDescriptiveName = name.GetChars();
|
mDescriptiveName = name.GetChars();
|
||||||
|
Flags |= TYPE_Container;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
|
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
|
||||||
|
@ -252,7 +284,7 @@ class PFloat : public PBasicType
|
||||||
{
|
{
|
||||||
DECLARE_CLASS(PFloat, PBasicType);
|
DECLARE_CLASS(PFloat, PBasicType);
|
||||||
public:
|
public:
|
||||||
PFloat(unsigned int size);
|
PFloat(unsigned int size = 8);
|
||||||
|
|
||||||
void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
|
void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
|
||||||
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
|
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
|
||||||
|
@ -263,7 +295,6 @@ public:
|
||||||
virtual double GetValueFloat(void *addr) const;
|
virtual double GetValueFloat(void *addr) const;
|
||||||
virtual bool isNumeric() override { return true; }
|
virtual bool isNumeric() override { return true; }
|
||||||
protected:
|
protected:
|
||||||
PFloat();
|
|
||||||
void SetOps();
|
void SetOps();
|
||||||
private:
|
private:
|
||||||
struct SymbolInitF
|
struct SymbolInitF
|
||||||
|
|
|
@ -593,7 +593,7 @@ static void PrintExprConstant(FLispString &out, ZCC_TreeNode *node)
|
||||||
{
|
{
|
||||||
out.AddName(ENamedName(enode->IntVal));
|
out.AddName(ENamedName(enode->IntVal));
|
||||||
}
|
}
|
||||||
else if (enode->Type->IsKindOf(RUNTIME_CLASS(PInt)))
|
else if (enode->Type->isIntCompatible())
|
||||||
{
|
{
|
||||||
out.AddInt(enode->IntVal, static_cast<PInt *>(enode->Type)->Unsigned);
|
out.AddInt(enode->IntVal, static_cast<PInt *>(enode->Type)->Unsigned);
|
||||||
}
|
}
|
||||||
|
|
|
@ -403,7 +403,7 @@ enum_def(X) ::= ENUM(T) IDENTIFIER(A) enum_type(B) LBRACE opt_enum_list(C) RBRAC
|
||||||
// Compute implicit values by adding one to the preceding value.
|
// Compute implicit values by adding one to the preceding value.
|
||||||
assert(prev->Value != NULL);
|
assert(prev->Value != NULL);
|
||||||
// If the preceding node is a constant, then we can do this now.
|
// If the preceding node is a constant, then we can do this now.
|
||||||
if (prev->Value->Operation == PEX_ConstValue && prev->Value->Type->IsA(RUNTIME_CLASS(PInt)))
|
if (prev->Value->Operation == PEX_ConstValue && prev->Value->Type->isInt())
|
||||||
{
|
{
|
||||||
NEW_INTCONST_NODE(cval, prev->Value->Type, static_cast<ZCC_ExprConstant *>(prev->Value)->IntVal + 1, node);
|
NEW_INTCONST_NODE(cval, prev->Value->Type, static_cast<ZCC_ExprConstant *>(prev->Value)->IntVal + 1, node);
|
||||||
node->Value = cval;
|
node->Value = cval;
|
||||||
|
@ -1256,9 +1256,9 @@ unary_expr(X) ::= primary(X).
|
||||||
unary_expr(X) ::= SUB unary_expr(A). [UNARY]
|
unary_expr(X) ::= SUB unary_expr(A). [UNARY]
|
||||||
{
|
{
|
||||||
ZCC_ExprConstant *con = static_cast<ZCC_ExprConstant *>(A);
|
ZCC_ExprConstant *con = static_cast<ZCC_ExprConstant *>(A);
|
||||||
if (A->Operation == PEX_ConstValue && (con->Type->IsA(RUNTIME_CLASS(PInt)) || con->Type->IsA(RUNTIME_CLASS(PFloat))))
|
if (A->Operation == PEX_ConstValue && (con->Type->isInt() || con->Type->isFloat()))
|
||||||
{ // For constants, manipulate the child node directly, and don't create a new node.
|
{ // For constants, manipulate the child node directly, and don't create a new node.
|
||||||
if (con->Type->IsA(RUNTIME_CLASS(PInt)))
|
if (con->Type->isInt())
|
||||||
{
|
{
|
||||||
con->IntVal = -con->IntVal;
|
con->IntVal = -con->IntVal;
|
||||||
}
|
}
|
||||||
|
@ -1280,7 +1280,7 @@ unary_expr(X) ::= ADD unary_expr(A). [UNARY]
|
||||||
// it so we can type check that it is being applied to something numeric.
|
// it so we can type check that it is being applied to something numeric.
|
||||||
// But we can do that right now for constant numerals.
|
// But we can do that right now for constant numerals.
|
||||||
ZCC_ExprConstant *con = static_cast<ZCC_ExprConstant *>(A);
|
ZCC_ExprConstant *con = static_cast<ZCC_ExprConstant *>(A);
|
||||||
if (A->Operation != PEX_ConstValue || (!con->Type->IsA(RUNTIME_CLASS(PInt)) && !con->Type->IsA(RUNTIME_CLASS(PFloat))))
|
if (A->Operation != PEX_ConstValue || (!con->Type->isInt() && !con->Type->isFloat()))
|
||||||
{
|
{
|
||||||
UNARY_EXPR(A,PEX_AntiNegate);
|
UNARY_EXPR(A,PEX_AntiNegate);
|
||||||
X = expr1;
|
X = expr1;
|
||||||
|
|
|
@ -873,13 +873,13 @@ void ZCCCompiler::AddConstant(ZCC_ConstantWork &constant)
|
||||||
{
|
{
|
||||||
def->Symbol = new PSymbolConstString(def->NodeName, *(cval->StringVal));
|
def->Symbol = new PSymbolConstString(def->NodeName, *(cval->StringVal));
|
||||||
}
|
}
|
||||||
else if (cval->Type->IsA(RUNTIME_CLASS(PInt)))
|
else if (cval->Type->isInt())
|
||||||
{
|
{
|
||||||
// How do we get an Enum type in here without screwing everything up???
|
// How do we get an Enum type in here without screwing everything up???
|
||||||
//auto type = def->Type != nullptr ? def->Type : cval->Type;
|
//auto type = def->Type != nullptr ? def->Type : cval->Type;
|
||||||
def->Symbol = new PSymbolConstNumeric(def->NodeName, cval->Type, cval->IntVal);
|
def->Symbol = new PSymbolConstNumeric(def->NodeName, cval->Type, cval->IntVal);
|
||||||
}
|
}
|
||||||
else if (cval->Type->IsA(RUNTIME_CLASS(PFloat)))
|
else if (cval->Type->isFloat())
|
||||||
{
|
{
|
||||||
if (def->Type != nullptr)
|
if (def->Type != nullptr)
|
||||||
{
|
{
|
||||||
|
@ -899,13 +899,13 @@ void ZCCCompiler::AddConstant(ZCC_ConstantWork &constant)
|
||||||
{
|
{
|
||||||
def->Symbol = new PSymbolConstString(def->NodeName, c.GetString());
|
def->Symbol = new PSymbolConstString(def->NodeName, c.GetString());
|
||||||
}
|
}
|
||||||
else if (c.Type->IsA(RUNTIME_CLASS(PInt)))
|
else if (c.Type->isInt())
|
||||||
{
|
{
|
||||||
// How do we get an Enum type in here without screwing everything up???
|
// How do we get an Enum type in here without screwing everything up???
|
||||||
//auto type = def->Type != nullptr ? def->Type : cval->Type;
|
//auto type = def->Type != nullptr ? def->Type : cval->Type;
|
||||||
def->Symbol = new PSymbolConstNumeric(def->NodeName, c.Type, c.GetInt());
|
def->Symbol = new PSymbolConstNumeric(def->NodeName, c.Type, c.GetInt());
|
||||||
}
|
}
|
||||||
else if (c.Type->IsA(RUNTIME_CLASS(PFloat)))
|
else if (c.Type->isFloat())
|
||||||
{
|
{
|
||||||
if (def->Type != nullptr)
|
if (def->Type != nullptr)
|
||||||
{
|
{
|
||||||
|
@ -974,7 +974,7 @@ void ZCCCompiler::CompileArrays(ZCC_StructWork *work)
|
||||||
FArgumentList values;
|
FArgumentList values;
|
||||||
|
|
||||||
// Don't use narrow typea for casting.
|
// Don't use narrow typea for casting.
|
||||||
if (ctype->IsA(RUNTIME_CLASS(PInt))) ctype = static_cast<PInt*>(ztype)->Unsigned ? TypeUInt32 : TypeSInt32;
|
if (ctype->isInt()) ctype = static_cast<PInt*>(ztype)->Unsigned ? TypeUInt32 : TypeSInt32;
|
||||||
else if (ctype == TypeFloat32) ctype = TypeFloat64;
|
else if (ctype == TypeFloat32) ctype = TypeFloat64;
|
||||||
|
|
||||||
ConvertNodeList(values, sas->Values);
|
ConvertNodeList(values, sas->Values);
|
||||||
|
@ -1077,13 +1077,13 @@ ZCC_ExprConstant *ZCCCompiler::NodeFromSymbolConst(PSymbolConst *sym, ZCC_Expres
|
||||||
if (val->Type != TypeError)
|
if (val->Type != TypeError)
|
||||||
{
|
{
|
||||||
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolConstNumeric)));
|
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolConstNumeric)));
|
||||||
if (sym->ValueType->IsKindOf(RUNTIME_CLASS(PInt)))
|
if (sym->ValueType->isIntCompatible())
|
||||||
{
|
{
|
||||||
val->IntVal = static_cast<PSymbolConstNumeric *>(sym)->Value;
|
val->IntVal = static_cast<PSymbolConstNumeric *>(sym)->Value;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
assert(sym->ValueType->IsKindOf(RUNTIME_CLASS(PFloat)));
|
assert(sym->ValueType->isFloat());
|
||||||
val->DoubleVal = static_cast<PSymbolConstNumeric *>(sym)->Float;
|
val->DoubleVal = static_cast<PSymbolConstNumeric *>(sym)->Float;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1752,7 +1752,7 @@ PType *ZCCCompiler::ResolveArraySize(PType *baseType, ZCC_Expression *arraysize,
|
||||||
ex = ex->Resolve(ctx);
|
ex = ex->Resolve(ctx);
|
||||||
|
|
||||||
if (ex == nullptr) return TypeError;
|
if (ex == nullptr) return TypeError;
|
||||||
if (!ex->isConstant() || !ex->ValueType->IsA(RUNTIME_CLASS(PInt)))
|
if (!ex->isConstant() || !ex->ValueType->isInt())
|
||||||
{
|
{
|
||||||
Error(arraysize, "Array index must be an integer constant");
|
Error(arraysize, "Array index must be an integer constant");
|
||||||
return TypeError;
|
return TypeError;
|
||||||
|
@ -2023,15 +2023,15 @@ void ZCCCompiler::DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt *prop
|
||||||
{
|
{
|
||||||
*(PalEntry*)addr = V_GetColor(nullptr, GetStringConst(ex, ctx), &ex->ScriptPosition);
|
*(PalEntry*)addr = V_GetColor(nullptr, GetStringConst(ex, ctx), &ex->ScriptPosition);
|
||||||
}
|
}
|
||||||
else if (f->Type->IsKindOf(RUNTIME_CLASS(PInt)))
|
else if (f->Type->isIntCompatible())
|
||||||
{
|
{
|
||||||
static_cast<PInt*>(f->Type)->SetValue(addr, GetIntConst(ex, ctx));
|
static_cast<PInt*>(f->Type)->SetValue(addr, GetIntConst(ex, ctx));
|
||||||
}
|
}
|
||||||
else if (f->Type->IsKindOf(RUNTIME_CLASS(PFloat)))
|
else if (f->Type->isFloat())
|
||||||
{
|
{
|
||||||
static_cast<PFloat*>(f->Type)->SetValue(addr, GetFloatConst(ex, ctx));
|
static_cast<PFloat*>(f->Type)->SetValue(addr, GetFloatConst(ex, ctx));
|
||||||
}
|
}
|
||||||
else if (f->Type->IsKindOf(RUNTIME_CLASS(PString)))
|
else if (f->Type == TypeString)
|
||||||
{
|
{
|
||||||
*(FString*)addr = GetStringConst(ex, ctx);
|
*(FString*)addr = GetStringConst(ex, ctx);
|
||||||
}
|
}
|
||||||
|
@ -2304,7 +2304,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
auto type = DetermineType(c->Type(), f, f->Name, t, false, false);
|
auto type = DetermineType(c->Type(), f, f->Name, t, false, false);
|
||||||
if (type->IsKindOf(RUNTIME_CLASS(PContainerType)) && type != TypeVector2 && type != TypeVector3)
|
if (type->isContainer() && type != TypeVector2 && type != TypeVector3)
|
||||||
{
|
{
|
||||||
// structs and classes only get passed by pointer.
|
// structs and classes only get passed by pointer.
|
||||||
type = NewPointer(type);
|
type = NewPointer(type);
|
||||||
|
@ -3228,23 +3228,23 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast)
|
||||||
case AST_ExprConstant:
|
case AST_ExprConstant:
|
||||||
{
|
{
|
||||||
auto cnst = static_cast<ZCC_ExprConstant *>(ast);
|
auto cnst = static_cast<ZCC_ExprConstant *>(ast);
|
||||||
if (cnst->Type->IsA(RUNTIME_CLASS(PName)))
|
if (cnst->Type == TypeName)
|
||||||
{
|
{
|
||||||
return new FxConstant(FName(ENamedName(cnst->IntVal)), *ast);
|
return new FxConstant(FName(ENamedName(cnst->IntVal)), *ast);
|
||||||
}
|
}
|
||||||
else if (cnst->Type->IsA(RUNTIME_CLASS(PInt)))
|
else if (cnst->Type->isInt())
|
||||||
{
|
{
|
||||||
return new FxConstant(cnst->IntVal, *ast);
|
return new FxConstant(cnst->IntVal, *ast);
|
||||||
}
|
}
|
||||||
else if (cnst->Type->IsA(RUNTIME_CLASS(PBool)))
|
else if (cnst->Type == TypeBool)
|
||||||
{
|
{
|
||||||
return new FxConstant(!!cnst->IntVal, *ast);
|
return new FxConstant(!!cnst->IntVal, *ast);
|
||||||
}
|
}
|
||||||
else if (cnst->Type->IsA(RUNTIME_CLASS(PFloat)))
|
else if (cnst->Type->isFloat())
|
||||||
{
|
{
|
||||||
return new FxConstant(cnst->DoubleVal, *ast);
|
return new FxConstant(cnst->DoubleVal, *ast);
|
||||||
}
|
}
|
||||||
else if (cnst->Type->IsA(RUNTIME_CLASS(PString)))
|
else if (cnst->Type == TypeString)
|
||||||
{
|
{
|
||||||
return new FxConstant(*cnst->StringVal, *ast);
|
return new FxConstant(*cnst->StringVal, *ast);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue