diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ffeba6d49..b5c2cc949 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1280,7 +1280,6 @@ set (PCH_SOURCES scripting/vm/vmframe.cpp scripting/zscript/ast.cpp scripting/zscript/zcc_compile.cpp - scripting/zscript/zcc_expr.cpp scripting/zscript/zcc_parser.cpp sfmt/SFMT.cpp ) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 2d41a57e3..c3ab87e11 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -240,159 +240,6 @@ size_t PType::PropagateMark() return marked + Super::PropagateMark(); } -//========================================================================== -// -// PType :: AddConversion -// -//========================================================================== - -bool PType::AddConversion(PType *target, void (*convertconst)(ZCC_ExprConstant *, class FSharedStringArena &)) -{ - // Make sure a conversion hasn't already been registered - for (unsigned i = 0; i < Conversions.Size(); ++i) - { - if (Conversions[i].TargetType == target) - return false; - } - Conversions.Push(Conversion(target, convertconst)); - return true; -} - -//========================================================================== -// -// PType :: FindConversion -// -// Returns <0 if there is no path to target. Otherwise, returns the distance -// to target and fills slots (if non-NULL) with the necessary conversions -// to get there. A result of 0 means this is the target. -// -//========================================================================== - -int PType::FindConversion(PType *target, const PType::Conversion **slots, int numslots) -{ - if (this == target) - { - return 0; - } - // The queue is implemented as a ring buffer - VisitQueue queue; - VisitedNodeSet visited; - - // Use a breadth-first search to find the shortest path to the target. - MarkPred(NULL, -1, -1); - queue.Push(this); - visited.Insert(this); - while (!queue.IsEmpty()) - { - PType *t = queue.Pop(); - if (t == target) - { // found it - if (slots != NULL) - { - if (t->Distance >= numslots) - { // Distance is too far for the output - return -2; - } - t->FillConversionPath(slots); - } - return t->Distance + 1; - } - for (unsigned i = 0; i < t->Conversions.Size(); ++i) - { - PType *succ = t->Conversions[i].TargetType; - if (!visited.Check(succ)) - { - succ->MarkPred(t, i, t->Distance + 1); - visited.Insert(succ); - queue.Push(succ); - } - } - } - return -1; -} - -//========================================================================== -// -// PType :: FillConversionPath -// -// Traces backwards from the target type to the original type and fills in -// the conversions necessary to get between them. slots must point to an -// array large enough to contain the entire path. -// -//========================================================================== - -void PType::FillConversionPath(const PType::Conversion **slots) -{ - for (PType *node = this; node->Distance >= 0; node = node->PredType) - { - assert(node->PredType != NULL); - slots[node->Distance] = &node->PredType->Conversions[node->PredConv]; - } -} - -//========================================================================== -// -// PType :: VisitQueue :: Push -// -//========================================================================== - -void PType::VisitQueue::Push(PType *type) -{ - Queue[In] = type; - Advance(In); - assert(!IsEmpty() && "Queue overflowed"); -} - -//========================================================================== -// -// PType :: VisitQueue :: Pop -// -//========================================================================== - -PType *PType::VisitQueue::Pop() -{ - if (IsEmpty()) - { - return NULL; - } - PType *node = Queue[Out]; - Advance(Out); - return node; -} - -//========================================================================== -// -// PType :: VisitedNodeSet :: Insert -// -//========================================================================== - -void PType::VisitedNodeSet::Insert(PType *node) -{ - assert(!Check(node) && "Node was already inserted"); - size_t buck = Hash(node) & (countof(Buckets) - 1); - node->VisitNext = Buckets[buck]; - Buckets[buck] = node; -} - -//========================================================================== -// -// PType :: VisitedNodeSet :: Check -// -//========================================================================== - -bool PType::VisitedNodeSet::Check(const PType *node) -{ - size_t buck = Hash(node) & (countof(Buckets) - 1); - for (const PType *probe = Buckets[buck]; probe != NULL; probe = probe->VisitNext) - { - if (probe == node) - { - return true; - } - } - return false; -} - //========================================================================== // // PType :: WriteValue diff --git a/src/dobjtype.h b/src/dobjtype.h index d38c42c58..7054095bd 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -214,15 +214,6 @@ public: typedef PClassType MetaClass; MetaClass *GetClass() const; - struct Conversion - { - Conversion(PType *target, void (*convert)(ZCC_ExprConstant *, class FSharedStringArena &)) - : TargetType(target), ConvertConstant(convert) {} - - PType *TargetType; - void (*ConvertConstant)(ZCC_ExprConstant *val, class FSharedStringArena &strdump); - }; - unsigned int Size; // this type's size unsigned int Align; // this type's preferred alignment PType *HashNext; // next type in this type table @@ -235,10 +226,6 @@ public: virtual ~PType(); virtual bool isNumeric() { return false; } - bool AddConversion(PType *target, void (*convertconst)(ZCC_ExprConstant *, class FSharedStringArena &)); - - int FindConversion(PType *target, const Conversion **slots, int numslots); - // Writes the value of a variable of this type at (addr) to an archive, preceded by // a tag indicating its type. The tag is there so that variable types can be changed // without completely breaking savegames, provided that the change isn't between @@ -318,54 +305,6 @@ public: size_t PropagateMark(); static void StaticInit(); - -private: - // Stuff for type conversion searches - class VisitQueue - { - public: - VisitQueue() : In(0), Out(0) {} - void Push(PType *type); - PType *Pop(); - bool IsEmpty() { return In == Out; } - - private: - // This is a fixed-sized ring buffer. - PType *Queue[64]; - int In, Out; - - void Advance(int &ptr) - { - ptr = (ptr + 1) & (countof(Queue) - 1); - } - }; - - class VisitedNodeSet - { - public: - VisitedNodeSet() { memset(Buckets, 0, sizeof(Buckets)); } - void Insert(PType *node); - bool Check(const PType *node); - - private: - PType *Buckets[32]; - - size_t Hash(const PType *type) { return size_t(type) >> 4; } - }; - - TArray Conversions; - PType *PredType; - PType *VisitNext; - short PredConv; - short Distance; - - void MarkPred(PType *pred, int conv, int dist) - { - PredType = pred; - PredConv = conv; - Distance = dist; - } - void FillConversionPath(const Conversion **slots); }; // Not-really-a-type types -------------------------------------------------- @@ -1043,7 +982,7 @@ class PSymbolConstString : public PSymbolConst public: FString Str; - PSymbolConstString(FName name, FString &str) : PSymbolConst(name, TypeString), Str(str) {} + PSymbolConstString(FName name, const FString &str) : PSymbolConst(name, TypeString), Str(str) {} PSymbolConstString() {} }; diff --git a/src/g_game.cpp b/src/g_game.cpp index 936caea18..e5c327472 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -1891,168 +1891,150 @@ void G_DoLoadGame () hidecon = gameaction == ga_loadgamehidecon; gameaction = ga_nothing; - FResourceFile *resfile = FResourceFile::OpenResourceFile(savename.GetChars(), nullptr, true, true); + std::unique_ptr resfile(FResourceFile::OpenResourceFile(savename.GetChars(), nullptr, true, true)); if (resfile == nullptr) { Printf ("Could not read savegame '%s'\n", savename.GetChars()); return; } - try + FResourceLump *info = resfile->FindLump("info.json"); + if (info == nullptr) { - FResourceLump *info = resfile->FindLump("info.json"); - if (info == nullptr) - { - delete resfile; - Printf("'%s' is not a valid savegame: Missing 'info.json'.\n", savename.GetChars()); - return; - } - - SaveVersion = 0; - - void *data = info->CacheLump(); - FSerializer arc; - if (!arc.OpenReader((const char *)data, info->LumpSize)) - { - Printf("Failed to access savegame info\n"); - delete resfile; - return; - } - - // Check whether this savegame actually has been created by a compatible engine. - // Since there are ZDoom derivates using the exact same savegame format but - // with mutual incompatibilities this check simplifies things significantly. - FString savever, engine, map; - arc("Save Version", SaveVersion); - arc("Engine", engine); - arc("Current Map", map); - - if (engine.CompareNoCase(GAMESIG) != 0) - { - // Make a special case for the message printed for old savegames that don't - // have this information. - if (engine.IsEmpty()) - { - Printf("Savegame is from an incompatible version\n"); - } - else - { - Printf("Savegame is from another ZDoom-based engine: %s\n", engine.GetChars()); - } - delete resfile; - return; - } - - if (SaveVersion < MINSAVEVER || SaveVersion > SAVEVER) - { - delete resfile; - Printf("Savegame is from an incompatible version"); - if (SaveVersion < MINSAVEVER) - { - Printf(": %d (%d is the oldest supported)", SaveVersion, MINSAVEVER); - } - else - { - Printf(": %d (%d is the highest supported)", SaveVersion, SAVEVER); - } - Printf("\n"); - return; - } - - if (!G_CheckSaveGameWads(arc, true)) - { - delete resfile; - return; - } - - if (map.IsEmpty()) - { - Printf("Savegame is missing the current map\n"); - delete resfile; - return; - } - - // Now that it looks like we can load this save, hide the fullscreen console if it was up - // when the game was selected from the menu. - if (hidecon && gamestate == GS_FULLCONSOLE) - { - gamestate = GS_HIDECONSOLE; - } - // we are done with info.json. - arc.Close(); - - info = resfile->FindLump("globals.json"); - if (info == nullptr) - { - delete resfile; - Printf("'%s' is not a valid savegame: Missing 'globals.json'.\n", savename.GetChars()); - return; - } - - data = info->CacheLump(); - if (!arc.OpenReader((const char *)data, info->LumpSize)) - { - Printf("Failed to access savegame info\n"); - delete resfile; - return; - } - - - // Read intermission data for hubs - G_SerializeHub(arc); - - bglobal.RemoveAllBots(true); - - FString cvar; - arc("importantcvars", cvar); - if (!cvar.IsEmpty()) - { - BYTE *vars_p = (BYTE *)cvar.GetChars(); - C_ReadCVars(&vars_p); - } - - DWORD time[2] = { 1,0 }; - - arc("ticrate", time[0]) - ("leveltime", time[1]); - // dearchive all the modifications - level.time = Scale(time[1], TICRATE, time[0]); - - G_ReadSnapshots(resfile); - delete resfile; // we no longer need the resource file below this point - resfile = nullptr; - G_ReadVisited(arc); - - // load a base level - savegamerestore = true; // Use the player actors in the savegame - bool demoplaybacksave = demoplayback; - G_InitNew(map, false); - demoplayback = demoplaybacksave; - savegamerestore = false; - - STAT_Serialize(arc); - FRandom::StaticReadRNGState(arc); - P_ReadACSDefereds(arc); - P_ReadACSVars(arc); - - NextSkill = -1; - arc("nextskill", NextSkill); - - if (level.info != nullptr) - level.info->Snapshot.Clean(); - - BackupSaveName = savename; - - // At this point, the GC threshold is likely a lot higher than the - // amount of memory in use, so bring it down now by starting a - // collection. - GC::StartCollection(); + Printf("'%s' is not a valid savegame: Missing 'info.json'.\n", savename.GetChars()); + return; } - catch (...) + + SaveVersion = 0; + + void *data = info->CacheLump(); + FSerializer arc; + if (!arc.OpenReader((const char *)data, info->LumpSize)) { - // delete the resource file if anything goes wrong in here. - if (resfile != nullptr) delete resfile; - throw; + Printf("Failed to access savegame info\n"); + return; } + + // Check whether this savegame actually has been created by a compatible engine. + // Since there are ZDoom derivates using the exact same savegame format but + // with mutual incompatibilities this check simplifies things significantly. + FString savever, engine, map; + arc("Save Version", SaveVersion); + arc("Engine", engine); + arc("Current Map", map); + + if (engine.CompareNoCase(GAMESIG) != 0) + { + // Make a special case for the message printed for old savegames that don't + // have this information. + if (engine.IsEmpty()) + { + Printf("Savegame is from an incompatible version\n"); + } + else + { + Printf("Savegame is from another ZDoom-based engine: %s\n", engine.GetChars()); + } + return; + } + + if (SaveVersion < MINSAVEVER || SaveVersion > SAVEVER) + { + Printf("Savegame is from an incompatible version"); + if (SaveVersion < MINSAVEVER) + { + Printf(": %d (%d is the oldest supported)", SaveVersion, MINSAVEVER); + } + else + { + Printf(": %d (%d is the highest supported)", SaveVersion, SAVEVER); + } + Printf("\n"); + return; + } + + if (!G_CheckSaveGameWads(arc, true)) + { + return; + } + + if (map.IsEmpty()) + { + Printf("Savegame is missing the current map\n"); + return; + } + + // Now that it looks like we can load this save, hide the fullscreen console if it was up + // when the game was selected from the menu. + if (hidecon && gamestate == GS_FULLCONSOLE) + { + gamestate = GS_HIDECONSOLE; + } + // we are done with info.json. + arc.Close(); + + info = resfile->FindLump("globals.json"); + if (info == nullptr) + { + Printf("'%s' is not a valid savegame: Missing 'globals.json'.\n", savename.GetChars()); + return; + } + + data = info->CacheLump(); + if (!arc.OpenReader((const char *)data, info->LumpSize)) + { + Printf("Failed to access savegame info\n"); + return; + } + + + // Read intermission data for hubs + G_SerializeHub(arc); + + bglobal.RemoveAllBots(true); + + FString cvar; + arc("importantcvars", cvar); + if (!cvar.IsEmpty()) + { + BYTE *vars_p = (BYTE *)cvar.GetChars(); + C_ReadCVars(&vars_p); + } + + DWORD time[2] = { 1,0 }; + + arc("ticrate", time[0]) + ("leveltime", time[1]); + // dearchive all the modifications + level.time = Scale(time[1], TICRATE, time[0]); + + G_ReadSnapshots(resfile.get()); + resfile.reset(nullptr); // we no longer need the resource file below this point + G_ReadVisited(arc); + + // load a base level + savegamerestore = true; // Use the player actors in the savegame + bool demoplaybacksave = demoplayback; + G_InitNew(map, false); + demoplayback = demoplaybacksave; + savegamerestore = false; + + STAT_Serialize(arc); + FRandom::StaticReadRNGState(arc); + P_ReadACSDefereds(arc); + P_ReadACSVars(arc); + + NextSkill = -1; + arc("nextskill", NextSkill); + + if (level.info != nullptr) + level.info->Snapshot.Clean(); + + BackupSaveName = savename; + + // At this point, the GC threshold is likely a lot higher than the + // amount of memory in use, so bring it down now by starting a + // collection. + GC::StartCollection(); } diff --git a/src/gl/shaders/gl_shader.cpp b/src/gl/shaders/gl_shader.cpp index b7d8335f8..327ac5fd4 100644 --- a/src/gl/shaders/gl_shader.cpp +++ b/src/gl/shaders/gl_shader.cpp @@ -60,15 +60,15 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * static char buffer[10000]; FString error; - int i_lump = Wads.CheckNumForFullName("shaders/glsl/shaderdefs.i"); + int i_lump = Wads.CheckNumForFullName("shaders/glsl/shaderdefs.i", 0); if (i_lump == -1) I_Error("Unable to load 'shaders/glsl/shaderdefs.i'"); FMemLump i_data = Wads.ReadLump(i_lump); - int vp_lump = Wads.CheckNumForFullName(vert_prog_lump); + int vp_lump = Wads.CheckNumForFullName(vert_prog_lump, 0); if (vp_lump == -1) I_Error("Unable to load '%s'", vert_prog_lump); FMemLump vp_data = Wads.ReadLump(vp_lump); - int fp_lump = Wads.CheckNumForFullName(frag_prog_lump); + int fp_lump = Wads.CheckNumForFullName(frag_prog_lump, 0); if (fp_lump == -1) I_Error("Unable to load '%s'", frag_prog_lump); FMemLump fp_data = Wads.ReadLump(fp_lump); diff --git a/src/gl/shaders/gl_shaderprogram.cpp b/src/gl/shaders/gl_shaderprogram.cpp index 1ed19913a..7a4690874 100644 --- a/src/gl/shaders/gl_shaderprogram.cpp +++ b/src/gl/shaders/gl_shaderprogram.cpp @@ -89,7 +89,7 @@ void FShaderProgram::CreateShader(ShaderType type) void FShaderProgram::Compile(ShaderType type, const char *lumpName, const char *defines, int maxGlslVersion) { - int lump = Wads.CheckNumForFullName(lumpName); + int lump = Wads.CheckNumForFullName(lumpName, 0); if (lump == -1) I_FatalError("Unable to load '%s'", lumpName); FString code = Wads.ReadLump(lump).GetString().GetChars(); Compile(type, lumpName, code, defines, maxGlslVersion); diff --git a/src/gl/system/gl_menu.cpp b/src/gl/system/gl_menu.cpp index 11534436b..8dffbc4f2 100644 --- a/src/gl/system/gl_menu.cpp +++ b/src/gl/system/gl_menu.cpp @@ -84,8 +84,11 @@ void gl_SetupMenu() { for(int i = (*opt)->mValues.Size()-1; i>=0; i--) { - // Delete HQnX resize modes for non MSVC targets - if ((*opt)->mValues[i].Value >= 7.0) + // Delete hqNx MMX resize modes for targets + // without support of this instruction set + const auto index = llround((*opt)->mValues[i].Value); + + if (index > 6 && index < 10) { (*opt)->mValues.Delete(i); } diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 210c0cd5b..807326d78 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -924,8 +924,7 @@ DEFINE_ACTION_FUNCTION(AActor, TakeInventory) PARAM_INT(amount); PARAM_BOOL_DEF(fromdecorate); PARAM_BOOL_DEF(notakeinfinite); - self->TakeInventory(item, amount, fromdecorate, notakeinfinite); - return 0; + ACTION_RETURN_BOOL(self->TakeInventory(item, amount, fromdecorate, notakeinfinite)); } //============================================================================ diff --git a/src/posix/sdl/sdlglvideo.cpp b/src/posix/sdl/sdlglvideo.cpp index 7858fdad9..e8b61ef02 100644 --- a/src/posix/sdl/sdlglvideo.cpp +++ b/src/posix/sdl/sdlglvideo.cpp @@ -133,10 +133,6 @@ SDLGLVideo::SDLGLVideo (int parm) fprintf( stderr, "Video initialization failed: %s\n", SDL_GetError( ) ); } -#ifndef _WIN32 - // mouse cursor is visible by default on linux systems, we disable it by default - SDL_ShowCursor (0); -#endif } SDLGLVideo::~SDLGLVideo () diff --git a/src/sc_man.cpp b/src/sc_man.cpp index ccfb01ac5..5f944735a 100644 --- a/src/sc_man.cpp +++ b/src/sc_man.cpp @@ -1008,6 +1008,7 @@ void FScanner::CheckOpen() int FScriptPosition::ErrorCounter; int FScriptPosition::WarnCounter; bool FScriptPosition::StrictErrors; // makes all OPTERROR messages real errors. +bool FScriptPosition::errorout; // call I_Error instead of printing the error itself. FScriptPosition::FScriptPosition(const FScriptPosition &other) { @@ -1054,6 +1055,8 @@ void FScriptPosition::Message (int severity, const char *message, ...) const { severity = StrictErrors || strictdecorate ? MSG_ERROR : MSG_WARNING; } + // This is mainly for catching the error with an exception handler. + if (severity == MSG_ERROR && errorout) severity = MSG_FATAL; if (message == NULL) { diff --git a/src/sc_man.h b/src/sc_man.h index 362d57faf..3347fe26a 100644 --- a/src/sc_man.h +++ b/src/sc_man.h @@ -144,6 +144,7 @@ struct FScriptPosition static int WarnCounter; static int ErrorCounter; static bool StrictErrors; + static bool errorout; FString FileName; int ScriptLine; diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index cb5944ade..6065050a9 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -4078,7 +4078,7 @@ ExpEmit FxConcat::Emit(VMFunctionBuilder *build) } else { - int cast; + int cast = 0; strng2 = ExpEmit(build, REGT_STRING); if (op2.Konst) { @@ -5653,6 +5653,12 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) if (Identifier == NAME_Default) { + if (ctx.Function == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Unable to access class defaults from constant declaration"); + delete this; + return nullptr; + } if (ctx.Function->Variants[0].SelfClass == nullptr) { ScriptPosition.Message(MSG_ERROR, "Unable to access class defaults from static function"); @@ -5680,6 +5686,13 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) { if (sym->IsKindOf(RUNTIME_CLASS(PField))) { + if (ctx.Function == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Unable to access class member %s from constant declaration", sym->SymbolName.GetChars()); + delete this; + return nullptr; + } + FxExpression *self = new FxSelf(ScriptPosition); self = self->Resolve(ctx); newex = ResolveMember(ctx, ctx.Function->Variants[0].SelfClass, self, ctx.Function->Variants[0].SelfClass); @@ -5697,6 +5710,12 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) newex = FxConstant::MakeConstant(sym, ScriptPosition); goto foundit; } + else if (ctx.Function == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Unable to access class member %s from constant declaration", sym->SymbolName.GetChars()); + delete this; + return nullptr; + } // Do this check for ZScript as well, so that a clearer error message can be printed. MSG_OPTERROR will default to MSG_ERROR there. else if (ctx.Function->Variants[0].SelfClass != ctx.Class && sym->IsKindOf(RUNTIME_CLASS(PField))) { @@ -5810,7 +5829,7 @@ FxExpression *FxIdentifier::ResolveMember(FCompileContext &ctx, PStruct *classct return x->Resolve(ctx); } - if ((sym = objtype->Symbols.FindSymbolInTable(Identifier, symtbl)) != nullptr) + if (objtype != nullptr && (sym = objtype->Symbols.FindSymbolInTable(Identifier, symtbl)) != nullptr) { if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst))) { @@ -7149,7 +7168,6 @@ static bool CheckArgSize(FName fname, FArgumentList &args, int min, int max, FSc FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) { - ABORT(ctx.Class); bool error = false; for (auto a : ArgList) @@ -7162,20 +7180,30 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) } } - PFunction *afd = FindClassMemberFunction(ctx.Class, ctx.Class, MethodName, ScriptPosition, &error); - - if (afd != nullptr) + if (ctx.Class != nullptr) { - if (!CheckFunctionCompatiblity(ScriptPosition, ctx.Function, afd)) - { - delete this; - return nullptr; - } + PFunction *afd = FindClassMemberFunction(ctx.Class, ctx.Class, MethodName, ScriptPosition, &error); - auto self = (afd->Variants[0].Flags & VARF_Method)? new FxSelf(ScriptPosition) : nullptr; - auto x = new FxVMFunctionCall(self, afd, ArgList, ScriptPosition, false); - delete this; - return x->Resolve(ctx); + if (afd != nullptr) + { + if (ctx.Function == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Unable to call function %s from constant declaration", MethodName.GetChars()); + delete this; + return nullptr; + } + + if (!CheckFunctionCompatiblity(ScriptPosition, ctx.Function, afd)) + { + delete this; + return nullptr; + } + + auto self = (afd->Variants[0].Flags & VARF_Method) ? new FxSelf(ScriptPosition) : nullptr; + auto x = new FxVMFunctionCall(self, afd, ArgList, ScriptPosition, false); + delete this; + return x->Resolve(ctx); + } } for (size_t i = 0; i < countof(FxFlops); ++i) @@ -7202,7 +7230,13 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) if (special != 0 && min >= 0) { int paramcount = ArgList.Size(); - if (paramcount < min) + if (ctx.Function == nullptr || ctx.Class == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Unable to call action special %s from constant declaration", MethodName.GetChars()); + delete this; + return nullptr; + } + else if (paramcount < min) { ScriptPosition.Message(MSG_ERROR, "Not enough parameters for '%s' (expected %d, got %d)", MethodName.GetChars(), min, paramcount); @@ -7427,13 +7461,20 @@ FxMemberFunctionCall::~FxMemberFunctionCall() FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) { - ABORT(ctx.Class); PStruct *cls; bool staticonly = false; bool novirtual = false; PStruct *ccls = nullptr; + if (ctx.Class == nullptr) + { + // There's no way that a member function call can resolve to a constant so abort right away. + ScriptPosition.Message(MSG_ERROR, "Expression is not constant."); + delete this; + return nullptr; + } + for (auto a : ArgList) { if (a == nullptr) @@ -7467,6 +7508,12 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) staticonly = true; if (ccls->IsKindOf(RUNTIME_CLASS(PClass))) { + if (ctx.Function == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Unable to call %s from constant declaration", MethodName.GetChars()); + delete this; + return nullptr; + } auto clstype = dyn_cast(ctx.Function->Variants[0].SelfClass); if (clstype != nullptr) { @@ -7493,6 +7540,12 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) if (Self->ExprType == EFX_Super) { + if (ctx.Function == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Unable to call %s from constant declaration", MethodName.GetChars()); + delete this; + return nullptr; + } auto clstype = dyn_cast(ctx.Function->Variants[0].SelfClass); if (clstype != nullptr) { @@ -7743,6 +7796,12 @@ isresolved: if (afd->Variants[0].Flags & VARF_Method) { + if (ctx.Function == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Unable to call %s from constant declaration", MethodName.GetChars()); + delete this; + return nullptr; + } if (Self->ExprType == EFX_Self) { if (!CheckFunctionCompatiblity(ScriptPosition, ctx.Function, afd)) diff --git a/src/scripting/zscript/ast.cpp b/src/scripting/zscript/ast.cpp index b29e1eeb2..586601890 100644 --- a/src/scripting/zscript/ast.cpp +++ b/src/scripting/zscript/ast.cpp @@ -513,7 +513,7 @@ static void OpenExprType(FLispString &out, EZCCExprType type) if (unsigned(type) < PEX_COUNT_OF) { - mysnprintf(buf, countof(buf), "expr-%s", ZCC_OpInfo[type].OpName); + mysnprintf(buf, countof(buf), "expr %d", type); } else { diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index ddf08fbc4..714b56714 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -48,10 +48,59 @@ #include "p_lnspec.h" #include "i_system.h" #include "gdtoa.h" -#include "codegeneration/codegen.h" #include "vmbuilder.h" #include "version.h" +static int GetIntConst(FxExpression *ex, FCompileContext &ctx) +{ + ex = new FxIntCast(ex, false); + ex = ex->Resolve(ctx); + return ex ? static_cast(ex)->GetValue().GetInt() : 0; +} + +static double GetFloatConst(FxExpression *ex, FCompileContext &ctx) +{ + ex = new FxFloatCast(ex); + ex = ex->Resolve(ctx); + return ex ? static_cast(ex)->GetValue().GetFloat() : 0; +} + +static FString GetStringConst(FxExpression *ex, FCompileContext &ctx) +{ + ex = new FxStringCast(ex); + ex = ex->Resolve(ctx); + return static_cast(ex)->GetValue().GetString(); +} + +int ZCCCompiler::IntConstFromNode(ZCC_TreeNode *node, PStruct *cls) +{ + FCompileContext ctx(cls, false); + FxExpression *ex = new FxIntCast(ConvertNode(node), false); + ex = ex->Resolve(ctx); + if (ex == nullptr) return 0; + if (!ex->isConstant()) + { + ex->ScriptPosition.Message(MSG_ERROR, "Expression is not constant"); + return 0; + } + return static_cast(ex)->GetValue().GetInt(); +} + +FString ZCCCompiler::StringConstFromNode(ZCC_TreeNode *node, PStruct *cls) +{ + FCompileContext ctx(cls, false); + FxExpression *ex = new FxStringCast(ConvertNode(node)); + ex = ex->Resolve(ctx); + if (ex == nullptr) return ""; + if (!ex->isConstant()) + { + ex->ScriptPosition.Message(MSG_ERROR, "Expression is not constant"); + return ""; + } + return static_cast(ex)->GetValue().GetString(); +} + + //========================================================================== // // ZCCCompiler :: ProcessClass @@ -606,11 +655,11 @@ void ZCCCompiler::CreateClassTypes() // //========================================================================== -void ZCCCompiler::CopyConstants(TArray &dest, TArray &Constants, PSymbolTable *ot) +void ZCCCompiler::CopyConstants(TArray &dest, TArray &Constants, PStruct *cls, PSymbolTable *ot) { for (auto c : Constants) { - dest.Push({ c, ot }); + dest.Push({ c, cls, ot }); } } @@ -629,14 +678,14 @@ void ZCCCompiler::CompileAllConstants() // put all constants in one list to make resolving this easier. TArray constantwork; - CopyConstants(constantwork, Constants, OutputSymbols); + CopyConstants(constantwork, Constants, nullptr, OutputSymbols); for (auto c : Classes) { - CopyConstants(constantwork, c->Constants, &c->Type()->Symbols); + CopyConstants(constantwork, c->Constants, c->Type(), &c->Type()->Symbols); } for (auto s : Structs) { - CopyConstants(constantwork, s->Constants, &s->Type()->Symbols); + CopyConstants(constantwork, s->Constants, s->Type(), &s->Type()->Symbols); } // Before starting to resolve the list, let's create symbols for all already resolved ones first (i.e. all literal constants), to reduce work. @@ -657,7 +706,7 @@ void ZCCCompiler::CompileAllConstants() donesomething = false; for (unsigned i = 0; i < constantwork.Size(); i++) { - if (CompileConstant(constantwork[i].node, constantwork[i].outputtable)) + if (CompileConstant(&constantwork[i])) { AddConstant(constantwork[i]); // Remove the constant from the list @@ -685,6 +734,9 @@ void ZCCCompiler::AddConstant(ZCC_ConstantWork &constant) { auto def = constant.node; auto val = def->Value; + ExpVal &c = constant.constval; + + // This is for literal constants. if (val->NodeType == AST_ExprConstant) { ZCC_ExprConstant *cval = static_cast(val); @@ -711,14 +763,40 @@ void ZCCCompiler::AddConstant(ZCC_ConstantWork &constant) Error(def->Value, "Bad type for constant definiton"); def->Symbol = nullptr; } - - if (def->Symbol == nullptr) - { - // Create a dummy constant so we don't make any undefined value warnings. - def->Symbol = new PSymbolConstNumeric(def->NodeName, TypeError, 0); - } - constant.outputtable->ReplaceSymbol(def->Symbol); } + else + { + if (c.Type == TypeString) + { + def->Symbol = new PSymbolConstString(def->NodeName, c.GetString()); + } + else if (c.Type->IsA(RUNTIME_CLASS(PInt))) + { + // How do we get an Enum type in here without screwing everything up??? + //auto type = def->Type != nullptr ? def->Type : cval->Type; + def->Symbol = new PSymbolConstNumeric(def->NodeName, c.Type, c.GetInt()); + } + else if (c.Type->IsA(RUNTIME_CLASS(PFloat))) + { + if (def->Type != nullptr) + { + Error(def, "Enum members must be integer values"); + } + def->Symbol = new PSymbolConstNumeric(def->NodeName, c.Type, c.GetFloat()); + } + else + { + Error(def->Value, "Bad type for constant definiton"); + def->Symbol = nullptr; + } + } + + if (def->Symbol == nullptr) + { + // Create a dummy constant so we don't make any undefined value warnings. + def->Symbol = new PSymbolConstNumeric(def->NodeName, TypeError, 0); + } + constant.Outputtable->ReplaceSymbol(def->Symbol); } //========================================================================== @@ -730,309 +808,33 @@ void ZCCCompiler::AddConstant(ZCC_ConstantWork &constant) // //========================================================================== -bool ZCCCompiler::CompileConstant(ZCC_ConstantDef *def, PSymbolTable *sym) +bool ZCCCompiler::CompileConstant(ZCC_ConstantWork *work) { - assert(def->Symbol == nullptr); - - ZCC_Expression *val = Simplify(def->Value, sym, true); - def->Value = val; - return (val->NodeType == AST_ExprConstant); -} - - -//========================================================================== -// -// ZCCCompiler :: Simplify -// -// For an expression, -// Evaluate operators whose arguments are both constants, replacing it -// with a new constant. -// For a binary operator with one constant argument, put it on the right- -// hand operand, where permitted. -// Perform automatic type promotion. -// -//========================================================================== - -ZCC_Expression *ZCCCompiler::Simplify(ZCC_Expression *root, PSymbolTable *sym, bool wantconstant) -{ - SimplifyingConstant = wantconstant; - return DoSimplify(root, sym); -} - -ZCC_Expression *ZCCCompiler::DoSimplify(ZCC_Expression *root, PSymbolTable *sym) -{ - if (root->NodeType == AST_ExprUnary) + FCompileContext ctx(work->cls, false); + FxExpression *exp = ConvertNode(work->node->Value); + try { - return SimplifyUnary(static_cast(root), sym); - } - else if (root->NodeType == AST_ExprBinary) - { - return SimplifyBinary(static_cast(root), sym); - } - else if (root->Operation == PEX_ID) - { - return IdentifyIdentifier(static_cast(root), sym); - } - else if (root->Operation == PEX_MemberAccess) - { - return SimplifyMemberAccess(static_cast(root), sym); - } - else if (root->Operation == PEX_FuncCall) - { - return SimplifyFunctionCall(static_cast(root), sym); - } - return root; -} - -//========================================================================== -// -// ZCCCompiler :: SimplifyUnary -// -//========================================================================== - -ZCC_Expression *ZCCCompiler::SimplifyUnary(ZCC_ExprUnary *unary, PSymbolTable *sym) -{ - unary->Operand = DoSimplify(unary->Operand, sym); - if (unary->Operand->Type == nullptr) - { - return unary; - } - ZCC_OpProto *op = PromoteUnary(unary->Operation, unary->Operand); - if (op == NULL) - { // Oh, poo! - unary->Type = TypeError; - } - else if (unary->Operand->Operation == PEX_ConstValue) - { - return op->EvalConst1(static_cast(unary->Operand)); - } - return unary; -} - -//========================================================================== -// -// ZCCCompiler :: SimplifyBinary -// -//========================================================================== - -ZCC_Expression *ZCCCompiler::SimplifyBinary(ZCC_ExprBinary *binary, PSymbolTable *sym) -{ - binary->Left = DoSimplify(binary->Left, sym); - binary->Right = DoSimplify(binary->Right, sym); - if (binary->Left->Type == nullptr || binary->Right->Type == nullptr) - { - // We do not know yet what this is so we cannot promote it (yet.) - return binary; - } - ZCC_OpProto *op = PromoteBinary(binary->Operation, binary->Left, binary->Right); - if (op == NULL) - { - binary->Type = TypeError; - } - else if (binary->Left->Operation == PEX_ConstValue && - binary->Right->Operation == PEX_ConstValue) - { - return op->EvalConst2(static_cast(binary->Left), - static_cast(binary->Right), AST.Strings); - } - return binary; -} - -//========================================================================== -// -// ZCCCompiler :: SimplifyMemberAccess -// -//========================================================================== - -ZCC_Expression *ZCCCompiler::SimplifyMemberAccess(ZCC_ExprMemberAccess *dotop, PSymbolTable *symt) -{ - PSymbolTable *symtable; - - // TBD: Is it safe to simplify the left side here when not processing a constant? - dotop->Left = DoSimplify(dotop->Left, symt); - - if (dotop->Left->Operation == PEX_TypeRef) - { // Type refs can be evaluated now. - PType *ref = static_cast(dotop->Left)->RefType; - PSymbol *sym = ref->Symbols.FindSymbolInTable(dotop->Right, symtable); - if (sym != nullptr) + FScriptPosition::errorout = true; + exp = exp->Resolve(ctx); + if (exp == nullptr) return false; + FScriptPosition::errorout = false; + if (!exp->isConstant()) { - ZCC_Expression *expr = NodeFromSymbol(sym, dotop, symtable); - if (expr != nullptr) - { - return expr; - } + delete exp; + return false; } + work->constval = static_cast(exp)->GetValue(); + delete exp; + return true; } - else if (dotop->Left->Operation == PEX_Super) + catch (...) { - symt = symt->GetParentTable(); - if (symt != nullptr) - { - PSymbol *sym = symt->FindSymbolInTable(dotop->Right, symtable); - if (sym != nullptr) - { - ZCC_Expression *expr = NodeFromSymbol(sym, dotop, symtable); - if (expr != nullptr) - { - return expr; - } - } - } + // eat the reported error and treat this as a temorary failure. All unresolved contants will be reported at the end. + FScriptPosition::errorout = false; + return false; } - return dotop; } -//========================================================================== -// -// ZCCCompiler :: SimplifyFunctionCall -// -// This may replace a function call with cast(s), since they look like the -// same thing to the parser. -// -//========================================================================== - -ZCC_Expression *ZCCCompiler::SimplifyFunctionCall(ZCC_ExprFuncCall *callop, PSymbolTable *sym) -{ - ZCC_FuncParm *parm; - int parmcount = 0; - - parm = callop->Parameters; - if (parm != NULL) - { - do - { - parmcount++; - assert(parm->NodeType == AST_FuncParm); - parm->Value = DoSimplify(parm->Value, sym); - parm = static_cast(parm->SiblingNext); - } - while (parm != callop->Parameters); - } - // Only simplify the 'function' part if we want to retrieve a constant. - // This is necessary to evaluate the type casts, but for actual functions - // the simplification process is destructive and has to be avoided. - if (SimplifyingConstant) - { - callop->Function = DoSimplify(callop->Function, sym); - } - // If the left side is a type ref, then this is actually a cast - // and not a function call. - if (callop->Function->Operation == PEX_TypeRef) - { - if (parmcount != 1) - { - Error(callop, "Type cast requires one parameter"); - callop->ToErrorNode(); - } - else - { - PType *dest = static_cast(callop->Function)->RefType; - const PType::Conversion *route[CONVERSION_ROUTE_SIZE]; - int routelen = parm->Value->Type->FindConversion(dest, route, countof(route)); - if (routelen < 0) - { - ///FIXME: Need real type names - Error(callop, "Cannot convert %s to %s", parm->Value->Type->DescriptiveName(), dest->DescriptiveName()); - callop->ToErrorNode(); - } - else - { - ZCC_Expression *val = ApplyConversion(parm->Value, route, routelen); - assert(val->Type == dest); - return val; - } - } - } - return callop; -} - -//========================================================================== -// -// ZCCCompiler :: PromoteUnary -// -// Converts the operand into a format preferred by the operator. -// -//========================================================================== - -ZCC_OpProto *ZCCCompiler::PromoteUnary(EZCCExprType op, ZCC_Expression *&expr) -{ - if (expr->Type == TypeError) - { - return NULL; - } - const PType::Conversion *route[CONVERSION_ROUTE_SIZE]; - int routelen = countof(route); - ZCC_OpProto *proto = ZCC_OpInfo[op].FindBestProto(expr->Type, route, routelen); - - if (proto != NULL) - { - expr = ApplyConversion(expr, route, routelen); - } - return proto; -} - -//========================================================================== -// -// ZCCCompiler :: PromoteBinary -// -// Converts the operands into a format (hopefully) compatible with the -// operator. -// -//========================================================================== - -ZCC_OpProto *ZCCCompiler::PromoteBinary(EZCCExprType op, ZCC_Expression *&left, ZCC_Expression *&right) -{ - // If either operand is of type 'error', the result is also 'error' - if (left->Type == TypeError || right->Type == TypeError) - { - return NULL; - } - const PType::Conversion *route1[CONVERSION_ROUTE_SIZE], *route2[CONVERSION_ROUTE_SIZE]; - int route1len = countof(route1), route2len = countof(route2); - ZCC_OpProto *proto = ZCC_OpInfo[op].FindBestProto(left->Type, route1, route1len, right->Type, route2, route2len); - if (proto != NULL) - { - left = ApplyConversion(left, route1, route1len); - right = ApplyConversion(right, route2, route2len); - } - return proto; -} - -//========================================================================== -// -// ZCCCompiler :: ApplyConversion -// -//========================================================================== - -ZCC_Expression *ZCCCompiler::ApplyConversion(ZCC_Expression *expr, const PType::Conversion **route, int routelen) -{ - for (int i = 0; i < routelen; ++i) - { - if (expr->Operation != PEX_ConstValue) - { - expr = AddCastNode(route[i]->TargetType, expr); - } - else - { - route[i]->ConvertConstant(static_cast(expr), AST.Strings); - } - } - return expr; -} - -//========================================================================== -// -// ZCCCompiler :: AddCastNode -// -//========================================================================== - -ZCC_Expression *ZCCCompiler::AddCastNode(PType *type, ZCC_Expression *expr) -{ - assert(expr->Operation != PEX_ConstValue && "Expression must not be constant"); - // TODO: add a node here - return expr; -} //========================================================================== // @@ -1293,7 +1095,7 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray &Fiel if (field->Type->ArraySize != nullptr) { - fieldtype = ResolveArraySize(fieldtype, field->Type->ArraySize, &type->Symbols); + fieldtype = ResolveArraySize(fieldtype, field->Type->ArraySize, type); } auto name = field->Names; @@ -1304,7 +1106,7 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray &Fiel auto thisfieldtype = fieldtype; if (name->ArraySize != nullptr) { - thisfieldtype = ResolveArraySize(thisfieldtype, name->ArraySize, &type->Symbols); + thisfieldtype = ResolveArraySize(thisfieldtype, name->ArraySize, type); } if (varflags & VARF_Native) @@ -1662,7 +1464,7 @@ PType *ZCCCompiler::ResolveUserType(ZCC_BasicType *type, PSymbolTable *symt) // //========================================================================== -PType *ZCCCompiler::ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PSymbolTable *sym) +PType *ZCCCompiler::ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PStruct *cls) { TArray indices; @@ -1674,15 +1476,21 @@ PType *ZCCCompiler::ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, node = static_cast(node->SiblingNext); } while (node != arraysize); + + FCompileContext ctx(cls, false); for (auto node : indices) { - auto val = Simplify(node, sym, true); - if (val->Operation != PEX_ConstValue || !val->Type->IsA(RUNTIME_CLASS(PInt))) + // There is no float->int casting here. + FxExpression *ex = ConvertNode(node); + ex = ex->Resolve(ctx); + + if (ex == nullptr) return TypeError; + if (!ex->isConstant() || !ex->ValueType->IsA(RUNTIME_CLASS(PInt))) { Error(arraysize, "Array index must be an integer constant"); return TypeError; } - int size = static_cast(val)->IntVal; + int size = static_cast(ex)->GetValue().GetInt(); if (size < 1) { Error(arraysize, "Array size must be positive"); @@ -1693,78 +1501,6 @@ PType *ZCCCompiler::ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, return baseType; } -//========================================================================== -// -// ZCCCompiler :: GetInt - Input must be a constant expression -// -//========================================================================== - -int ZCCCompiler::GetInt(ZCC_Expression *expr) -{ - if (expr->Type == TypeError) - { - return 0; - } - const PType::Conversion *route[CONVERSION_ROUTE_SIZE]; - int routelen = expr->Type->FindConversion(TypeSInt32, route, countof(route)); - if (routelen < 0) - { - Error(expr, "Cannot convert to integer"); - return 0; - } - else - { - if (expr->Type->IsKindOf(RUNTIME_CLASS(PFloat))) - { - Warn(expr, "Truncation of floating point value"); - } - auto ex = static_cast(ApplyConversion(expr, route, routelen)); - return ex->IntVal; - } -} - -double ZCCCompiler::GetDouble(ZCC_Expression *expr) -{ - if (expr->Type == TypeError) - { - return 0; - } - const PType::Conversion *route[CONVERSION_ROUTE_SIZE]; - int routelen = expr->Type->FindConversion(TypeFloat64, route, countof(route)); - if (routelen < 0) - { - Error(expr, "Cannot convert to float"); - return 0; - } - else - { - auto ex = static_cast(ApplyConversion(expr, route, routelen)); - return ex->DoubleVal; - } -} - -const char *ZCCCompiler::GetString(ZCC_Expression *expr, bool silent) -{ - if (expr->Type == TypeError) - { - return nullptr; - } - else if (expr->Type->IsKindOf(RUNTIME_CLASS(PString))) - { - return static_cast(expr)->StringVal->GetChars(); - } - else if (expr->Type->IsKindOf(RUNTIME_CLASS(PName))) - { - // Ugh... What a mess... - return FName(ENamedName(static_cast(expr)->IntVal)).GetChars(); - } - else - { - if (!silent) Error(expr, "Cannot convert to string"); - return nullptr; - } -} - //========================================================================== // // Parses an actor property's parameters and calls the handler @@ -1787,16 +1523,22 @@ void ZCCCompiler::DispatchProperty(FPropertyInfo *prop, ZCC_PropertyStmt *proper Error(property, "%s: arguments missing", prop->name); return; } - property->Values = Simplify(property->Values, &bag.Info->Symbols, true); // need to do this before the loop so that we can find the head node again. const char * p = prop->params; auto exp = property->Values; + FCompileContext ctx(bag.Info, false); while (true) { FPropParam conv; FPropParam pref; - if (exp->NodeType != AST_ExprConstant) + FxExpression *ex = ConvertNode(exp); + ex = ex->Resolve(ctx); + if (ex == nullptr) + { + return; + } + else if (!ex->isConstant()) { // If we get TypeError, there has already been a message from deeper down so do not print another one. if (exp->Type != TypeError) Error(exp, "%s: non-constant parameter", prop->name); @@ -1809,7 +1551,7 @@ void ZCCCompiler::DispatchProperty(FPropertyInfo *prop, ZCC_PropertyStmt *proper { case 'X': // Expression in parentheses or number. We only support the constant here. The function will have to be handled by a separate property to get past the parser. - conv.i = GetInt(exp); + conv.i = GetIntConst(ex, ctx); params.Push(conv); conv.exp = nullptr; break; @@ -1817,15 +1559,15 @@ void ZCCCompiler::DispatchProperty(FPropertyInfo *prop, ZCC_PropertyStmt *proper case 'I': case 'M': // special case for morph styles in DECORATE . This expression-aware parser will not need this. case 'N': // special case for thing activations in DECORATE. This expression-aware parser will not need this. - conv.i = GetInt(exp); + conv.i = GetIntConst(ex, ctx); break; case 'F': - conv.d = GetDouble(exp); + conv.d = GetFloatConst(ex, ctx); break; case 'Z': // an optional string. Does not allow any numeric value. - if (!GetString(exp, true)) + if (ex->ValueType != TypeString) { // apply this expression to the next argument on the list. params.Push(conv); @@ -1833,21 +1575,21 @@ void ZCCCompiler::DispatchProperty(FPropertyInfo *prop, ZCC_PropertyStmt *proper p++; continue; } - conv.s = GetString(exp); + conv.s = GetStringConst(ex, ctx); break; case 'C': // this parser accepts colors only in string form. pref.i = 1; case 'S': case 'T': // a filtered string (ZScript only parses filtered strings so there's nothing to do here.) - conv.s = GetString(exp); + conv.s = GetStringConst(ex, ctx); break; case 'L': // Either a number or a list of strings - if (!GetString(exp, true)) + if (ex->ValueType != TypeString) { pref.i = 0; - conv.i = GetInt(exp); + conv.i = GetIntConst(ex, ctx); } else { @@ -1857,13 +1599,13 @@ void ZCCCompiler::DispatchProperty(FPropertyInfo *prop, ZCC_PropertyStmt *proper do { - conv.s = GetString(exp); + conv.s = GetStringConst(ex, ctx); if (conv.s != nullptr) { params.Push(conv); params[0].i++; } - exp = Simplify(static_cast(exp->SiblingNext), &bag.Info->Symbols, true); + exp = static_cast(exp->SiblingNext); } while (exp != property->Values); goto endofparm; } @@ -1881,7 +1623,7 @@ void ZCCCompiler::DispatchProperty(FPropertyInfo *prop, ZCC_PropertyStmt *proper } params.Push(conv); params[0].i++; - exp = Simplify(static_cast(exp->SiblingNext), &bag.Info->Symbols, true); + exp = static_cast(exp->SiblingNext); endofparm: p++; // Skip the DECORATE 'no comma' marker @@ -1950,8 +1692,8 @@ void ZCCCompiler::DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt *prop return; } - auto values = Simplify(property->Values, &bag.Info->Symbols, true); // need to do this before the loop so that we can find the head node again. - auto exp = values; + auto exp = property->Values; + FCompileContext ctx(bag.Info, false); for (auto f : prop->Variables) { void *addr; @@ -1965,25 +1707,38 @@ void ZCCCompiler::DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt *prop addr = ((char*)defaults) + f->Offset; } + FxExpression *ex = ConvertNode(exp); + ex = ex->Resolve(ctx); + if (ex == nullptr) + { + return; + } + else if (!ex->isConstant()) + { + // If we get TypeError, there has already been a message from deeper down so do not print another one. + if (exp->Type != TypeError) Error(exp, "%s: non-constant parameter", prop->SymbolName.GetChars()); + return; + } + if (f->Type == TypeBool) { - static_cast(f->Type)->SetValue(addr, !!GetInt(exp)); + static_cast(f->Type)->SetValue(addr, !!GetIntConst(ex, ctx)); } if (f->Type->IsKindOf(RUNTIME_CLASS(PInt))) { - static_cast(f->Type)->SetValue(addr, GetInt(exp)); + static_cast(f->Type)->SetValue(addr, GetIntConst(ex, ctx)); } else if (f->Type->IsKindOf(RUNTIME_CLASS(PFloat))) { - static_cast(f->Type)->SetValue(addr, GetDouble(exp)); + static_cast(f->Type)->SetValue(addr, GetFloatConst(ex, ctx)); } else if (f->Type->IsKindOf(RUNTIME_CLASS(PString))) { - *(FString*)addr = GetString(exp); + *(FString*)addr = GetStringConst(ex, ctx); } else if (f->Type->IsKindOf(RUNTIME_CLASS(PClassPointer))) { - auto clsname = GetString(exp); + auto clsname = GetStringConst(ex, ctx); auto cls = PClass::FindClass(clsname); if (cls == nullptr) { @@ -1991,7 +1746,7 @@ void ZCCCompiler::DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt *prop } else if (!cls->IsDescendantOf(static_cast(f->Type)->ClassRestriction)) { - Error(property, "class %s is not compatible with property type %s", clsname, static_cast(f->Type)->ClassRestriction->TypeName.GetChars()); + Error(property, "class %s is not compatible with property type %s", clsname.GetChars(), static_cast(f->Type)->ClassRestriction->TypeName.GetChars()); } *(PClass**)addr = cls; } @@ -2772,7 +2527,7 @@ void ZCCCompiler::CompileStates() { state.sprite = GetSpriteIndex(sl->Sprite->GetChars()); } - // It is important to call CheckRandom before Simplify, because Simplify will resolve the function's name to nonsense + FCompileContext ctx(c->Type(), false); if (CheckRandom(sl->Duration)) { auto func = static_cast(sl->Duration); @@ -2780,26 +2535,16 @@ void ZCCCompiler::CompileStates() { Error(sl, "Random duration requires exactly 2 parameters"); } - auto p1 = Simplify(func->Parameters->Value, &c->Type()->Symbols, true); - auto p2 = Simplify(static_cast(func->Parameters->SiblingNext)->Value, &c->Type()->Symbols, true); - int v1 = GetInt(p1); - int v2 = GetInt(p2); + int v1 = IntConstFromNode(func->Parameters->Value, c->Type()); + int v2 = IntConstFromNode(static_cast(func->Parameters->SiblingNext)->Value, c->Type()); if (v1 > v2) std::swap(v1, v2); state.Tics = (int16_t)clamp(v1, 0, INT16_MAX); state.TicRange = (uint16_t)clamp(v2 - v1, 0, UINT16_MAX); } else { - auto duration = Simplify(sl->Duration, &c->Type()->Symbols, true); - if (duration->Operation == PEX_ConstValue) - { - state.Tics = (int16_t)clamp(GetInt(duration), -1, INT16_MAX); - state.TicRange = 0; - } - else - { - Error(sl, "Duration is not a constant"); - } + state.Tics = (int16_t)IntConstFromNode(sl->Duration, c->Type()); + state.TicRange = 0; } if (sl->bBright) state.StateFlags |= STF_FULLBRIGHT; if (sl->bFast) state.StateFlags |= STF_FAST; @@ -2815,18 +2560,8 @@ void ZCCCompiler::CompileStates() } if (sl->Offset != nullptr) { - auto o1 = static_cast(Simplify(sl->Offset, &c->Type()->Symbols, true)); - auto o2 = static_cast(Simplify(static_cast(o1->SiblingNext), &c->Type()->Symbols, true)); - - if (o1->Operation != PEX_ConstValue || o2->Operation != PEX_ConstValue) - { - Error(o1, "State offsets must be constant"); - } - else - { - state.Misc1 = GetInt(o1); - state.Misc2 = GetInt(o2); - } + state.Misc1 = IntConstFromNode(sl->Offset, c->Type()); + state.Misc2 = IntConstFromNode(static_cast(sl->Offset->SiblingNext), c->Type()); } #ifdef DYNLIGHT if (sl->Lights != nullptr) @@ -2834,7 +2569,7 @@ void ZCCCompiler::CompileStates() auto l = sl->Lights; do { - AddStateLight(&state, GetString(l)); + AddStateLight(&state, StringConstFromNode(l, c->Type())); l = static_cast(l->SiblingNext); } while (l != sl->Lights); } @@ -2875,23 +2610,15 @@ void ZCCCompiler::CompileStates() statename.Truncate((long)statename.Len() - 1); // remove the last '.' in the label name if (sg->Offset != nullptr) { - auto ofs = Simplify(sg->Offset, &c->Type()->Symbols, true); - if (ofs->Operation != PEX_ConstValue) + int offset = IntConstFromNode(sg->Offset, c->Type()); + if (offset < 0) { - Error(sg, "Constant offset expected for GOTO"); + Error(sg, "GOTO offset must be positive"); + offset = 0; } - else + if (offset > 0) { - int offset = GetInt(ofs); - if (offset < 0) - { - Error(sg, "GOTO offset must be positive"); - offset = 0; - } - if (offset > 0) - { - statename.AppendFormat("+%d", offset); - } + statename.AppendFormat("+%d", offset); } } if (!statedef.SetGotoLabel(statename)) @@ -3292,7 +3019,7 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast) if (loc->Type->ArraySize != nullptr) { - ztype = ResolveArraySize(ztype, loc->Type->ArraySize, &ConvertClass->Symbols); + ztype = ResolveArraySize(ztype, loc->Type->ArraySize, ConvertClass); } do @@ -3301,7 +3028,7 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast) if (node->ArraySize != nullptr) { - type = ResolveArraySize(ztype, node->ArraySize, &ConvertClass->Symbols); + type = ResolveArraySize(ztype, node->ArraySize, ConvertClass); } else { diff --git a/src/scripting/zscript/zcc_compile.h b/src/scripting/zscript/zcc_compile.h index 8675b1af7..79dc3b135 100644 --- a/src/scripting/zscript/zcc_compile.h +++ b/src/scripting/zscript/zcc_compile.h @@ -2,6 +2,7 @@ #define ZCC_COMPILE_H #include +#include "codegeneration/codegen.h" struct Baggage; struct FPropertyInfo; @@ -77,7 +78,9 @@ struct ZCC_PropertyWork struct ZCC_ConstantWork { ZCC_ConstantDef *node; - PSymbolTable *outputtable; + PStruct *cls; + PSymbolTable *Outputtable; + ExpVal constval; }; class ZCCCompiler @@ -88,14 +91,16 @@ public: int Compile(); private: + int IntConstFromNode(ZCC_TreeNode *node, PStruct *cls); + FString ZCCCompiler::StringConstFromNode(ZCC_TreeNode *node, PStruct *cls); void ProcessClass(ZCC_Class *node, PSymbolTreeNode *tnode); void ProcessStruct(ZCC_Struct *node, PSymbolTreeNode *tnode, ZCC_Class *outer); void CreateStructTypes(); void CreateClassTypes(); - void CopyConstants(TArray &dest, TArray &Constants, PSymbolTable *ot); + void CopyConstants(TArray &dest, TArray &Constants, PStruct *cls, PSymbolTable *ot); void CompileAllConstants(); void AddConstant(ZCC_ConstantWork &constant); - bool CompileConstant(ZCC_ConstantDef *def, PSymbolTable *Symbols); + bool CompileConstant(ZCC_ConstantWork *def); void CompileAllFields(); bool CompileFields(PStruct *type, TArray &Fields, PClass *Outer, PSymbolTable *TreeNodes, bool forstruct, bool hasnativechildren = false); @@ -103,7 +108,7 @@ private: bool CompileProperties(PClass *type, TArray &Properties, FName prefix); FString FlagsToString(uint32_t flags); PType *DetermineType(PType *outertype, ZCC_TreeNode *field, FName name, ZCC_Type *ztype, bool allowarraytypes, bool formember); - PType *ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PSymbolTable *sym); + PType *ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PStruct *cls); PType *ResolveUserType(ZCC_BasicType *type, PSymbolTable *sym); void InitDefaults(); @@ -111,9 +116,6 @@ private: void ProcessDefaultProperty(PClassActor *cls, ZCC_PropertyStmt *flg, Baggage &bag); void DispatchProperty(FPropertyInfo *prop, ZCC_PropertyStmt *pex, AActor *defaults, Baggage &bag); void DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt *pex, AActor *defaults, Baggage &bag); - int GetInt(ZCC_Expression *expr); - double GetDouble(ZCC_Expression *expr); - const char *GetString(ZCC_Expression *expr, bool silent = false); void CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool forclass); void InitFunctions(); @@ -128,18 +130,6 @@ private: PSymbolTreeNode *AddTreeNode(FName name, ZCC_TreeNode *node, PSymbolTable *treenodes, bool searchparents = false); - ZCC_Expression *Simplify(ZCC_Expression *root, PSymbolTable *Symbols, bool wantconstant); - ZCC_Expression *DoSimplify(ZCC_Expression *root, PSymbolTable *Symbols); - ZCC_Expression *SimplifyUnary(ZCC_ExprUnary *unary, PSymbolTable *Symbols); - ZCC_Expression *SimplifyBinary(ZCC_ExprBinary *binary, PSymbolTable *Symbols); - ZCC_Expression *SimplifyMemberAccess(ZCC_ExprMemberAccess *dotop, PSymbolTable *Symbols); - ZCC_Expression *SimplifyFunctionCall(ZCC_ExprFuncCall *callop, PSymbolTable *Symbols); - ZCC_OpProto *PromoteUnary(EZCCExprType op, ZCC_Expression *&expr); - ZCC_OpProto *PromoteBinary(EZCCExprType op, ZCC_Expression *&left, ZCC_Expression *&right); - - ZCC_Expression *ApplyConversion(ZCC_Expression *expr, const PType::Conversion **route, int routelen); - ZCC_Expression *AddCastNode(PType *type, ZCC_Expression *expr); - ZCC_Expression *IdentifyIdentifier(ZCC_ExprID *idnode, PSymbolTable *sym); ZCC_Expression *NodeFromSymbol(PSymbol *sym, ZCC_Expression *source, PSymbolTable *table); ZCC_ExprConstant *NodeFromSymbolConst(PSymbolConst *sym, ZCC_Expression *idnode); diff --git a/src/scripting/zscript/zcc_expr.cpp b/src/scripting/zscript/zcc_expr.cpp deleted file mode 100644 index 0c2c6baee..000000000 --- a/src/scripting/zscript/zcc_expr.cpp +++ /dev/null @@ -1,530 +0,0 @@ -/* -** zcc_expr.cpp -** -**--------------------------------------------------------------------------- -** Copyright -2016 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**--------------------------------------------------------------------------- -** -*/ - -#include -#include "dobject.h" -#include "sc_man.h" -#include "c_console.h" -#include "c_dispatch.h" -#include "w_wad.h" -#include "cmdlib.h" -#include "m_alloc.h" -#include "zcc_parser.h" -#include "templates.h" -#include "math/cmath.h" - -#define luai_nummod(a,b) ((a) - floor((a)/(b))*(b)) - -static void FtoD(ZCC_ExprConstant *expr, FSharedStringArena &str_arena); - -ZCC_OpInfoType ZCC_OpInfo[PEX_COUNT_OF] = -{ -#define xx(a,z) { #a, NULL }, -#include "zcc_exprlist.h" -}; - -// Structures used for initializing operator overloads -struct OpProto1 -{ - EZCCExprType Op; - PType **Type; - EvalConst1op EvalConst; -}; - -struct OpProto2 -{ - EZCCExprType Op; - PType **Res, **Ltype, **Rtype; - EvalConst2op EvalConst; -}; - -static struct FreeOpInfoProtos -{ - ~FreeOpInfoProtos() - { - for (size_t i = 0; i < countof(ZCC_OpInfo); ++i) - { - ZCC_OpInfo[i].FreeAllProtos(); - } - } -} ProtoFreeer; - -void ZCC_OpInfoType::FreeAllProtos() -{ - for (ZCC_OpProto *proto = Protos, *next = NULL; proto != NULL; proto = next) - { - next = proto->Next; - delete proto; - } - Protos = NULL; -} - -void ZCC_OpInfoType::AddProto(PType *res, PType *optype, EvalConst1op evalconst) -{ - ZCC_OpProto *proto = new ZCC_OpProto(res, optype, NULL); - proto->EvalConst1 = evalconst; - proto->Next = Protos; - Protos = proto; -} - -void ZCC_OpInfoType::AddProto(PType *res, PType *ltype, PType *rtype, EvalConst2op evalconst) -{ - assert(ltype != NULL); - ZCC_OpProto *proto = new ZCC_OpProto(res, ltype, rtype); - proto->EvalConst2 = evalconst; - proto->Next = Protos; - Protos = proto; -} - -//========================================================================== -// -// ZCC_OpInfoType :: FindBestProto (Unary) -// -// Finds the "best" prototype for this operand type. Best is defined as the -// one that requires the fewest conversions. Also returns the conversion -// route necessary to get from the input type to the desired type. -// -//========================================================================== - -ZCC_OpProto *ZCC_OpInfoType::FindBestProto(PType *optype, const PType::Conversion **route, int &numslots) -{ - assert(optype != NULL); - - const PType::Conversion *routes[2][CONVERSION_ROUTE_SIZE]; - const PType::Conversion **best_route = NULL; - int cur_route = 0; - ZCC_OpProto *best_proto = NULL; - int best_dist = INT_MAX; - - // Find the best prototype. - for (ZCC_OpProto *proto = Protos; best_dist != 0 && proto != NULL; proto = proto->Next) - { - if (proto->Type2 != NULL) - { // Not a unary prototype. - continue; - } - int dist = optype->FindConversion(proto->Type1, routes[cur_route], CONVERSION_ROUTE_SIZE); - if (dist >= 0 && dist < best_dist) - { - best_dist = dist; - best_proto = proto; - best_route = routes[cur_route]; - cur_route ^= 1; - } - } - // Copy best conversion route to the caller's array. - if (best_route != NULL && route != NULL && numslots > 0) - { - numslots = MIN(numslots, best_dist); - if (numslots > 0) - { - memcpy(route, best_route, sizeof(*route) * numslots); - } - } - return best_proto; -} - -//========================================================================== -// -// ZCC_OpInfoType :: FindBestProto (Binary) -// -// Finds the "best" prototype for the given operand types. Here, best is -// defined as the one that requires the fewest conversions for *one* of the -// operands. For prototypes with matching distances, the first one found -// is used. ZCC_InitOperators() initializes the prototypes in order such -// that this will result in the precedences: double > uint > int -// -//========================================================================== - -ZCC_OpProto *ZCC_OpInfoType::FindBestProto( - PType *left, const PType::Conversion **route1, int &numslots1, - PType *right, const PType::Conversion **route2, int &numslots2) -{ - assert(left != NULL && right != NULL); - - const PType::Conversion *routes[2][2][CONVERSION_ROUTE_SIZE]; - const PType::Conversion **best_route1 = NULL, **best_route2 = NULL; - int cur_route1 = 0, cur_route2 = 0; - int best_dist1 = INT_MAX, best_dist2 = INT_MAX; - - ZCC_OpProto *best_proto = NULL; - int best_low_dist = INT_MAX; - - for (ZCC_OpProto *proto = Protos; best_low_dist != 0 && proto != NULL; proto = proto->Next) - { - if (proto->Type2 == NULL) - { // Not a binary prototype - continue; - } - int dist1 = left->FindConversion(proto->Type1, routes[0][cur_route1], CONVERSION_ROUTE_SIZE); - int dist2 = right->FindConversion(proto->Type2, routes[1][cur_route2], CONVERSION_ROUTE_SIZE); - if (dist1 < 0 || dist2 < 0) - { // one or both operator types are unreachable - continue; - } - // Do not count F32->F64 conversions in the distance comparisons. If we do, then - // [[float32 (op) int]] will choose the integer version instead of the floating point - // version, which we do not want. - int test_dist1 = dist1, test_dist2 = dist2; - if (test_dist1 > 0 && routes[0][cur_route1][0]->ConvertConstant == FtoD) - { - test_dist1--; - } - if (test_dist2 > 0 && routes[1][cur_route2][0]->ConvertConstant == FtoD) - { - test_dist2--; - } - int dist = MIN(test_dist1, test_dist2); - if (dist < best_low_dist) - { - best_low_dist = dist; - best_proto = proto; - best_dist1 = dist1; - best_dist2 = dist2; - best_route1 = routes[0][cur_route1]; - best_route2 = routes[1][cur_route2]; - cur_route1 ^= 1; - cur_route2 ^= 1; - } - } - // Copy best conversion route to the caller's arrays. - if (best_route1 != NULL && route1 != NULL && numslots1 > 0) - { - numslots1 = MIN(numslots1, best_dist1); - if (numslots1 > 0) - { - memcpy(route1, best_route1, sizeof(*route1) * numslots1); - } - } - if (best_route2 != NULL && route2 != NULL && numslots2 > 0) - { - numslots2 = MIN(numslots2, best_dist2); - if (numslots2 > 0) - { - memcpy(route2, best_route2, sizeof(*route2) * numslots2); - } - } - return best_proto; -} - -static ZCC_ExprConstant *EvalIdentity(ZCC_ExprConstant *val) -{ - return val; -} - - -static ZCC_ExprConstant *EvalConcat(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &strings) -{ - FString str = *l->StringVal + *r->StringVal; - l->StringVal = strings.Alloc(str); - return l; -} - -static ZCC_ExprConstant *EvalLTGTEQSInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) -{ - l->IntVal = l->IntVal < r->IntVal ? -1 : l->IntVal == r->IntVal ? 0 : 1; - return l; -} - -static ZCC_ExprConstant *EvalLTGTEQUInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) -{ - l->IntVal = l->UIntVal < r->UIntVal ? -1 : l->UIntVal == r->UIntVal ? 0 : 1; - l->Type = TypeSInt32; - return l; -} - -static ZCC_ExprConstant *EvalLTGTEQFloat64(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &) -{ - l->IntVal = l->DoubleVal < r->DoubleVal ? -1 : l->DoubleVal == r->DoubleVal ? 0 : 1; - l->Type = TypeSInt32; - return l; -} - -void ZCC_InitOperators() -{ - // Prototypes are added from lowest to highest conversion precedence. - - // Unary operators - static const OpProto1 UnaryOpInit[] = - { - { PEX_PostInc , (PType **)&TypeSInt32, EvalIdentity }, - { PEX_PostInc , (PType **)&TypeUInt32, EvalIdentity }, - { PEX_PostInc , (PType **)&TypeFloat64, EvalIdentity }, - - { PEX_PostDec , (PType **)&TypeSInt32, EvalIdentity }, - { PEX_PostDec , (PType **)&TypeUInt32, EvalIdentity }, - { PEX_PostDec , (PType **)&TypeFloat64, EvalIdentity }, - - { PEX_PreInc , (PType **)&TypeSInt32, [](auto *val) { val->IntVal += 1; return val; } }, - { PEX_PreInc , (PType **)&TypeUInt32, [](auto *val) { val->UIntVal += 1; return val; } }, - { PEX_PreInc , (PType **)&TypeFloat64, [](auto *val) { val->DoubleVal += 1; return val; } }, - - { PEX_PreDec , (PType **)&TypeSInt32, [](auto *val) { val->IntVal -= 1; return val; } }, - { PEX_PreDec , (PType **)&TypeUInt32, [](auto *val) { val->UIntVal -= 1; return val; } }, - { PEX_PreDec , (PType **)&TypeFloat64, [](auto *val) { val->DoubleVal -= 1; return val; } }, - - { PEX_Negate , (PType **)&TypeSInt32, [](auto *val) { val->IntVal = -val->IntVal; return val; } }, - { PEX_Negate , (PType **)&TypeFloat64, [](auto *val) { val->DoubleVal = -val->DoubleVal; return val; } }, - - { PEX_AntiNegate , (PType **)&TypeSInt32, EvalIdentity }, - { PEX_AntiNegate , (PType **)&TypeUInt32, EvalIdentity }, - { PEX_AntiNegate , (PType **)&TypeFloat64, EvalIdentity }, - - { PEX_BitNot , (PType **)&TypeSInt32, [](auto *val) { val->IntVal = ~val->IntVal; return val; } }, - { PEX_BitNot , (PType **)&TypeUInt32, [](auto *val) { val->UIntVal = ~val->UIntVal; return val; } }, - - { PEX_BoolNot , (PType **)&TypeBool, [](auto *val) { val->IntVal = !val->IntVal; return val; } }, - }; - for (size_t i = 0; i < countof(UnaryOpInit); ++i) - { - ZCC_OpInfo[UnaryOpInit[i].Op].AddProto(*UnaryOpInit[i].Type, *UnaryOpInit[i].Type, UnaryOpInit[i].EvalConst); - } - - // Binary operators - static const OpProto2 BinaryOpInit[] = - { - { PEX_Add , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal += r->IntVal; return l; } }, - { PEX_Add , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->UIntVal += r->UIntVal; return l; } }, - { PEX_Add , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->DoubleVal += r->DoubleVal; return l; } }, - - { PEX_Sub , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal -= r->IntVal; return l; } }, - { PEX_Sub , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->UIntVal -= r->UIntVal; return l; } }, - { PEX_Sub , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->DoubleVal -= r->DoubleVal; return l; } }, - - { PEX_Mul , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal *= r->IntVal; return l; } }, - { PEX_Mul , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->UIntVal *= r->UIntVal; return l; } }, - { PEX_Mul , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->DoubleVal *= r->DoubleVal; return l; } }, - - { PEX_Div , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal /= r->IntVal; return l; } }, - { PEX_Div , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->UIntVal /= r->UIntVal; return l; } }, - { PEX_Div , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->DoubleVal /= r->DoubleVal; return l; } }, - - { PEX_Mod , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal %= r->IntVal; return l; } }, - { PEX_Mod , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->UIntVal %= r->UIntVal; return l; } }, - { PEX_Mod , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->DoubleVal = luai_nummod(l->DoubleVal, r->DoubleVal); return l; } }, - - { PEX_Pow , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->DoubleVal = g_pow(l->DoubleVal, r->DoubleVal); return l; } }, - - { PEX_Concat , (PType **)&TypeString, (PType **)&TypeString, (PType **)&TypeString, EvalConcat }, - - { PEX_BitAnd , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal &= r->IntVal; return l; } }, - { PEX_BitAnd , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->UIntVal &= r->UIntVal; return l; } }, - - { PEX_BitOr , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal |= r->IntVal; return l; } }, - { PEX_BitOr , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->UIntVal |= r->UIntVal; return l; } }, - - { PEX_BitXor , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal ^= r->IntVal; return l; } }, - { PEX_BitXor , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->UIntVal ^= r->UIntVal; return l; } }, - - { PEX_BoolAnd , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->IntVal && r->IntVal; l->Type = TypeBool; return l; } }, - { PEX_BoolAnd , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->UIntVal && r->UIntVal; l->Type = TypeBool; return l; } }, - - { PEX_BoolOr , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->IntVal || r->IntVal; l->Type = TypeBool; return l; } }, - { PEX_BoolOr , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->UIntVal || r->UIntVal; l->Type = TypeBool; return l; } }, - - { PEX_LeftShift , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->IntVal <<= r->UIntVal; return l; } }, - { PEX_LeftShift , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->UIntVal <<= r->UIntVal; return l; } }, - - { PEX_RightShift , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->IntVal >>= r->UIntVal; return l; } }, - { PEX_RightShift , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->UIntVal >>= r->UIntVal; return l; } }, - - { PEX_LT , (PType **)&TypeBool, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->IntVal < r->IntVal; l->Type = TypeBool; return l; } }, - { PEX_LT , (PType **)&TypeBool, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->UIntVal < r->UIntVal; l->Type = TypeBool; return l; } }, - { PEX_LT , (PType **)&TypeBool, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->IntVal = l->DoubleVal < r->DoubleVal; l->Type = TypeBool; return l; } }, - - { PEX_LTEQ , (PType **)&TypeBool, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->IntVal <= r->IntVal; l->Type = TypeBool; return l; } }, - { PEX_LTEQ , (PType **)&TypeBool, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->UIntVal <= r->UIntVal; l->Type = TypeBool; return l; } }, - { PEX_LTEQ , (PType **)&TypeBool, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->IntVal = l->DoubleVal <= r->DoubleVal; l->Type = TypeBool; return l; } }, - - { PEX_GT , (PType **)&TypeBool, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->IntVal > r->IntVal; l->Type = TypeBool; return l; } }, - { PEX_GT , (PType **)&TypeBool, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->UIntVal > r->UIntVal; l->Type = TypeBool; return l; } }, - { PEX_GT , (PType **)&TypeBool, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->IntVal = l->DoubleVal > r->DoubleVal; l->Type = TypeBool; return l; } }, - - { PEX_GTEQ , (PType **)&TypeBool, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->IntVal >= r->IntVal; l->Type = TypeBool; return l; } }, - { PEX_GTEQ , (PType **)&TypeBool, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->UIntVal >= r->UIntVal; l->Type = TypeBool; return l; } }, - { PEX_GTEQ , (PType **)&TypeBool, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->IntVal = l->DoubleVal >= r->DoubleVal; l->Type = TypeBool; return l; } }, - - { PEX_NEQ , (PType **)&TypeBool, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->IntVal != r->IntVal; l->Type = TypeBool; return l; } }, - { PEX_NEQ , (PType **)&TypeBool, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->UIntVal != r->UIntVal; l->Type = TypeBool; return l; } }, - { PEX_NEQ , (PType **)&TypeBool, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->IntVal = l->DoubleVal != r->DoubleVal; l->Type = TypeBool; return l; } }, - - { PEX_EQEQ , (PType **)&TypeBool, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->IntVal == r->IntVal; l->Type = TypeBool; return l; } }, - { PEX_EQEQ , (PType **)&TypeBool, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->UIntVal == r->UIntVal; l->Type = TypeBool; return l; } }, - { PEX_EQEQ , (PType **)&TypeBool, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->IntVal = l->DoubleVal == r->DoubleVal; l->Type = TypeBool; return l; } }, - - { PEX_LTGTEQ , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalLTGTEQSInt32 }, - { PEX_LTGTEQ , (PType **)&TypeSInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalLTGTEQUInt32 }, - { PEX_LTGTEQ , (PType **)&TypeSInt32, (PType **)&TypeFloat64, (PType **)&TypeFloat64, EvalLTGTEQFloat64 }, - }; - for (size_t i = 0; i < countof(BinaryOpInit); ++i) - { - ZCC_OpInfo[BinaryOpInit[i].Op].AddProto(*BinaryOpInit[i].Res, *BinaryOpInit[i].Ltype, *BinaryOpInit[i].Rtype, BinaryOpInit[i].EvalConst); - } -} - -static void IntToS32(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) -{ - // Integers always fill out the full sized 32-bit field, so converting - // from a smaller sized integer to a 32-bit one is as simple as changing - // the type field. - expr->Type = TypeSInt32; -} - -static void S32toS8(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) -{ - expr->IntVal = ((expr->IntVal << 24) >> 24); - expr->Type = TypeSInt8; -} - -static void S32toS16(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) -{ - expr->IntVal = ((expr->IntVal << 16) >> 16); - expr->Type = TypeSInt16; -} - -static void S32toU8(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) -{ - expr->IntVal &= 0xFF; - expr->Type = TypeUInt8; -} - -static void S32toU16(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) -{ - expr->IntVal &= 0xFFFF; - expr->Type = TypeUInt16; -} - -static void S32toU32(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) -{ - expr->Type = TypeUInt32; -} - -static void S32toD(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) -{ - expr->DoubleVal = expr->IntVal; - expr->Type = TypeFloat64; -} - -static void DtoS32(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) -{ - expr->IntVal = (int)expr->DoubleVal; - expr->Type = TypeSInt32; -} - -static void U32toD(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) -{ - expr->DoubleVal = expr->UIntVal; - expr->Type = TypeFloat64; -} - -static void DtoU32(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) -{ - expr->UIntVal = (unsigned int)expr->DoubleVal; - expr->Type = TypeUInt32; -} - -static void FtoD(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) -{ - // Constant single precision numbers are stored as doubles. - assert(expr->Type == TypeFloat32); - expr->Type = TypeFloat64; -} - -static void DtoF(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) -{ - // Truncate double precision to single precision. - float poop = (float)expr->DoubleVal; - expr->DoubleVal = poop; - expr->Type = TypeFloat32; -} - -static void S32toS(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) -{ - char str[16]; - int len = mysnprintf(str, countof(str), "%i", expr->IntVal); - expr->StringVal = str_arena.Alloc(str, len); - expr->Type = TypeString; -} - -static void U32toS(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) -{ - char str[16]; - int len = mysnprintf(str, countof(str), "%u", expr->UIntVal); - expr->StringVal = str_arena.Alloc(str, len); - expr->Type = TypeString; -} - -static void DtoS(ZCC_ExprConstant *expr, FSharedStringArena &str_arena) -{ - // Convert to a string with enough precision such that converting - // back to a double will not lose any data. - char str[64]; - IGNORE_FORMAT_PRE - int len = mysnprintf(str, countof(str), "%H", expr->DoubleVal); - IGNORE_FORMAT_POST - expr->StringVal = str_arena.Alloc(str, len); - expr->Type = TypeString; -} - -//========================================================================== -// -// ZCC_InitConversions -// -//========================================================================== - -void ZCC_InitConversions() -{ - TypeUInt8->AddConversion(TypeSInt32, IntToS32); - TypeSInt8->AddConversion(TypeSInt32, IntToS32); - TypeUInt16->AddConversion(TypeSInt32, IntToS32); - TypeSInt16->AddConversion(TypeSInt32, IntToS32); - - TypeUInt32->AddConversion(TypeSInt32, IntToS32); - TypeUInt32->AddConversion(TypeFloat64, U32toD); - TypeUInt32->AddConversion(TypeString, U32toS); - - TypeSInt32->AddConversion(TypeUInt8, S32toU8); - TypeSInt32->AddConversion(TypeSInt8, S32toS8); - TypeSInt32->AddConversion(TypeSInt16, S32toS16); - TypeSInt32->AddConversion(TypeUInt16, S32toU16); - TypeSInt32->AddConversion(TypeUInt32, S32toU32); - TypeSInt32->AddConversion(TypeFloat64, S32toD); - TypeSInt32->AddConversion(TypeString, S32toS); - - TypeFloat32->AddConversion(TypeFloat64, FtoD); - - TypeFloat64->AddConversion(TypeUInt32, DtoU32); - TypeFloat64->AddConversion(TypeSInt32, DtoS32); - TypeFloat64->AddConversion(TypeFloat32, DtoF); - TypeFloat64->AddConversion(TypeString, DtoS); -} diff --git a/src/scripting/zscript/zcc_parser.cpp b/src/scripting/zscript/zcc_parser.cpp index 95f75aea6..872ab2cc8 100644 --- a/src/scripting/zscript/zcc_parser.cpp +++ b/src/scripting/zscript/zcc_parser.cpp @@ -316,6 +316,8 @@ static void DoParse(int lumpnum) FScanner sc; void *parser; ZCCToken value; + auto baselump = lumpnum; + auto fileno = Wads.GetLumpFile(lumpnum); parser = ZCCParseAlloc(malloc); ZCCParseState state; @@ -344,6 +346,13 @@ static void DoParse(int lumpnum) } else { + auto fileno2 = Wads.GetLumpFile(lumpnum); + if (fileno == 0 && fileno2 != 0) + { + I_FatalError("File %s is overriding core lump %s.", + Wads.GetWadFullName(Wads.GetLumpFile(baselump)), Includes[i].GetChars()); + } + ParseSingleFile(nullptr, lumpnum, parser, state); } } @@ -408,9 +417,6 @@ void ParseScripts() { InitTokenMap(); } - ZCC_InitOperators(); - ZCC_InitConversions(); - int lump, lastlump = 0; FScriptPosition::ResetErrorCounter(); diff --git a/src/scripting/zscript/zcc_parser.h b/src/scripting/zscript/zcc_parser.h index b80686bb0..95bafd54f 100644 --- a/src/scripting/zscript/zcc_parser.h +++ b/src/scripting/zscript/zcc_parser.h @@ -527,47 +527,8 @@ struct ZCC_FlagStmt : ZCC_Statement bool set; }; -typedef ZCC_ExprConstant *(*EvalConst1op)(ZCC_ExprConstant *); -typedef ZCC_ExprConstant *(*EvalConst2op)(ZCC_ExprConstant *, ZCC_ExprConstant *, FSharedStringArena &); - -struct ZCC_OpProto -{ - ZCC_OpProto *Next; - PType *ResType; - PType *Type1; - PType *Type2; - union - { - EvalConst1op EvalConst1; - EvalConst2op EvalConst2; - }; - - ZCC_OpProto(PType *res, PType *t1, PType *t2) - : ResType(res), Type1(t1), Type2(t2) {} -}; - -struct ZCC_OpInfoType -{ - const char *OpName; - ZCC_OpProto *Protos; - - void AddProto(PType *res, PType *optype, EvalConst1op evalconst); - void AddProto(PType *res, PType *left, PType *right, EvalConst2op evalconst); - - ZCC_OpProto *FindBestProto(PType *optype, const PType::Conversion **route, int &numslots); - ZCC_OpProto *FindBestProto(PType *left, const PType::Conversion **route1, int &numslots, - PType *right, const PType::Conversion **route2, int &numslots2); - - void FreeAllProtos(); -}; - -#define CONVERSION_ROUTE_SIZE 8 - FString ZCC_PrintAST(ZCC_TreeNode *root); -void ZCC_InitOperators(); - -extern ZCC_OpInfoType ZCC_OpInfo[PEX_COUNT_OF]; struct ZCC_AST { diff --git a/src/swrenderer/things/r_particle.cpp b/src/swrenderer/things/r_particle.cpp index 4cf4803ce..510d05b7f 100644 --- a/src/swrenderer/things/r_particle.cpp +++ b/src/swrenderer/things/r_particle.cpp @@ -179,6 +179,8 @@ namespace swrenderer // store information in a vissprite RenderParticle *vis = RenderMemory::NewObject(); + memset(vis, 0, sizeof(*vis)); + vis->CurrentPortalUniq = renderportal->CurrentPortalUniq; vis->heightsec = heightsec; vis->xscale = FLOAT2FIXED(xscale); diff --git a/src/swrenderer/things/r_playersprite.cpp b/src/swrenderer/things/r_playersprite.cpp index 0d35fdea4..4cba801b7 100644 --- a/src/swrenderer/things/r_playersprite.cpp +++ b/src/swrenderer/things/r_playersprite.cpp @@ -273,6 +273,8 @@ namespace swrenderer // store information in a vissprite RenderSprite *vis = &avis[vispspindex]; + memset(vis, 0, sizeof(*vis)); + vis->renderflags = owner->renderflags; vis->floorclip = 0; diff --git a/src/swrenderer/things/r_sprite.cpp b/src/swrenderer/things/r_sprite.cpp index d237348f4..377654043 100644 --- a/src/swrenderer/things/r_sprite.cpp +++ b/src/swrenderer/things/r_sprite.cpp @@ -157,6 +157,7 @@ namespace swrenderer // store information in a vissprite RenderSprite *vis = RenderMemory::NewObject(); + memset(vis, 0, sizeof(*vis)); vis->CurrentPortalUniq = renderportal->CurrentPortalUniq; vis->xscale = FLOAT2FIXED(xscale); diff --git a/wadsrc/static/zscript/strife/inquisitor.txt b/wadsrc/static/zscript/strife/inquisitor.txt index 5c15f4af7..c1265b474 100644 --- a/wadsrc/static/zscript/strife/inquisitor.txt +++ b/wadsrc/static/zscript/strife/inquisitor.txt @@ -143,9 +143,9 @@ class Inquisitor : Actor A_PlaySound ("inquisitor/jump", CHAN_ITEM, 1, true); AddZ(64); A_FaceTarget (); - speed = Speed * (2./3); - VelFromAngle(speed); - double dist = DistanceBySpeed(target, speed); + let localspeed = Speed * (2./3); + VelFromAngle(localspeed); + double dist = DistanceBySpeed(target, localspeed); Vel.Z = (target.pos.z - pos.z) / dist; reactiontime = 60; bNoGravity = true;