- 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;
}
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)
{
basex=x;
ValueType = TypeSInt32;
NoWarn = nowarn;
}
//==========================================================================
@ -536,6 +537,7 @@ FxExpression *FxIntCast::Resolve(FCompileContext &ctx)
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. :(
// 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");
else ScriptPosition.Message(MSG_OPTERROR, "Numeric type expected, got \"%s\"", static_cast<FxConstant*>(basex)->GetValue().GetName().GetChars());
FxExpression * x = new FxConstant(0, ScriptPosition);
@ -549,9 +551,19 @@ FxExpression *FxIntCast::Resolve(FCompileContext &ctx)
{
ExpVal constval = static_cast<FxConstant *>(basex)->GetValue();
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;
return x;
}
else if (!NoWarn)
{
ScriptPosition.Message(MSG_WARNING, "Truncation of floating point value");
}
return this;
}
ScriptPosition.Message(MSG_ERROR, "Numeric type expected");
@ -634,6 +646,7 @@ FxExpression *FxFloatCast::Resolve(FCompileContext &ctx)
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. :(
// 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");
else ScriptPosition.Message(MSG_OPTERROR, "Numeric type expected, got \"%s\"", static_cast<FxConstant*>(basex)->GetValue().GetName().GetChars());
FxExpression *x = new FxConstant(0.0, ScriptPosition);
@ -837,7 +850,7 @@ FxExpression *FxUnaryNotBitwise::Resolve(FCompileContext& ctx)
if (Operand->ValueType->GetRegType() == REGT_FLOAT /* lax */)
{
// DECORATE allows floats here so cast them to int.
Operand = new FxIntCast(Operand);
Operand = new FxIntCast(Operand, ctx.FromDecorate);
Operand = Operand->Resolve(ctx);
if (Operand == NULL)
{
@ -1165,7 +1178,7 @@ FxExpression *FxAssign::Resolve(FCompileContext &ctx)
}
else if (ValueType->GetRegType() == REGT_INT)
{
Right = new FxIntCast(Right);
Right = new FxIntCast(Right, ctx.FromDecorate);
}
else
{
@ -1840,12 +1853,12 @@ FxExpression *FxBinaryInt::Resolve(FCompileContext& ctx)
// For DECORATE which allows floats here.
if (left->ValueType->GetRegType() != REGT_INT)
{
left = new FxIntCast(left);
left = new FxIntCast(left, ctx.FromDecorate);
left = left->Resolve(ctx);
}
if (right->ValueType->GetRegType() != REGT_INT)
{
right = new FxIntCast(right);
right = new FxIntCast(right, ctx.FromDecorate);
right = right->Resolve(ctx);
}
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)
{
EmitTail = false;
if (mi != NULL && ma != NULL)
{
min = new FxIntCast(mi);
max = new FxIntCast(ma);
min = new FxIntCast(mi, nowarn);
max = new FxIntCast(ma, nowarn);
}
else min = max = NULL;
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)
{
assert(expr.Size() > 0);
@ -2856,7 +2869,7 @@ FxRandomPick::FxRandomPick(FRandom *r, TArray<FxExpression*> &expr, bool floaty,
}
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)
: FxRandom(r, NULL, NULL, pos)
: FxRandom(r, NULL, NULL, pos, true)
{
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)
{
EmitTail = false;
rng = r;
if (m) mask = new FxIntCast(m);
if (m) mask = new FxIntCast(m, nowarn);
else mask = new FxConstant(-1, pos);
ValueType = TypeSInt32;
}
@ -3505,7 +3518,7 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx)
if (index->ValueType->GetRegType() == REGT_FLOAT /* lax */)
{
// DECORATE allows floats here so cast them to int.
index = new FxIntCast(index);
index = new FxIntCast(index, ctx.FromDecorate);
index = index->Resolve(ctx);
if (index == NULL)
{
@ -3792,7 +3805,7 @@ FxExpression *FxActionSpecialCall::Resolve(FCompileContext& ctx)
{
if ((*ArgList)[i]->ValueType->GetRegType() == REGT_FLOAT /* lax */)
{
(*ArgList)[i] = new FxIntCast((*ArgList)[i]);
(*ArgList)[i] = new FxIntCast((*ArgList)[i], ctx.FromDecorate);
}
else
{
@ -5075,7 +5088,7 @@ FxExpression *FxRuntimeStateIndex::Resolve(FCompileContext &ctx)
}
else if (Index->ValueType->GetRegType() != REGT_INT)
{ // Float.
Index = new FxIntCast(Index);
Index = new FxIntCast(Index, ctx.FromDecorate);
SAFE_RESOLVE(Index, ctx);
}

View File

@ -69,8 +69,9 @@ struct FCompileContext
PPrototype *ReturnProto;
PFunction *Function; // The function that is currently being compiled (or nullptr for constant evaluation.)
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!
PSymbol *FindInClass(FName identifier, PSymbolTable *&symt);
@ -383,10 +384,11 @@ public:
class FxIntCast : public FxExpression
{
FxExpression *basex;
bool NoWarn;
public:
FxIntCast(FxExpression *x);
FxIntCast(FxExpression *x, bool nowarn);
~FxIntCast();
FxExpression *Resolve(FCompileContext&);
@ -759,7 +761,7 @@ protected:
public:
FxRandom(FRandom *, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos);
FxRandom(FRandom *, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos, bool nowarn);
~FxRandom();
FxExpression *Resolve(FCompileContext&);
PPrototype *ReturnProto();
@ -780,7 +782,7 @@ protected:
public:
FxRandomPick(FRandom *, TArray<FxExpression*> &expr, bool floaty, const FScriptPosition &pos);
FxRandomPick(FRandom *, TArray<FxExpression*> &expr, bool floaty, const FScriptPosition &pos, bool nowarn);
~FxRandomPick();
FxExpression *Resolve(FCompileContext&);
@ -814,7 +816,7 @@ class FxRandom2 : public FxExpression
public:
FxRandom2(FRandom *, FxExpression *m, const FScriptPosition &pos);
FxRandom2(FRandom *, FxExpression *m, const FScriptPosition &pos, bool nowarn);
~FxRandom2();
FxExpression *Resolve(FCompileContext&);
PPrototype *ReturnProto();

View File

@ -448,7 +448,7 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls)
sc.MustGetToken('(');
FxExpression *exp = ParseExpressionM(sc, cls);
sc.MustGetToken(')');
return new FxIntCast(exp);
return new FxIntCast(exp, true);
}
else if (sc.CheckToken(TK_Float))
{
@ -600,7 +600,7 @@ static FxExpression *ParseRandom(FScanner &sc, FName identifier, PClassActor *cl
if (identifier == NAME_Random)
{
return new FxRandom(rng, min, max, sc);
return new FxRandom(rng, min, max, sc, true);
}
else
{
@ -627,7 +627,7 @@ static FxExpression *ParseRandomPick(FScanner &sc, FName identifier, PClassActor
break;
sc.MustGetToken(',');
}
return new FxRandomPick(rng, list, floaty, sc);
return new FxRandomPick(rng, list, floaty, sc, true);
}
static FxExpression *ParseRandom2(FScanner &sc, PClassActor *cls)
@ -642,7 +642,7 @@ static FxExpression *ParseRandom2(FScanner &sc, PClassActor *cls)
mask = ParseExpressionM(sc, cls);
sc.MustGetToken(')');
}
return new FxRandom2(rng, mask, sc);
return new FxRandom2(rng, mask, sc, true);
}
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)
{
x = new FxIntCast(x);
x = new FxIntCast(x, true);
}
else
{
@ -871,7 +871,7 @@ static bool ParsePropertyParams(FScanner &sc, FPropertyInfo *prop, AActor *defau
{
conv.i = -1;
params.Push(conv);
x = new FxDamageValue(new FxIntCast(ParseExpression(sc, bag.Info)));
x = new FxDamageValue(new FxIntCast(ParseExpression(sc, bag.Info), true));
sc.MustGetStringName(")");
conv.exp = x;
params.Push(conv);

View File

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

View File

@ -658,7 +658,7 @@ DEFINE_PROPERTY(damage, X, Actor)
else
{
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;
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();
if (func != nullptr)
@ -666,7 +666,7 @@ VMFunction *FFunctionBuildList::AddFunction(PFunction *functype, FxExpression *c
it.DumpName = name;
it.Function = new VMScriptFunction;
it.Proto = nullptr;
it.type = statecall;
it.FromDecorate = fromdecorate;
mItems.Push(it);
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
// 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.
FCompileContext ctx(item.Func, nullptr);
FCompileContext ctx(item.Func, nullptr, item.FromDecorate);
item.Code = item.Code->Resolve(ctx);
item.Proto = ctx.ReturnProto;

View File

@ -106,13 +106,13 @@ class FFunctionBuildList
PPrototype *Proto = nullptr;
VMScriptFunction *Function = nullptr;
FString DumpName;
int type; // temporary kludge
bool FromDecorate;
};
TArray<Item> mItems;
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();
};

View File

@ -2172,7 +2172,7 @@ void ZCCCompiler::CompileStates()
if (code != nullptr)
{
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);
}
}