Allow calling const methods on readonly structs

This commit is contained in:
ZZYZX 2017-02-17 19:25:29 +02:00
parent 0f031c5f22
commit 338e676e73
3 changed files with 27 additions and 23 deletions

View file

@ -167,7 +167,8 @@ void FCompileContext::CheckReturn(PPrototype *proto, FScriptPosition &pos)
} }
} }
bool FCompileContext::CheckReadOnly(int flags) // [ZZ] I find it really dumb that something called CheckReadOnly returns false for readonly. renamed.
bool FCompileContext::CheckWritable(int flags)
{ {
if (!(flags & VARF_ReadOnly)) return false; if (!(flags & VARF_ReadOnly)) return false;
if (!(flags & VARF_InternalAccess)) return true; if (!(flags & VARF_InternalAccess)) return true;
@ -6202,7 +6203,7 @@ FxExpression *FxLocalVariable::Resolve(FCompileContext &ctx)
bool FxLocalVariable::RequestAddress(FCompileContext &ctx, bool *writable) bool FxLocalVariable::RequestAddress(FCompileContext &ctx, bool *writable)
{ {
AddressRequested = true; AddressRequested = true;
if (writable != nullptr) *writable = !ctx.CheckReadOnly(Variable->VarFlags); if (writable != nullptr) *writable = !ctx.CheckWritable(Variable->VarFlags);
return true; return true;
} }
@ -6420,7 +6421,7 @@ FxGlobalVariable::FxGlobalVariable(PField* mem, const FScriptPosition &pos)
bool FxGlobalVariable::RequestAddress(FCompileContext &ctx, bool *writable) bool FxGlobalVariable::RequestAddress(FCompileContext &ctx, bool *writable)
{ {
AddressRequested = true; AddressRequested = true;
if (writable != nullptr) *writable = AddressWritable && !ctx.CheckReadOnly(membervar->Flags); if (writable != nullptr) *writable = AddressWritable && !ctx.CheckWritable(membervar->Flags);
return true; return true;
} }
@ -6610,7 +6611,7 @@ FxStackVariable::~FxStackVariable()
bool FxStackVariable::RequestAddress(FCompileContext &ctx, bool *writable) bool FxStackVariable::RequestAddress(FCompileContext &ctx, bool *writable)
{ {
AddressRequested = true; AddressRequested = true;
if (writable != nullptr) *writable = AddressWritable && !ctx.CheckReadOnly(membervar->Flags); if (writable != nullptr) *writable = AddressWritable && !ctx.CheckWritable(membervar->Flags);
return true; return true;
} }
@ -6708,7 +6709,7 @@ bool FxStructMember::RequestAddress(FCompileContext &ctx, bool *writable)
return false; return false;
} }
AddressRequested = true; AddressRequested = true;
if (writable != nullptr) *writable = (AddressWritable && !ctx.CheckReadOnly(membervar->Flags) && if (writable != nullptr) *writable = (AddressWritable && !ctx.CheckWritable(membervar->Flags) &&
(!classx->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) || !static_cast<PPointer*>(classx->ValueType)->IsConst)); (!classx->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) || !static_cast<PPointer*>(classx->ValueType)->IsConst));
return true; return true;
} }
@ -7618,6 +7619,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
PStruct *cls; PStruct *cls;
bool staticonly = false; bool staticonly = false;
bool novirtual = false; bool novirtual = false;
bool isreadonly = false;
PStruct *ccls = nullptr; PStruct *ccls = nullptr;
@ -7912,7 +7914,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
auto x = new FxGetParentClass(Self); auto x = new FxGetParentClass(Self);
return x->Resolve(ctx); return x->Resolve(ctx);
} }
if (Self->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && !Self->ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer))) if (Self->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && !Self->ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)))
{ {
auto ptype = static_cast<PPointer *>(Self->ValueType)->PointedType; auto ptype = static_cast<PPointer *>(Self->ValueType)->PointedType;
@ -7943,18 +7945,11 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
else if (Self->ValueType->IsKindOf(RUNTIME_CLASS(PStruct))) else if (Self->ValueType->IsKindOf(RUNTIME_CLASS(PStruct)))
{ {
bool writable; bool writable;
if (Self->RequestAddress(ctx, &writable) && writable)
{ // [ZZ] allow const method to be called on a readonly struct
cls = static_cast<PStruct*>(Self->ValueType); isreadonly = !(Self->RequestAddress(ctx, &writable) && writable);
Self->ValueType = NewPointer(Self->ValueType); cls = static_cast<PStruct*>(Self->ValueType);
} Self->ValueType = NewPointer(Self->ValueType);
else
{
// Cannot be made writable so we cannot use its methods.
ScriptPosition.Message(MSG_ERROR, "Invalid expression on left hand side of %s\n", MethodName.GetChars());
delete this;
return nullptr;
}
} }
else else
{ {
@ -7981,6 +7976,15 @@ isresolved:
return nullptr; return nullptr;
} }
if (isreadonly && !(afd->Variants[0].Flags & VARF_ReadOnly))
{
// Cannot be made writable so we cannot use its methods.
// [ZZ] Why this esoteric message?
ScriptPosition.Message(MSG_ERROR, "Readonly struct on left hand side of %s not allowed\n", MethodName.GetChars());
delete this;
return nullptr;
}
if (staticonly && (afd->Variants[0].Flags & VARF_Method)) if (staticonly && (afd->Variants[0].Flags & VARF_Method))
{ {
if (!novirtual || !(afd->Variants[0].Flags & VARF_Virtual)) if (!novirtual || !(afd->Variants[0].Flags & VARF_Virtual))

View file

@ -219,7 +219,7 @@ struct FCompileContext
void HandleJumps(int token, FxExpression *handler); void HandleJumps(int token, FxExpression *handler);
void CheckReturn(PPrototype *proto, FScriptPosition &pos); void CheckReturn(PPrototype *proto, FScriptPosition &pos);
bool CheckReadOnly(int flags); bool CheckWritable(int flags);
FxLocalVariableDeclaration *FindLocalVariable(FName name); FxLocalVariableDeclaration *FindLocalVariable(FName name);
}; };

View file

@ -579,10 +579,10 @@ struct StringStruct native
native vararg void AppendFormat(String fmt, ...); native vararg void AppendFormat(String fmt, ...);
native void Replace(String pattern, String replacement); native void Replace(String pattern, String replacement);
native String Mid(int pos = 0, int len = 2147483647); native String Mid(int pos = 0, int len = 2147483647) const;
native int Len(); native int Len() const;
native String CharAt(int pos); native String CharAt(int pos) const;
native int CharCodeAt(int pos); native int CharCodeAt(int pos) const;
} }
class Floor : Thinker native class Floor : Thinker native