mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-11 15:21:51 +00:00
# Conflicts: # src/r_things.cpp
This commit is contained in:
commit
03226e5a0a
22 changed files with 431 additions and 1444 deletions
|
@ -1280,7 +1280,6 @@ set (PCH_SOURCES
|
||||||
scripting/vm/vmframe.cpp
|
scripting/vm/vmframe.cpp
|
||||||
scripting/zscript/ast.cpp
|
scripting/zscript/ast.cpp
|
||||||
scripting/zscript/zcc_compile.cpp
|
scripting/zscript/zcc_compile.cpp
|
||||||
scripting/zscript/zcc_expr.cpp
|
|
||||||
scripting/zscript/zcc_parser.cpp
|
scripting/zscript/zcc_parser.cpp
|
||||||
sfmt/SFMT.cpp
|
sfmt/SFMT.cpp
|
||||||
)
|
)
|
||||||
|
|
153
src/dobjtype.cpp
153
src/dobjtype.cpp
|
@ -240,159 +240,6 @@ size_t PType::PropagateMark()
|
||||||
return marked + Super::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
|
// PType :: WriteValue
|
||||||
|
|
|
@ -214,15 +214,6 @@ public:
|
||||||
typedef PClassType MetaClass;
|
typedef PClassType MetaClass;
|
||||||
MetaClass *GetClass() const;
|
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 Size; // this type's size
|
||||||
unsigned int Align; // this type's preferred alignment
|
unsigned int Align; // this type's preferred alignment
|
||||||
PType *HashNext; // next type in this type table
|
PType *HashNext; // next type in this type table
|
||||||
|
@ -235,10 +226,6 @@ public:
|
||||||
virtual ~PType();
|
virtual ~PType();
|
||||||
virtual bool isNumeric() { return false; }
|
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
|
// 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
|
// 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
|
// without completely breaking savegames, provided that the change isn't between
|
||||||
|
@ -318,54 +305,6 @@ public:
|
||||||
size_t PropagateMark();
|
size_t PropagateMark();
|
||||||
|
|
||||||
static void StaticInit();
|
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<Conversion> 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 --------------------------------------------------
|
// Not-really-a-type types --------------------------------------------------
|
||||||
|
@ -1043,7 +982,7 @@ class PSymbolConstString : public PSymbolConst
|
||||||
public:
|
public:
|
||||||
FString Str;
|
FString Str;
|
||||||
|
|
||||||
PSymbolConstString(FName name, FString &str) : PSymbolConst(name, TypeString), Str(str) {}
|
PSymbolConstString(FName name, const FString &str) : PSymbolConst(name, TypeString), Str(str) {}
|
||||||
PSymbolConstString() {}
|
PSymbolConstString() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
288
src/g_game.cpp
288
src/g_game.cpp
|
@ -1891,168 +1891,150 @@ void G_DoLoadGame ()
|
||||||
hidecon = gameaction == ga_loadgamehidecon;
|
hidecon = gameaction == ga_loadgamehidecon;
|
||||||
gameaction = ga_nothing;
|
gameaction = ga_nothing;
|
||||||
|
|
||||||
FResourceFile *resfile = FResourceFile::OpenResourceFile(savename.GetChars(), nullptr, true, true);
|
std::unique_ptr<FResourceFile> resfile(FResourceFile::OpenResourceFile(savename.GetChars(), nullptr, true, true));
|
||||||
if (resfile == nullptr)
|
if (resfile == nullptr)
|
||||||
{
|
{
|
||||||
Printf ("Could not read savegame '%s'\n", savename.GetChars());
|
Printf ("Could not read savegame '%s'\n", savename.GetChars());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try
|
FResourceLump *info = resfile->FindLump("info.json");
|
||||||
|
if (info == nullptr)
|
||||||
{
|
{
|
||||||
FResourceLump *info = resfile->FindLump("info.json");
|
Printf("'%s' is not a valid savegame: Missing 'info.json'.\n", savename.GetChars());
|
||||||
if (info == nullptr)
|
return;
|
||||||
{
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
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.
|
Printf("Failed to access savegame info\n");
|
||||||
if (resfile != nullptr) delete resfile;
|
return;
|
||||||
throw;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -60,15 +60,15 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char *
|
||||||
static char buffer[10000];
|
static char buffer[10000];
|
||||||
FString error;
|
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'");
|
if (i_lump == -1) I_Error("Unable to load 'shaders/glsl/shaderdefs.i'");
|
||||||
FMemLump i_data = Wads.ReadLump(i_lump);
|
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);
|
if (vp_lump == -1) I_Error("Unable to load '%s'", vert_prog_lump);
|
||||||
FMemLump vp_data = Wads.ReadLump(vp_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);
|
if (fp_lump == -1) I_Error("Unable to load '%s'", frag_prog_lump);
|
||||||
FMemLump fp_data = Wads.ReadLump(fp_lump);
|
FMemLump fp_data = Wads.ReadLump(fp_lump);
|
||||||
|
|
||||||
|
|
|
@ -89,7 +89,7 @@ void FShaderProgram::CreateShader(ShaderType type)
|
||||||
|
|
||||||
void FShaderProgram::Compile(ShaderType type, const char *lumpName, const char *defines, int maxGlslVersion)
|
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);
|
if (lump == -1) I_FatalError("Unable to load '%s'", lumpName);
|
||||||
FString code = Wads.ReadLump(lump).GetString().GetChars();
|
FString code = Wads.ReadLump(lump).GetString().GetChars();
|
||||||
Compile(type, lumpName, code, defines, maxGlslVersion);
|
Compile(type, lumpName, code, defines, maxGlslVersion);
|
||||||
|
|
|
@ -84,8 +84,11 @@ void gl_SetupMenu()
|
||||||
{
|
{
|
||||||
for(int i = (*opt)->mValues.Size()-1; i>=0; i--)
|
for(int i = (*opt)->mValues.Size()-1; i>=0; i--)
|
||||||
{
|
{
|
||||||
// Delete HQnX resize modes for non MSVC targets
|
// Delete hqNx MMX resize modes for targets
|
||||||
if ((*opt)->mValues[i].Value >= 7.0)
|
// without support of this instruction set
|
||||||
|
const auto index = llround((*opt)->mValues[i].Value);
|
||||||
|
|
||||||
|
if (index > 6 && index < 10)
|
||||||
{
|
{
|
||||||
(*opt)->mValues.Delete(i);
|
(*opt)->mValues.Delete(i);
|
||||||
}
|
}
|
||||||
|
|
|
@ -924,8 +924,7 @@ DEFINE_ACTION_FUNCTION(AActor, TakeInventory)
|
||||||
PARAM_INT(amount);
|
PARAM_INT(amount);
|
||||||
PARAM_BOOL_DEF(fromdecorate);
|
PARAM_BOOL_DEF(fromdecorate);
|
||||||
PARAM_BOOL_DEF(notakeinfinite);
|
PARAM_BOOL_DEF(notakeinfinite);
|
||||||
self->TakeInventory(item, amount, fromdecorate, notakeinfinite);
|
ACTION_RETURN_BOOL(self->TakeInventory(item, amount, fromdecorate, notakeinfinite));
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
|
@ -133,10 +133,6 @@ SDLGLVideo::SDLGLVideo (int parm)
|
||||||
fprintf( stderr, "Video initialization failed: %s\n",
|
fprintf( stderr, "Video initialization failed: %s\n",
|
||||||
SDL_GetError( ) );
|
SDL_GetError( ) );
|
||||||
}
|
}
|
||||||
#ifndef _WIN32
|
|
||||||
// mouse cursor is visible by default on linux systems, we disable it by default
|
|
||||||
SDL_ShowCursor (0);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SDLGLVideo::~SDLGLVideo ()
|
SDLGLVideo::~SDLGLVideo ()
|
||||||
|
|
|
@ -1008,6 +1008,7 @@ void FScanner::CheckOpen()
|
||||||
int FScriptPosition::ErrorCounter;
|
int FScriptPosition::ErrorCounter;
|
||||||
int FScriptPosition::WarnCounter;
|
int FScriptPosition::WarnCounter;
|
||||||
bool FScriptPosition::StrictErrors; // makes all OPTERROR messages real errors.
|
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)
|
FScriptPosition::FScriptPosition(const FScriptPosition &other)
|
||||||
{
|
{
|
||||||
|
@ -1054,6 +1055,8 @@ void FScriptPosition::Message (int severity, const char *message, ...) const
|
||||||
{
|
{
|
||||||
severity = StrictErrors || strictdecorate ? MSG_ERROR : MSG_WARNING;
|
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)
|
if (message == NULL)
|
||||||
{
|
{
|
||||||
|
|
|
@ -144,6 +144,7 @@ struct FScriptPosition
|
||||||
static int WarnCounter;
|
static int WarnCounter;
|
||||||
static int ErrorCounter;
|
static int ErrorCounter;
|
||||||
static bool StrictErrors;
|
static bool StrictErrors;
|
||||||
|
static bool errorout;
|
||||||
FString FileName;
|
FString FileName;
|
||||||
int ScriptLine;
|
int ScriptLine;
|
||||||
|
|
||||||
|
|
|
@ -4078,7 +4078,7 @@ ExpEmit FxConcat::Emit(VMFunctionBuilder *build)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int cast;
|
int cast = 0;
|
||||||
strng2 = ExpEmit(build, REGT_STRING);
|
strng2 = ExpEmit(build, REGT_STRING);
|
||||||
if (op2.Konst)
|
if (op2.Konst)
|
||||||
{
|
{
|
||||||
|
@ -5653,6 +5653,12 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx)
|
||||||
|
|
||||||
if (Identifier == NAME_Default)
|
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)
|
if (ctx.Function->Variants[0].SelfClass == nullptr)
|
||||||
{
|
{
|
||||||
ScriptPosition.Message(MSG_ERROR, "Unable to access class defaults from static function");
|
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 (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);
|
FxExpression *self = new FxSelf(ScriptPosition);
|
||||||
self = self->Resolve(ctx);
|
self = self->Resolve(ctx);
|
||||||
newex = ResolveMember(ctx, ctx.Function->Variants[0].SelfClass, self, ctx.Function->Variants[0].SelfClass);
|
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);
|
newex = FxConstant::MakeConstant(sym, ScriptPosition);
|
||||||
goto foundit;
|
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.
|
// 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)))
|
else if (ctx.Function->Variants[0].SelfClass != ctx.Class && sym->IsKindOf(RUNTIME_CLASS(PField)))
|
||||||
{
|
{
|
||||||
|
@ -5810,7 +5829,7 @@ FxExpression *FxIdentifier::ResolveMember(FCompileContext &ctx, PStruct *classct
|
||||||
return x->Resolve(ctx);
|
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)))
|
if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst)))
|
||||||
{
|
{
|
||||||
|
@ -7149,7 +7168,6 @@ static bool CheckArgSize(FName fname, FArgumentList &args, int min, int max, FSc
|
||||||
|
|
||||||
FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
|
FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
|
||||||
{
|
{
|
||||||
ABORT(ctx.Class);
|
|
||||||
bool error = false;
|
bool error = false;
|
||||||
|
|
||||||
for (auto a : ArgList)
|
for (auto a : ArgList)
|
||||||
|
@ -7162,20 +7180,30 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PFunction *afd = FindClassMemberFunction(ctx.Class, ctx.Class, MethodName, ScriptPosition, &error);
|
if (ctx.Class != nullptr)
|
||||||
|
|
||||||
if (afd != nullptr)
|
|
||||||
{
|
{
|
||||||
if (!CheckFunctionCompatiblity(ScriptPosition, ctx.Function, afd))
|
PFunction *afd = FindClassMemberFunction(ctx.Class, ctx.Class, MethodName, ScriptPosition, &error);
|
||||||
{
|
|
||||||
delete this;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto self = (afd->Variants[0].Flags & VARF_Method)? new FxSelf(ScriptPosition) : nullptr;
|
if (afd != nullptr)
|
||||||
auto x = new FxVMFunctionCall(self, afd, ArgList, ScriptPosition, false);
|
{
|
||||||
delete this;
|
if (ctx.Function == nullptr)
|
||||||
return x->Resolve(ctx);
|
{
|
||||||
|
ScriptPosition.Message(MSG_ERROR, "Unable to call function %s from constant declaration", MethodName.GetChars());
|
||||||
|
delete this;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CheckFunctionCompatiblity(ScriptPosition, ctx.Function, afd))
|
||||||
|
{
|
||||||
|
delete this;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto self = (afd->Variants[0].Flags & VARF_Method) ? new FxSelf(ScriptPosition) : nullptr;
|
||||||
|
auto x = new FxVMFunctionCall(self, afd, ArgList, ScriptPosition, false);
|
||||||
|
delete this;
|
||||||
|
return x->Resolve(ctx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < countof(FxFlops); ++i)
|
for (size_t i = 0; i < countof(FxFlops); ++i)
|
||||||
|
@ -7202,7 +7230,13 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
|
||||||
if (special != 0 && min >= 0)
|
if (special != 0 && min >= 0)
|
||||||
{
|
{
|
||||||
int paramcount = ArgList.Size();
|
int paramcount = ArgList.Size();
|
||||||
if (paramcount < min)
|
if (ctx.Function == nullptr || ctx.Class == nullptr)
|
||||||
|
{
|
||||||
|
ScriptPosition.Message(MSG_ERROR, "Unable to call action special %s from constant declaration", MethodName.GetChars());
|
||||||
|
delete this;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
else if (paramcount < min)
|
||||||
{
|
{
|
||||||
ScriptPosition.Message(MSG_ERROR, "Not enough parameters for '%s' (expected %d, got %d)",
|
ScriptPosition.Message(MSG_ERROR, "Not enough parameters for '%s' (expected %d, got %d)",
|
||||||
MethodName.GetChars(), min, paramcount);
|
MethodName.GetChars(), min, paramcount);
|
||||||
|
@ -7427,13 +7461,20 @@ FxMemberFunctionCall::~FxMemberFunctionCall()
|
||||||
|
|
||||||
FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
|
FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
|
||||||
{
|
{
|
||||||
ABORT(ctx.Class);
|
|
||||||
PStruct *cls;
|
PStruct *cls;
|
||||||
bool staticonly = false;
|
bool staticonly = false;
|
||||||
bool novirtual = false;
|
bool novirtual = false;
|
||||||
|
|
||||||
PStruct *ccls = nullptr;
|
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)
|
for (auto a : ArgList)
|
||||||
{
|
{
|
||||||
if (a == nullptr)
|
if (a == nullptr)
|
||||||
|
@ -7467,6 +7508,12 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
|
||||||
staticonly = true;
|
staticonly = true;
|
||||||
if (ccls->IsKindOf(RUNTIME_CLASS(PClass)))
|
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<PClass>(ctx.Function->Variants[0].SelfClass);
|
auto clstype = dyn_cast<PClass>(ctx.Function->Variants[0].SelfClass);
|
||||||
if (clstype != nullptr)
|
if (clstype != nullptr)
|
||||||
{
|
{
|
||||||
|
@ -7493,6 +7540,12 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
|
||||||
|
|
||||||
if (Self->ExprType == EFX_Super)
|
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<PClass>(ctx.Function->Variants[0].SelfClass);
|
auto clstype = dyn_cast<PClass>(ctx.Function->Variants[0].SelfClass);
|
||||||
if (clstype != nullptr)
|
if (clstype != nullptr)
|
||||||
{
|
{
|
||||||
|
@ -7743,6 +7796,12 @@ isresolved:
|
||||||
|
|
||||||
if (afd->Variants[0].Flags & VARF_Method)
|
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 (Self->ExprType == EFX_Self)
|
||||||
{
|
{
|
||||||
if (!CheckFunctionCompatiblity(ScriptPosition, ctx.Function, afd))
|
if (!CheckFunctionCompatiblity(ScriptPosition, ctx.Function, afd))
|
||||||
|
|
|
@ -513,7 +513,7 @@ static void OpenExprType(FLispString &out, EZCCExprType type)
|
||||||
|
|
||||||
if (unsigned(type) < PEX_COUNT_OF)
|
if (unsigned(type) < PEX_COUNT_OF)
|
||||||
{
|
{
|
||||||
mysnprintf(buf, countof(buf), "expr-%s", ZCC_OpInfo[type].OpName);
|
mysnprintf(buf, countof(buf), "expr %d", type);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -48,10 +48,59 @@
|
||||||
#include "p_lnspec.h"
|
#include "p_lnspec.h"
|
||||||
#include "i_system.h"
|
#include "i_system.h"
|
||||||
#include "gdtoa.h"
|
#include "gdtoa.h"
|
||||||
#include "codegeneration/codegen.h"
|
|
||||||
#include "vmbuilder.h"
|
#include "vmbuilder.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
||||||
|
static int GetIntConst(FxExpression *ex, FCompileContext &ctx)
|
||||||
|
{
|
||||||
|
ex = new FxIntCast(ex, false);
|
||||||
|
ex = ex->Resolve(ctx);
|
||||||
|
return ex ? static_cast<FxConstant*>(ex)->GetValue().GetInt() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static double GetFloatConst(FxExpression *ex, FCompileContext &ctx)
|
||||||
|
{
|
||||||
|
ex = new FxFloatCast(ex);
|
||||||
|
ex = ex->Resolve(ctx);
|
||||||
|
return ex ? static_cast<FxConstant*>(ex)->GetValue().GetFloat() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FString GetStringConst(FxExpression *ex, FCompileContext &ctx)
|
||||||
|
{
|
||||||
|
ex = new FxStringCast(ex);
|
||||||
|
ex = ex->Resolve(ctx);
|
||||||
|
return static_cast<FxConstant*>(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<FxConstant*>(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<FxConstant*>(ex)->GetValue().GetString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// ZCCCompiler :: ProcessClass
|
// ZCCCompiler :: ProcessClass
|
||||||
|
@ -606,11 +655,11 @@ void ZCCCompiler::CreateClassTypes()
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
void ZCCCompiler::CopyConstants(TArray<ZCC_ConstantWork> &dest, TArray<ZCC_ConstantDef*> &Constants, PSymbolTable *ot)
|
void ZCCCompiler::CopyConstants(TArray<ZCC_ConstantWork> &dest, TArray<ZCC_ConstantDef*> &Constants, PStruct *cls, PSymbolTable *ot)
|
||||||
{
|
{
|
||||||
for (auto c : Constants)
|
for (auto c : Constants)
|
||||||
{
|
{
|
||||||
dest.Push({ c, ot });
|
dest.Push({ c, cls, ot });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -629,14 +678,14 @@ void ZCCCompiler::CompileAllConstants()
|
||||||
// put all constants in one list to make resolving this easier.
|
// put all constants in one list to make resolving this easier.
|
||||||
TArray<ZCC_ConstantWork> constantwork;
|
TArray<ZCC_ConstantWork> constantwork;
|
||||||
|
|
||||||
CopyConstants(constantwork, Constants, OutputSymbols);
|
CopyConstants(constantwork, Constants, nullptr, OutputSymbols);
|
||||||
for (auto c : Classes)
|
for (auto c : Classes)
|
||||||
{
|
{
|
||||||
CopyConstants(constantwork, c->Constants, &c->Type()->Symbols);
|
CopyConstants(constantwork, c->Constants, c->Type(), &c->Type()->Symbols);
|
||||||
}
|
}
|
||||||
for (auto s : Structs)
|
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.
|
// Before starting to resolve the list, let's create symbols for all already resolved ones first (i.e. all literal constants), to reduce work.
|
||||||
|
@ -657,7 +706,7 @@ void ZCCCompiler::CompileAllConstants()
|
||||||
donesomething = false;
|
donesomething = false;
|
||||||
for (unsigned i = 0; i < constantwork.Size(); i++)
|
for (unsigned i = 0; i < constantwork.Size(); i++)
|
||||||
{
|
{
|
||||||
if (CompileConstant(constantwork[i].node, constantwork[i].outputtable))
|
if (CompileConstant(&constantwork[i]))
|
||||||
{
|
{
|
||||||
AddConstant(constantwork[i]);
|
AddConstant(constantwork[i]);
|
||||||
// Remove the constant from the list
|
// Remove the constant from the list
|
||||||
|
@ -685,6 +734,9 @@ void ZCCCompiler::AddConstant(ZCC_ConstantWork &constant)
|
||||||
{
|
{
|
||||||
auto def = constant.node;
|
auto def = constant.node;
|
||||||
auto val = def->Value;
|
auto val = def->Value;
|
||||||
|
ExpVal &c = constant.constval;
|
||||||
|
|
||||||
|
// This is for literal constants.
|
||||||
if (val->NodeType == AST_ExprConstant)
|
if (val->NodeType == AST_ExprConstant)
|
||||||
{
|
{
|
||||||
ZCC_ExprConstant *cval = static_cast<ZCC_ExprConstant *>(val);
|
ZCC_ExprConstant *cval = static_cast<ZCC_ExprConstant *>(val);
|
||||||
|
@ -711,14 +763,40 @@ void ZCCCompiler::AddConstant(ZCC_ConstantWork &constant)
|
||||||
Error(def->Value, "Bad type for constant definiton");
|
Error(def->Value, "Bad type for constant definiton");
|
||||||
def->Symbol = nullptr;
|
def->Symbol = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (def->Symbol == nullptr)
|
|
||||||
{
|
|
||||||
// Create a dummy constant so we don't make any undefined value warnings.
|
|
||||||
def->Symbol = new PSymbolConstNumeric(def->NodeName, TypeError, 0);
|
|
||||||
}
|
|
||||||
constant.outputtable->ReplaceSymbol(def->Symbol);
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (c.Type == TypeString)
|
||||||
|
{
|
||||||
|
def->Symbol = new PSymbolConstString(def->NodeName, c.GetString());
|
||||||
|
}
|
||||||
|
else if (c.Type->IsA(RUNTIME_CLASS(PInt)))
|
||||||
|
{
|
||||||
|
// How do we get an Enum type in here without screwing everything up???
|
||||||
|
//auto type = def->Type != nullptr ? def->Type : cval->Type;
|
||||||
|
def->Symbol = new PSymbolConstNumeric(def->NodeName, c.Type, c.GetInt());
|
||||||
|
}
|
||||||
|
else if (c.Type->IsA(RUNTIME_CLASS(PFloat)))
|
||||||
|
{
|
||||||
|
if (def->Type != nullptr)
|
||||||
|
{
|
||||||
|
Error(def, "Enum members must be integer values");
|
||||||
|
}
|
||||||
|
def->Symbol = new PSymbolConstNumeric(def->NodeName, c.Type, c.GetFloat());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Error(def->Value, "Bad type for constant definiton");
|
||||||
|
def->Symbol = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (def->Symbol == nullptr)
|
||||||
|
{
|
||||||
|
// Create a dummy constant so we don't make any undefined value warnings.
|
||||||
|
def->Symbol = new PSymbolConstNumeric(def->NodeName, TypeError, 0);
|
||||||
|
}
|
||||||
|
constant.Outputtable->ReplaceSymbol(def->Symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -730,309 +808,33 @@ void ZCCCompiler::AddConstant(ZCC_ConstantWork &constant)
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
bool ZCCCompiler::CompileConstant(ZCC_ConstantDef *def, PSymbolTable *sym)
|
bool ZCCCompiler::CompileConstant(ZCC_ConstantWork *work)
|
||||||
{
|
{
|
||||||
assert(def->Symbol == nullptr);
|
FCompileContext ctx(work->cls, false);
|
||||||
|
FxExpression *exp = ConvertNode(work->node->Value);
|
||||||
ZCC_Expression *val = Simplify(def->Value, sym, true);
|
try
|
||||||
def->Value = val;
|
|
||||||
return (val->NodeType == AST_ExprConstant);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// ZCCCompiler :: Simplify
|
|
||||||
//
|
|
||||||
// For an expression,
|
|
||||||
// Evaluate operators whose arguments are both constants, replacing it
|
|
||||||
// with a new constant.
|
|
||||||
// For a binary operator with one constant argument, put it on the right-
|
|
||||||
// hand operand, where permitted.
|
|
||||||
// Perform automatic type promotion.
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
ZCC_Expression *ZCCCompiler::Simplify(ZCC_Expression *root, PSymbolTable *sym, bool wantconstant)
|
|
||||||
{
|
|
||||||
SimplifyingConstant = wantconstant;
|
|
||||||
return DoSimplify(root, sym);
|
|
||||||
}
|
|
||||||
|
|
||||||
ZCC_Expression *ZCCCompiler::DoSimplify(ZCC_Expression *root, PSymbolTable *sym)
|
|
||||||
{
|
|
||||||
if (root->NodeType == AST_ExprUnary)
|
|
||||||
{
|
{
|
||||||
return SimplifyUnary(static_cast<ZCC_ExprUnary *>(root), sym);
|
FScriptPosition::errorout = true;
|
||||||
}
|
exp = exp->Resolve(ctx);
|
||||||
else if (root->NodeType == AST_ExprBinary)
|
if (exp == nullptr) return false;
|
||||||
{
|
FScriptPosition::errorout = false;
|
||||||
return SimplifyBinary(static_cast<ZCC_ExprBinary *>(root), sym);
|
if (!exp->isConstant())
|
||||||
}
|
|
||||||
else if (root->Operation == PEX_ID)
|
|
||||||
{
|
|
||||||
return IdentifyIdentifier(static_cast<ZCC_ExprID *>(root), sym);
|
|
||||||
}
|
|
||||||
else if (root->Operation == PEX_MemberAccess)
|
|
||||||
{
|
|
||||||
return SimplifyMemberAccess(static_cast<ZCC_ExprMemberAccess *>(root), sym);
|
|
||||||
}
|
|
||||||
else if (root->Operation == PEX_FuncCall)
|
|
||||||
{
|
|
||||||
return SimplifyFunctionCall(static_cast<ZCC_ExprFuncCall *>(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<ZCC_ExprConstant *>(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<ZCC_ExprConstant *>(binary->Left),
|
|
||||||
static_cast<ZCC_ExprConstant *>(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<ZCC_ExprTypeRef *>(dotop->Left)->RefType;
|
|
||||||
PSymbol *sym = ref->Symbols.FindSymbolInTable(dotop->Right, symtable);
|
|
||||||
if (sym != nullptr)
|
|
||||||
{
|
{
|
||||||
ZCC_Expression *expr = NodeFromSymbol(sym, dotop, symtable);
|
delete exp;
|
||||||
if (expr != nullptr)
|
return false;
|
||||||
{
|
|
||||||
return expr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
work->constval = static_cast<FxConstant*>(exp)->GetValue();
|
||||||
|
delete exp;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
else if (dotop->Left->Operation == PEX_Super)
|
catch (...)
|
||||||
{
|
{
|
||||||
symt = symt->GetParentTable();
|
// eat the reported error and treat this as a temorary failure. All unresolved contants will be reported at the end.
|
||||||
if (symt != nullptr)
|
FScriptPosition::errorout = false;
|
||||||
{
|
return false;
|
||||||
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<ZCC_FuncParm *>(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<ZCC_ExprTypeRef *>(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<ZCC_ExprConstant *>(expr), AST.Strings);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return expr;
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// ZCCCompiler :: AddCastNode
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
ZCC_Expression *ZCCCompiler::AddCastNode(PType *type, ZCC_Expression *expr)
|
|
||||||
{
|
|
||||||
assert(expr->Operation != PEX_ConstValue && "Expression must not be constant");
|
|
||||||
// TODO: add a node here
|
|
||||||
return expr;
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
|
@ -1293,7 +1095,7 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray<ZCC_VarDeclarator *> &Fiel
|
||||||
|
|
||||||
if (field->Type->ArraySize != nullptr)
|
if (field->Type->ArraySize != nullptr)
|
||||||
{
|
{
|
||||||
fieldtype = ResolveArraySize(fieldtype, field->Type->ArraySize, &type->Symbols);
|
fieldtype = ResolveArraySize(fieldtype, field->Type->ArraySize, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto name = field->Names;
|
auto name = field->Names;
|
||||||
|
@ -1304,7 +1106,7 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray<ZCC_VarDeclarator *> &Fiel
|
||||||
auto thisfieldtype = fieldtype;
|
auto thisfieldtype = fieldtype;
|
||||||
if (name->ArraySize != nullptr)
|
if (name->ArraySize != nullptr)
|
||||||
{
|
{
|
||||||
thisfieldtype = ResolveArraySize(thisfieldtype, name->ArraySize, &type->Symbols);
|
thisfieldtype = ResolveArraySize(thisfieldtype, name->ArraySize, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (varflags & VARF_Native)
|
if (varflags & VARF_Native)
|
||||||
|
@ -1662,7 +1464,7 @@ PType *ZCCCompiler::ResolveUserType(ZCC_BasicType *type, PSymbolTable *symt)
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
PType *ZCCCompiler::ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PSymbolTable *sym)
|
PType *ZCCCompiler::ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PStruct *cls)
|
||||||
{
|
{
|
||||||
TArray<ZCC_Expression *> indices;
|
TArray<ZCC_Expression *> indices;
|
||||||
|
|
||||||
|
@ -1674,15 +1476,21 @@ PType *ZCCCompiler::ResolveArraySize(PType *baseType, ZCC_Expression *arraysize,
|
||||||
node = static_cast<ZCC_Expression*>(node->SiblingNext);
|
node = static_cast<ZCC_Expression*>(node->SiblingNext);
|
||||||
} while (node != arraysize);
|
} while (node != arraysize);
|
||||||
|
|
||||||
|
|
||||||
|
FCompileContext ctx(cls, false);
|
||||||
for (auto node : indices)
|
for (auto node : indices)
|
||||||
{
|
{
|
||||||
auto val = Simplify(node, sym, true);
|
// There is no float->int casting here.
|
||||||
if (val->Operation != PEX_ConstValue || !val->Type->IsA(RUNTIME_CLASS(PInt)))
|
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");
|
Error(arraysize, "Array index must be an integer constant");
|
||||||
return TypeError;
|
return TypeError;
|
||||||
}
|
}
|
||||||
int size = static_cast<ZCC_ExprConstant *>(val)->IntVal;
|
int size = static_cast<FxConstant*>(ex)->GetValue().GetInt();
|
||||||
if (size < 1)
|
if (size < 1)
|
||||||
{
|
{
|
||||||
Error(arraysize, "Array size must be positive");
|
Error(arraysize, "Array size must be positive");
|
||||||
|
@ -1693,78 +1501,6 @@ PType *ZCCCompiler::ResolveArraySize(PType *baseType, ZCC_Expression *arraysize,
|
||||||
return baseType;
|
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<ZCC_ExprConstant *>(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<ZCC_ExprConstant *>(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<ZCC_ExprConstant *>(expr)->StringVal->GetChars();
|
|
||||||
}
|
|
||||||
else if (expr->Type->IsKindOf(RUNTIME_CLASS(PName)))
|
|
||||||
{
|
|
||||||
// Ugh... What a mess...
|
|
||||||
return FName(ENamedName(static_cast<ZCC_ExprConstant *>(expr)->IntVal)).GetChars();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!silent) Error(expr, "Cannot convert to string");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// Parses an actor property's parameters and calls the handler
|
// Parses an actor property's parameters and calls the handler
|
||||||
|
@ -1787,16 +1523,22 @@ void ZCCCompiler::DispatchProperty(FPropertyInfo *prop, ZCC_PropertyStmt *proper
|
||||||
Error(property, "%s: arguments missing", prop->name);
|
Error(property, "%s: arguments missing", prop->name);
|
||||||
return;
|
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;
|
const char * p = prop->params;
|
||||||
auto exp = property->Values;
|
auto exp = property->Values;
|
||||||
|
|
||||||
|
FCompileContext ctx(bag.Info, false);
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
FPropParam conv;
|
FPropParam conv;
|
||||||
FPropParam pref;
|
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 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);
|
if (exp->Type != TypeError) Error(exp, "%s: non-constant parameter", prop->name);
|
||||||
|
@ -1809,7 +1551,7 @@ void ZCCCompiler::DispatchProperty(FPropertyInfo *prop, ZCC_PropertyStmt *proper
|
||||||
{
|
{
|
||||||
|
|
||||||
case 'X': // Expression in parentheses or number. We only support the constant here. The function will have to be handled by a separate property to get past the parser.
|
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);
|
params.Push(conv);
|
||||||
conv.exp = nullptr;
|
conv.exp = nullptr;
|
||||||
break;
|
break;
|
||||||
|
@ -1817,15 +1559,15 @@ void ZCCCompiler::DispatchProperty(FPropertyInfo *prop, ZCC_PropertyStmt *proper
|
||||||
case 'I':
|
case 'I':
|
||||||
case 'M': // special case for morph styles in DECORATE . This expression-aware parser will not need this.
|
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.
|
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;
|
break;
|
||||||
|
|
||||||
case 'F':
|
case 'F':
|
||||||
conv.d = GetDouble(exp);
|
conv.d = GetFloatConst(ex, ctx);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'Z': // an optional string. Does not allow any numeric value.
|
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.
|
// apply this expression to the next argument on the list.
|
||||||
params.Push(conv);
|
params.Push(conv);
|
||||||
|
@ -1833,21 +1575,21 @@ void ZCCCompiler::DispatchProperty(FPropertyInfo *prop, ZCC_PropertyStmt *proper
|
||||||
p++;
|
p++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
conv.s = GetString(exp);
|
conv.s = GetStringConst(ex, ctx);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'C': // this parser accepts colors only in string form.
|
case 'C': // this parser accepts colors only in string form.
|
||||||
pref.i = 1;
|
pref.i = 1;
|
||||||
case 'S':
|
case 'S':
|
||||||
case 'T': // a filtered string (ZScript only parses filtered strings so there's nothing to do here.)
|
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;
|
break;
|
||||||
|
|
||||||
case 'L': // Either a number or a list of strings
|
case 'L': // Either a number or a list of strings
|
||||||
if (!GetString(exp, true))
|
if (ex->ValueType != TypeString)
|
||||||
{
|
{
|
||||||
pref.i = 0;
|
pref.i = 0;
|
||||||
conv.i = GetInt(exp);
|
conv.i = GetIntConst(ex, ctx);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1857,13 +1599,13 @@ void ZCCCompiler::DispatchProperty(FPropertyInfo *prop, ZCC_PropertyStmt *proper
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
conv.s = GetString(exp);
|
conv.s = GetStringConst(ex, ctx);
|
||||||
if (conv.s != nullptr)
|
if (conv.s != nullptr)
|
||||||
{
|
{
|
||||||
params.Push(conv);
|
params.Push(conv);
|
||||||
params[0].i++;
|
params[0].i++;
|
||||||
}
|
}
|
||||||
exp = Simplify(static_cast<ZCC_Expression *>(exp->SiblingNext), &bag.Info->Symbols, true);
|
exp = static_cast<ZCC_Expression *>(exp->SiblingNext);
|
||||||
} while (exp != property->Values);
|
} while (exp != property->Values);
|
||||||
goto endofparm;
|
goto endofparm;
|
||||||
}
|
}
|
||||||
|
@ -1881,7 +1623,7 @@ void ZCCCompiler::DispatchProperty(FPropertyInfo *prop, ZCC_PropertyStmt *proper
|
||||||
}
|
}
|
||||||
params.Push(conv);
|
params.Push(conv);
|
||||||
params[0].i++;
|
params[0].i++;
|
||||||
exp = Simplify(static_cast<ZCC_Expression *>(exp->SiblingNext), &bag.Info->Symbols, true);
|
exp = static_cast<ZCC_Expression *>(exp->SiblingNext);
|
||||||
endofparm:
|
endofparm:
|
||||||
p++;
|
p++;
|
||||||
// Skip the DECORATE 'no comma' marker
|
// Skip the DECORATE 'no comma' marker
|
||||||
|
@ -1950,8 +1692,8 @@ void ZCCCompiler::DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt *prop
|
||||||
return;
|
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 = property->Values;
|
||||||
auto exp = values;
|
FCompileContext ctx(bag.Info, false);
|
||||||
for (auto f : prop->Variables)
|
for (auto f : prop->Variables)
|
||||||
{
|
{
|
||||||
void *addr;
|
void *addr;
|
||||||
|
@ -1965,25 +1707,38 @@ void ZCCCompiler::DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt *prop
|
||||||
addr = ((char*)defaults) + f->Offset;
|
addr = ((char*)defaults) + f->Offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FxExpression *ex = ConvertNode(exp);
|
||||||
|
ex = ex->Resolve(ctx);
|
||||||
|
if (ex == nullptr)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (!ex->isConstant())
|
||||||
|
{
|
||||||
|
// If we get TypeError, there has already been a message from deeper down so do not print another one.
|
||||||
|
if (exp->Type != TypeError) Error(exp, "%s: non-constant parameter", prop->SymbolName.GetChars());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (f->Type == TypeBool)
|
if (f->Type == TypeBool)
|
||||||
{
|
{
|
||||||
static_cast<PBool*>(f->Type)->SetValue(addr, !!GetInt(exp));
|
static_cast<PBool*>(f->Type)->SetValue(addr, !!GetIntConst(ex, ctx));
|
||||||
}
|
}
|
||||||
if (f->Type->IsKindOf(RUNTIME_CLASS(PInt)))
|
if (f->Type->IsKindOf(RUNTIME_CLASS(PInt)))
|
||||||
{
|
{
|
||||||
static_cast<PInt*>(f->Type)->SetValue(addr, GetInt(exp));
|
static_cast<PInt*>(f->Type)->SetValue(addr, GetIntConst(ex, ctx));
|
||||||
}
|
}
|
||||||
else if (f->Type->IsKindOf(RUNTIME_CLASS(PFloat)))
|
else if (f->Type->IsKindOf(RUNTIME_CLASS(PFloat)))
|
||||||
{
|
{
|
||||||
static_cast<PFloat*>(f->Type)->SetValue(addr, GetDouble(exp));
|
static_cast<PFloat*>(f->Type)->SetValue(addr, GetFloatConst(ex, ctx));
|
||||||
}
|
}
|
||||||
else if (f->Type->IsKindOf(RUNTIME_CLASS(PString)))
|
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)))
|
else if (f->Type->IsKindOf(RUNTIME_CLASS(PClassPointer)))
|
||||||
{
|
{
|
||||||
auto clsname = GetString(exp);
|
auto clsname = GetStringConst(ex, ctx);
|
||||||
auto cls = PClass::FindClass(clsname);
|
auto cls = PClass::FindClass(clsname);
|
||||||
if (cls == nullptr)
|
if (cls == nullptr)
|
||||||
{
|
{
|
||||||
|
@ -1991,7 +1746,7 @@ void ZCCCompiler::DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt *prop
|
||||||
}
|
}
|
||||||
else if (!cls->IsDescendantOf(static_cast<PClassPointer*>(f->Type)->ClassRestriction))
|
else if (!cls->IsDescendantOf(static_cast<PClassPointer*>(f->Type)->ClassRestriction))
|
||||||
{
|
{
|
||||||
Error(property, "class %s is not compatible with property type %s", clsname, static_cast<PClassPointer*>(f->Type)->ClassRestriction->TypeName.GetChars());
|
Error(property, "class %s is not compatible with property type %s", clsname.GetChars(), static_cast<PClassPointer*>(f->Type)->ClassRestriction->TypeName.GetChars());
|
||||||
}
|
}
|
||||||
*(PClass**)addr = cls;
|
*(PClass**)addr = cls;
|
||||||
}
|
}
|
||||||
|
@ -2772,7 +2527,7 @@ void ZCCCompiler::CompileStates()
|
||||||
{
|
{
|
||||||
state.sprite = GetSpriteIndex(sl->Sprite->GetChars());
|
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))
|
if (CheckRandom(sl->Duration))
|
||||||
{
|
{
|
||||||
auto func = static_cast<ZCC_ExprFuncCall *>(sl->Duration);
|
auto func = static_cast<ZCC_ExprFuncCall *>(sl->Duration);
|
||||||
|
@ -2780,26 +2535,16 @@ void ZCCCompiler::CompileStates()
|
||||||
{
|
{
|
||||||
Error(sl, "Random duration requires exactly 2 parameters");
|
Error(sl, "Random duration requires exactly 2 parameters");
|
||||||
}
|
}
|
||||||
auto p1 = Simplify(func->Parameters->Value, &c->Type()->Symbols, true);
|
int v1 = IntConstFromNode(func->Parameters->Value, c->Type());
|
||||||
auto p2 = Simplify(static_cast<ZCC_FuncParm *>(func->Parameters->SiblingNext)->Value, &c->Type()->Symbols, true);
|
int v2 = IntConstFromNode(static_cast<ZCC_FuncParm *>(func->Parameters->SiblingNext)->Value, c->Type());
|
||||||
int v1 = GetInt(p1);
|
|
||||||
int v2 = GetInt(p2);
|
|
||||||
if (v1 > v2) std::swap(v1, v2);
|
if (v1 > v2) std::swap(v1, v2);
|
||||||
state.Tics = (int16_t)clamp<int>(v1, 0, INT16_MAX);
|
state.Tics = (int16_t)clamp<int>(v1, 0, INT16_MAX);
|
||||||
state.TicRange = (uint16_t)clamp<int>(v2 - v1, 0, UINT16_MAX);
|
state.TicRange = (uint16_t)clamp<int>(v2 - v1, 0, UINT16_MAX);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto duration = Simplify(sl->Duration, &c->Type()->Symbols, true);
|
state.Tics = (int16_t)IntConstFromNode(sl->Duration, c->Type());
|
||||||
if (duration->Operation == PEX_ConstValue)
|
state.TicRange = 0;
|
||||||
{
|
|
||||||
state.Tics = (int16_t)clamp<int>(GetInt(duration), -1, INT16_MAX);
|
|
||||||
state.TicRange = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Error(sl, "Duration is not a constant");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (sl->bBright) state.StateFlags |= STF_FULLBRIGHT;
|
if (sl->bBright) state.StateFlags |= STF_FULLBRIGHT;
|
||||||
if (sl->bFast) state.StateFlags |= STF_FAST;
|
if (sl->bFast) state.StateFlags |= STF_FAST;
|
||||||
|
@ -2815,18 +2560,8 @@ void ZCCCompiler::CompileStates()
|
||||||
}
|
}
|
||||||
if (sl->Offset != nullptr)
|
if (sl->Offset != nullptr)
|
||||||
{
|
{
|
||||||
auto o1 = static_cast<ZCC_Expression *>(Simplify(sl->Offset, &c->Type()->Symbols, true));
|
state.Misc1 = IntConstFromNode(sl->Offset, c->Type());
|
||||||
auto o2 = static_cast<ZCC_Expression *>(Simplify(static_cast<ZCC_Expression *>(o1->SiblingNext), &c->Type()->Symbols, true));
|
state.Misc2 = IntConstFromNode(static_cast<ZCC_Expression *>(sl->Offset->SiblingNext), c->Type());
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#ifdef DYNLIGHT
|
#ifdef DYNLIGHT
|
||||||
if (sl->Lights != nullptr)
|
if (sl->Lights != nullptr)
|
||||||
|
@ -2834,7 +2569,7 @@ void ZCCCompiler::CompileStates()
|
||||||
auto l = sl->Lights;
|
auto l = sl->Lights;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
AddStateLight(&state, GetString(l));
|
AddStateLight(&state, StringConstFromNode(l, c->Type()));
|
||||||
l = static_cast<decltype(l)>(l->SiblingNext);
|
l = static_cast<decltype(l)>(l->SiblingNext);
|
||||||
} while (l != sl->Lights);
|
} while (l != sl->Lights);
|
||||||
}
|
}
|
||||||
|
@ -2875,23 +2610,15 @@ void ZCCCompiler::CompileStates()
|
||||||
statename.Truncate((long)statename.Len() - 1); // remove the last '.' in the label name
|
statename.Truncate((long)statename.Len() - 1); // remove the last '.' in the label name
|
||||||
if (sg->Offset != nullptr)
|
if (sg->Offset != nullptr)
|
||||||
{
|
{
|
||||||
auto ofs = Simplify(sg->Offset, &c->Type()->Symbols, true);
|
int offset = IntConstFromNode(sg->Offset, c->Type());
|
||||||
if (ofs->Operation != PEX_ConstValue)
|
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);
|
statename.AppendFormat("+%d", offset);
|
||||||
if (offset < 0)
|
|
||||||
{
|
|
||||||
Error(sg, "GOTO offset must be positive");
|
|
||||||
offset = 0;
|
|
||||||
}
|
|
||||||
if (offset > 0)
|
|
||||||
{
|
|
||||||
statename.AppendFormat("+%d", offset);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!statedef.SetGotoLabel(statename))
|
if (!statedef.SetGotoLabel(statename))
|
||||||
|
@ -3292,7 +3019,7 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast)
|
||||||
|
|
||||||
if (loc->Type->ArraySize != nullptr)
|
if (loc->Type->ArraySize != nullptr)
|
||||||
{
|
{
|
||||||
ztype = ResolveArraySize(ztype, loc->Type->ArraySize, &ConvertClass->Symbols);
|
ztype = ResolveArraySize(ztype, loc->Type->ArraySize, ConvertClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
do
|
do
|
||||||
|
@ -3301,7 +3028,7 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast)
|
||||||
|
|
||||||
if (node->ArraySize != nullptr)
|
if (node->ArraySize != nullptr)
|
||||||
{
|
{
|
||||||
type = ResolveArraySize(ztype, node->ArraySize, &ConvertClass->Symbols);
|
type = ResolveArraySize(ztype, node->ArraySize, ConvertClass);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define ZCC_COMPILE_H
|
#define ZCC_COMPILE_H
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include "codegeneration/codegen.h"
|
||||||
|
|
||||||
struct Baggage;
|
struct Baggage;
|
||||||
struct FPropertyInfo;
|
struct FPropertyInfo;
|
||||||
|
@ -77,7 +78,9 @@ struct ZCC_PropertyWork
|
||||||
struct ZCC_ConstantWork
|
struct ZCC_ConstantWork
|
||||||
{
|
{
|
||||||
ZCC_ConstantDef *node;
|
ZCC_ConstantDef *node;
|
||||||
PSymbolTable *outputtable;
|
PStruct *cls;
|
||||||
|
PSymbolTable *Outputtable;
|
||||||
|
ExpVal constval;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ZCCCompiler
|
class ZCCCompiler
|
||||||
|
@ -88,14 +91,16 @@ public:
|
||||||
int Compile();
|
int Compile();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
int IntConstFromNode(ZCC_TreeNode *node, PStruct *cls);
|
||||||
|
FString ZCCCompiler::StringConstFromNode(ZCC_TreeNode *node, PStruct *cls);
|
||||||
void ProcessClass(ZCC_Class *node, PSymbolTreeNode *tnode);
|
void ProcessClass(ZCC_Class *node, PSymbolTreeNode *tnode);
|
||||||
void ProcessStruct(ZCC_Struct *node, PSymbolTreeNode *tnode, ZCC_Class *outer);
|
void ProcessStruct(ZCC_Struct *node, PSymbolTreeNode *tnode, ZCC_Class *outer);
|
||||||
void CreateStructTypes();
|
void CreateStructTypes();
|
||||||
void CreateClassTypes();
|
void CreateClassTypes();
|
||||||
void CopyConstants(TArray<ZCC_ConstantWork> &dest, TArray<ZCC_ConstantDef*> &Constants, PSymbolTable *ot);
|
void CopyConstants(TArray<ZCC_ConstantWork> &dest, TArray<ZCC_ConstantDef*> &Constants, PStruct *cls, PSymbolTable *ot);
|
||||||
void CompileAllConstants();
|
void CompileAllConstants();
|
||||||
void AddConstant(ZCC_ConstantWork &constant);
|
void AddConstant(ZCC_ConstantWork &constant);
|
||||||
bool CompileConstant(ZCC_ConstantDef *def, PSymbolTable *Symbols);
|
bool CompileConstant(ZCC_ConstantWork *def);
|
||||||
|
|
||||||
void CompileAllFields();
|
void CompileAllFields();
|
||||||
bool CompileFields(PStruct *type, TArray<ZCC_VarDeclarator *> &Fields, PClass *Outer, PSymbolTable *TreeNodes, bool forstruct, bool hasnativechildren = false);
|
bool CompileFields(PStruct *type, TArray<ZCC_VarDeclarator *> &Fields, PClass *Outer, PSymbolTable *TreeNodes, bool forstruct, bool hasnativechildren = false);
|
||||||
|
@ -103,7 +108,7 @@ private:
|
||||||
bool CompileProperties(PClass *type, TArray<ZCC_Property *> &Properties, FName prefix);
|
bool CompileProperties(PClass *type, TArray<ZCC_Property *> &Properties, FName prefix);
|
||||||
FString FlagsToString(uint32_t flags);
|
FString FlagsToString(uint32_t flags);
|
||||||
PType *DetermineType(PType *outertype, ZCC_TreeNode *field, FName name, ZCC_Type *ztype, bool allowarraytypes, bool formember);
|
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);
|
PType *ResolveUserType(ZCC_BasicType *type, PSymbolTable *sym);
|
||||||
|
|
||||||
void InitDefaults();
|
void InitDefaults();
|
||||||
|
@ -111,9 +116,6 @@ private:
|
||||||
void ProcessDefaultProperty(PClassActor *cls, ZCC_PropertyStmt *flg, Baggage &bag);
|
void ProcessDefaultProperty(PClassActor *cls, ZCC_PropertyStmt *flg, Baggage &bag);
|
||||||
void DispatchProperty(FPropertyInfo *prop, ZCC_PropertyStmt *pex, AActor *defaults, Baggage &bag);
|
void DispatchProperty(FPropertyInfo *prop, ZCC_PropertyStmt *pex, AActor *defaults, Baggage &bag);
|
||||||
void DispatchScriptProperty(PProperty *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 CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool forclass);
|
||||||
|
|
||||||
void InitFunctions();
|
void InitFunctions();
|
||||||
|
@ -128,18 +130,6 @@ private:
|
||||||
|
|
||||||
PSymbolTreeNode *AddTreeNode(FName name, ZCC_TreeNode *node, PSymbolTable *treenodes, bool searchparents = false);
|
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 *IdentifyIdentifier(ZCC_ExprID *idnode, PSymbolTable *sym);
|
||||||
ZCC_Expression *NodeFromSymbol(PSymbol *sym, ZCC_Expression *source, PSymbolTable *table);
|
ZCC_Expression *NodeFromSymbol(PSymbol *sym, ZCC_Expression *source, PSymbolTable *table);
|
||||||
ZCC_ExprConstant *NodeFromSymbolConst(PSymbolConst *sym, ZCC_Expression *idnode);
|
ZCC_ExprConstant *NodeFromSymbolConst(PSymbolConst *sym, ZCC_Expression *idnode);
|
||||||
|
|
|
@ -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 <math.h>
|
|
||||||
#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);
|
|
||||||
}
|
|
|
@ -316,6 +316,8 @@ static void DoParse(int lumpnum)
|
||||||
FScanner sc;
|
FScanner sc;
|
||||||
void *parser;
|
void *parser;
|
||||||
ZCCToken value;
|
ZCCToken value;
|
||||||
|
auto baselump = lumpnum;
|
||||||
|
auto fileno = Wads.GetLumpFile(lumpnum);
|
||||||
|
|
||||||
parser = ZCCParseAlloc(malloc);
|
parser = ZCCParseAlloc(malloc);
|
||||||
ZCCParseState state;
|
ZCCParseState state;
|
||||||
|
@ -344,6 +346,13 @@ static void DoParse(int lumpnum)
|
||||||
}
|
}
|
||||||
else
|
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);
|
ParseSingleFile(nullptr, lumpnum, parser, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -408,9 +417,6 @@ void ParseScripts()
|
||||||
{
|
{
|
||||||
InitTokenMap();
|
InitTokenMap();
|
||||||
}
|
}
|
||||||
ZCC_InitOperators();
|
|
||||||
ZCC_InitConversions();
|
|
||||||
|
|
||||||
int lump, lastlump = 0;
|
int lump, lastlump = 0;
|
||||||
FScriptPosition::ResetErrorCounter();
|
FScriptPosition::ResetErrorCounter();
|
||||||
|
|
||||||
|
|
|
@ -527,47 +527,8 @@ struct ZCC_FlagStmt : ZCC_Statement
|
||||||
bool set;
|
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);
|
FString ZCC_PrintAST(ZCC_TreeNode *root);
|
||||||
|
|
||||||
void ZCC_InitOperators();
|
|
||||||
|
|
||||||
extern ZCC_OpInfoType ZCC_OpInfo[PEX_COUNT_OF];
|
|
||||||
|
|
||||||
struct ZCC_AST
|
struct ZCC_AST
|
||||||
{
|
{
|
||||||
|
|
|
@ -179,6 +179,8 @@ namespace swrenderer
|
||||||
|
|
||||||
// store information in a vissprite
|
// store information in a vissprite
|
||||||
RenderParticle *vis = RenderMemory::NewObject<RenderParticle>();
|
RenderParticle *vis = RenderMemory::NewObject<RenderParticle>();
|
||||||
|
memset(vis, 0, sizeof(*vis));
|
||||||
|
|
||||||
vis->CurrentPortalUniq = renderportal->CurrentPortalUniq;
|
vis->CurrentPortalUniq = renderportal->CurrentPortalUniq;
|
||||||
vis->heightsec = heightsec;
|
vis->heightsec = heightsec;
|
||||||
vis->xscale = FLOAT2FIXED(xscale);
|
vis->xscale = FLOAT2FIXED(xscale);
|
||||||
|
|
|
@ -273,6 +273,8 @@ namespace swrenderer
|
||||||
|
|
||||||
// store information in a vissprite
|
// store information in a vissprite
|
||||||
RenderSprite *vis = &avis[vispspindex];
|
RenderSprite *vis = &avis[vispspindex];
|
||||||
|
memset(vis, 0, sizeof(*vis));
|
||||||
|
|
||||||
vis->renderflags = owner->renderflags;
|
vis->renderflags = owner->renderflags;
|
||||||
vis->floorclip = 0;
|
vis->floorclip = 0;
|
||||||
|
|
||||||
|
|
|
@ -157,6 +157,7 @@ namespace swrenderer
|
||||||
|
|
||||||
// store information in a vissprite
|
// store information in a vissprite
|
||||||
RenderSprite *vis = RenderMemory::NewObject<RenderSprite>();
|
RenderSprite *vis = RenderMemory::NewObject<RenderSprite>();
|
||||||
|
memset(vis, 0, sizeof(*vis));
|
||||||
|
|
||||||
vis->CurrentPortalUniq = renderportal->CurrentPortalUniq;
|
vis->CurrentPortalUniq = renderportal->CurrentPortalUniq;
|
||||||
vis->xscale = FLOAT2FIXED(xscale);
|
vis->xscale = FLOAT2FIXED(xscale);
|
||||||
|
|
|
@ -143,9 +143,9 @@ class Inquisitor : Actor
|
||||||
A_PlaySound ("inquisitor/jump", CHAN_ITEM, 1, true);
|
A_PlaySound ("inquisitor/jump", CHAN_ITEM, 1, true);
|
||||||
AddZ(64);
|
AddZ(64);
|
||||||
A_FaceTarget ();
|
A_FaceTarget ();
|
||||||
speed = Speed * (2./3);
|
let localspeed = Speed * (2./3);
|
||||||
VelFromAngle(speed);
|
VelFromAngle(localspeed);
|
||||||
double dist = DistanceBySpeed(target, speed);
|
double dist = DistanceBySpeed(target, localspeed);
|
||||||
Vel.Z = (target.pos.z - pos.z) / dist;
|
Vel.Z = (target.pos.z - pos.z) / dist;
|
||||||
reactiontime = 60;
|
reactiontime = 60;
|
||||||
bNoGravity = true;
|
bNoGravity = true;
|
||||||
|
|
Loading…
Reference in a new issue