From 7b7b66d8b7d9462e2b59b8dc4d9601fd2520d79f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 8 Nov 2016 11:12:56 +0100 Subject: [PATCH] - added a new variable flag that allows defining variables which can only be modified by internal script code but not by external mods. Currently this is used by the NoBlockmap and NoSector flags which need special handling for changing. --- src/dobjtype.h | 1 + src/scripting/codegeneration/codegen.cpp | 64 +++++++++++++++--------- src/scripting/codegeneration/codegen.h | 18 ++++--- src/scripting/thingdef_data.cpp | 6 +-- src/scripting/vm/vmbuilder.cpp | 5 +- src/scripting/vm/vmbuilder.h | 3 +- src/scripting/zscript/zcc_compile.cpp | 8 +-- src/scripting/zscript/zcc_compile.h | 3 +- src/scripting/zscript/zcc_parser.cpp | 2 +- 9 files changed, 67 insertions(+), 43 deletions(-) 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)