diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index fc18f481ba..1ea2565cb4 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -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_InternalAccess)) return true; @@ -6202,7 +6203,7 @@ FxExpression *FxLocalVariable::Resolve(FCompileContext &ctx) bool FxLocalVariable::RequestAddress(FCompileContext &ctx, bool *writable) { AddressRequested = true; - if (writable != nullptr) *writable = !ctx.CheckReadOnly(Variable->VarFlags); + if (writable != nullptr) *writable = !ctx.CheckWritable(Variable->VarFlags); return true; } @@ -6420,7 +6421,7 @@ FxGlobalVariable::FxGlobalVariable(PField* mem, const FScriptPosition &pos) bool FxGlobalVariable::RequestAddress(FCompileContext &ctx, bool *writable) { AddressRequested = true; - if (writable != nullptr) *writable = AddressWritable && !ctx.CheckReadOnly(membervar->Flags); + if (writable != nullptr) *writable = AddressWritable && !ctx.CheckWritable(membervar->Flags); return true; } @@ -6610,7 +6611,7 @@ FxStackVariable::~FxStackVariable() bool FxStackVariable::RequestAddress(FCompileContext &ctx, bool *writable) { AddressRequested = true; - if (writable != nullptr) *writable = AddressWritable && !ctx.CheckReadOnly(membervar->Flags); + if (writable != nullptr) *writable = AddressWritable && !ctx.CheckWritable(membervar->Flags); return true; } @@ -6708,7 +6709,7 @@ bool FxStructMember::RequestAddress(FCompileContext &ctx, bool *writable) return false; } 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(classx->ValueType)->IsConst)); return true; } @@ -7618,6 +7619,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) PStruct *cls; bool staticonly = false; bool novirtual = false; + bool isreadonly = false; PStruct *ccls = nullptr; @@ -7912,7 +7914,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) auto x = new FxGetParentClass(Self); return x->Resolve(ctx); } - + if (Self->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && !Self->ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer))) { auto ptype = static_cast(Self->ValueType)->PointedType; @@ -7943,18 +7945,11 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) else if (Self->ValueType->IsKindOf(RUNTIME_CLASS(PStruct))) { bool writable; - if (Self->RequestAddress(ctx, &writable) && writable) - { - cls = static_cast(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; - } + + // [ZZ] allow const method to be called on a readonly struct + isreadonly = !(Self->RequestAddress(ctx, &writable) && writable); + cls = static_cast(Self->ValueType); + Self->ValueType = NewPointer(Self->ValueType); } else { @@ -7981,6 +7976,15 @@ isresolved: 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 (!novirtual || !(afd->Variants[0].Flags & VARF_Virtual)) diff --git a/src/scripting/backend/codegen.h b/src/scripting/backend/codegen.h index ecdeaec156..c8120f4d16 100644 --- a/src/scripting/backend/codegen.h +++ b/src/scripting/backend/codegen.h @@ -219,7 +219,7 @@ struct FCompileContext void HandleJumps(int token, FxExpression *handler); void CheckReturn(PPrototype *proto, FScriptPosition &pos); - bool CheckReadOnly(int flags); + bool CheckWritable(int flags); FxLocalVariableDeclaration *FindLocalVariable(FName name); }; diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index bffee91f01..208023b540 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -579,10 +579,10 @@ struct StringStruct native native vararg void AppendFormat(String fmt, ...); native void Replace(String pattern, String replacement); - native String Mid(int pos = 0, int len = 2147483647); - native int Len(); - native String CharAt(int pos); - native int CharCodeAt(int pos); + native String Mid(int pos = 0, int len = 2147483647) const; + native int Len() const; + native String CharAt(int pos) const; + native int CharCodeAt(int pos) const; } class Floor : Thinker native