Skip to content

Commit

Permalink
C4AulExec: Avoid incorrect line numbers in stack traces with utility …
Browse files Browse the repository at this point in the history
…function C4AulExec::ThrowExecError
  • Loading branch information
maxmitti committed Sep 8, 2024
1 parent aecd465 commit dc7d449
Showing 1 changed file with 30 additions and 21 deletions.
51 changes: 30 additions & 21 deletions src/C4AulExec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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]);
Expand All @@ -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];
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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))
Expand All @@ -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;
Expand All @@ -932,20 +935,20 @@ 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:
{
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<C4String *>(pCPos->bccX));
Expand All @@ -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);
Expand Down Expand Up @@ -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
Expand All @@ -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()));
Expand All @@ -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<int>(pCurCtx->ParCnt()))
{
Expand All @@ -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?
Expand All @@ -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)
Expand Down Expand Up @@ -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{};
Expand Down Expand Up @@ -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));
}
}

Expand Down Expand Up @@ -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();
Expand Down

0 comments on commit dc7d449

Please sign in to comment.