make const actually work, and add unsafe(const) for old behavior

This commit is contained in:
Ricardo Luís Vaz Silva 2025-02-07 19:39:27 -03:00
parent 236c9b4224
commit 7e86116ab1
9 changed files with 25 additions and 16 deletions

View file

@ -177,6 +177,7 @@ std2:
/* Other keywords from UnrealScript */
'abstract' { RET(TK_Abstract); }
'foreach' { RET(ParseVersion >= MakeVersion(4, 10, 0)? TK_ForEach : TK_Identifier); }
'unsafe' { RET(ParseVersion >= MakeVersion(4, 15, 0)? TK_Unsafe : TK_Identifier); }
'true' { RET(TK_True); }
'false' { RET(TK_False); }
'none' { RET(TK_None); }

View file

@ -80,6 +80,7 @@ xx(TK_Color, "'color'")
xx(TK_Goto, "'goto'")
xx(TK_Abstract, "'abstract'")
xx(TK_ForEach, "'foreach'")
xx(TK_Unsafe, "'unsafe'")
xx(TK_True, "'true'")
xx(TK_False, "'false'")
xx(TK_None, "'none'")

View file

@ -6701,7 +6701,7 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx)
}
FxExpression *self = new FxSelf(ScriptPosition);
self = self->Resolve(ctx);
newex = ResolveMember(ctx, ctx.Function->Variants[0].SelfClass, self, ctx.Function->Variants[0].SelfClass);
newex = ResolveMember(ctx, ctx.Function->Variants[0].SelfClass, self, ctx.Function->Variants[0].SelfClass, ctx.Function->Variants[0].Flags & VARF_SafeConst);
ABORT(newex);
goto foundit;
}
@ -6863,7 +6863,7 @@ foundit:
//
//==========================================================================
FxExpression *FxIdentifier::ResolveMember(FCompileContext &ctx, PContainerType *classctx, FxExpression *&object, PContainerType *objtype)
FxExpression *FxIdentifier::ResolveMember(FCompileContext &ctx, PContainerType *classctx, FxExpression *&object, PContainerType *objtype, bool isConst)
{
PSymbol *sym;
PSymbolTable *symtbl;
@ -6956,7 +6956,7 @@ FxExpression *FxIdentifier::ResolveMember(FCompileContext &ctx, PContainerType *
}
}
auto x = isclass ? new FxClassMember(object, vsym, ScriptPosition) : new FxStructMember(object, vsym, ScriptPosition);
auto x = isclass ? new FxClassMember(object, vsym, ScriptPosition, isConst) : new FxStructMember(object, vsym, ScriptPosition, isConst);
object = nullptr;
return x->Resolve(ctx);
}
@ -7611,8 +7611,8 @@ FxMemberBase::FxMemberBase(EFxType type, PField *f, const FScriptPosition &p)
}
FxStructMember::FxStructMember(FxExpression *x, PField* mem, const FScriptPosition &pos)
: FxMemberBase(EFX_StructMember, mem, pos)
FxStructMember::FxStructMember(FxExpression *x, PField* mem, const FScriptPosition &pos, bool isConst)
: FxMemberBase(EFX_StructMember, mem, pos), IsConst(isConst)
{
classx = x;
}
@ -7662,7 +7662,7 @@ bool FxStructMember::RequestAddress(FCompileContext &ctx, bool *writable)
bWritable = false;
}
*writable = bWritable;
*writable = bWritable && !IsConst;
}
return true;
}
@ -7873,8 +7873,8 @@ ExpEmit FxStructMember::Emit(VMFunctionBuilder *build)
//
//==========================================================================
FxClassMember::FxClassMember(FxExpression *x, PField* mem, const FScriptPosition &pos)
: FxStructMember(x, mem, pos)
FxClassMember::FxClassMember(FxExpression *x, PField* mem, const FScriptPosition &pos, bool isConst)
: FxStructMember(x, mem, pos, isConst)
{
ExprType = EFX_ClassMember;
}

View file

@ -396,7 +396,7 @@ public:
FxIdentifier(FName i, const FScriptPosition &p);
FxExpression *Resolve(FCompileContext&);
FxExpression *ResolveMember(FCompileContext&, PContainerType*, FxExpression*&, PContainerType*);
FxExpression *ResolveMember(FCompileContext&, PContainerType*, FxExpression*&, PContainerType*, bool isConst = false);
};
@ -1475,8 +1475,9 @@ class FxStructMember : public FxMemberBase
{
public:
FxExpression *classx;
bool IsConst;
FxStructMember(FxExpression*, PField*, const FScriptPosition&);
FxStructMember(FxExpression*, PField*, const FScriptPosition&, bool isConst = false);
~FxStructMember();
FxExpression *Resolve(FCompileContext&);
bool RequestAddress(FCompileContext &ctx, bool *writable);
@ -1494,7 +1495,7 @@ class FxClassMember : public FxStructMember
{
public:
FxClassMember(FxExpression*, PField*, const FScriptPosition&);
FxClassMember(FxExpression*, PField*, const FScriptPosition&, bool isConst = false);
};
//==========================================================================

View file

@ -37,6 +37,7 @@ enum
VARF_VirtualScope = (1<<22), // [ZZ] virtualscope: object should use the scope of the particular class it's being used with (methods only)
VARF_ClearScope = (1<<23), // [ZZ] clearscope: this method ignores the member access chain that leads to it and is always plain data.
VARF_Abstract = (1<<24), // [Player701] Function does not have a body and must be overridden in subclasses
VARF_SafeConst = (1<<25), // [Jay] properly-working const function/unsafe clearscope field
};
// Basic information shared by all types ------------------------------------

