diff --git a/src/dobjtype.h b/src/dobjtype.h index fd8bfb60a..d907feeeb 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -30,6 +30,7 @@ enum VARF_Out = (1<<11), VARF_Implicit = (1<<12), // implicitly created parameters (i.e. do not compare types when checking function signatures) VARF_Static = (1<<13), // static class data (by necessity read only.) + VARF_InternalAccess = (1<<14), // overrides VARF_ReadOnly for internal script code. }; // Symbol information ------------------------------------------------------- diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 0972ed002..32ee2d012 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -53,6 +53,7 @@ #include "m_fixed.h" #include "vmbuilder.h" #include "v_text.h" +#include "w_wad.h" #include "math/cmath.h" extern FRandom pr_exrandom; @@ -93,14 +94,14 @@ static const FLOP FxFlops[] = // //========================================================================== -FCompileContext::FCompileContext(PFunction *fnc, PPrototype *ret, bool fromdecorate, int stateindex, int statecount) - : ReturnProto(ret), Function(fnc), Class(nullptr), FromDecorate(fromdecorate), StateIndex(stateindex), StateCount(statecount) +FCompileContext::FCompileContext(PFunction *fnc, PPrototype *ret, bool fromdecorate, int stateindex, int statecount, int lump) + : ReturnProto(ret), Function(fnc), Class(nullptr), FromDecorate(fromdecorate), StateIndex(stateindex), StateCount(statecount), Lump(lump) { if (fnc != nullptr) Class = fnc->OwningClass; } FCompileContext::FCompileContext(PClass *cls, bool fromdecorate) - : ReturnProto(nullptr), Function(nullptr), Class(cls), FromDecorate(fromdecorate), StateIndex(-1), StateCount(0) + : ReturnProto(nullptr), Function(nullptr), Class(cls), FromDecorate(fromdecorate), StateIndex(-1), StateCount(0), Lump(-1) { } @@ -164,6 +165,13 @@ void FCompileContext::CheckReturn(PPrototype *proto, FScriptPosition &pos) } } +bool FCompileContext::CheckReadOnly(int flags) +{ + if (!(flags & VARF_ReadOnly)) return false; + if (!(flags & VARF_InternalAccess)) return true; + return Wads.GetLumpFile(Lump) != 0; +} + FxLocalVariableDeclaration *FCompileContext::FindLocalVariable(FName name) { if (Block == nullptr) @@ -307,7 +315,7 @@ FxExpression *FxExpression::Resolve(FCompileContext &ctx) // //========================================================================== -bool FxExpression::RequestAddress(bool *writable) +bool FxExpression::RequestAddress(FCompileContext &ctx, bool *writable) { if (writable != nullptr) *writable = false; return false; @@ -1178,9 +1186,19 @@ FxExpression *FxColorCast::Resolve(FCompileContext &ctx) if (basex->isConstant()) { ExpVal constval = static_cast(basex)->GetValue(); - FxExpression *x = new FxConstant(V_GetColor(nullptr, constval.GetString()), ScriptPosition); - delete this; - return x; + if (constval.GetString().Len() == 0) + { + // empty string means 'no state'. This would otherwise just cause endless errors and have the same result anyway. + FxExpression *x = new FxConstant(-1, ScriptPosition); + delete this; + return x; + } + else + { + FxExpression *x = new FxConstant(V_GetColor(nullptr, constval.GetString()), ScriptPosition); + delete this; + return x; + } } return this; } @@ -1870,7 +1888,7 @@ FxExpression *FxSizeAlign::Resolve(FCompileContext& ctx) delete this; return nullptr; } - else if (!Operand->RequestAddress(nullptr)) + else if (!Operand->RequestAddress(ctx, nullptr)) { ScriptPosition.Message(MSG_ERROR, "Operand must be addressable to determine %s", Which == TK_AlignOf ? "alignment" : "size"); delete this; @@ -1907,7 +1925,7 @@ FxPreIncrDecr::~FxPreIncrDecr() SAFE_DELETE(Base); } -bool FxPreIncrDecr::RequestAddress(bool *writable) +bool FxPreIncrDecr::RequestAddress(FCompileContext &ctx, bool *writable) { AddressRequested = true; if (writable != nullptr) *writable = AddressWritable; @@ -1933,7 +1951,7 @@ FxExpression *FxPreIncrDecr::Resolve(FCompileContext &ctx) delete this; return nullptr; } - if (!Base->RequestAddress(&AddressWritable) || !AddressWritable ) + if (!Base->RequestAddress(ctx, &AddressWritable) || !AddressWritable ) { ScriptPosition.Message(MSG_ERROR, "Expression must be a modifiable value"); delete this; @@ -2019,7 +2037,7 @@ FxExpression *FxPostIncrDecr::Resolve(FCompileContext &ctx) delete this; return nullptr; } - if (!Base->RequestAddress(&AddressWritable) || !AddressWritable) + if (!Base->RequestAddress(ctx, &AddressWritable) || !AddressWritable) { ScriptPosition.Message(MSG_ERROR, "Expression must be a modifiable value"); delete this; @@ -2107,7 +2125,7 @@ FxAssign::~FxAssign() } /* I don't think we should allow constructs like (a = b) = c;... -bool FxAssign::RequestAddress(bool *writable) +bool FxAssign::RequestAddress(FCompileContext &ctx, bool *writable) { AddressRequested = true; if (writable != nullptr) *writable = AddressWritable; @@ -2177,7 +2195,7 @@ FxExpression *FxAssign::Resolve(FCompileContext &ctx) SAFE_RESOLVE(Right, ctx); } - if (!Base->RequestAddress(&AddressWritable) || !AddressWritable) + if (!Base->RequestAddress(ctx, &AddressWritable) || !AddressWritable) { ScriptPosition.Message(MSG_ERROR, "Expression must be a modifiable value"); delete this; @@ -2188,7 +2206,7 @@ FxExpression *FxAssign::Resolve(FCompileContext &ctx) if (Base->ExprType == EFX_StructMember || Base->ExprType == EFX_ClassMember) { auto f = static_cast(Base)->membervar; - if (f->BitValue != -1 && !(f->Flags & VARF_ReadOnly)) + if (f->BitValue != -1 && !ctx.CheckReadOnly(f->Flags)) { IsBitWrite = f->BitValue; return this; @@ -5335,10 +5353,10 @@ FxExpression *FxLocalVariable::Resolve(FCompileContext &ctx) return this; } -bool FxLocalVariable::RequestAddress(bool *writable) +bool FxLocalVariable::RequestAddress(FCompileContext &ctx, bool *writable) { AddressRequested = true; - if (writable != nullptr) *writable = !(Variable->VarFlags & VARF_ReadOnly); + if (writable != nullptr) *writable = !ctx.CheckReadOnly(Variable->VarFlags); return true; } @@ -5504,10 +5522,10 @@ FxGlobalVariable::FxGlobalVariable(PField* mem, const FScriptPosition &pos) // //========================================================================== -bool FxGlobalVariable::RequestAddress(bool *writable) +bool FxGlobalVariable::RequestAddress(FCompileContext &ctx, bool *writable) { AddressRequested = true; - if (writable != nullptr) *writable = AddressWritable && !(membervar->Flags & VARF_ReadOnly); + if (writable != nullptr) *writable = AddressWritable && !ctx.CheckReadOnly(membervar->Flags); return true; } @@ -5582,10 +5600,10 @@ FxStructMember::~FxStructMember() // //========================================================================== -bool FxStructMember::RequestAddress(bool *writable) +bool FxStructMember::RequestAddress(FCompileContext &ctx, bool *writable) { AddressRequested = true; - if (writable != nullptr) *writable = (AddressWritable && !(membervar->Flags & VARF_ReadOnly) && + if (writable != nullptr) *writable = (AddressWritable && !ctx.CheckReadOnly(membervar->Flags) && (!classx->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) || !static_cast(classx->ValueType)->IsConst)); return true; } @@ -5662,7 +5680,7 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx) } else { - if (!(classx->RequestAddress(&AddressWritable))) + if (!(classx->RequestAddress(ctx, &AddressWritable))) { ScriptPosition.Message(MSG_ERROR, "unable to dereference left side of %s", membervar->SymbolName.GetChars()); delete this; @@ -5767,7 +5785,7 @@ FxArrayElement::~FxArrayElement() // //========================================================================== -bool FxArrayElement::RequestAddress(bool *writable) +bool FxArrayElement::RequestAddress(FCompileContext &ctx, bool *writable) { AddressRequested = true; if (writable != nullptr) *writable = AddressWritable; @@ -5830,7 +5848,7 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) delete this; return nullptr; } - if (!Array->RequestAddress(&AddressWritable)) + if (!Array->RequestAddress(ctx, &AddressWritable)) { ScriptPosition.Message(MSG_ERROR, "Unable to dereference array."); delete this; diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index 3cc86d1e6..df0ba7594 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -76,9 +76,10 @@ struct FCompileContext bool FromDecorate; // DECORATE must silence some warnings and demote some errors. int StateIndex; // index in actor's state table for anonymous functions, otherwise -1 (not used by DECORATE which pre-resolves state indices) int StateCount; // amount of states an anoymous function is being used on (must be 1 for state indices to be allowed.) + int Lump; TDeletingArray FunctionArgs; - FCompileContext(PFunction *func, PPrototype *ret, bool fromdecorate, int stateindex, int statecount); + FCompileContext(PFunction *func, PPrototype *ret, bool fromdecorate, int stateindex, int statecount, int lump); FCompileContext(PClass *cls, bool fromdecorate); // only to be used to resolve constants! PSymbol *FindInClass(FName identifier, PSymbolTable *&symt); @@ -87,6 +88,7 @@ struct FCompileContext void HandleJumps(int token, FxExpression *handler); void CheckReturn(PPrototype *proto, FScriptPosition &pos); + bool CheckReadOnly(int flags); FxLocalVariableDeclaration *FindLocalVariable(FName name); }; @@ -296,7 +298,7 @@ public: virtual FxExpression *Resolve(FCompileContext &ctx); virtual bool isConstant() const; - virtual bool RequestAddress(bool *writable); + virtual bool RequestAddress(FCompileContext &ctx, bool *writable); virtual PPrototype *ReturnProto(); virtual VMFunction *GetDirectFunction(); virtual bool CheckReturn() { return false; } @@ -715,7 +717,7 @@ public: FxPreIncrDecr(FxExpression *base, int token); ~FxPreIncrDecr(); FxExpression *Resolve(FCompileContext&); - bool RequestAddress(bool *writable); + bool RequestAddress(FCompileContext &ctx, bool *writable); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -758,7 +760,7 @@ public: FxAssign(FxExpression *base, FxExpression *right, bool ismodify = false); ~FxAssign(); FxExpression *Resolve(FCompileContext&); - //bool RequestAddress(bool *writable); + //bool RequestAddress(FCompileContext &ctx, bool *writable); ExpEmit Emit(VMFunctionBuilder *build); ExpEmit Address; @@ -1157,7 +1159,7 @@ public: FxGlobalVariable(PField*, const FScriptPosition&); FxExpression *Resolve(FCompileContext&); - bool RequestAddress(bool *writable); + bool RequestAddress(FCompileContext &ctx, bool *writable); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -1178,7 +1180,7 @@ public: FxStructMember(FxExpression*, PField*, const FScriptPosition&); ~FxStructMember(); FxExpression *Resolve(FCompileContext&); - bool RequestAddress(bool *writable); + bool RequestAddress(FCompileContext &ctx, bool *writable); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -1210,7 +1212,7 @@ public: FxLocalVariable(FxLocalVariableDeclaration*, const FScriptPosition&); FxExpression *Resolve(FCompileContext&); - bool RequestAddress(bool *writable); + bool RequestAddress(FCompileContext &ctx, bool *writable); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -1245,7 +1247,7 @@ public: FxArrayElement(FxExpression*, FxExpression*); ~FxArrayElement(); FxExpression *Resolve(FCompileContext&); - bool RequestAddress(bool *writable); + bool RequestAddress(FCompileContext &ctx, bool *writable); ExpEmit Emit(VMFunctionBuilder *build); }; diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 8152e9977..4ccc72748 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -55,7 +55,7 @@ static TArray AFTable; // [RH] Keep GCC quiet by not using offsetof on Actor types. #define DEFINE_FLAG(prefix, name, type, variable) { (unsigned int)prefix##_##name, #name, (int)(size_t)&((type*)1)->variable - 1, sizeof(((type *)0)->variable), VARF_Native } -#define DEFINE_READONLY_FLAG(prefix, name, type, variable) { (unsigned int)prefix##_##name, #name, (int)(size_t)&((type*)1)->variable - 1, sizeof(((type *)0)->variable), VARF_Native|VARF_ReadOnly } +#define DEFINE_PROTECTED_FLAG(prefix, name, type, variable) { (unsigned int)prefix##_##name, #name, (int)(size_t)&((type*)1)->variable - 1, sizeof(((type *)0)->variable), VARF_Native|VARF_ReadOnly|VARF_InternalAccess } #define DEFINE_FLAG2(symbol, name, type, variable) { (unsigned int)symbol, #name, (int)(size_t)&((type*)1)->variable - 1, sizeof(((type *)0)->variable), VARF_Native } #define DEFINE_FLAG2_DEPRECATED(symbol, name, type, variable) { (unsigned int)symbol, #name, (int)(size_t)&((type*)1)->variable - 1, sizeof(((type *)0)->variable), VARF_Native|VARF_Deprecated } #define DEFINE_DEPRECATED_FLAG(name) { DEPF_##name, #name, -1, 0, true } @@ -99,8 +99,8 @@ FFlagDef ActorFlagDefs[]= DEFINE_FLAG(MF, SPECIAL, APlayerPawn, flags), DEFINE_FLAG(MF, SOLID, AActor, flags), DEFINE_FLAG(MF, SHOOTABLE, AActor, flags), - DEFINE_FLAG(MF, NOSECTOR, AActor, flags), - DEFINE_FLAG(MF, NOBLOCKMAP, AActor, flags), + DEFINE_PROTECTED_FLAG(MF, NOSECTOR, AActor, flags), + DEFINE_PROTECTED_FLAG(MF, NOBLOCKMAP, AActor, flags), DEFINE_FLAG(MF, AMBUSH, AActor, flags), DEFINE_FLAG(MF, JUSTHIT, AActor, flags), DEFINE_FLAG(MF, JUSTATTACKED, AActor, flags), diff --git a/src/scripting/vm/vmbuilder.cpp b/src/scripting/vm/vmbuilder.cpp index 1544ca4a6..e5ed249b1 100644 --- a/src/scripting/vm/vmbuilder.cpp +++ b/src/scripting/vm/vmbuilder.cpp @@ -653,7 +653,7 @@ void VMFunctionBuilder::BackpatchToHere(size_t loc) //========================================================================== FFunctionBuildList FunctionBuildList; -VMFunction *FFunctionBuildList::AddFunction(PFunction *functype, FxExpression *code, const FString &name, bool fromdecorate, int stateindex, int statecount) +VMFunction *FFunctionBuildList::AddFunction(PFunction *functype, FxExpression *code, const FString &name, bool fromdecorate, int stateindex, int statecount, int lumpnum) { auto func = code->GetDirectFunction(); if (func != nullptr) @@ -675,6 +675,7 @@ VMFunction *FFunctionBuildList::AddFunction(PFunction *functype, FxExpression *c it.FromDecorate = fromdecorate; it.StateIndex = stateindex; it.StateCount = statecount; + it.Lump = lumpnum; // set prototype for named functions. if (it.Func->SymbolName != NAME_None) @@ -700,7 +701,7 @@ void FFunctionBuildList::Build() assert(item.Code != NULL); // We don't know the return type in advance for anonymous functions. - FCompileContext ctx(item.Func, item.Func->SymbolName == NAME_None ? nullptr : item.Func->Variants[0].Proto, item.FromDecorate, item.StateIndex, item.StateCount); + FCompileContext ctx(item.Func, item.Func->SymbolName == NAME_None ? nullptr : item.Func->Variants[0].Proto, item.FromDecorate, item.StateIndex, item.StateCount, item.Lump); // Allocate registers for the function's arguments and create local variable nodes before starting to resolve it. VMFunctionBuilder buildit(item.Func->GetImplicitArgs()); diff --git a/src/scripting/vm/vmbuilder.h b/src/scripting/vm/vmbuilder.h index 452a7882c..5394dec32 100644 --- a/src/scripting/vm/vmbuilder.h +++ b/src/scripting/vm/vmbuilder.h @@ -108,13 +108,14 @@ class FFunctionBuildList FString PrintableName; int StateIndex; int StateCount; + int Lump; bool FromDecorate; }; TArray mItems; public: - VMFunction *AddFunction(PFunction *func, FxExpression *code, const FString &name, bool fromdecorate, int currentstate = -1, int statecnt = 0); + VMFunction *AddFunction(PFunction *func, FxExpression *code, const FString &name, bool fromdecorate, int currentstate = -1, int statecnt = 0, int lumpnum = -1); void Build(); }; diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 41c3cde34..2965357dd 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -217,8 +217,8 @@ void ZCCCompiler::ProcessStruct(ZCC_Struct *cnode, PSymbolTreeNode *treenode, ZC // //========================================================================== -ZCCCompiler::ZCCCompiler(ZCC_AST &ast, DObject *_outer, PSymbolTable &_symbols, PSymbolTable &_outsymbols) - : Outer(_outer), GlobalTreeNodes(&_symbols), OutputSymbols(&_outsymbols), AST(ast) +ZCCCompiler::ZCCCompiler(ZCC_AST &ast, DObject *_outer, PSymbolTable &_symbols, PSymbolTable &_outsymbols, int lumpnum) + : Outer(_outer), GlobalTreeNodes(&_symbols), OutputSymbols(&_outsymbols), AST(ast), Lump(lumpnum) { FScriptPosition::ResetErrorCounter(); // Group top-level nodes by type @@ -2146,7 +2146,7 @@ void ZCCCompiler::InitFunctions() auto code = ConvertAST(c->Type(), f->Body); if (code != nullptr) { - sym->Variants[0].Implementation = FunctionBuildList.AddFunction(sym, code, FStringf("%s.%s", c->Type()->TypeName.GetChars(), FName(f->Name).GetChars()), false); + sym->Variants[0].Implementation = FunctionBuildList.AddFunction(sym, code, FStringf("%s.%s", c->Type()->TypeName.GetChars(), FName(f->Name).GetChars()), false, -1, 0, Lump); } } if (sym->Variants[0].Implementation != nullptr && hasdefault) // do not copy empty default lists, they only waste space and processing time. @@ -2344,7 +2344,7 @@ void ZCCCompiler::CompileStates() if (code != nullptr) { auto funcsym = CreateAnonymousFunction(c->Type(), nullptr, VARF_Method | VARF_Action); - state.ActionFunc = FunctionBuildList.AddFunction(funcsym, code, FStringf("%s.StateFunction.%d", c->Type()->TypeName.GetChars(), statedef.GetStateCount()), false, statedef.GetStateCount(), (int)sl->Frames->Len()); + state.ActionFunc = FunctionBuildList.AddFunction(funcsym, code, FStringf("%s.StateFunction.%d", c->Type()->TypeName.GetChars(), statedef.GetStateCount()), false, statedef.GetStateCount(), (int)sl->Frames->Len(), Lump); } } diff --git a/src/scripting/zscript/zcc_compile.h b/src/scripting/zscript/zcc_compile.h index 4ad72769a..c901fc42e 100644 --- a/src/scripting/zscript/zcc_compile.h +++ b/src/scripting/zscript/zcc_compile.h @@ -78,7 +78,7 @@ struct ZCC_ConstantWork class ZCCCompiler { public: - ZCCCompiler(ZCC_AST &tree, DObject *outer, PSymbolTable &symbols, PSymbolTable &outsymbols); + ZCCCompiler(ZCC_AST &tree, DObject *outer, PSymbolTable &symbols, PSymbolTable &outsymbols, int lumpnum); ~ZCCCompiler(); int Compile(); @@ -149,6 +149,7 @@ private: PSymbolTable *GlobalTreeNodes; PSymbolTable *OutputSymbols; ZCC_AST &AST; + int Lump; }; void ZCC_InitConversions(); diff --git a/src/scripting/zscript/zcc_parser.cpp b/src/scripting/zscript/zcc_parser.cpp index 1f0800302..c84b72c66 100644 --- a/src/scripting/zscript/zcc_parser.cpp +++ b/src/scripting/zscript/zcc_parser.cpp @@ -374,7 +374,7 @@ static void DoParse(int lumpnum) PSymbolTable symtable; symtable.SetName("Global_Node"); - ZCCCompiler cc(state, NULL, symtable, GlobalSymbols); + ZCCCompiler cc(state, NULL, symtable, GlobalSymbols, lumpnum); cc.Compile(); if (FScriptPosition::ErrorCounter > 0)