mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-10 23:02:08 +00:00
- implemented the Defaults property initializer.
This uses the same property and flag tables as DECORATE with a few changes: * it sets the parse mode to strict, so that several DECORATE warnings are now errors. * trying to change a deprecated flag will print a warning. * setting of editor numbers, spawn and conversation ID id not possible. Use MAPINFO to do this. * all subclass flags must use the qualified name now (e.g. +ALWAYSPICKUP will print an error.) * the scriptable Damage property is not yet implemented. This will require a special case with a differently named property in the processing function because in the AST it is no longer possible to distinguish between a damage value and a constant damage function.
This commit is contained in:
parent
2b9af0176c
commit
3b19887637
11 changed files with 438 additions and 25 deletions
|
@ -3163,6 +3163,7 @@ PClass *PClass::FindClassTentative(FName name, bool fatal)
|
|||
|
||||
type->TypeName = name;
|
||||
type->ParentClass = this;
|
||||
type->ConstructNative = ConstructNative;
|
||||
type->Size = TentativeClass;
|
||||
type->bRuntimeClass = true;
|
||||
type->Symbols.SetParentTable(&Symbols);
|
||||
|
|
|
@ -1696,7 +1696,7 @@ PClassHealth::PClassHealth()
|
|||
|
||||
//===========================================================================
|
||||
//
|
||||
// PClassHealth :: Derive
|
||||
// PClassHealth :: DeriveData
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
|
|
|
@ -1006,6 +1006,7 @@ void FScanner::CheckOpen()
|
|||
//
|
||||
//==========================================================================
|
||||
int FScriptPosition::ErrorCounter;
|
||||
bool FScriptPosition::StrictErrors; // makes all OPTERRPR messages real errors.
|
||||
|
||||
FScriptPosition::FScriptPosition(const FScriptPosition &other)
|
||||
{
|
||||
|
@ -1047,7 +1048,7 @@ void FScriptPosition::Message (int severity, const char *message, ...) const
|
|||
if ((severity == MSG_DEBUG || severity == MSG_DEBUGLOG) && developer < DMSG_NOTIFY) return;
|
||||
if (severity == MSG_OPTERROR)
|
||||
{
|
||||
severity = strictdecorate ? MSG_ERROR : MSG_WARNING;
|
||||
severity = StrictErrors || strictdecorate ? MSG_ERROR : MSG_WARNING;
|
||||
}
|
||||
|
||||
if (message == NULL)
|
||||
|
|
|
@ -140,6 +140,7 @@ enum
|
|||
struct FScriptPosition
|
||||
{
|
||||
static int ErrorCounter;
|
||||
static bool StrictErrors;
|
||||
FString FileName;
|
||||
int ScriptLine;
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ struct FFlagDef
|
|||
int fieldsize;
|
||||
};
|
||||
|
||||
FFlagDef *FindFlag (const PClass *type, const char *part1, const char *part2);
|
||||
FFlagDef *FindFlag (const PClass *type, const char *part1, const char *part2, bool strict = false);
|
||||
void HandleDeprecatedFlags(AActor *defaults, PClassActor *info, bool set, int index);
|
||||
bool CheckDeprecatedFlags(const AActor *actor, PClassActor *info, int index);
|
||||
const char *GetFlagName(unsigned int flagnum, int flagoffset);
|
||||
|
@ -146,6 +146,7 @@ struct Baggage
|
|||
PClassActor *Info;
|
||||
bool DropItemSet;
|
||||
bool StateSet;
|
||||
bool fromZScript;
|
||||
int CurrentState;
|
||||
int Lumpnum;
|
||||
FStateDefinitions statedef;
|
||||
|
@ -272,7 +273,7 @@ typedef void (*PropHandler)(AActor *defaults, PClassActor *info, Baggage &bag, F
|
|||
enum ECategory
|
||||
{
|
||||
CAT_PROPERTY, // Inheritable property
|
||||
CAT_INFO // non-inheritable info (spawn ID, Doomednum, game filter, conversation ID)
|
||||
CAT_INFO // non-inheritable info (spawn ID, Doomednum, game filter, conversation ID, not usable in ZScript)
|
||||
};
|
||||
|
||||
struct FPropertyInfo
|
||||
|
|
|
@ -436,14 +436,15 @@ static FFlagDef *FindFlag (FFlagDef *flags, int numflags, const char *flag)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
FFlagDef *FindFlag (const PClass *type, const char *part1, const char *part2)
|
||||
FFlagDef *FindFlag (const PClass *type, const char *part1, const char *part2, bool strict)
|
||||
{
|
||||
FFlagDef *def;
|
||||
size_t i;
|
||||
|
||||
if (part2 == NULL)
|
||||
{ // Search all lists
|
||||
for (i = 0; i < NUM_FLAG_LISTS; ++i)
|
||||
int max = strict ? 1 : NUM_FLAG_LISTS;
|
||||
for (i = 0; i < max; ++i)
|
||||
{
|
||||
if (type->IsDescendantOf (*FlagLists[i].Type))
|
||||
{
|
||||
|
|
|
@ -1063,7 +1063,7 @@ static void ParseActorProperty(FScanner &sc, Baggage &bag)
|
|||
}
|
||||
else
|
||||
{
|
||||
sc.ScriptMessage("\"%s\" requires an actor of type \"%s\"\n", propname.GetChars(), (*prop->cls)->TypeName.GetChars());
|
||||
sc.ScriptMessage("'%s' requires an actor of type '%s'\n", propname.GetChars(), (*prop->cls)->TypeName.GetChars());
|
||||
FScriptPosition::ErrorCounter++;
|
||||
}
|
||||
}
|
||||
|
@ -1073,7 +1073,7 @@ static void ParseActorProperty(FScanner &sc, Baggage &bag)
|
|||
}
|
||||
else
|
||||
{
|
||||
sc.ScriptError("\"%s\" is an unknown actor property\n", propname.GetChars());
|
||||
sc.ScriptError("'%s' is an unknown actor property\n", propname.GetChars());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -514,10 +514,11 @@ DEFINE_INFO_PROPERTY(conversationid, IiI, Actor)
|
|||
//==========================================================================
|
||||
DEFINE_PROPERTY(skip_super, 0, Actor)
|
||||
{
|
||||
if (info->IsDescendantOf(RUNTIME_CLASS(AInventory)))
|
||||
auto actorclass = RUNTIME_CLASS(AActor);
|
||||
if (info->Size != actorclass->Size)
|
||||
{
|
||||
bag.ScriptPosition.Message(MSG_WARNING,
|
||||
"'skip_super' in definition of inventory item '%s' ignored.", info->TypeName.GetChars() );
|
||||
bag.ScriptPosition.Message(MSG_OPTERROR,
|
||||
"'skip_super' is only allowed in subclasses of AActor with no additional fields and will be ignored.", info->TypeName.GetChars());
|
||||
return;
|
||||
}
|
||||
if (bag.StateSet)
|
||||
|
@ -2484,7 +2485,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, face, S, PlayerPawn)
|
|||
);
|
||||
if (!valid)
|
||||
{
|
||||
bag.ScriptPosition.Message(MSG_WARNING,
|
||||
bag.ScriptPosition.Message(MSG_OPTERROR,
|
||||
"Invalid face '%s' for '%s';\nSTF replacement codes must be 3 alphanumeric characters.\n",
|
||||
tmp.GetChars(), info->TypeName.GetChars ());
|
||||
}
|
||||
|
@ -2551,13 +2552,13 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, colorset, ISIIIiiiiiiiiiiiiiiiiiiiiiiii, Pl
|
|||
}
|
||||
if (count != 0)
|
||||
{
|
||||
bag.ScriptPosition.Message(MSG_WARNING, "Extra ranges require 4 parameters each.\n");
|
||||
bag.ScriptPosition.Message(MSG_OPTERROR, "Extra ranges require 4 parameters each.\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (setnum < 0)
|
||||
{
|
||||
bag.ScriptPosition.Message(MSG_WARNING, "Color set number must not be negative.\n");
|
||||
bag.ScriptPosition.Message(MSG_OPTERROR, "Color set number must not be negative.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2584,7 +2585,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, colorsetfile, ISSI, PlayerPawn)
|
|||
|
||||
if (setnum < 0)
|
||||
{
|
||||
bag.ScriptPosition.Message(MSG_WARNING, "Color set number must not be negative.\n");
|
||||
bag.ScriptPosition.Message(MSG_OPTERROR, "Color set number must not be negative.\n");
|
||||
}
|
||||
else if (color.Lump >= 0)
|
||||
{
|
||||
|
@ -2602,7 +2603,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, clearcolorset, I, PlayerPawn)
|
|||
|
||||
if (setnum < 0)
|
||||
{
|
||||
bag.ScriptPosition.Message(MSG_WARNING, "Color set number must not be negative.\n");
|
||||
bag.ScriptPosition.Message(MSG_OPTERROR, "Color set number must not be negative.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -528,7 +528,7 @@ default_statement_list(X) ::= default_statement_list(X) default_statement(B).
|
|||
|
||||
default_statement(X) ::= SEMICOLON. { X = NULL; }
|
||||
//default_statement(X) ::= assign_statement(A) SEMICOLON. { X = A; /*X-overwrites-A*/ }
|
||||
default_statement(X) ::= property_statement(A) SEMICOLON. { X = A; /*X-overwrites-A*/ }
|
||||
default_statement(X) ::= property_statement(A). { X = A; /*X-overwrites-A*/ }
|
||||
default_statement(X) ::= flag_statement(A). { X = A; /*X-overwrites-A*/ }
|
||||
|
||||
%type flag_statement { ZCC_FlagStmt *}
|
||||
|
@ -550,7 +550,7 @@ flag_statement(X) ::= SUB dottable_id(A).
|
|||
|
||||
%type property_statement{ZCC_PropertyStmt *}
|
||||
|
||||
property_statement(X) ::= dottable_id(A) expr_list(B).
|
||||
property_statement(X) ::= dottable_id(A) expr_list(B) SEMICOLON.
|
||||
{
|
||||
NEW_AST_NODE(PropertyStmt,stmt,A);
|
||||
stmt->Prop = A;
|
||||
|
@ -558,6 +558,14 @@ property_statement(X) ::= dottable_id(A) expr_list(B).
|
|||
X = stmt;
|
||||
}
|
||||
|
||||
property_statement(X) ::= dottable_id(A) SEMICOLON.
|
||||
{
|
||||
NEW_AST_NODE(PropertyStmt,stmt,A);
|
||||
stmt->Prop = A;
|
||||
stmt->Values = nullptr;
|
||||
X = stmt;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Type names */
|
||||
|
|
|
@ -32,10 +32,12 @@
|
|||
**
|
||||
*/
|
||||
|
||||
#include "dobject.h"
|
||||
#include "actor.h"
|
||||
#include "thingdef.h"
|
||||
#include "sc_man.h"
|
||||
#include "c_console.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "doomerrors.h"
|
||||
#include "w_wad.h"
|
||||
#include "cmdlib.h"
|
||||
#include "m_alloc.h"
|
||||
|
@ -110,8 +112,11 @@ void ZCCCompiler::ProcessClass(ZCC_Class *cnode, PSymbolTreeNode *treenode)
|
|||
// todo
|
||||
case AST_States:
|
||||
case AST_FuncDeclarator:
|
||||
break;
|
||||
|
||||
case AST_Default:
|
||||
break;
|
||||
cls->Defaults.Push(static_cast<ZCC_Default *>(node));
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0 && "Unhandled AST node type");
|
||||
|
@ -358,6 +363,7 @@ int ZCCCompiler::Compile()
|
|||
CreateStructTypes();
|
||||
CompileAllConstants();
|
||||
CompileAllFields();
|
||||
InitDefaults();
|
||||
return ErrorCount;
|
||||
}
|
||||
|
||||
|
@ -1433,3 +1439,388 @@ PType *ZCCCompiler::ResolveArraySize(PType *baseType, ZCC_Expression *arraysize,
|
|||
} while (val != arraysize);
|
||||
return baseType;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ZCCCompiler :: GetInt - Input must be a constant expression
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int ZCCCompiler::GetInt(ZCC_Expression *expr)
|
||||
{
|
||||
if (expr->Type == TypeError)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
const PType::Conversion *route[CONVERSION_ROUTE_SIZE];
|
||||
int routelen = expr->Type->FindConversion(TypeSInt32, route, countof(route));
|
||||
if (routelen < 0)
|
||||
{
|
||||
Error(expr, "Cannot convert to integer");
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (expr->Type->IsKindOf(RUNTIME_CLASS(PFloat)))
|
||||
{
|
||||
Warn(expr, "Truncation of floating point value");
|
||||
}
|
||||
auto ex = static_cast<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 0;
|
||||
}
|
||||
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 0;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Parses an actor property's parameters and calls the handler
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void ZCCCompiler::DispatchProperty(FPropertyInfo *prop, ZCC_PropertyStmt *property, AActor *defaults, Baggage &bag)
|
||||
{
|
||||
static TArray<FPropParam> params;
|
||||
static TArray<FString> strings;
|
||||
|
||||
params.Clear();
|
||||
strings.Clear();
|
||||
params.Reserve(1);
|
||||
params[0].i = 0;
|
||||
if (prop->params[0] != '0')
|
||||
{
|
||||
if (property->Values == nullptr)
|
||||
{
|
||||
Error(property, "%s: arguments missing", prop->name);
|
||||
return;
|
||||
}
|
||||
property->Values = Simplify(property->Values, &bag.Info->Symbols); // need to do this before the loop so that we can find the head node again.
|
||||
const char * p = prop->params;
|
||||
auto exp = property->Values;
|
||||
|
||||
while (true)
|
||||
{
|
||||
FPropParam conv;
|
||||
FPropParam pref;
|
||||
|
||||
if (exp->NodeType != AST_ExprConstant)
|
||||
{
|
||||
Error(exp, "%s: non-constant parameter", prop->name);
|
||||
}
|
||||
conv.s = nullptr;
|
||||
pref.s = nullptr;
|
||||
pref.i = -1;
|
||||
switch ((*p) & 223)
|
||||
{
|
||||
|
||||
case 'I':
|
||||
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 'M': // special case for morph styles in DECORATE . This expression-aware parser will not need this.
|
||||
case 'N': // special case for thing activations in DECORATE. This expression-aware parser will not need this.
|
||||
conv.i = GetInt(exp);
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
conv.d = GetDouble(exp);
|
||||
break;
|
||||
|
||||
case 'Z': // an optional string. Does not allow any numerical value.
|
||||
if (!GetString(exp, true))
|
||||
{
|
||||
// apply this expression to the next argument on the list.
|
||||
params.Push(conv);
|
||||
params[0].i++;
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
// fall through
|
||||
|
||||
case 'C': // this parser accepts colors only in string form.
|
||||
pref.i = 1;
|
||||
case 'S':
|
||||
conv.s = GetString(exp);
|
||||
break;
|
||||
|
||||
case 'T': // a filtered string
|
||||
conv.s = strings[strings.Reserve(1)] = strbin1(GetString(exp));
|
||||
break;
|
||||
|
||||
case 'L': // Either a number or a list of strings
|
||||
if (!GetString(exp, true))
|
||||
{
|
||||
pref.i = 0;
|
||||
conv.i = GetInt(exp);
|
||||
}
|
||||
else
|
||||
{
|
||||
pref.i = 1;
|
||||
params.Push(pref);
|
||||
params[0].i++;
|
||||
|
||||
do
|
||||
{
|
||||
conv.s = GetString(exp);
|
||||
if (conv.s != nullptr)
|
||||
{
|
||||
params.Push(conv);
|
||||
params[0].i++;
|
||||
}
|
||||
exp = Simplify(static_cast<ZCC_Expression *>(exp->SiblingNext), &bag.Info->Symbols);
|
||||
} while (exp != property->Values);
|
||||
goto endofparm;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
|
||||
}
|
||||
if (pref.i != -1)
|
||||
{
|
||||
params.Push(pref);
|
||||
params[0].i++;
|
||||
}
|
||||
params.Push(conv);
|
||||
params[0].i++;
|
||||
exp = Simplify(static_cast<ZCC_Expression *>(exp->SiblingNext), &bag.Info->Symbols);
|
||||
endofparm:
|
||||
p++;
|
||||
// Skip the DECORATE 'no comma' marker
|
||||
if (*p == '_') p++;
|
||||
|
||||
else if (*p == 0)
|
||||
{
|
||||
if (exp != property->Values)
|
||||
{
|
||||
Error(property, "Too many values for '%s'", prop->name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (exp == property->Values)
|
||||
{
|
||||
if (*p < 'a')
|
||||
{
|
||||
Error(property, "Insufficient parameters for %s", prop->name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// call the handler
|
||||
try
|
||||
{
|
||||
prop->Handler(defaults, bag.Info, bag, ¶ms[0]);
|
||||
}
|
||||
catch (CRecoverableError &error)
|
||||
{
|
||||
Error(property, "%s", error.GetMessage());
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Parses an actor property
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void ZCCCompiler::ProcessDefaultProperty(PClassActor *cls, ZCC_PropertyStmt *prop, Baggage &bag)
|
||||
{
|
||||
auto namenode = prop->Prop;
|
||||
FString propname;
|
||||
|
||||
if (namenode->SiblingNext == namenode)
|
||||
{
|
||||
// a one-name property
|
||||
propname = FName(namenode->Id);
|
||||
}
|
||||
else if (namenode->SiblingNext->SiblingNext == namenode)
|
||||
{
|
||||
// a two-name property
|
||||
propname << FName(namenode->Id) << "." << FName(static_cast<ZCC_Identifier *>(namenode->SiblingNext)->Id);
|
||||
}
|
||||
else
|
||||
{
|
||||
Error(prop, "Property name may at most contain two parts");
|
||||
return;
|
||||
}
|
||||
|
||||
FPropertyInfo *property = FindProperty(propname);
|
||||
|
||||
if (property != nullptr && property->category != CAT_INFO)
|
||||
{
|
||||
if (cls->IsDescendantOf(*property->cls))
|
||||
{
|
||||
DispatchProperty(property, prop, (AActor *)bag.Info->Defaults, bag);
|
||||
}
|
||||
else
|
||||
{
|
||||
Error(prop, "'%s' requires an actor of type '%s'\n", propname.GetChars(), (*property->cls)->TypeName.GetChars());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Error(prop, "'%s' is an unknown actor property\n", propname.GetChars());
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Finds a flag and sets or clears it
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void ZCCCompiler::ProcessDefaultFlag(PClassActor *cls, ZCC_FlagStmt *flg)
|
||||
{
|
||||
auto namenode = flg->name;
|
||||
const char *n1 = FName(namenode->Id).GetChars(), *n2;
|
||||
|
||||
if (namenode->SiblingNext == namenode)
|
||||
{
|
||||
// a one-name flag
|
||||
n2 = nullptr;
|
||||
}
|
||||
else if (namenode->SiblingNext->SiblingNext == namenode)
|
||||
{
|
||||
// a two-name flag
|
||||
n2 = FName(static_cast<ZCC_Identifier *>(namenode->SiblingNext)->Id).GetChars();
|
||||
}
|
||||
else
|
||||
{
|
||||
Error(flg, "Flag name may at most contain two parts");
|
||||
return;
|
||||
}
|
||||
|
||||
auto fd = FindFlag(cls, n1, n2, true);
|
||||
if (fd != nullptr)
|
||||
{
|
||||
if (fd->structoffset == -1)
|
||||
{
|
||||
Warn(flg, "Deprecated flag '%s%s%s' used", n1, n2 ? "." : "", n2 ? n2 : "");
|
||||
HandleDeprecatedFlags((AActor*)cls->Defaults, cls, flg->set, fd->flagbit);
|
||||
}
|
||||
else
|
||||
{
|
||||
ModActorFlag((AActor*)cls->Defaults, fd, flg->set);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Error(flg, "Unknown flag '%s%s%s'", n1, n2 ? "." : "", n2 ? n2 : "");
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Parses the default list
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void ZCCCompiler::InitDefaults()
|
||||
{
|
||||
for (auto c : Classes)
|
||||
{
|
||||
// This may be removed if the conditions change, but right now only subclasses of Actor can define a Default block.
|
||||
if (!c->Type()->IsDescendantOf(RUNTIME_CLASS(AActor)))
|
||||
{
|
||||
if (c->Defaults.Size()) Error(c->cls, "%s: Non-actor classes may not have defaults", c->Type()->TypeName.GetChars());
|
||||
}
|
||||
else
|
||||
{
|
||||
// This should never happen.
|
||||
if (c->Type()->Defaults != nullptr)
|
||||
{
|
||||
Error(c->cls, "%s already has defaults", c->Type()->TypeName.GetChars());
|
||||
}
|
||||
// This can only occur if a native parent is not initialized. In all other cases the sorting of the class list should prevent this from ever happening.
|
||||
else if (c->Type()->ParentClass->Defaults == nullptr && c->Type() != RUNTIME_CLASS(AActor))
|
||||
{
|
||||
Error(c->cls, "Parent class %s of %s is not initialized", c->Type()->ParentClass->TypeName.GetChars(), c->Type()->TypeName.GetChars());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy the parent's defaults and meta data.
|
||||
auto ti = static_cast<PClassActor *>(c->Type());
|
||||
ti->InitializeNativeDefaults();
|
||||
ti->ParentClass->DeriveData(ti);
|
||||
|
||||
|
||||
Baggage bag;
|
||||
#ifdef _DEBUG
|
||||
bag.ClassName = c->Type()->TypeName;
|
||||
#endif
|
||||
bag.Info = ti;
|
||||
bag.DropItemSet = false;
|
||||
bag.StateSet = false;
|
||||
bag.fromZScript = true;
|
||||
bag.CurrentState = 0;
|
||||
bag.Lumpnum = Wads.CheckNumForFullName(*c->cls->SourceName, true);
|
||||
bag.DropItemList = nullptr;
|
||||
bag.ScriptPosition.StrictErrors = true;
|
||||
// The actual script position needs to be set per property.
|
||||
|
||||
for (auto d : c->Defaults)
|
||||
{
|
||||
auto content = d->Content;
|
||||
do
|
||||
{
|
||||
switch (content->NodeType)
|
||||
{
|
||||
case AST_PropertyStmt:
|
||||
bag.ScriptPosition.FileName = *content->SourceName;
|
||||
bag.ScriptPosition.ScriptLine = content->SourceLoc;
|
||||
ProcessDefaultProperty(ti, static_cast<ZCC_PropertyStmt *>(content), bag);
|
||||
break;
|
||||
|
||||
case AST_FlagStmt:
|
||||
ProcessDefaultFlag(ti, static_cast<ZCC_FlagStmt *>(content));
|
||||
break;
|
||||
}
|
||||
content = static_cast<decltype(content)>(content->SiblingNext);
|
||||
} while (content != d->Content);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
#ifndef ZCC_COMPILE_H
|
||||
#define ZCC_COMPILE_H
|
||||
|
||||
struct Baggage;
|
||||
struct FPropertyInfo;
|
||||
class AActor;
|
||||
|
||||
struct ZCC_StructWork
|
||||
{
|
||||
PSymbolTable TreeNodes;
|
||||
|
@ -40,6 +44,7 @@ struct ZCC_ClassWork
|
|||
TArray<ZCC_Enum *> Enums;
|
||||
TArray<ZCC_ConstantDef *> Constants;
|
||||
TArray<ZCC_VarDeclarator *> Fields;
|
||||
TArray<ZCC_Default *> Defaults;
|
||||
|
||||
ZCC_ClassWork(ZCC_Class * s, PSymbolTreeNode *n)
|
||||
{
|
||||
|
@ -89,6 +94,14 @@ private:
|
|||
PType *ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PSymbolTable *sym);
|
||||
PType *ResolveUserType(ZCC_BasicType *type, PSymbolTable *sym);
|
||||
|
||||
void InitDefaults();
|
||||
void ProcessDefaultFlag(PClassActor *cls, ZCC_FlagStmt *flg);
|
||||
void ProcessDefaultProperty(PClassActor *cls, ZCC_PropertyStmt *flg, Baggage &bag);
|
||||
void DispatchProperty(FPropertyInfo *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);
|
||||
|
||||
TArray<ZCC_ConstantDef *> Constants;
|
||||
TArray<ZCC_StructWork *> Structs;
|
||||
TArray<ZCC_ClassWork *> Classes;
|
||||
|
@ -103,11 +116,6 @@ private:
|
|||
ZCC_OpProto *PromoteUnary(EZCCExprType op, ZCC_Expression *&expr);
|
||||
ZCC_OpProto *PromoteBinary(EZCCExprType op, ZCC_Expression *&left, ZCC_Expression *&right);
|
||||
|
||||
void PromoteToInt(ZCC_Expression *&expr);
|
||||
void PromoteToUInt(ZCC_Expression *&expr);
|
||||
void PromoteToDouble(ZCC_Expression *&expr);
|
||||
void PromoteToString(ZCC_Expression *&expr);
|
||||
|
||||
ZCC_Expression *ApplyConversion(ZCC_Expression *expr, const PType::Conversion **route, int routelen);
|
||||
ZCC_Expression *AddCastNode(PType *type, ZCC_Expression *expr);
|
||||
|
||||
|
|
Loading…
Reference in a new issue