From 24925c88a80e24478883a47dab8e5000e34b3e61 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 5 Nov 2016 13:51:46 +0100 Subject: [PATCH] - added readonly pointers. They need to be defined with 'readonly'. These are significantly different from declaring a field readonly in that they do not disallow modification of the variable itself but what it points to. For the actor defaults this is necessary to prevent accidental modification. A readonly pointer is actually a different type than a regular pointer. - fixed code generation for dynamic cast. It was missing the jump instruction after the compare. --- src/dobjtype.cpp | 14 +++++++------- src/dobjtype.h | 5 +++-- src/scripting/codegeneration/codegen.cpp | 19 +++++++++++++++---- src/scripting/zscript/zcc-parse.lemon | 16 +++++++++++++++- src/scripting/zscript/zcc_compile.cpp | 10 +++++----- src/scripting/zscript/zcc_parser.h | 1 + wadsrc/static/zscript/actor.txt | 2 +- 7 files changed, 47 insertions(+), 20 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index f1726adbf1..1b5d3bc7ec 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -1467,7 +1467,7 @@ END_POINTERS //========================================================================== PPointer::PPointer() -: PBasicType(sizeof(void *), __alignof(void *)), PointedType(NULL) +: PBasicType(sizeof(void *), __alignof(void *)), PointedType(NULL), IsConst(false) { mDescriptiveName = "NullPointer"; SetOps(); @@ -1479,10 +1479,10 @@ PPointer::PPointer() // //========================================================================== -PPointer::PPointer(PType *pointsat) -: PBasicType(sizeof(void *), __alignof(void *)), PointedType(pointsat) +PPointer::PPointer(PType *pointsat, bool isconst) +: PBasicType(sizeof(void *), __alignof(void *)), PointedType(pointsat), IsConst(isconst) { - mDescriptiveName.Format("Pointer<%s>", pointsat->DescriptiveName()); + mDescriptiveName.Format("Pointer<%s%s>", pointsat->DescriptiveName(), isconst? "readonly " : ""); SetOps(); } @@ -1570,14 +1570,14 @@ bool PPointer::ReadValue(FSerializer &ar, const char *key, void *addr) const // //========================================================================== -PPointer *NewPointer(PType *type) +PPointer *NewPointer(PType *type, bool isconst) { size_t bucket; - PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PPointer), (intptr_t)type, 0, &bucket); + PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PPointer), (intptr_t)type, isconst ? 1 : 0, &bucket); if (ptype == NULL) { ptype = new PPointer(type); - TypeTable.AddType(ptype, RUNTIME_CLASS(PPointer), (intptr_t)type, 0, bucket); + TypeTable.AddType(ptype, RUNTIME_CLASS(PPointer), (intptr_t)type, isconst ? 1 : 0, bucket); } return static_cast(ptype); } diff --git a/src/dobjtype.h b/src/dobjtype.h index 30e22e8680..9cf6639831 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -535,9 +535,10 @@ class PPointer : public PBasicType HAS_OBJECT_POINTERS; public: PPointer(); - PPointer(PType *pointsat); + PPointer(PType *pointsat, bool isconst = false); PType *PointedType; + bool IsConst; virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; @@ -877,7 +878,7 @@ PVector *NewVector(unsigned int size); PMap *NewMap(PType *keytype, PType *valuetype); PArray *NewArray(PType *type, unsigned int count); PDynArray *NewDynArray(PType *type); -PPointer *NewPointer(PType *type); +PPointer *NewPointer(PType *type, bool isconst = false); PClassPointer *NewClassPointer(PClass *restrict); PEnum *NewEnum(FName name, PTypeBase *outer); PStruct *NewStruct(FName name, PTypeBase *outer); diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index f19e8901f3..39034c7521 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -241,6 +241,7 @@ static bool AreCompatiblePointerTypes(PType *dest, PType *source) auto fromtype = static_cast(source); auto totype = static_cast(dest); if (fromtype == nullptr) return true; + if (totype->IsConst && !fromtype->IsConst) return false; if (fromtype == totype) return true; if (fromtype->PointedType->IsKindOf(RUNTIME_CLASS(PClass)) && totype->PointedType->IsKindOf(RUNTIME_CLASS(PClass))) { @@ -3852,8 +3853,7 @@ ExpEmit FxTypeCheck::Emit(VMFunctionBuilder *build) FxDynamicCast::FxDynamicCast(PClass * cls, FxExpression *r) : FxExpression(EFX_DynamicCast, r->ScriptPosition) { - expr = new FxTypeCast(r, NewPointer(RUNTIME_CLASS(DObject)), true, true); - ValueType = NewPointer(cls); + expr = r; CastType = cls; } @@ -3878,6 +3878,15 @@ FxExpression *FxDynamicCast::Resolve(FCompileContext& ctx) { CHECKRESOLVED(); SAFE_RESOLVE(expr, ctx); + bool constflag = expr->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast(expr->ValueType)->IsConst; + expr = new FxTypeCast(expr, NewPointer(RUNTIME_CLASS(DObject), constflag), true, true); + expr = expr->Resolve(ctx); + if (expr == nullptr) + { + delete this; + return nullptr; + } + ValueType = NewPointer(CastType, constflag); return this; } @@ -3903,7 +3912,8 @@ ExpEmit FxDynamicCast::Emit(VMFunctionBuilder *build) build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2, 1); build->Emit(OP_RESULT, 0, REGT_INT, check.RegNum); - auto patch = build->Emit(OP_EQ_K, 0, check.RegNum, build->GetConstantInt(0)); + build->Emit(OP_EQ_K, 0, check.RegNum, build->GetConstantInt(0)); + auto patch = build->Emit(OP_JMP, 0); build->Emit(OP_LKP, out.RegNum, build->GetConstantAddress(nullptr, ATAG_OBJECT)); build->BackpatchToHere(patch); return out; @@ -5439,7 +5449,8 @@ FxStructMember::~FxStructMember() bool FxStructMember::RequestAddress(bool *writable) { AddressRequested = true; - if (writable != nullptr) *writable = AddressWritable && !(membervar->Flags & VARF_ReadOnly); + if (writable != nullptr) *writable = (AddressWritable && !(membervar->Flags & VARF_ReadOnly) && + (!classx->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) || !static_cast(classx->ValueType)->IsConst)); return true; } diff --git a/src/scripting/zscript/zcc-parse.lemon b/src/scripting/zscript/zcc-parse.lemon index 9d22765fc2..666eff5a2a 100644 --- a/src/scripting/zscript/zcc-parse.lemon +++ b/src/scripting/zscript/zcc-parse.lemon @@ -668,6 +668,7 @@ type_name(X) ::= type_name1(A). NEW_AST_NODE(BasicType, type, A); type->Type = (EZCCBuiltinType)A.Int; type->UserType = NULL; + type->isconst = false; X = type; } type_name(X) ::= IDENTIFIER(A). /* User-defined type (struct, enum, or class) */ @@ -676,14 +677,27 @@ type_name(X) ::= IDENTIFIER(A). /* User-defined type (struct, enum, or class) NEW_AST_NODE(Identifier, id, A); type->Type = ZCC_UserType; type->UserType = id; + type->isconst = false; id->Id = A.Name(); X = type; } +type_name(X) ::= READONLY LT IDENTIFIER(A) GT. +{ + NEW_AST_NODE(BasicType, type, A); + NEW_AST_NODE(Identifier, id, A); + type->Type = ZCC_UserType; + type->UserType = id; + type->isconst = true; + id->Id = A.Name(); + X = type; +} + type_name(X) ::= DOT dottable_id(A). { NEW_AST_NODE(BasicType, type, A); type->Type = ZCC_UserType; type->UserType = A; + type->isconst = false; X = type; } @@ -698,7 +712,7 @@ type_name(X) ::= DOT dottable_id(A). %type type_list {ZCC_Type *} %type type_list_or_void {ZCC_Type *} %type type_or_array {ZCC_Type *} -%type class_restrictor {ZCC_Identifier *} + %type class_restrictor {ZCC_Identifier *} %type array_size{ZCC_Expression *} %type array_size_expr{ZCC_Expression *} diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index f296a91b6c..d6bf1d7f34 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -1481,16 +1481,16 @@ PType *ZCCCompiler::ResolveUserType(ZCC_BasicType *type, PSymbolTable *symt) if (sym == nullptr && symt != &GlobalSymbols) sym = GlobalSymbols.FindSymbolInTable(type->UserType->Id, table); if (sym != nullptr && sym->IsKindOf(RUNTIME_CLASS(PSymbolType))) { - auto type = static_cast(sym)->Type; - if (type->IsKindOf(RUNTIME_CLASS(PEnum))) + auto ptype = static_cast(sym)->Type; + if (ptype->IsKindOf(RUNTIME_CLASS(PEnum))) { return TypeSInt32; // hack this to an integer until we can resolve the enum mess. } - if (type->IsKindOf(RUNTIME_CLASS(PClass))) + if (ptype->IsKindOf(RUNTIME_CLASS(PClass))) { - return NewPointer(type); + return NewPointer(ptype, type->isconst); } - return type; + return ptype; } Error(type, "Unable to resolve %s as type.", FName(type->UserType->Id).GetChars()); return TypeError; diff --git a/src/scripting/zscript/zcc_parser.h b/src/scripting/zscript/zcc_parser.h index 715fa0be65..01ea0d2d07 100644 --- a/src/scripting/zscript/zcc_parser.h +++ b/src/scripting/zscript/zcc_parser.h @@ -310,6 +310,7 @@ struct ZCC_BasicType : ZCC_Type { EZCCBuiltinType Type; ZCC_Identifier *UserType; + bool isconst; }; struct ZCC_MapType : ZCC_Type diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index c6175b6f10..fdadab53c6 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -53,7 +53,7 @@ class Actor : Thinker native return GetPointer(ptr_select1) == GetPointer(ptr_select2); } - native static /*readonly*/ Actor GetDefaultByType(class cls); + native static readonly GetDefaultByType(class cls); native void SetDamage(int dmg); native static bool isDehState(state st); native void SetOrigin(vector3 newpos, bool moving);