From dc7d449c842de5626299e7986e8f229121ae73f6 Mon Sep 17 00:00:00 2001 From: Markus Mittendrein Date: Sun, 26 Nov 2023 11:11:29 +0100 Subject: [PATCH] C4AulExec: Avoid incorrect line numbers in stack traces with utility function C4AulExec::ThrowExecError --- src/C4AulExec.cpp | 51 ++++++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/src/C4AulExec.cpp b/src/C4AulExec.cpp index 64443a47..8aa83786 100644 --- a/src/C4AulExec.cpp +++ b/src/C4AulExec.cpp @@ -309,6 +309,8 @@ class C4AulExec } C4AulBCC *Call(C4AulFunc *pFunc, C4Value *pReturn, C4Value *pPars, C4Object *pObj = nullptr, C4Def *pDef = nullptr, bool globalContext = false); + + [[noreturn]] void ThrowExecError(C4AulBCC *cPos, std::string_view message) const; }; C4AulExec AulExec; @@ -382,10 +384,10 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors) break; case AB_EOFN: - throw C4AulExecError(pCurCtx->Obj, "function didn't return"); + ThrowExecError(pCPos, "function didn't return"); case AB_ERR: - throw C4AulExecError(pCurCtx->Obj, "syntax error: see previous parser error for details."); + ThrowExecError(pCPos, "syntax error: see previous parser error for details."); case AB_PARN_R: PushValueRef(pCurCtx->Pars[pCPos->bccX]); @@ -403,13 +405,14 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors) case AB_LOCALN_R: case AB_LOCALN_V: if (!pCurCtx->Obj) - throw C4AulExecError(pCurCtx->Obj, "can't access local variables in a definition call!"); + ThrowExecError(pCPos, "can't access local variables in a definition call!"); + if (pCurCtx->Func->Owner->Def != pCurCtx->Obj->Def) { const auto localName = pCurCtx->Func->Owner->Def->Script.LocalNamed.pNames[pCPos->bccX]; if (pCurCtx->Func->pOrgScript->Strict >= C4AulScriptStrict::STRICT3 || pCurCtx->Obj->LocalNamed.pNames->iSize <= pCPos->bccX) { - throw C4AulExecError(pCurCtx->Obj, std::format("can't access local variable \"{}\" after ChangeDef!", localName)); + ThrowExecError(pCPos, std::format("can't access local variable \"{}\" after ChangeDef!", localName)); } const auto actualLocalName = pCurCtx->Obj->Def->Script.LocalNamed.pNames[pCPos->bccX]; @@ -626,12 +629,12 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors) auto par1String = pPar1->toString(); if (!par1String) { - throw C4AulExecError(pCurCtx->Obj, std::format("operator \"{}\" left side: can not convert \"{}\" to \"string\", \"array\" or \"map\"!", operatorName, GetC4VName(pPar1->GetType()))); + ThrowExecError(pCPos, std::format("operator \"{}\" left side: can not convert \"{}\" to \"string\", \"array\" or \"map\"!", operatorName, GetC4VName(pPar1->GetType()))); } auto par2String = pPar2->toString(); if (!par2String) { - throw C4AulExecError(pCurCtx->Obj, std::format("operator \"{}\" right side: can not convert \"{}\" to \"string\"!", operatorName, GetC4VName(pPar2->GetType()))); + ThrowExecError(pCPos, std::format("operator \"{}\" right side: can not convert \"{}\" to \"string\"!", operatorName, GetC4VName(pPar2->GetType()))); } par1String->Append(*par2String); @@ -895,7 +898,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors) C4Value &Index = pCurVal[0]; if (Container.GetType() == C4V_Any) { - throw C4AulExecError(pCurCtx->Obj, "indexed access [index]: array, map or string expected, but got nil"); + ThrowExecError(pCPos, "indexed access [index]: array, map or string expected, but got nil"); } if (Container.ConvertTo(C4V_Map) || Container.ConvertTo(C4V_Array) || Container.ConvertTo(C4V_C4Object)) @@ -909,7 +912,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors) if (Container.ConvertTo(C4V_String)) { if (!Index.ConvertTo(C4V_Int)) - throw C4AulExecError(pCurCtx->Obj, std::format("indexed string access: index of type {}, int expected!", Index.GetTypeName())); + ThrowExecError(pCPos, std::format("indexed string access: index of type {}, int expected!", Index.GetTypeName())); auto index = Index._getInt(); StdStrBuf &str = Container._getStr()->Data; @@ -932,7 +935,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors) break; } else - throw C4AulExecError(pCurCtx->Obj, std::format("indexed access: can't access {} by index!", Container.GetTypeName())); + ThrowExecError(pCPos, std::format("indexed access: can't access {} by index!", Container.GetTypeName())); } case AB_MAPA_R: case AB_MAPA_V: @@ -940,12 +943,12 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors) C4Value &Map = pCurVal->GetRefVal(); if (Map.GetType() == C4V_Any) { - throw C4AulExecError(pCurCtx->Obj, "map access with .: map expected, but got nil!"); + ThrowExecError(pCPos, "map access with .: map expected, but got nil!"); } if (!Map.ConvertTo(C4V_Map) && !Map.ConvertTo(C4V_C4Object)) { - throw C4AulExecError(pCurCtx->Obj, std::format("map access with .: map expected, but got \"{}\"!", GetC4VName(Map.GetType()))); + ThrowExecError(pCPos, std::format("map access with .: map expected, but got \"{}\"!", GetC4VName(Map.GetType()))); } C4Value key(reinterpret_cast(pCPos->bccX)); @@ -959,7 +962,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors) C4Value &Array = pCurVal[0].GetRefVal(); // Typcheck if (!Array.ConvertTo(C4V_Array) || Array.GetType() != C4V_Array) - throw C4AulExecError(pCurCtx->Obj, std::format("array append accesss: can't access {} as an array!", Array.GetType() == C4V_Any ? "nil" : Array.GetTypeName())); + ThrowExecError(pCPos, std::format("array append accesss: can't access {} as an array!", Array.GetType() == C4V_Any ? "nil" : Array.GetTypeName())); C4Value index = C4VInt(Array._getArray()->GetSize()); Array.GetContainerElement(&index, pCurVal[0], pCurCtx); @@ -1085,7 +1088,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors) if (C4AulScriptFunc *sfunc = pFunc->SFunc(); sfunc && sfunc->Access < sfunc->pOrgScript->GetAllowedAccess(pFunc, pCurCtx->Func->pOrgScript)) { - throw C4AulExecError(pCurCtx->Obj, std::format("Insufficient access level for function \"{}\"!", pFunc->Name)); + ThrowExecError(pCPos, std::format("Insufficient access level for function \"{}\"!", pFunc->Name)); } C4Value *pPars = pCurVal - pFunc->GetParCount() + 1; // Save current position @@ -1102,7 +1105,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors) case AB_VAR_R: case AB_VAR_V: if (!pCurVal->ConvertTo(C4V_Int)) - throw C4AulExecError(pCurCtx->Obj, std::format("Var: index of type {}, int expected!", pCurVal->GetTypeName())); + ThrowExecError(pCPos, std::format("Var: index of type {}, int expected!", pCurVal->GetTypeName())); // Push reference to variable on the stack if (pCPos->bccType == AB_VAR_R) pCurVal->SetRef(&pCurCtx->NumVars.GetItem(pCurVal->_getInt())); @@ -1112,7 +1115,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors) case AB_PAR_R: case AB_PAR_V: if (!pCurVal->ConvertTo(C4V_Int)) - throw C4AulExecError(pCurCtx->Obj, std::format("Par: index of type {}, int expected!", pCurVal->GetTypeName())); + ThrowExecError(pCPos, std::format("Par: index of type {}, int expected!", pCurVal->GetTypeName())); // Push reference to parameter on the stack if (pCurVal->_getInt() >= 0 && pCurVal->_getInt() < static_cast(pCurCtx->ParCnt())) { @@ -1134,9 +1137,9 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors) if (!iItem) { if (!pCurVal[-1].ConvertTo(C4V_Array)) - throw C4AulExecError(pCurCtx->Obj, std::format("for: array expected, but got {}!", pCurVal[-1].GetTypeName())); + ThrowExecError(pCPos, std::format("for: array expected, but got {}!", pCurVal[-1].GetTypeName())); if (!pCurVal[-1]._getArray()) - throw C4AulExecError(pCurCtx->Obj, std::format("for: array expected, but got nil!")); + ThrowExecError(pCPos, "for: array expected, but got nil!"); } C4ValueArray *pArray = pCurVal[-1]._getArray(); // No more entries? @@ -1162,9 +1165,9 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors) if (!iterator) { if (!pCurVal[-2].ConvertTo(C4V_Map)) - throw C4AulExecError(pCurCtx->Obj, std::format("for: map expected, but got {}!", pCurVal[-1].GetTypeName())); + ThrowExecError(pCPos, std::format("for: map expected, but got {}!", pCurVal[-1].GetTypeName())); if (!pCurVal[-2]._getMap()) - throw C4AulExecError(pCurCtx->Obj, std::format("for: map expected, but got nil!")); + ThrowExecError(pCPos, "for: map expected, but got nil!"); } C4ValueHash *map = pCurVal[-2]._getMap(); if (!iterator) @@ -1209,7 +1212,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors) // Check for call to null if (!isGlobal && !*pTargetVal) - throw C4AulExecError(pCurCtx->Obj, "Object call: target is zero!"); + ThrowExecError(pCPos, "Object call: target is zero!"); // Get call target - "object" or "id" are allowed C4Object *pDestObj{}; C4Def *pDestDef{}; @@ -1269,7 +1272,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors) C4AulScript *script = sfunc->pOrgScript; if (sfunc->Access < script->GetAllowedAccess(pFunc, sfunc->pOrgScript)) { - throw C4AulExecError(pCurCtx->Obj, std::format("Insufficient access level for function \"{}\"!", pFunc->Name)); + ThrowExecError(pCPos, std::format("Insufficient access level for function \"{}\"!", pFunc->Name)); } } @@ -1509,6 +1512,12 @@ C4AulBCC *C4AulExec::Call(C4AulFunc *pFunc, C4Value *pReturn, C4Value *pPars, C4 } } +[[noreturn]] void C4AulExec::ThrowExecError(C4AulBCC *const cPos, const std::string_view message) const +{ + pCurCtx->CPos = cPos; + throw C4AulExecError{pCurCtx->Obj, message}; +} + void C4AulStartTrace() { AulExec.StartTrace();