From da4981ef91f588aeeb79be7d49f477dd94cd2851 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sun, 22 Jan 2017 10:25:37 +0200 Subject: [PATCH 01/15] Fixed invisible mouse cursor in SDL backend See https://mantis.zdoom.org/view.php?id=71 --- src/posix/sdl/sdlglvideo.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/posix/sdl/sdlglvideo.cpp b/src/posix/sdl/sdlglvideo.cpp index 290dfd6a1..d88c2bc6a 100644 --- a/src/posix/sdl/sdlglvideo.cpp +++ b/src/posix/sdl/sdlglvideo.cpp @@ -131,10 +131,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 () From 03f9425eb1df47845337c92e4142eb89b86a84dc Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sun, 22 Jan 2017 12:09:56 +0200 Subject: [PATCH 02/15] Fixed missing xBRZ menu options on platforms without MMX support xBRZ texture resize modes are no longer removed from menu for targets with HAVE_MMX undefined --- src/gl/system/gl_menu.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) 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); } From 89d9a43b68473f205806b79128b2fad7dc1980e1 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 22 Jan 2017 12:26:05 +0100 Subject: [PATCH 03/15] - fixed local variable having the same name as a member in Strife's inquisitor. --- wadsrc/static/zscript/strife/inquisitor.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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; From 935d49d75fe148702af3d197fd55339695a56621 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sun, 22 Jan 2017 13:51:22 +0200 Subject: [PATCH 04/15] Fixed returning of value from TakeInventory() function Issuing take CCMD no longer causes assertion failure at src/scripting/vm/vmexec.h:662 assert(numret == C && "Number of parameters returned differs from what was expected by the caller") --- src/p_mobj.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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)); } //============================================================================ From f9ef9358404d96f9039b0a53b11255b61d47320e Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sun, 22 Jan 2017 17:00:36 +0200 Subject: [PATCH 05/15] Fixed warning reported by GCC/Clang when optimization is enabled src/scripting/codegeneration/codegen.cpp:4097:12: warning: variable 'cast' is used uninitialized whenever 'if' condition is false --- src/scripting/codegeneration/codegen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index cb5944ade..2c96a2144 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) { From f15b0513275a82473f5ef9a89bd21592cab96948 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 22 Jan 2017 20:04:38 +0100 Subject: [PATCH 06/15] - use std::unique_ptr to manage the resource file for loading a savegame because the try/catch handler to ensure its deletion was causing some problems. --- src/g_game.cpp | 288 +++++++++++++++++++++++-------------------------- 1 file changed, 135 insertions(+), 153 deletions(-) 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(); } From f9f5e458248b2fbb8cb4d7a72650e210903f2cef Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 22 Jan 2017 20:12:44 +0100 Subject: [PATCH 07/15] - memset the entire vissprite structure when drawing a psprite because this does not initialize all fields. --- src/r_things.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/r_things.cpp b/src/r_things.cpp index b6b4a472a..730448706 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -1361,6 +1361,7 @@ void R_DrawPSprite(DPSprite *pspr, AActor *owner, float bobx, float boby, double // store information in a vissprite vis = &avis[vispspindex]; + memset(vis, 0, sizeof(*vis)); vis->renderflags = owner->renderflags; vis->floorclip = 0; vis->sector = nullptr; From 4c93e2baa3df3eca38ee697d152902bb22e69a95 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 22 Jan 2017 22:19:32 +0100 Subject: [PATCH 08/15] - use the expression evaluation capabilities of the compiler backend to resolve constants in actor defaults. This is the first step to get rid of Simplify and all the baggage it depends on. --- src/scripting/zscript/zcc_compile.cpp | 53 ++++++++++++++++++++------- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index ddf08fbc4..03bc15e45 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -1765,6 +1765,27 @@ const char *ZCCCompiler::GetString(ZCC_Expression *expr, bool silent) } } +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(); +} + //========================================================================== // // Parses an actor property's parameters and calls the handler @@ -1787,16 +1808,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 +1836,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 +1844,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 +1860,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 +1884,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 +1908,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 From 2880f5608002224b3f1ab9580ec145dacd7c14f5 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 22 Jan 2017 23:00:41 +0100 Subject: [PATCH 09/15] - also switched scripted properties away from Simplify. --- src/scripting/zscript/zcc_compile.cpp | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 03bc15e45..e76fcb2dd 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -1977,8 +1977,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; @@ -1992,25 +1992,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); + 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) { From 061ba48dc1d61a2df91221f48cf05b085b2d9eba Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 22 Jan 2017 23:53:50 +0100 Subject: [PATCH 10/15] - no more simplify in state parameters. - resolving constants with the backend requires a few more error checks. --- src/sc_man.cpp | 2 + src/sc_man.h | 1 + src/scripting/codegeneration/codegen.cpp | 52 ++++++++- src/scripting/zscript/zcc_compile.cpp | 133 +++++++++++------------ src/scripting/zscript/zcc_compile.h | 3 +- 5 files changed, 119 insertions(+), 72 deletions(-) diff --git a/src/sc_man.cpp b/src/sc_man.cpp index ccfb01ac5..b05349d00 100644 --- a/src/sc_man.cpp +++ b/src/sc_man.cpp @@ -1054,6 +1054,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..ded92b398 100644 --- a/src/sc_man.h +++ b/src/sc_man.h @@ -146,6 +146,7 @@ struct FScriptPosition static bool StrictErrors; FString FileName; int ScriptLine; + bool errorout = false; FScriptPosition() { diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 2c96a2144..e5a0470b0 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -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))) { @@ -7166,6 +7185,13 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& 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; @@ -7202,7 +7228,13 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) if (special != 0 && min >= 0) { int paramcount = ArgList.Size(); - if (paramcount < min) + if (ctx.Function == 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); @@ -7467,6 +7499,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 +7531,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 +7787,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/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index e76fcb2dd..365a29abb 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -52,6 +52,42 @@ #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(); +} + + //========================================================================== // // ZCCCompiler :: ProcessClass @@ -1293,7 +1329,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 +1340,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 +1698,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 +1710,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"); @@ -1765,27 +1807,6 @@ const char *ZCCCompiler::GetString(ZCC_Expression *expr, bool silent) } } -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(); -} - //========================================================================== // // Parses an actor property's parameters and calls the handler @@ -2812,7 +2833,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); @@ -2820,26 +2841,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; @@ -2855,18 +2866,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) @@ -2915,23 +2916,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)) @@ -3332,7 +3325,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 @@ -3341,7 +3334,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..2b9671cdc 100644 --- a/src/scripting/zscript/zcc_compile.h +++ b/src/scripting/zscript/zcc_compile.h @@ -88,6 +88,7 @@ public: int Compile(); private: + int ZCCCompiler::IntConstFromNode(ZCC_TreeNode *node, PStruct *cls); void ProcessClass(ZCC_Class *node, PSymbolTreeNode *tnode); void ProcessStruct(ZCC_Struct *node, PSymbolTreeNode *tnode, ZCC_Class *outer); void CreateStructTypes(); @@ -103,7 +104,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(); From 092b2d6ea0337ce8313cecb8cac43ff53e9d094d Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Sun, 22 Jan 2017 23:21:05 +0100 Subject: [PATCH 11/15] - Fixed Clang compile error [-Wnon-pod-varargs]. --- src/scripting/zscript/zcc_compile.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 365a29abb..41c58dc1c 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -2022,7 +2022,7 @@ void ZCCCompiler::DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt *prop 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); + if (exp->Type != TypeError) Error(exp, "%s: non-constant parameter", prop->SymbolName.GetChars()); return; } @@ -2052,7 +2052,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; } From 4694f9b20112b8100351d46622d8c82c28aebb95 Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Mon, 23 Jan 2017 00:22:25 +0100 Subject: [PATCH 12/15] - Fixed GCC/Clang 'extra qualification' error. --- src/scripting/zscript/zcc_compile.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripting/zscript/zcc_compile.h b/src/scripting/zscript/zcc_compile.h index 2b9671cdc..bda57e7b4 100644 --- a/src/scripting/zscript/zcc_compile.h +++ b/src/scripting/zscript/zcc_compile.h @@ -88,7 +88,7 @@ public: int Compile(); private: - int ZCCCompiler::IntConstFromNode(ZCC_TreeNode *node, PStruct *cls); + int IntConstFromNode(ZCC_TreeNode *node, PStruct *cls); void ProcessClass(ZCC_Class *node, PSymbolTreeNode *tnode); void ProcessStruct(ZCC_Struct *node, PSymbolTreeNode *tnode, ZCC_Class *outer); void CreateStructTypes(); From 68c3f42a53f9f1ae1678884e0425f57efaf5d7a5 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 23 Jan 2017 01:10:40 +0100 Subject: [PATCH 13/15] - no more Simplify for global constants as well. --- src/dobjtype.h | 2 +- src/sc_man.cpp | 1 + src/sc_man.h | 2 +- src/scripting/codegeneration/codegen.cpp | 51 ++++++++------ src/scripting/zscript/zcc_compile.cpp | 86 ++++++++++++++++++------ src/scripting/zscript/zcc_compile.h | 9 ++- 6 files changed, 105 insertions(+), 46 deletions(-) diff --git a/src/dobjtype.h b/src/dobjtype.h index d38c42c58..96c1a05e0 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -1043,7 +1043,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/sc_man.cpp b/src/sc_man.cpp index b05349d00..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) { diff --git a/src/sc_man.h b/src/sc_man.h index ded92b398..3347fe26a 100644 --- a/src/sc_man.h +++ b/src/sc_man.h @@ -144,9 +144,9 @@ struct FScriptPosition static int WarnCounter; static int ErrorCounter; static bool StrictErrors; + static bool errorout; FString FileName; int ScriptLine; - bool errorout = false; FScriptPosition() { diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index e5a0470b0..6065050a9 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -5829,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))) { @@ -7168,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) @@ -7181,27 +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 (ctx.Function == nullptr) - { - ScriptPosition.Message(MSG_ERROR, "Unable to call function %s from constant declaration", MethodName.GetChars()); - delete this; - return nullptr; - } + PFunction *afd = FindClassMemberFunction(ctx.Class, ctx.Class, MethodName, ScriptPosition, &error); - if (!CheckFunctionCompatiblity(ScriptPosition, ctx.Function, afd)) + if (afd != nullptr) { - delete this; - return nullptr; - } + if (ctx.Function == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Unable to call function %s from constant declaration", MethodName.GetChars()); + 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); + 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) @@ -7228,7 +7230,7 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) if (special != 0 && min >= 0) { int paramcount = ArgList.Size(); - if (ctx.Function == nullptr) + if (ctx.Function == nullptr || ctx.Class == nullptr) { ScriptPosition.Message(MSG_ERROR, "Unable to call action special %s from constant declaration", MethodName.GetChars()); delete this; @@ -7459,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) diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 365a29abb..83b93cafb 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -48,7 +48,6 @@ #include "p_lnspec.h" #include "i_system.h" #include "gdtoa.h" -#include "codegeneration/codegen.h" #include "vmbuilder.h" #include "version.h" @@ -642,11 +641,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 }); } } @@ -665,14 +664,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. @@ -693,7 +692,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 @@ -721,6 +720,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); @@ -747,14 +749,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); } //========================================================================== @@ -766,13 +794,31 @@ 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); + FCompileContext ctx(work->cls, false); + FxExpression *exp = ConvertNode(work->node->Value); + try + { + FScriptPosition::errorout = true; + exp = exp->Resolve(ctx); + if (exp == nullptr) return false; + FScriptPosition::errorout = false; + if (!exp->isConstant()) + { + delete exp; + return false; + } + work->constval = static_cast(exp)->GetValue(); + delete exp; + return true; + } + catch (...) + { + // 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; + } } diff --git a/src/scripting/zscript/zcc_compile.h b/src/scripting/zscript/zcc_compile.h index 2b9671cdc..d0284263a 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 @@ -93,10 +96,10 @@ private: 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); From f720073b317c45d1da8f1cca2ad34345c551b12f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 23 Jan 2017 01:37:43 +0100 Subject: [PATCH 14/15] - removed all code that was only there to implement the broken Simplifier that just got removed. --- src/CMakeLists.txt | 1 - src/dobjtype.cpp | 153 -------- src/dobjtype.h | 61 --- src/scripting/zscript/ast.cpp | 2 +- src/scripting/zscript/zcc_compile.cpp | 382 +------------------ src/scripting/zscript/zcc_compile.h | 16 +- src/scripting/zscript/zcc_expr.cpp | 530 -------------------------- src/scripting/zscript/zcc_parser.cpp | 3 - src/scripting/zscript/zcc_parser.h | 39 -- 9 files changed, 17 insertions(+), 1170 deletions(-) delete mode 100644 src/scripting/zscript/zcc_expr.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 870275324..55d728097 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1211,7 +1211,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 96c1a05e0..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 -------------------------------------------------- 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 83b93cafb..519db4d7e 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -86,6 +86,20 @@ int ZCCCompiler::IntConstFromNode(ZCC_TreeNode *node, PStruct *cls) 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(); +} + //========================================================================== // @@ -822,300 +836,6 @@ bool ZCCCompiler::CompileConstant(ZCC_ConstantWork *work) } -//========================================================================== -// -// 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) - { - 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) - { - ZCC_Expression *expr = NodeFromSymbol(sym, dotop, symtable); - if (expr != nullptr) - { - return expr; - } - } - } - else if (dotop->Left->Operation == PEX_Super) - { - 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; - } - } - } - } - 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; -} - //========================================================================== // // ZCCCompiler :: IdentifyIdentifier @@ -1781,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 @@ -2921,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); } diff --git a/src/scripting/zscript/zcc_compile.h b/src/scripting/zscript/zcc_compile.h index d0284263a..c01d8f339 100644 --- a/src/scripting/zscript/zcc_compile.h +++ b/src/scripting/zscript/zcc_compile.h @@ -92,6 +92,7 @@ public: private: int ZCCCompiler::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(); @@ -115,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(); @@ -132,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..78458876a 100644 --- a/src/scripting/zscript/zcc_parser.cpp +++ b/src/scripting/zscript/zcc_parser.cpp @@ -408,9 +408,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 { From 5a4a5a17db9c612f5265d19aaa5dd22ae408cf34 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 23 Jan 2017 01:56:15 +0100 Subject: [PATCH 15/15] - added core lump checks for ZScript. - load internal shaders only from file 0. This does not contain aborts, like most of the other checks,but it will now refuse to load any core shader file from anything but gzdoom.pk3. --- src/gl/shaders/gl_shader.cpp | 6 +++--- src/gl/shaders/gl_shaderprogram.cpp | 2 +- src/scripting/zscript/zcc_parser.cpp | 9 +++++++++ 3 files changed, 13 insertions(+), 4 deletions(-) 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/scripting/zscript/zcc_parser.cpp b/src/scripting/zscript/zcc_parser.cpp index 78458876a..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); } }