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->TypeName = name;
|
||||||
type->ParentClass = this;
|
type->ParentClass = this;
|
||||||
|
type->ConstructNative = ConstructNative;
|
||||||
type->Size = TentativeClass;
|
type->Size = TentativeClass;
|
||||||
type->bRuntimeClass = true;
|
type->bRuntimeClass = true;
|
||||||
type->Symbols.SetParentTable(&Symbols);
|
type->Symbols.SetParentTable(&Symbols);
|
||||||
|
|
|
@ -1696,7 +1696,7 @@ PClassHealth::PClassHealth()
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
//
|
//
|
||||||
// PClassHealth :: Derive
|
// PClassHealth :: DeriveData
|
||||||
//
|
//
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
|
||||||
|
|
|
@ -1006,6 +1006,7 @@ void FScanner::CheckOpen()
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
int FScriptPosition::ErrorCounter;
|
int FScriptPosition::ErrorCounter;
|
||||||
|
bool FScriptPosition::StrictErrors; // makes all OPTERRPR messages real errors.
|
||||||
|
|
||||||
FScriptPosition::FScriptPosition(const FScriptPosition &other)
|
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_DEBUG || severity == MSG_DEBUGLOG) && developer < DMSG_NOTIFY) return;
|
||||||
if (severity == MSG_OPTERROR)
|
if (severity == MSG_OPTERROR)
|
||||||
{
|
{
|
||||||
severity = strictdecorate ? MSG_ERROR : MSG_WARNING;
|
severity = StrictErrors || strictdecorate ? MSG_ERROR : MSG_WARNING;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message == NULL)
|
if (message == NULL)
|
||||||
|
|
|
@ -140,6 +140,7 @@ enum
|
||||||
struct FScriptPosition
|
struct FScriptPosition
|
||||||
{
|
{
|
||||||
static int ErrorCounter;
|
static int ErrorCounter;
|
||||||
|
static bool StrictErrors;
|
||||||
FString FileName;
|
FString FileName;
|
||||||
int ScriptLine;
|
int ScriptLine;
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ struct FFlagDef
|
||||||
int fieldsize;
|
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);
|
void HandleDeprecatedFlags(AActor *defaults, PClassActor *info, bool set, int index);
|
||||||
bool CheckDeprecatedFlags(const AActor *actor, PClassActor *info, int index);
|
bool CheckDeprecatedFlags(const AActor *actor, PClassActor *info, int index);
|
||||||
const char *GetFlagName(unsigned int flagnum, int flagoffset);
|
const char *GetFlagName(unsigned int flagnum, int flagoffset);
|
||||||
|
@ -146,6 +146,7 @@ struct Baggage
|
||||||
PClassActor *Info;
|
PClassActor *Info;
|
||||||
bool DropItemSet;
|
bool DropItemSet;
|
||||||
bool StateSet;
|
bool StateSet;
|
||||||
|
bool fromZScript;
|
||||||
int CurrentState;
|
int CurrentState;
|
||||||
int Lumpnum;
|
int Lumpnum;
|
||||||
FStateDefinitions statedef;
|
FStateDefinitions statedef;
|
||||||
|
@ -272,7 +273,7 @@ typedef void (*PropHandler)(AActor *defaults, PClassActor *info, Baggage &bag, F
|
||||||
enum ECategory
|
enum ECategory
|
||||||
{
|
{
|
||||||
CAT_PROPERTY, // Inheritable property
|
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
|
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;
|
FFlagDef *def;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
if (part2 == NULL)
|
if (part2 == NULL)
|
||||||
{ // Search all lists
|
{ // 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))
|
if (type->IsDescendantOf (*FlagLists[i].Type))
|
||||||
{
|
{
|
||||||
|
|
|
@ -1063,7 +1063,7 @@ static void ParseActorProperty(FScanner &sc, Baggage &bag)
|
||||||
}
|
}
|
||||||
else
|
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++;
|
FScriptPosition::ErrorCounter++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1073,7 +1073,7 @@ static void ParseActorProperty(FScanner &sc, Baggage &bag)
|
||||||
}
|
}
|
||||||
else
|
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)
|
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,
|
bag.ScriptPosition.Message(MSG_OPTERROR,
|
||||||
"'skip_super' in definition of inventory item '%s' ignored.", info->TypeName.GetChars() );
|
"'skip_super' is only allowed in subclasses of AActor with no additional fields and will be ignored.", info->TypeName.GetChars());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (bag.StateSet)
|
if (bag.StateSet)
|
||||||
|
@ -2484,7 +2485,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, face, S, PlayerPawn)
|
||||||
);
|
);
|
||||||
if (!valid)
|
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",
|
"Invalid face '%s' for '%s';\nSTF replacement codes must be 3 alphanumeric characters.\n",
|
||||||
tmp.GetChars(), info->TypeName.GetChars ());
|
tmp.GetChars(), info->TypeName.GetChars ());
|
||||||
}
|
}
|
||||||
|
@ -2551,13 +2552,13 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, colorset, ISIIIiiiiiiiiiiiiiiiiiiiiiiii, Pl
|
||||||
}
|
}
|
||||||
if (count != 0)
|
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)
|
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
|
else
|
||||||
{
|
{
|
||||||
|
@ -2584,7 +2585,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, colorsetfile, ISSI, PlayerPawn)
|
||||||
|
|
||||||
if (setnum < 0)
|
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)
|
else if (color.Lump >= 0)
|
||||||
{
|
{
|
||||||
|
@ -2602,7 +2603,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, clearcolorset, I, PlayerPawn)
|
||||||
|
|
||||||
if (setnum < 0)
|
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
|
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) ::= SEMICOLON. { X = NULL; }
|
||||||
//default_statement(X) ::= assign_statement(A) SEMICOLON. { X = A; /*X-overwrites-A*/ }
|
//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*/ }
|
default_statement(X) ::= flag_statement(A). { X = A; /*X-overwrites-A*/ }
|
||||||
|
|
||||||
%type flag_statement { ZCC_FlagStmt *}
|
%type flag_statement { ZCC_FlagStmt *}
|
||||||
|
@ -550,7 +550,7 @@ flag_statement(X) ::= SUB dottable_id(A).
|
||||||
|
|
||||||
%type property_statement{ZCC_PropertyStmt *}
|
%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);
|
NEW_AST_NODE(PropertyStmt,stmt,A);
|
||||||
stmt->Prop = A;
|
stmt->Prop = A;
|
||||||
|
@ -558,6 +558,14 @@ property_statement(X) ::= dottable_id(A) expr_list(B).
|
||||||
X = stmt;
|
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 */
|
/* Type names */
|
||||||
|
|
|
@ -32,10 +32,12 @@
|
||||||
**
|
**
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "dobject.h"
|
#include "actor.h"
|
||||||
|
#include "thingdef.h"
|
||||||
#include "sc_man.h"
|
#include "sc_man.h"
|
||||||
#include "c_console.h"
|
#include "c_console.h"
|
||||||
#include "c_dispatch.h"
|
#include "c_dispatch.h"
|
||||||
|
#include "doomerrors.h"
|
||||||
#include "w_wad.h"
|
#include "w_wad.h"
|
||||||
#include "cmdlib.h"
|
#include "cmdlib.h"
|
||||||
#include "m_alloc.h"
|
#include "m_alloc.h"
|
||||||
|
@ -110,8 +112,11 @@ void ZCCCompiler::ProcessClass(ZCC_Class *cnode, PSymbolTreeNode *treenode)
|
||||||
// todo
|
// todo
|
||||||
case AST_States:
|
case AST_States:
|
||||||
case AST_FuncDeclarator:
|
case AST_FuncDeclarator:
|
||||||
|
break;
|
||||||
|
|
||||||
case AST_Default:
|
case AST_Default:
|
||||||
break;
|
cls->Defaults.Push(static_cast<ZCC_Default *>(node));
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
assert(0 && "Unhandled AST node type");
|
assert(0 && "Unhandled AST node type");
|
||||||
|
@ -358,6 +363,7 @@ int ZCCCompiler::Compile()
|
||||||
CreateStructTypes();
|
CreateStructTypes();
|
||||||
CompileAllConstants();
|
CompileAllConstants();
|
||||||
CompileAllFields();
|
CompileAllFields();
|
||||||
|
InitDefaults();
|
||||||
return ErrorCount;
|
return ErrorCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1433,3 +1439,388 @@ PType *ZCCCompiler::ResolveArraySize(PType *baseType, ZCC_Expression *arraysize,
|
||||||
} while (val != arraysize);
|
} while (val != 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 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
|
#ifndef ZCC_COMPILE_H
|
||||||
#define ZCC_COMPILE_H
|
#define ZCC_COMPILE_H
|
||||||
|
|
||||||
|
struct Baggage;
|
||||||
|
struct FPropertyInfo;
|
||||||
|
class AActor;
|
||||||
|
|
||||||
struct ZCC_StructWork
|
struct ZCC_StructWork
|
||||||
{
|
{
|
||||||
PSymbolTable TreeNodes;
|
PSymbolTable TreeNodes;
|
||||||
|
@ -40,6 +44,7 @@ struct ZCC_ClassWork
|
||||||
TArray<ZCC_Enum *> Enums;
|
TArray<ZCC_Enum *> Enums;
|
||||||
TArray<ZCC_ConstantDef *> Constants;
|
TArray<ZCC_ConstantDef *> Constants;
|
||||||
TArray<ZCC_VarDeclarator *> Fields;
|
TArray<ZCC_VarDeclarator *> Fields;
|
||||||
|
TArray<ZCC_Default *> Defaults;
|
||||||
|
|
||||||
ZCC_ClassWork(ZCC_Class * s, PSymbolTreeNode *n)
|
ZCC_ClassWork(ZCC_Class * s, PSymbolTreeNode *n)
|
||||||
{
|
{
|
||||||
|
@ -89,6 +94,14 @@ private:
|
||||||
PType *ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PSymbolTable *sym);
|
PType *ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PSymbolTable *sym);
|
||||||
PType *ResolveUserType(ZCC_BasicType *type, 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_ConstantDef *> Constants;
|
||||||
TArray<ZCC_StructWork *> Structs;
|
TArray<ZCC_StructWork *> Structs;
|
||||||
TArray<ZCC_ClassWork *> Classes;
|
TArray<ZCC_ClassWork *> Classes;
|
||||||
|
@ -103,11 +116,6 @@ private:
|
||||||
ZCC_OpProto *PromoteUnary(EZCCExprType op, ZCC_Expression *&expr);
|
ZCC_OpProto *PromoteUnary(EZCCExprType op, ZCC_Expression *&expr);
|
||||||
ZCC_OpProto *PromoteBinary(EZCCExprType op, ZCC_Expression *&left, ZCC_Expression *&right);
|
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 *ApplyConversion(ZCC_Expression *expr, const PType::Conversion **route, int routelen);
|
||||||
ZCC_Expression *AddCastNode(PType *type, ZCC_Expression *expr);
|
ZCC_Expression *AddCastNode(PType *type, ZCC_Expression *expr);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue