mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-11 15:21:51 +00:00
- added null pointer.
- fixed: FxMemberIdentifier checked for ClassPointers instead of object pointers to resolve the left hand side of the expression. - allow comparison of pointers.
This commit is contained in:
parent
3b0b0baf05
commit
4b41e735f1
7 changed files with 104 additions and 61 deletions
|
@ -1671,7 +1671,7 @@ int PPointer::GetStoreOp() const
|
||||||
|
|
||||||
int PPointer::GetLoadOp() const
|
int PPointer::GetLoadOp() const
|
||||||
{
|
{
|
||||||
return PointedType->IsKindOf(RUNTIME_CLASS(PClass)) ? OP_LO : OP_LP;
|
return (PointedType && PointedType->IsKindOf(RUNTIME_CLASS(PClass))) ? OP_LO : OP_LP;
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
|
@ -229,6 +229,31 @@ static PSymbol *FindDecorateBuiltinFunction(FName funcname, VMNativeFunction::Na
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
|
static bool AreCompatiblePointerTypes(PType *dest, PType *source)
|
||||||
|
{
|
||||||
|
if (dest->IsKindOf(RUNTIME_CLASS(PPointer)) && source->IsKindOf(RUNTIME_CLASS(PPointer)))
|
||||||
|
{
|
||||||
|
// Pointers to different types are only compatible if both point to an object and the source type is a child of the destination type.
|
||||||
|
auto fromtype = static_cast<PPointer *>(source);
|
||||||
|
auto totype = static_cast<PPointer *>(dest);
|
||||||
|
if (fromtype == nullptr) return true;
|
||||||
|
if (fromtype == totype) return true;
|
||||||
|
if (fromtype->PointedType->IsKindOf(RUNTIME_CLASS(PClass)) && totype->PointedType->IsKindOf(RUNTIME_CLASS(PClass)))
|
||||||
|
{
|
||||||
|
auto fromcls = static_cast<PClass *>(fromtype->PointedType);
|
||||||
|
auto tocls = static_cast<PClass *>(totype->PointedType);
|
||||||
|
return (fromcls->IsDescendantOf(tocls));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
ExpEmit FxExpression::Emit (VMFunctionBuilder *build)
|
ExpEmit FxExpression::Emit (VMFunctionBuilder *build)
|
||||||
{
|
{
|
||||||
ScriptPosition.Message(MSG_ERROR, "Unemitted expression found");
|
ScriptPosition.Message(MSG_ERROR, "Unemitted expression found");
|
||||||
|
@ -1174,21 +1199,9 @@ FxExpression *FxTypeCast::Resolve(FCompileContext &ctx)
|
||||||
if (fromtype->IsDescendantOf(totype)) goto basereturn;
|
if (fromtype->IsDescendantOf(totype)) goto basereturn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (ValueType->IsKindOf(RUNTIME_CLASS(PPointer)))
|
else if (AreCompatiblePointerTypes(ValueType, basex->ValueType))
|
||||||
{
|
{
|
||||||
// Pointers to different types are only compatible if both point to an object and the source type is a child of the destination type.
|
goto basereturn;
|
||||||
if (basex->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)))
|
|
||||||
{
|
|
||||||
auto fromtype = static_cast<PPointer *>(basex->ValueType);
|
|
||||||
auto totype = static_cast<PPointer *>(ValueType);
|
|
||||||
if (fromtype->PointedType->IsKindOf(RUNTIME_CLASS(PClass)) && totype->PointedType->IsKindOf(RUNTIME_CLASS(PClass)))
|
|
||||||
{
|
|
||||||
|
|
||||||
auto fromcls = static_cast<PClass *>(fromtype->PointedType);
|
|
||||||
auto tocls = static_cast<PClass *>(totype->PointedType);
|
|
||||||
if (fromcls->IsDescendantOf(tocls)) goto basereturn;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// todo: pointers to class objects.
|
// todo: pointers to class objects.
|
||||||
// All other types are only compatible to themselves and have already been handled above by the equality check.
|
// All other types are only compatible to themselves and have already been handled above by the equality check.
|
||||||
|
@ -1201,9 +1214,9 @@ errormsg:
|
||||||
|
|
||||||
basereturn:
|
basereturn:
|
||||||
auto x = basex;
|
auto x = basex;
|
||||||
|
x->ValueType = ValueType;
|
||||||
basex = nullptr;
|
basex = nullptr;
|
||||||
delete this;
|
delete this;
|
||||||
x->ValueType = ValueType;
|
|
||||||
return x;
|
return x;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1996,14 +2009,21 @@ bool FxBinary::ResolveLR(FCompileContext& ctx, bool castnumeric)
|
||||||
ValueType = TypeFloat64;
|
ValueType = TypeFloat64;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (left->ValueType->GetRegType() == REGT_POINTER && left->ValueType == right->ValueType)
|
else if (left->ValueType->GetRegType() == REGT_POINTER)
|
||||||
{
|
{
|
||||||
ValueType = left->ValueType;
|
if (left->ValueType == right->ValueType || right->ValueType == TypeNullPtr || left->ValueType == TypeNullPtr ||
|
||||||
|
AreCompatiblePointerTypes(left->ValueType, right->ValueType))
|
||||||
|
{
|
||||||
|
// pointers can only be compared for equality.
|
||||||
|
assert(Operator == TK_Eq || Operator == TK_Neq);
|
||||||
|
ValueType = TypeBool;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ValueType = TypeVoid;
|
ValueType = TypeVoid;
|
||||||
}
|
}
|
||||||
|
assert(ValueType > nullptr && ValueType < (PType*)0xfffffffffffffff);
|
||||||
|
|
||||||
if (castnumeric)
|
if (castnumeric)
|
||||||
{
|
{
|
||||||
|
@ -4191,70 +4211,75 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx)
|
||||||
|
|
||||||
SAFE_RESOLVE(Object, ctx);
|
SAFE_RESOLVE(Object, ctx);
|
||||||
|
|
||||||
if (Object->ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)))
|
if (Object->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)))
|
||||||
{
|
{
|
||||||
PSymbolTable *symtbl;
|
PSymbolTable *symtbl;
|
||||||
PClass *cls = static_cast<PClassPointer *>(Object->ValueType)->ClassRestriction;
|
auto ptype = static_cast<PPointer *>(Object->ValueType)->PointedType;
|
||||||
if ((sym = cls->Symbols.FindSymbolInTable(Identifier, symtbl)) != nullptr)
|
|
||||||
|
if (ptype->IsKindOf(RUNTIME_CLASS(PClass)))
|
||||||
{
|
{
|
||||||
if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst)))
|
PClass *cls = static_cast<PClass *>(ptype);
|
||||||
|
if ((sym = cls->Symbols.FindSymbolInTable(Identifier, symtbl)) != nullptr)
|
||||||
{
|
{
|
||||||
ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as class constant\n", Identifier.GetChars());
|
if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst)))
|
||||||
newex = FxConstant::MakeConstant(sym, ScriptPosition);
|
|
||||||
}
|
|
||||||
else if (sym->IsKindOf(RUNTIME_CLASS(PField)))
|
|
||||||
{
|
|
||||||
PField *vsym = static_cast<PField*>(sym);
|
|
||||||
|
|
||||||
// We have 4 cases to consider here:
|
|
||||||
// 1. The symbol is a static/meta member (not implemented yet) which is always accessible.
|
|
||||||
// 2. This is a static function
|
|
||||||
// 3. This is an action function with a restricted self pointer
|
|
||||||
// 4. This is a normal member or unrestricted action function.
|
|
||||||
if (vsym->Flags & VARF_Deprecated)
|
|
||||||
{
|
{
|
||||||
ScriptPosition.Message(MSG_WARNING, "Accessing deprecated member variable %s", vsym->SymbolName.GetChars());
|
ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as class constant\n", Identifier.GetChars());
|
||||||
|
newex = FxConstant::MakeConstant(sym, ScriptPosition);
|
||||||
}
|
}
|
||||||
if ((vsym->Flags & VARF_Private) && symtbl != &ctx.Class->Symbols)
|
else if (sym->IsKindOf(RUNTIME_CLASS(PField)))
|
||||||
{
|
{
|
||||||
ScriptPosition.Message(MSG_ERROR, "Private member %s not accessible", vsym->SymbolName.GetChars());
|
PField *vsym = static_cast<PField*>(sym);
|
||||||
|
|
||||||
|
// We have 4 cases to consider here:
|
||||||
|
// 1. The symbol is a static/meta member (not implemented yet) which is always accessible.
|
||||||
|
// 2. This is a static function
|
||||||
|
// 3. This is an action function with a restricted self pointer
|
||||||
|
// 4. This is a normal member or unrestricted action function.
|
||||||
|
if (vsym->Flags & VARF_Deprecated)
|
||||||
|
{
|
||||||
|
ScriptPosition.Message(MSG_WARNING, "Accessing deprecated member variable %s", vsym->SymbolName.GetChars());
|
||||||
|
}
|
||||||
|
if ((vsym->Flags & VARF_Private) && symtbl != &ctx.Class->Symbols)
|
||||||
|
{
|
||||||
|
ScriptPosition.Message(MSG_ERROR, "Private member %s not accessible", vsym->SymbolName.GetChars());
|
||||||
|
delete this;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vsym->Flags & VARF_Static)
|
||||||
|
{
|
||||||
|
// todo. For now these cannot be defined so let's just exit.
|
||||||
|
ScriptPosition.Message(MSG_ERROR, "Static members not implemented yet.");
|
||||||
|
delete this;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
auto x = new FxClassMember(Object, vsym, ScriptPosition);
|
||||||
|
delete this;
|
||||||
|
return x->Resolve(ctx);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ScriptPosition.Message(MSG_ERROR, "Invalid member identifier '%s'\n", Identifier.GetChars());
|
||||||
delete this;
|
delete this;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vsym->Flags & VARF_Static)
|
|
||||||
{
|
|
||||||
// todo. For now these cannot be defined so let's just exit.
|
|
||||||
ScriptPosition.Message(MSG_ERROR, "Static members not implemented yet.");
|
|
||||||
delete this;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
auto x = new FxClassMember(Object, vsym, ScriptPosition);
|
|
||||||
delete this;
|
|
||||||
return x->Resolve(ctx);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ScriptPosition.Message(MSG_ERROR, "Invalid member identifier '%s'\n", Identifier.GetChars());
|
ScriptPosition.Message(MSG_ERROR, "Unknown identifier '%s'", Identifier.GetChars());
|
||||||
delete this;
|
delete this;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else if (ptype->IsA(RUNTIME_CLASS(PStruct)))
|
||||||
{
|
{
|
||||||
ScriptPosition.Message(MSG_ERROR, "Unknown identifier '%s'", Identifier.GetChars());
|
// todo
|
||||||
delete this;
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Object->ValueType->IsA(RUNTIME_CLASS(PStruct)))
|
else if (Object->ValueType->IsA(RUNTIME_CLASS(PStruct)))
|
||||||
{
|
{
|
||||||
// todo
|
// todo
|
||||||
}
|
}
|
||||||
else if (Object->ValueType->IsA(RUNTIME_CLASS(PPointer)))
|
|
||||||
{
|
|
||||||
// todo
|
|
||||||
}
|
|
||||||
|
|
||||||
ScriptPosition.Message(MSG_ERROR, "Left side of %s is not a struct or class", Identifier.GetChars());
|
ScriptPosition.Message(MSG_ERROR, "Left side of %s is not a struct or class", Identifier.GetChars());
|
||||||
delete this;
|
delete this;
|
||||||
|
|
|
@ -380,7 +380,7 @@ public:
|
||||||
isresolved = true;
|
isresolved = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
FxConstant(nullptr_t *nullp, const FScriptPosition &pos) : FxExpression(pos)
|
FxConstant(const FScriptPosition &pos) : FxExpression(pos)
|
||||||
{
|
{
|
||||||
value.pointer = nullptr;
|
value.pointer = nullptr;
|
||||||
ValueType = value.Type = TypeNullPtr;
|
ValueType = value.Type = TypeNullPtr;
|
||||||
|
|
|
@ -636,7 +636,7 @@ void InitThingdef()
|
||||||
// Define some member variables we feel like exposing to the user
|
// Define some member variables we feel like exposing to the user
|
||||||
PSymbolTable &symt = RUNTIME_CLASS(AActor)->Symbols;
|
PSymbolTable &symt = RUNTIME_CLASS(AActor)->Symbols;
|
||||||
PType *array5 = NewArray(TypeSInt32, 5);
|
PType *array5 = NewArray(TypeSInt32, 5);
|
||||||
PType *TypeActor = NewClassPointer(RUNTIME_CLASS(AActor));
|
PType *TypeActor = NewPointer(RUNTIME_CLASS(AActor));
|
||||||
symt.AddSymbol(new PField(NAME_Alpha, TypeFloat64, VARF_Native, myoffsetof(AActor, Alpha)));
|
symt.AddSymbol(new PField(NAME_Alpha, TypeFloat64, VARF_Native, myoffsetof(AActor, Alpha)));
|
||||||
symt.AddSymbol(new PField(NAME_Angle, TypeFloat64, VARF_Native, myoffsetof(AActor, Angles.Yaw)));
|
symt.AddSymbol(new PField(NAME_Angle, TypeFloat64, VARF_Native, myoffsetof(AActor, Angles.Yaw)));
|
||||||
symt.AddSymbol(new PField(NAME_Args, array5, VARF_Native, myoffsetof(AActor, args)));
|
symt.AddSymbol(new PField(NAME_Args, array5, VARF_Native, myoffsetof(AActor, args)));
|
||||||
|
|
|
@ -1450,6 +1450,14 @@ constant(X) ::= TRUE(A).
|
||||||
NEW_INTCONST_NODE(boolconst, TypeBool, true, A);
|
NEW_INTCONST_NODE(boolconst, TypeBool, true, A);
|
||||||
X = boolconst;
|
X = boolconst;
|
||||||
}
|
}
|
||||||
|
constant(X) ::= NULLPTR(A).
|
||||||
|
{
|
||||||
|
NEW_AST_NODE(ExprConstant, nullptrconst, A);
|
||||||
|
nullptrconst->Operation = PEX_ConstValue;
|
||||||
|
nullptrconst->Type = TypeNullPtr;
|
||||||
|
nullptrconst->StringVal = nullptr;
|
||||||
|
X = nullptrconst;
|
||||||
|
}
|
||||||
|
|
||||||
/************ Statements ************/
|
/************ Statements ************/
|
||||||
|
|
||||||
|
|
|
@ -1462,6 +1462,10 @@ PType *ZCCCompiler::ResolveUserType(ZCC_BasicType *type, PSymbolTable *symt)
|
||||||
{
|
{
|
||||||
return TypeSInt32; // hack this to an integer until we can resolve the enum mess.
|
return TypeSInt32; // hack this to an integer until we can resolve the enum mess.
|
||||||
}
|
}
|
||||||
|
if (type->IsKindOf(RUNTIME_CLASS(PClass)))
|
||||||
|
{
|
||||||
|
return NewPointer(type);
|
||||||
|
}
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
return TypeError;
|
return TypeError;
|
||||||
|
@ -2353,6 +2357,8 @@ static FxExpression *ModifyAssign(FxBinary *operation, FxExpression *left)
|
||||||
|
|
||||||
FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast)
|
FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast)
|
||||||
{
|
{
|
||||||
|
if (ast == nullptr) return nullptr;
|
||||||
|
|
||||||
// Note: Do not call 'Simplify' here because that function tends to destroy identifiers due to lack of context in which to resolve them.
|
// Note: Do not call 'Simplify' here because that function tends to destroy identifiers due to lack of context in which to resolve them.
|
||||||
// The Fx nodes created here will be better suited for that.
|
// The Fx nodes created here will be better suited for that.
|
||||||
switch (ast->NodeType)
|
switch (ast->NodeType)
|
||||||
|
@ -2436,6 +2442,10 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast)
|
||||||
{
|
{
|
||||||
return new FxConstant(*cnst->StringVal, *ast);
|
return new FxConstant(*cnst->StringVal, *ast);
|
||||||
}
|
}
|
||||||
|
else if (cnst->Type == TypeNullPtr)
|
||||||
|
{
|
||||||
|
return new FxConstant(*ast);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// can there be other types?
|
// can there be other types?
|
||||||
|
|
|
@ -154,7 +154,7 @@ static void InitTokenMap()
|
||||||
TOKENDEF (TK_Out, ZCC_OUT);
|
TOKENDEF (TK_Out, ZCC_OUT);
|
||||||
TOKENDEF (TK_Optional, ZCC_OPTIONAL);
|
TOKENDEF (TK_Optional, ZCC_OPTIONAL);
|
||||||
TOKENDEF (TK_Super, ZCC_SUPER);
|
TOKENDEF (TK_Super, ZCC_SUPER);
|
||||||
TOKENDEF (TK_Null, ZCC_NULL);
|
TOKENDEF (TK_Null, ZCC_NULLPTR);
|
||||||
TOKENDEF (TK_Self, ZCC_SELF);
|
TOKENDEF (TK_Self, ZCC_SELF);
|
||||||
TOKENDEF ('~', ZCC_TILDE);
|
TOKENDEF ('~', ZCC_TILDE);
|
||||||
TOKENDEF ('!', ZCC_BANG);
|
TOKENDEF ('!', ZCC_BANG);
|
||||||
|
|
Loading…
Reference in a new issue