From b299b64e47736227a098aa42bd5c5292c165dfd3 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 15 Oct 2016 21:35:31 +0200 Subject: [PATCH] - 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. --- src/scripting/codegeneration/codegen.cpp | 49 ++++++++++++++-------- src/scripting/codegeneration/codegen.h | 12 +++--- src/scripting/decorate/thingdef_exp.cpp | 8 ++-- src/scripting/decorate/thingdef_parse.cpp | 4 +- src/scripting/decorate/thingdef_states.cpp | 2 +- src/scripting/thingdef_properties.cpp | 2 +- src/scripting/vm/vmbuilder.cpp | 6 +-- src/scripting/vm/vmbuilder.h | 4 +- src/scripting/zscript/zcc_compile.cpp | 2 +- 9 files changed, 52 insertions(+), 37 deletions(-) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 9cdd9c1f2..c66c96f32 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -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(basex)->GetValue().GetName().GetChars()); FxExpression * x = new FxConstant(0, ScriptPosition); @@ -549,9 +551,19 @@ FxExpression *FxIntCast::Resolve(FCompileContext &ctx) { ExpVal constval = static_cast(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(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 &expr, bool floaty, const FScriptPosition &pos) +FxRandomPick::FxRandomPick(FRandom *r, TArray &expr, bool floaty, const FScriptPosition &pos, bool nowarn) : FxExpression(pos) { assert(expr.Size() > 0); @@ -2856,7 +2869,7 @@ FxRandomPick::FxRandomPick(FRandom *r, TArray &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); } diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index 7f00020c1..9ee8704cc 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -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 &expr, bool floaty, const FScriptPosition &pos); + FxRandomPick(FRandom *, TArray &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(); diff --git a/src/scripting/decorate/thingdef_exp.cpp b/src/scripting/decorate/thingdef_exp.cpp index 8b12e1c1e..c10ef9ad8 100644 --- a/src/scripting/decorate/thingdef_exp.cpp +++ b/src/scripting/decorate/thingdef_exp.cpp @@ -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) diff --git a/src/scripting/decorate/thingdef_parse.cpp b/src/scripting/decorate/thingdef_parse.cpp index b2f1cac07..534c74d18 100644 --- a/src/scripting/decorate/thingdef_parse.cpp +++ b/src/scripting/decorate/thingdef_parse.cpp @@ -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); diff --git a/src/scripting/decorate/thingdef_states.cpp b/src/scripting/decorate/thingdef_states.cpp index d5a3395d7..59ec3e39d 100644 --- a/src/scripting/decorate/thingdef_states.cpp +++ b/src/scripting/decorate/thingdef_states.cpp @@ -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; } diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 34f424ab4..8fc660913 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -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); } } diff --git a/src/scripting/vm/vmbuilder.cpp b/src/scripting/vm/vmbuilder.cpp index 7c5118467..7e946a17c 100644 --- a/src/scripting/vm/vmbuilder.cpp +++ b/src/scripting/vm/vmbuilder.cpp @@ -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; diff --git a/src/scripting/vm/vmbuilder.h b/src/scripting/vm/vmbuilder.h index 6b9a0aa68..c5ca868e0 100644 --- a/src/scripting/vm/vmbuilder.h +++ b/src/scripting/vm/vmbuilder.h @@ -106,13 +106,13 @@ class FFunctionBuildList PPrototype *Proto = nullptr; VMScriptFunction *Function = nullptr; FString DumpName; - int type; // temporary kludge + bool FromDecorate; }; TArray 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(); }; diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 1561bc096..cbf6b08c1 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -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); } }