diff --git a/src/sc_man.cpp b/src/sc_man.cpp index ccfb01ac5..b05349d00 100644 --- a/src/sc_man.cpp +++ b/src/sc_man.cpp @@ -1054,6 +1054,8 @@ void FScriptPosition::Message (int severity, const char *message, ...) const { severity = StrictErrors || strictdecorate ? MSG_ERROR : MSG_WARNING; } + // This is mainly for catching the error with an exception handler. + if (severity == MSG_ERROR && errorout) severity = MSG_FATAL; if (message == NULL) { diff --git a/src/sc_man.h b/src/sc_man.h index 362d57faf..ded92b398 100644 --- a/src/sc_man.h +++ b/src/sc_man.h @@ -146,6 +146,7 @@ struct FScriptPosition static bool StrictErrors; FString FileName; int ScriptLine; + bool errorout = false; FScriptPosition() { diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 2c96a2144..e5a0470b0 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -5653,6 +5653,12 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) if (Identifier == NAME_Default) { + if (ctx.Function == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Unable to access class defaults from constant declaration"); + delete this; + return nullptr; + } if (ctx.Function->Variants[0].SelfClass == nullptr) { ScriptPosition.Message(MSG_ERROR, "Unable to access class defaults from static function"); @@ -5680,6 +5686,13 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) { if (sym->IsKindOf(RUNTIME_CLASS(PField))) { + if (ctx.Function == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Unable to access class member %s from constant declaration", sym->SymbolName.GetChars()); + delete this; + return nullptr; + } + FxExpression *self = new FxSelf(ScriptPosition); self = self->Resolve(ctx); newex = ResolveMember(ctx, ctx.Function->Variants[0].SelfClass, self, ctx.Function->Variants[0].SelfClass); @@ -5697,6 +5710,12 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) newex = FxConstant::MakeConstant(sym, ScriptPosition); goto foundit; } + else if (ctx.Function == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Unable to access class member %s from constant declaration", sym->SymbolName.GetChars()); + delete this; + return nullptr; + } // Do this check for ZScript as well, so that a clearer error message can be printed. MSG_OPTERROR will default to MSG_ERROR there. else if (ctx.Function->Variants[0].SelfClass != ctx.Class && sym->IsKindOf(RUNTIME_CLASS(PField))) { @@ -7166,6 +7185,13 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) if (afd != nullptr) { + if (ctx.Function == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Unable to call function %s from constant declaration", MethodName.GetChars()); + delete this; + return nullptr; + } + if (!CheckFunctionCompatiblity(ScriptPosition, ctx.Function, afd)) { delete this; @@ -7202,7 +7228,13 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) if (special != 0 && min >= 0) { int paramcount = ArgList.Size(); - if (paramcount < min) + if (ctx.Function == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Unable to call action special %s from constant declaration", MethodName.GetChars()); + delete this; + return nullptr; + } + else if (paramcount < min) { ScriptPosition.Message(MSG_ERROR, "Not enough parameters for '%s' (expected %d, got %d)", MethodName.GetChars(), min, paramcount); @@ -7467,6 +7499,12 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) staticonly = true; if (ccls->IsKindOf(RUNTIME_CLASS(PClass))) { + if (ctx.Function == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Unable to call %s from constant declaration", MethodName.GetChars()); + delete this; + return nullptr; + } auto clstype = dyn_cast(ctx.Function->Variants[0].SelfClass); if (clstype != nullptr) { @@ -7493,6 +7531,12 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) if (Self->ExprType == EFX_Super) { + if (ctx.Function == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Unable to call %s from constant declaration", MethodName.GetChars()); + delete this; + return nullptr; + } auto clstype = dyn_cast(ctx.Function->Variants[0].SelfClass); if (clstype != nullptr) { @@ -7743,6 +7787,12 @@ isresolved: if (afd->Variants[0].Flags & VARF_Method) { + if (ctx.Function == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Unable to call %s from constant declaration", MethodName.GetChars()); + delete this; + return nullptr; + } if (Self->ExprType == EFX_Self) { if (!CheckFunctionCompatiblity(ScriptPosition, ctx.Function, afd)) diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index e76fcb2dd..365a29abb 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -52,6 +52,42 @@ #include "vmbuilder.h" #include "version.h" +static int GetIntConst(FxExpression *ex, FCompileContext &ctx) +{ + ex = new FxIntCast(ex, false); + ex = ex->Resolve(ctx); + return ex ? static_cast(ex)->GetValue().GetInt() : 0; +} + +static double GetFloatConst(FxExpression *ex, FCompileContext &ctx) +{ + ex = new FxFloatCast(ex); + ex = ex->Resolve(ctx); + return ex ? static_cast(ex)->GetValue().GetFloat() : 0; +} + +static FString GetStringConst(FxExpression *ex, FCompileContext &ctx) +{ + ex = new FxStringCast(ex); + ex = ex->Resolve(ctx); + return static_cast(ex)->GetValue().GetString(); +} + +int ZCCCompiler::IntConstFromNode(ZCC_TreeNode *node, PStruct *cls) +{ + FCompileContext ctx(cls, false); + FxExpression *ex = new FxIntCast(ConvertNode(node), false); + ex = ex->Resolve(ctx); + if (ex == nullptr) return 0; + if (!ex->isConstant()) + { + ex->ScriptPosition.Message(MSG_ERROR, "Expression is not constant"); + return 0; + } + return static_cast(ex)->GetValue().GetInt(); +} + + //========================================================================== // // ZCCCompiler :: ProcessClass @@ -1293,7 +1329,7 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray &Fiel if (field->Type->ArraySize != nullptr) { - fieldtype = ResolveArraySize(fieldtype, field->Type->ArraySize, &type->Symbols); + fieldtype = ResolveArraySize(fieldtype, field->Type->ArraySize, type); } auto name = field->Names; @@ -1304,7 +1340,7 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray &Fiel auto thisfieldtype = fieldtype; if (name->ArraySize != nullptr) { - thisfieldtype = ResolveArraySize(thisfieldtype, name->ArraySize, &type->Symbols); + thisfieldtype = ResolveArraySize(thisfieldtype, name->ArraySize, type); } if (varflags & VARF_Native) @@ -1662,7 +1698,7 @@ PType *ZCCCompiler::ResolveUserType(ZCC_BasicType *type, PSymbolTable *symt) // //========================================================================== -PType *ZCCCompiler::ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PSymbolTable *sym) +PType *ZCCCompiler::ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PStruct *cls) { TArray indices; @@ -1674,15 +1710,21 @@ PType *ZCCCompiler::ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, node = static_cast(node->SiblingNext); } while (node != arraysize); + + FCompileContext ctx(cls, false); for (auto node : indices) { - auto val = Simplify(node, sym, true); - if (val->Operation != PEX_ConstValue || !val->Type->IsA(RUNTIME_CLASS(PInt))) + // There is no float->int casting here. + FxExpression *ex = ConvertNode(node); + ex = ex->Resolve(ctx); + + if (ex == nullptr) return TypeError; + if (!ex->isConstant() || !ex->ValueType->IsA(RUNTIME_CLASS(PInt))) { Error(arraysize, "Array index must be an integer constant"); return TypeError; } - int size = static_cast(val)->IntVal; + int size = static_cast(ex)->GetValue().GetInt(); if (size < 1) { Error(arraysize, "Array size must be positive"); @@ -1765,27 +1807,6 @@ const char *ZCCCompiler::GetString(ZCC_Expression *expr, bool silent) } } -static int GetIntConst(FxExpression *ex, FCompileContext &ctx) -{ - ex = new FxIntCast(ex, false); - ex = ex->Resolve(ctx); - return ex ? static_cast(ex)->GetValue().GetInt() : 0; -} - -static double GetFloatConst(FxExpression *ex, FCompileContext &ctx) -{ - ex = new FxFloatCast(ex); - ex = ex->Resolve(ctx); - return ex ? static_cast(ex)->GetValue().GetFloat() : 0; -} - -static FString GetStringConst(FxExpression *ex, FCompileContext &ctx) -{ - ex = new FxStringCast(ex); - ex = ex->Resolve(ctx); - return static_cast(ex)->GetValue().GetString(); -} - //========================================================================== // // Parses an actor property's parameters and calls the handler @@ -2812,7 +2833,7 @@ void ZCCCompiler::CompileStates() { state.sprite = GetSpriteIndex(sl->Sprite->GetChars()); } - // It is important to call CheckRandom before Simplify, because Simplify will resolve the function's name to nonsense + FCompileContext ctx(c->Type(), false); if (CheckRandom(sl->Duration)) { auto func = static_cast(sl->Duration); @@ -2820,26 +2841,16 @@ void ZCCCompiler::CompileStates() { Error(sl, "Random duration requires exactly 2 parameters"); } - auto p1 = Simplify(func->Parameters->Value, &c->Type()->Symbols, true); - auto p2 = Simplify(static_cast(func->Parameters->SiblingNext)->Value, &c->Type()->Symbols, true); - int v1 = GetInt(p1); - int v2 = GetInt(p2); + int v1 = IntConstFromNode(func->Parameters->Value, c->Type()); + int v2 = IntConstFromNode(static_cast(func->Parameters->SiblingNext)->Value, c->Type()); if (v1 > v2) std::swap(v1, v2); state.Tics = (int16_t)clamp(v1, 0, INT16_MAX); state.TicRange = (uint16_t)clamp(v2 - v1, 0, UINT16_MAX); } else { - auto duration = Simplify(sl->Duration, &c->Type()->Symbols, true); - if (duration->Operation == PEX_ConstValue) - { - state.Tics = (int16_t)clamp(GetInt(duration), -1, INT16_MAX); - state.TicRange = 0; - } - else - { - Error(sl, "Duration is not a constant"); - } + state.Tics = (int16_t)IntConstFromNode(sl->Duration, c->Type()); + state.TicRange = 0; } if (sl->bBright) state.StateFlags |= STF_FULLBRIGHT; if (sl->bFast) state.StateFlags |= STF_FAST; @@ -2855,18 +2866,8 @@ void ZCCCompiler::CompileStates() } if (sl->Offset != nullptr) { - auto o1 = static_cast(Simplify(sl->Offset, &c->Type()->Symbols, true)); - auto o2 = static_cast(Simplify(static_cast(o1->SiblingNext), &c->Type()->Symbols, true)); - - if (o1->Operation != PEX_ConstValue || o2->Operation != PEX_ConstValue) - { - Error(o1, "State offsets must be constant"); - } - else - { - state.Misc1 = GetInt(o1); - state.Misc2 = GetInt(o2); - } + state.Misc1 = IntConstFromNode(sl->Offset, c->Type()); + state.Misc2 = IntConstFromNode(static_cast(sl->Offset->SiblingNext), c->Type()); } #ifdef DYNLIGHT if (sl->Lights != nullptr) @@ -2915,23 +2916,15 @@ void ZCCCompiler::CompileStates() statename.Truncate((long)statename.Len() - 1); // remove the last '.' in the label name if (sg->Offset != nullptr) { - auto ofs = Simplify(sg->Offset, &c->Type()->Symbols, true); - if (ofs->Operation != PEX_ConstValue) + int offset = IntConstFromNode(sg->Offset, c->Type()); + if (offset < 0) { - Error(sg, "Constant offset expected for GOTO"); + Error(sg, "GOTO offset must be positive"); + offset = 0; } - else + if (offset > 0) { - int offset = GetInt(ofs); - if (offset < 0) - { - Error(sg, "GOTO offset must be positive"); - offset = 0; - } - if (offset > 0) - { - statename.AppendFormat("+%d", offset); - } + statename.AppendFormat("+%d", offset); } } if (!statedef.SetGotoLabel(statename)) @@ -3332,7 +3325,7 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast) if (loc->Type->ArraySize != nullptr) { - ztype = ResolveArraySize(ztype, loc->Type->ArraySize, &ConvertClass->Symbols); + ztype = ResolveArraySize(ztype, loc->Type->ArraySize, ConvertClass); } do @@ -3341,7 +3334,7 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast) if (node->ArraySize != nullptr) { - type = ResolveArraySize(ztype, node->ArraySize, &ConvertClass->Symbols); + type = ResolveArraySize(ztype, node->ArraySize, ConvertClass); } else { diff --git a/src/scripting/zscript/zcc_compile.h b/src/scripting/zscript/zcc_compile.h index 8675b1af7..2b9671cdc 100644 --- a/src/scripting/zscript/zcc_compile.h +++ b/src/scripting/zscript/zcc_compile.h @@ -88,6 +88,7 @@ public: int Compile(); private: + int ZCCCompiler::IntConstFromNode(ZCC_TreeNode *node, PStruct *cls); void ProcessClass(ZCC_Class *node, PSymbolTreeNode *tnode); void ProcessStruct(ZCC_Struct *node, PSymbolTreeNode *tnode, ZCC_Class *outer); void CreateStructTypes(); @@ -103,7 +104,7 @@ private: bool CompileProperties(PClass *type, TArray &Properties, FName prefix); FString FlagsToString(uint32_t flags); PType *DetermineType(PType *outertype, ZCC_TreeNode *field, FName name, ZCC_Type *ztype, bool allowarraytypes, bool formember); - PType *ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PSymbolTable *sym); + PType *ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PStruct *cls); PType *ResolveUserType(ZCC_BasicType *type, PSymbolTable *sym); void InitDefaults();