View file

@ -1316,8 +1316,9 @@ decl_flag(X) ::= PLAY(T). { X.Int = ZCC_Play; X.SourceLoc = T.SourceLoc; }
decl_flag(X) ::= CLEARSCOPE(T). { X.Int = ZCC_ClearScope; X.SourceLoc = T.SourceLoc; }
decl_flag(X) ::= VIRTUALSCOPE(T). { X.Int = ZCC_VirtualScope; X.SourceLoc = T.SourceLoc; }
func_const(X) ::= . { X.Int = 0; X.SourceLoc = stat->sc->GetMessageLine(); }
func_const(X) ::= CONST(T). { X.Int = ZCC_FuncConst; X.SourceLoc = T.SourceLoc; }
func_const(X) ::= . { X.Int = 0; X.SourceLoc = stat->sc->GetMessageLine(); }
func_const(X) ::= CONST(T). { X.Int = ZCC_FuncConst; X.SourceLoc = T.SourceLoc; }
func_const(X) ::= UNSAFE(T) LPAREN CONST RPAREN. { X.Int = ZCC_FuncConstUnsafe; X.SourceLoc = T.SourceLoc; }
opt_func_body(X) ::= SEMICOLON. { X = NULL; }
opt_func_body(X) ::= function_body(X).

View file

@ -1475,8 +1475,8 @@ bool ZCCCompiler::CompileFields(PContainerType *type, TArray<ZCC_VarDeclarator *
// For structs only allow 'deprecated', for classes exclude function qualifiers.
int notallowed = forstruct?
ZCC_Latent | ZCC_Final | ZCC_Action | ZCC_Static | ZCC_FuncConst | ZCC_Abstract | ZCC_Virtual | ZCC_Override | ZCC_Meta | ZCC_Extension | ZCC_VirtualScope | ZCC_ClearScope :
ZCC_Latent | ZCC_Final | ZCC_Action | ZCC_Static | ZCC_FuncConst | ZCC_Abstract | ZCC_Virtual | ZCC_Override | ZCC_Extension | ZCC_VirtualScope | ZCC_ClearScope;
ZCC_Latent | ZCC_Final | ZCC_Action | ZCC_Static | ZCC_FuncConst | ZCC_FuncConstUnsafe | ZCC_Abstract | ZCC_Virtual | ZCC_Override | ZCC_Meta | ZCC_Extension | ZCC_VirtualScope | ZCC_ClearScope :
ZCC_Latent | ZCC_Final | ZCC_Action | ZCC_Static | ZCC_FuncConst | ZCC_FuncConstUnsafe | ZCC_Abstract | ZCC_Virtual | ZCC_Override | ZCC_Extension | ZCC_VirtualScope | ZCC_ClearScope;
// Some internal fields need to be set to clearscope.
if (fileSystem.GetFileContainer(Lump) == 0) notallowed &= ~ZCC_ClearScope;
@ -2446,7 +2446,9 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
if (f->Flags & ZCC_Override) varflags |= VARF_Override;
if (f->Flags & ZCC_Abstract) varflags |= VARF_Abstract;
if (f->Flags & ZCC_VarArg) varflags |= VARF_VarArg;
if (f->Flags & ZCC_FuncConst) varflags |= VARF_ReadOnly; // FuncConst method is internally marked as VARF_ReadOnly
if (f->Flags & ZCC_FuncConst) varflags |= (mVersion >= MakeVersion(4, 15, 0) ? VARF_ReadOnly | VARF_SafeConst : VARF_ReadOnly); // FuncConst method is internally marked as VARF_ReadOnly
if (f->Flags & ZCC_FuncConstUnsafe) varflags |= VARF_ReadOnly;
if (mVersion >= MakeVersion(2, 4, 0))
{
if (c->Type()->ScopeFlags & Scope_UI)

View file

@ -251,6 +251,7 @@ static void InitTokenMap()
TOKENDEF (TK_Do, ZCC_DO);
TOKENDEF (TK_For, ZCC_FOR);
TOKENDEF (TK_ForEach, ZCC_FOREACH);
TOKENDEF (TK_Unsafe, ZCC_UNSAFE);
TOKENDEF (TK_While, ZCC_WHILE);
TOKENDEF (TK_Until, ZCC_UNTIL);
TOKENDEF (TK_If, ZCC_IF);

View file

@ -65,6 +65,7 @@ enum
ZCC_Version = 1 << 21,
ZCC_Internal = 1 << 22,
ZCC_Sealed = 1 << 23,
ZCC_FuncConstUnsafe = 1 << 24,
};
// Function parameter modifiers