diff --git a/src/common/engine/sc_man_scanner.re b/src/common/engine/sc_man_scanner.re index 5af7e62f9..a1283778e 100644 --- a/src/common/engine/sc_man_scanner.re +++ b/src/common/engine/sc_man_scanner.re @@ -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); } diff --git a/src/common/engine/sc_man_tokens.h b/src/common/engine/sc_man_tokens.h index 487003125..85bb55d42 100644 --- a/src/common/engine/sc_man_tokens.h +++ b/src/common/engine/sc_man_tokens.h @@ -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'") diff --git a/src/common/scripting/backend/codegen.cpp b/src/common/scripting/backend/codegen.cpp index 1fcaeae2c..1ce7d6acf 100644 --- a/src/common/scripting/backend/codegen.cpp +++ b/src/common/scripting/backend/codegen.cpp @@ -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; } diff --git a/src/common/scripting/backend/codegen.h b/src/common/scripting/backend/codegen.h index cd37a7102..bfe08ec74 100644 --- a/src/common/scripting/backend/codegen.h +++ b/src/common/scripting/backend/codegen.h @@ -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); }; //========================================================================== diff --git a/src/common/scripting/core/types.h b/src/common/scripting/core/types.h index f09ddb32b..69d73bd77 100644 --- a/src/common/scripting/core/types.h +++ b/src/common/scripting/core/types.h @@ -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 ------------------------------------ diff --git a/src/common/scripting/frontend/zcc-parse.lemon b/src/common/scripting/frontend/zcc-parse.lemon index 199771949..72dbc35fa 100644 --- a/src/common/scripting/frontend/zcc-parse.lemon +++ b/src/common/scripting/frontend/zcc-parse.lemon @@ -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). diff --git a/src/common/scripting/frontend/zcc_compile.cpp b/src/common/scripting/frontend/zcc_compile.cpp index faef50959..51591c399 100644 --- a/src/common/scripting/frontend/zcc_compile.cpp +++ b/src/common/scripting/frontend/zcc_compile.cpp @@ -1475,8 +1475,8 @@ bool ZCCCompiler::CompileFields(PContainerType *type, TArrayFlags & 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) diff --git a/src/common/scripting/frontend/zcc_parser.cpp b/src/common/scripting/frontend/zcc_parser.cpp index 6ea3c316e..35c6cc74e 100644 --- a/src/common/scripting/frontend/zcc_parser.cpp +++ b/src/common/scripting/frontend/zcc_parser.cpp @@ -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); diff --git a/src/common/scripting/frontend/zcc_parser.h b/src/common/scripting/frontend/zcc_parser.h index d0b6264da..cf2574c28 100644 --- a/src/common/scripting/frontend/zcc_parser.h +++ b/src/common/scripting/frontend/zcc_parser.h @@ -65,6 +65,7 @@ enum ZCC_Version = 1 << 21, ZCC_Internal = 1 << 22, ZCC_Sealed = 1 << 23, + ZCC_FuncConstUnsafe = 1 << 24, }; // Function parameter modifiers