- the compile context now knows if it is invoked by ZScript or DECORATE, so that it can be more strict with ZScript if needed.

- added a truncation warning to FxIntCast, which only occurs with ZScript, not with DECORATE. FxBoolCast is intentionally left out because it would defeat the reason for this cast type.
This commit is contained in:
Christoph Oelckers 2016-10-15 21:35:31 +02:00
parent c3e693b507
commit b299b64e47
9 changed files with 52 additions and 37 deletions

View file

@ -91,12 +91,12 @@ static const FLOP FxFlops[] =
// //
//========================================================================== //==========================================================================
FCompileContext::FCompileContext(PFunction *fnc, PPrototype *ret) : ReturnProto(ret), Function(fnc), Class(nullptr) FCompileContext::FCompileContext(PFunction *fnc, PPrototype *ret, bool fromdecorate) : ReturnProto(ret), Function(fnc), Class(nullptr), FromDecorate(fromdecorate)
{ {
if (fnc != nullptr) Class = fnc->OwningClass; if (fnc != nullptr) Class = fnc->OwningClass;
} }
FCompileContext::FCompileContext(PClass *cls) : ReturnProto(nullptr), Function(nullptr), Class(cls) FCompileContext::FCompileContext(PClass *cls) : ReturnProto(nullptr), Function(nullptr), Class(cls), FromDecorate(true) // only used by DECORATE constants.
{ {
} }
@ -495,11 +495,12 @@ ExpEmit FxBoolCast::Emit(VMFunctionBuilder *build)
// //
//========================================================================== //==========================================================================
FxIntCast::FxIntCast(FxExpression *x) FxIntCast::FxIntCast(FxExpression *x, bool nowarn)
: FxExpression(x->ScriptPosition) : FxExpression(x->ScriptPosition)
{ {
basex=x; basex=x;
ValueType = TypeSInt32; ValueType = TypeSInt32;
NoWarn = nowarn;
} }
//========================================================================== //==========================================================================
@ -536,6 +537,7 @@ FxExpression *FxIntCast::Resolve(FCompileContext &ctx)
else else
{ {
// Ugh. This should abort, but too many mods fell into this logic hole somewhere, so this seroious error needs to be reduced to a warning. :( // Ugh. This should abort, but too many mods fell into this logic hole somewhere, so this seroious error needs to be reduced to a warning. :(
// At least in ZScript, MSG_OPTERROR always means to report an error, not a warning so the problem only exists in DECORATE.
if (!basex->isConstant()) ScriptPosition.Message(MSG_OPTERROR, "Numeric type expected, got a name"); if (!basex->isConstant()) ScriptPosition.Message(MSG_OPTERROR, "Numeric type expected, got a name");
else ScriptPosition.Message(MSG_OPTERROR, "Numeric type expected, got \"%s\"", static_cast<FxConstant*>(basex)->GetValue().GetName().GetChars()); else ScriptPosition.Message(MSG_OPTERROR, "Numeric type expected, got \"%s\"", static_cast<FxConstant*>(basex)->GetValue().GetName().GetChars());
FxExpression * x = new FxConstant(0, ScriptPosition); FxExpression * x = new FxConstant(0, ScriptPosition);
@ -549,9 +551,19 @@ FxExpression *FxIntCast::Resolve(FCompileContext &ctx)
{ {
ExpVal constval = static_cast<FxConstant *>(basex)->GetValue(); ExpVal constval = static_cast<FxConstant *>(basex)->GetValue();
FxExpression *x = new FxConstant(constval.GetInt(), ScriptPosition); FxExpression *x = new FxConstant(constval.GetInt(), ScriptPosition);
if (!NoWarn && constval.GetInt() != constval.GetFloat())
{
ScriptPosition.Message(MSG_WARNING, "Truncation of floating point constant %f", constval.GetFloat());
}
delete this; delete this;
return x; return x;
} }
else if (!NoWarn)
{
ScriptPosition.Message(MSG_WARNING, "Truncation of floating point value");
}
return this; return this;
} }
ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); ScriptPosition.Message(MSG_ERROR, "Numeric type expected");
@ -634,6 +646,7 @@ FxExpression *FxFloatCast::Resolve(FCompileContext &ctx)
else else
{ {
// Ugh. This should abort, but too many mods fell into this logic hole somewhere, so this seroious error needs to be reduced to a warning. :( // Ugh. This should abort, but too many mods fell into this logic hole somewhere, so this seroious error needs to be reduced to a warning. :(
// At least in ZScript, MSG_OPTERROR always means to report an error, not a warning so the problem only exists in DECORATE.
if (!basex->isConstant()) ScriptPosition.Message(MSG_OPTERROR, "Numeric type expected, got a name"); if (!basex->isConstant()) ScriptPosition.Message(MSG_OPTERROR, "Numeric type expected, got a name");
else ScriptPosition.Message(MSG_OPTERROR, "Numeric type expected, got \"%s\"", static_cast<FxConstant*>(basex)->GetValue().GetName().GetChars()); else ScriptPosition.Message(MSG_OPTERROR, "Numeric type expected, got \"%s\"", static_cast<FxConstant*>(basex)->GetValue().GetName().GetChars());
FxExpression *x = new FxConstant(0.0, ScriptPosition); FxExpression *x = new FxConstant(0.0, ScriptPosition);
@ -837,7 +850,7 @@ FxExpression *FxUnaryNotBitwise::Resolve(FCompileContext& ctx)
if (Operand->ValueType->GetRegType() == REGT_FLOAT /* lax */) if (Operand->ValueType->GetRegType() == REGT_FLOAT /* lax */)
{ {
// DECORATE allows floats here so cast them to int. // DECORATE allows floats here so cast them to int.
Operand = new FxIntCast(Operand); Operand = new FxIntCast(Operand, ctx.FromDecorate);
Operand = Operand->Resolve(ctx); Operand = Operand->Resolve(ctx);
if (Operand == NULL) if (Operand == NULL)
{ {
@ -1165,7 +1178,7 @@ FxExpression *FxAssign::Resolve(FCompileContext &ctx)
} }
else if (ValueType->GetRegType() == REGT_INT) else if (ValueType->GetRegType() == REGT_INT)
{ {
Right = new FxIntCast(Right); Right = new FxIntCast(Right, ctx.FromDecorate);
} }
else else
{ {
@ -1840,12 +1853,12 @@ FxExpression *FxBinaryInt::Resolve(FCompileContext& ctx)
// For DECORATE which allows floats here. // For DECORATE which allows floats here.
if (left->ValueType->GetRegType() != REGT_INT) if (left->ValueType->GetRegType() != REGT_INT)
{ {
left = new FxIntCast(left); left = new FxIntCast(left, ctx.FromDecorate);
left = left->Resolve(ctx); left = left->Resolve(ctx);
} }
if (right->ValueType->GetRegType() != REGT_INT) if (right->ValueType->GetRegType() != REGT_INT)
{ {
right = new FxIntCast(right); right = new FxIntCast(right, ctx.FromDecorate);
right = right->Resolve(ctx); right = right->Resolve(ctx);
} }
if (left == NULL || right == NULL) if (left == NULL || right == NULL)
@ -2710,14 +2723,14 @@ ExpEmit FxMinMax::Emit(VMFunctionBuilder *build)
// //
// //
//========================================================================== //==========================================================================
FxRandom::FxRandom(FRandom * r, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos) FxRandom::FxRandom(FRandom * r, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos, bool nowarn)
: FxExpression(pos) : FxExpression(pos)
{ {
EmitTail = false; EmitTail = false;
if (mi != NULL && ma != NULL) if (mi != NULL && ma != NULL)
{ {
min = new FxIntCast(mi); min = new FxIntCast(mi, nowarn);
max = new FxIntCast(ma); max = new FxIntCast(ma, nowarn);
} }
else min = max = NULL; else min = max = NULL;
rng = r; rng = r;
@ -2843,7 +2856,7 @@ ExpEmit FxRandom::Emit(VMFunctionBuilder *build)
// //
// //
//========================================================================== //==========================================================================
FxRandomPick::FxRandomPick(FRandom *r, TArray<FxExpression*> &expr, bool floaty, const FScriptPosition &pos) FxRandomPick::FxRandomPick(FRandom *r, TArray<FxExpression*> &expr, bool floaty, const FScriptPosition &pos, bool nowarn)
: FxExpression(pos) : FxExpression(pos)
{ {
assert(expr.Size() > 0); assert(expr.Size() > 0);
@ -2856,7 +2869,7 @@ FxRandomPick::FxRandomPick(FRandom *r, TArray<FxExpression*> &expr, bool floaty,
} }
else else
{ {
choices[index] = new FxIntCast(expr[index]); choices[index] = new FxIntCast(expr[index], nowarn);
} }
} }
@ -3008,7 +3021,7 @@ ExpEmit FxRandomPick::Emit(VMFunctionBuilder *build)
// //
//========================================================================== //==========================================================================
FxFRandom::FxFRandom(FRandom *r, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos) FxFRandom::FxFRandom(FRandom *r, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos)
: FxRandom(r, NULL, NULL, pos) : FxRandom(r, NULL, NULL, pos, true)
{ {
if (mi != NULL && ma != NULL) if (mi != NULL && ma != NULL)
{ {
@ -3089,12 +3102,12 @@ ExpEmit FxFRandom::Emit(VMFunctionBuilder *build)
// //
//========================================================================== //==========================================================================
FxRandom2::FxRandom2(FRandom *r, FxExpression *m, const FScriptPosition &pos) FxRandom2::FxRandom2(FRandom *r, FxExpression *m, const FScriptPosition &pos, bool nowarn)
: FxExpression(pos) : FxExpression(pos)
{ {
EmitTail = false; EmitTail = false;
rng = r; rng = r;
if (m) mask = new FxIntCast(m); if (m) mask = new FxIntCast(m, nowarn);
else mask = new FxConstant(-1, pos); else mask = new FxConstant(-1, pos);
ValueType = TypeSInt32; ValueType = TypeSInt32;
} }
@ -3505,7 +3518,7 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx)
if (index->ValueType->GetRegType() == REGT_FLOAT /* lax */) if (index->ValueType->GetRegType() == REGT_FLOAT /* lax */)
{ {
// DECORATE allows floats here so cast them to int. // DECORATE allows floats here so cast them to int.
index = new FxIntCast(index); index = new FxIntCast(index, ctx.FromDecorate);
index = index->Resolve(ctx); index = index->Resolve(ctx);
if (index == NULL) if (index == NULL)
{ {
@ -3792,7 +3805,7 @@ FxExpression *FxActionSpecialCall::Resolve(FCompileContext& ctx)
{ {
if ((*ArgList)[i]->ValueType->GetRegType() == REGT_FLOAT /* lax */) if ((*ArgList)[i]->ValueType->GetRegType() == REGT_FLOAT /* lax */)
{ {
(*ArgList)[i] = new FxIntCast((*ArgList)[i]); (*ArgList)[i] = new FxIntCast((*ArgList)[i], ctx.FromDecorate);
} }
else else
{ {
@ -5075,7 +5088,7 @@ FxExpression *FxRuntimeStateIndex::Resolve(FCompileContext &ctx)
} }
else if (Index->ValueType->GetRegType() != REGT_INT) else if (Index->ValueType->GetRegType() != REGT_INT)
{ // Float. { // Float.
Index = new FxIntCast(Index); Index = new FxIntCast(Index, ctx.FromDecorate);
SAFE_RESOLVE(Index, ctx); SAFE_RESOLVE(Index, ctx);
} }

View file

@ -69,8 +69,9 @@ struct FCompileContext
PPrototype *ReturnProto; PPrototype *ReturnProto;
PFunction *Function; // The function that is currently being compiled (or nullptr for constant evaluation.) PFunction *Function; // The function that is currently being compiled (or nullptr for constant evaluation.)
PClass *Class; // The type of the owning class. PClass *Class; // The type of the owning class.
bool FromDecorate;
FCompileContext(PFunction *func = nullptr, PPrototype *ret = nullptr); FCompileContext(PFunction *func, PPrototype *ret, bool fromdecorate);
FCompileContext(PClass *cls); // only to be used to resolve constants! FCompileContext(PClass *cls); // only to be used to resolve constants!
PSymbol *FindInClass(FName identifier, PSymbolTable *&symt); PSymbol *FindInClass(FName identifier, PSymbolTable *&symt);
@ -383,10 +384,11 @@ public:
class FxIntCast : public FxExpression class FxIntCast : public FxExpression
{ {
FxExpression *basex; FxExpression *basex;
bool NoWarn;
public: public:
FxIntCast(FxExpression *x); FxIntCast(FxExpression *x, bool nowarn);
~FxIntCast(); ~FxIntCast();
FxExpression *Resolve(FCompileContext&); FxExpression *Resolve(FCompileContext&);
@ -759,7 +761,7 @@ protected:
public: public:
FxRandom(FRandom *, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos); FxRandom(FRandom *, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos, bool nowarn);
~FxRandom(); ~FxRandom();
FxExpression *Resolve(FCompileContext&); FxExpression *Resolve(FCompileContext&);
PPrototype *ReturnProto(); PPrototype *ReturnProto();
@ -780,7 +782,7 @@ protected:
public: public:
FxRandomPick(FRandom *, TArray<FxExpression*> &expr, bool floaty, const FScriptPosition &pos); FxRandomPick(FRandom *, TArray<FxExpression*> &expr, bool floaty, const FScriptPosition &pos, bool nowarn);
~FxRandomPick(); ~FxRandomPick();
FxExpression *Resolve(FCompileContext&); FxExpression *Resolve(FCompileContext&);
@ -814,7 +816,7 @@ class FxRandom2 : public FxExpression
public: public:
FxRandom2(FRandom *, FxExpression *m, const FScriptPosition &pos); FxRandom2(FRandom *, FxExpression *m, const FScriptPosition &pos, bool nowarn);
~FxRandom2(); ~FxRandom2();
FxExpression *Resolve(FCompileContext&); FxExpression *Resolve(FCompileContext&);
PPrototype *ReturnProto(); PPrototype *ReturnProto();

View file

@ -448,7 +448,7 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls)
sc.MustGetToken('('); sc.MustGetToken('(');
FxExpression *exp = ParseExpressionM(sc, cls); FxExpression *exp = ParseExpressionM(sc, cls);
sc.MustGetToken(')'); sc.MustGetToken(')');
return new FxIntCast(exp); return new FxIntCast(exp, true);
} }
else if (sc.CheckToken(TK_Float)) else if (sc.CheckToken(TK_Float))
{ {
@ -600,7 +600,7 @@ static FxExpression *ParseRandom(FScanner &sc, FName identifier, PClassActor *cl
if (identifier == NAME_Random) if (identifier == NAME_Random)
{ {
return new FxRandom(rng, min, max, sc); return new FxRandom(rng, min, max, sc, true);
} }
else else
{ {
@ -627,7 +627,7 @@ static FxExpression *ParseRandomPick(FScanner &sc, FName identifier, PClassActor
break; break;
sc.MustGetToken(','); sc.MustGetToken(',');
} }
return new FxRandomPick(rng, list, floaty, sc); return new FxRandomPick(rng, list, floaty, sc, true);
} }
static FxExpression *ParseRandom2(FScanner &sc, PClassActor *cls) static FxExpression *ParseRandom2(FScanner &sc, PClassActor *cls)
@ -642,7 +642,7 @@ static FxExpression *ParseRandom2(FScanner &sc, PClassActor *cls)
mask = ParseExpressionM(sc, cls); mask = ParseExpressionM(sc, cls);
sc.MustGetToken(')'); sc.MustGetToken(')');
} }
return new FxRandom2(rng, mask, sc); return new FxRandom2(rng, mask, sc, true);
} }
static FxExpression *ParseAbs(FScanner &sc, PClassActor *cls) static FxExpression *ParseAbs(FScanner &sc, PClassActor *cls)

View file

@ -131,7 +131,7 @@ FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type, bool c
} }
else if (type == TypeSInt32) else if (type == TypeSInt32)
{ {
x = new FxIntCast(x); x = new FxIntCast(x, true);
} }
else else
{ {
@ -871,7 +871,7 @@ static bool ParsePropertyParams(FScanner &sc, FPropertyInfo *prop, AActor *defau
{ {
conv.i = -1; conv.i = -1;
params.Push(conv); params.Push(conv);
x = new FxDamageValue(new FxIntCast(ParseExpression(sc, bag.Info))); x = new FxDamageValue(new FxIntCast(ParseExpression(sc, bag.Info), true));
sc.MustGetStringName(")"); sc.MustGetStringName(")");
conv.exp = x; conv.exp = x;
params.Push(conv); params.Push(conv);

View file

@ -84,7 +84,7 @@ FxVMFunctionCall *DoActionSpecials(FScanner &sc, FState & state, Baggage &bag)
{ {
while (i < 5) while (i < 5)
{ {
args->Push(new FxIntCast(ParseExpression(sc, bag.Info))); args->Push(new FxIntCast(ParseExpression(sc, bag.Info), true));
i++; i++;
if (!sc.CheckToken (',')) break; if (!sc.CheckToken (',')) break;
} }

View file

@ -658,7 +658,7 @@ DEFINE_PROPERTY(damage, X, Actor)
else else
{ {
auto funcsym = CreateAnonymousFunction(bag.Info, TypeSInt32, VARF_Method); auto funcsym = CreateAnonymousFunction(bag.Info, TypeSInt32, VARF_Method);
defaults->DamageFunc = FunctionBuildList.AddFunction(funcsym, id, FStringf("%s.DamageFunction", bag.Info->TypeName.GetChars()), false); defaults->DamageFunc = FunctionBuildList.AddFunction(funcsym, id, FStringf("%s.DamageFunction", bag.Info->TypeName.GetChars()), !bag.fromZScript);
} }
} }

View file

@ -649,7 +649,7 @@ void VMFunctionBuilder::BackpatchToHere(size_t loc)
//========================================================================== //==========================================================================
FFunctionBuildList FunctionBuildList; FFunctionBuildList FunctionBuildList;
VMFunction *FFunctionBuildList::AddFunction(PFunction *functype, FxExpression *code, const FString &name, bool statecall) VMFunction *FFunctionBuildList::AddFunction(PFunction *functype, FxExpression *code, const FString &name, bool fromdecorate)
{ {
auto func = code->GetDirectFunction(); auto func = code->GetDirectFunction();
if (func != nullptr) if (func != nullptr)
@ -666,7 +666,7 @@ VMFunction *FFunctionBuildList::AddFunction(PFunction *functype, FxExpression *c
it.DumpName = name; it.DumpName = name;
it.Function = new VMScriptFunction; it.Function = new VMScriptFunction;
it.Proto = nullptr; it.Proto = nullptr;
it.type = statecall; it.FromDecorate = fromdecorate;
mItems.Push(it); mItems.Push(it);
return it.Function; return it.Function;
} }
@ -687,7 +687,7 @@ void FFunctionBuildList::Build()
// This needs to be fixed, so that the compile context receives the entire function symbol, including the containing class, the prototype and argument names, which will be needed to run the code generator // This needs to be fixed, so that the compile context receives the entire function symbol, including the containing class, the prototype and argument names, which will be needed to run the code generator
// As a first step this just needs to get working so fetch the class type from the prototype's argument list. // As a first step this just needs to get working so fetch the class type from the prototype's argument list.
// We don't know the return type in advance for anonymous functions. // We don't know the return type in advance for anonymous functions.
FCompileContext ctx(item.Func, nullptr); FCompileContext ctx(item.Func, nullptr, item.FromDecorate);
item.Code = item.Code->Resolve(ctx); item.Code = item.Code->Resolve(ctx);
item.Proto = ctx.ReturnProto; item.Proto = ctx.ReturnProto;

View file

@ -106,13 +106,13 @@ class FFunctionBuildList
PPrototype *Proto = nullptr; PPrototype *Proto = nullptr;
VMScriptFunction *Function = nullptr; VMScriptFunction *Function = nullptr;
FString DumpName; FString DumpName;
int type; // temporary kludge bool FromDecorate;
}; };
TArray<Item> mItems; TArray<Item> mItems;
public: public:
VMFunction *AddFunction(PFunction *func, FxExpression *code, const FString &name, bool statecall = false); VMFunction *AddFunction(PFunction *func, FxExpression *code, const FString &name, bool fromdecorate);
void Build(); void Build();
}; };

View file

@ -2172,7 +2172,7 @@ void ZCCCompiler::CompileStates()
if (code != nullptr) if (code != nullptr)
{ {
auto funcsym = CreateAnonymousFunction(c->Type(), nullptr, VARF_Method | VARF_Action); auto funcsym = CreateAnonymousFunction(c->Type(), nullptr, VARF_Method | VARF_Action);
state.ActionFunc = FunctionBuildList.AddFunction(funcsym, code, FStringf("%s.StateFunction.%d", c->Type()->TypeName.GetChars(), statedef.GetStateCount()), true); state.ActionFunc = FunctionBuildList.AddFunction(funcsym, code, FStringf("%s.StateFunction.%d", c->Type()->TypeName.GetChars(), statedef.GetStateCount()), false);
} }
} }