- 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.

This commit is contained in:
Christoph Oelckers 2016-11-08 11:12:56 +01:00
parent 3661e479d9
commit 7b7b66d8b7
9 changed files with 67 additions and 43 deletions

View File

@ -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 -------------------------------------------------------

View File

@ -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<FxConstant *>(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<FxStructMember *>(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<PPointer*>(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;

View File

@ -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<FxLocalVariableDeclaration *> 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);
};

View File

@ -55,7 +55,7 @@ static TArray<AFuncDesc> 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),

View File

@ -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());

View File

@ -108,13 +108,14 @@ class FFunctionBuildList
FString PrintableName;
int StateIndex;
int StateCount;
int Lump;
bool FromDecorate;
};
TArray<Item> 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();
};

View File

@ -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);
}
}

View File

@ -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();

View File

@ -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)