/**************************************************************************** ** ** This file is part of GAP, a system for computational discrete algebra. ** ** Copyright of GAP belongs to its developers, whose names are too numerous ** to list here. Please refer to the COPYRIGHT file for details. ** ** SPDX-License-Identifier: GPL-2.0-or-later ** ** This file implements functions for raising user errors and interacting ** with the break loop. **
*/
/**************************************************************************** ** *F OpenErrorOutput() . . . . . . . open the file or stream assigned to the ** ERROR_OUTPUT global variable defined in ** error.g, or "*errout*" otherwise
*/
UInt OpenErrorOutput(TypOutputFile * output)
{ // Try to print the output to stream. Use *errout* as a fallback.
UInt ret = 0;
if (ERROR_OUTPUT != NULL) { if (IsStringConv(ERROR_OUTPUT)) {
ret = OpenOutput(output, CONST_CSTR_STRING(ERROR_OUTPUT), FALSE);
} else { if (CALL_1ARGS(IsOutputStream, ERROR_OUTPUT) == True) {
ret = OpenOutputStream(output, ERROR_OUTPUT);
}
}
}
if (!ret) { // It may be we already tried and failed to open *errout* above but // but this is an extreme case so it can't hurt to try again // anyways
ret = OpenOutput(output, "*errout*", FALSE); if (ret) {
Pr("failed to open error stream\n", 0, 0);
} else {
Panic("failed to open *errout*");
}
}
Obj func = FUNC_LVARS(context);
GAP_ASSERT(func);
Stat call = STAT_LVARS(context); if (IsKernelFunction(func)) { return Fail;
}
Obj body = BODY_FUNC(func); if (call < OFFSET_FIRST_STAT ||
call > SIZE_BAG(body) - sizeof(StatHeader)) { return Fail;
}
Obj filename = GET_FILENAME_BODY(body); if (!filename) { return Fail;
}
Obj currLVars = SWITCH_TO_OLD_LVARS(context);
Obj retlist = Fail; Int type = TNUM_STAT(call); if ((FIRST_STAT_TNUM <= type && type <= LAST_STAT_TNUM) ||
(FIRST_EXPR_TNUM <= type && type <= LAST_EXPR_TNUM)) { Int line = LINE_STAT(call);
retlist = NewPlistFromArgs(filename, INTOBJ_INT(line));
}
SWITCH_TO_OLD_LVARS(currLVars); return retlist;
}
// HACK: we want to redirect output // Try to print the output to stream. Use *errout* as a fallback.
TypOutputFile output = { 0 }; if ((IsStringConv(stream) &&
!OpenOutput(&output, CONST_CSTR_STRING(stream), FALSE)) ||
(!IS_STRING(stream) && !OpenOutputStream(&output, stream))) { if (OpenOutput(&output, "*errout*", FALSE)) {
Pr("PRINT_CURRENT_STATEMENT: failed to open error stream\n", 0, 0);
} else {
Panic("failed to open *errout*");
}
}
Int type = TNUM_STAT(call); if (FIRST_STAT_TNUM <= type && type <= LAST_STAT_TNUM) {
PrintStat(call);
Pr(" at %g:%d", (Int)filename, LINE_STAT(call));
} elseif (FIRST_EXPR_TNUM <= type && type <= LAST_EXPR_TNUM) {
PrintExpr(call);
Pr(" at %g:%d", (Int)filename, LINE_STAT(call));
}
SWITCH_TO_OLD_LVARS(currLVars);
}
}
GAP_CATCH
{
rethrow = TRUE;
}
// HACK: close the output again
CloseOutput(&output);
RequireFunction("CALL_WITH_CATCH", func); if (!IS_LIST(args))
RequireArgument("CALL_WITH_CATCH", args, "must be a list"); #ifdef HPCGAP if (!IS_PLIST(args)) {
args = PLAIN_LIST_COPY(args);
} #endif
currLVars = STATE(CurrLVars);
tilde = STATE(Tilde);
res = NEW_PLIST_IMM(T_PLIST_DENSE, 2); #ifdef HPCGAP int lockSP = RegionLockSP();
Region * savedRegion = TLS(currentRegion); #endif
GAP_TRY
{
Obj result = CallFuncList(func, args); // Make an explicit check if an interrupt occurred // in case func was a kernel function.
TakeInterrupt(); #ifdef HPCGAP // There should be no locks to pop off the stack, but better safe than // sorry.
PopRegionLocks(lockSP);
TLS(currentRegion) = savedRegion; #endif
SET_ELM_PLIST(res, 1, True); if (result) {
SET_LEN_PLIST(res, 2);
SET_ELM_PLIST(res, 2, result);
CHANGED_BAG(res);
} else
SET_LEN_PLIST(res, 1);
}
GAP_CATCH
{
SET_LEN_PLIST(res, 2);
SET_ELM_PLIST(res, 1, False);
SET_ELM_PLIST(res, 2, STATE(ThrownObject));
CHANGED_BAG(res);
STATE(ThrownObject) = 0;
SWITCH_TO_OLD_LVARS(currLVars);
STATE(Tilde) = tilde; #ifdef HPCGAP
PopRegionLocks(lockSP);
TLS(currentRegion) = savedRegion; if (TLS(CurrentHashLock))
HashUnlock(TLS(CurrentHashLock)); #endif
} return res;
}
Int RegisterBreakloopObserver(intfunc func)
{ Int i; for (i = 0; i < ARRAY_SIZE(signalBreakFuncList); ++i) { if (signalBreakFuncList[i] == 0) {
signalBreakFuncList[i] = func; return 1;
}
} return 0;
}
static Obj CallErrorInner(constChar * msg, Int arg1, Int arg2,
UInt justQuit,
UInt mayReturnVoid,
UInt mayReturnObj,
Obj lateMessage,
UInt printThisStatement)
{ // Must do this before creating any other GAP objects, // as one of the args could be a pointer into a Bag.
Obj EarlyMsg = ErrorMessageToGAPString(msg, arg1, arg2);
if (!ErrorInner || !IS_FUNC(ErrorInner)) {
fprintf(stderr, "%s\n", CONST_CSTR_STRING(EarlyMsg)); if (!ErrorInner)
Panic("error handler not yet initialized"); else
Panic("error handler must be a function");
}
// Signal functions about entering and leaving break loop for (i = 0; i < ARRAY_SIZE(signalBreakFuncList) && signalBreakFuncList[i];
++i)
(signalBreakFuncList[i])(1);
Obj res = CALL_2ARGS(ErrorInner, r, l); for (i = 0; i < ARRAY_SIZE(signalBreakFuncList) && signalBreakFuncList[i];
++i)
(signalBreakFuncList[i])(0); #ifdef HPCGAP
TLS(currentRegion) = savedRegion; #endif return res;
}
void ErrorQuit(constChar * msg, Int arg1, Int arg2)
{
CallErrorInner(msg, arg1, arg2, 1, 0, 0, False, 1);
Panic("ErrorQuit must not return");
}
/**************************************************************************** ** *F ErrorMayQuitNrArgs( <narg>, <actual> ) . . . . wrong number of arguments
*/ void ErrorMayQuitNrArgs(Int narg, Int actual)
{
ErrorMayQuit("Function: number of arguments must be %d (not %d)",
narg, actual);
}
/**************************************************************************** ** *F ErrorMayQuitNrAtLeastArgs( <narg>, <actual> ) . . . not enough arguments
*/ void ErrorMayQuitNrAtLeastArgs(Int narg, Int actual)
{
ErrorMayQuit( "Function: number of arguments must be at least %d (not %d)",
narg, actual);
}
if (funcname) {
gap_strlcat(msgbuf, funcname, sizeof(msgbuf));
gap_strlcat(msgbuf, ": ", sizeof(msgbuf));
} if (argname) {
gap_strlcat(msgbuf, argname, sizeof(msgbuf));
gap_strlcat(msgbuf, " ", sizeof(msgbuf));
}
gap_strlcat(msgbuf, msg, sizeof(msgbuf)); if (IS_INTOBJ(op)) {
gap_strlcat(msgbuf, " (not the integer %d)", sizeof(msgbuf));
arg1 = INT_INTOBJ(op);
} elseif (op == True)
gap_strlcat(msgbuf, " (not the value 'true')", sizeof(msgbuf)); elseif (op == False)
gap_strlcat(msgbuf, " (not the value 'false')", sizeof(msgbuf)); elseif (op == Fail)
gap_strlcat(msgbuf, " (not the value 'fail')", sizeof(msgbuf)); else { constchar * tnam = TNAM_OBJ(op); // heuristic to choose between 'a' and 'an': use 'an' before a vowel // and 'a' otherwise; however, that's not always correct, e.g. it is // "an FFE", so we add a special case for that as well if (TNUM_OBJ(op) == T_FFE || tnam[0] == 'a' || tnam[0] == 'e' ||
tnam[0] == 'i' || tnam[0] == 'o' || tnam[0] == 'u')
gap_strlcat(msgbuf, " (not an %s)", sizeof(msgbuf)); else
gap_strlcat(msgbuf, " (not a %s)", sizeof(msgbuf));
arg1 = (Int)tnam;
}
void ErrorBoundedInt( constchar * funcname, Obj op, constchar * argname, int min, int max)
{ #define BOUNDED_INT_FORMAT "must be an integer between %d and %d" // The maximal number of decimal digits in a signed 64 bit value is 20, so // reserve space for that (actually, we would need a bit less because the // `%d` in the format string of course also adds to the length, but a // few bytes more or less don't matter). // Also note that in practice, `int` will be a 32 bit type anyway... char msg[sizeof(BOUNDED_INT_FORMAT) + 2 * 20];
snprintf(msg, sizeof(msg), BOUNDED_INT_FORMAT, min, max);
RequireArgumentEx(funcname, op, argname, msg); #undef BOUNDED_INT_FORMAT
}
void AssertionFailureWithMessage(Obj message)
{ if (message == 0) { // this case is triggered by code like this: Assert(0, false, Error("boo")); // at least if the user enters `return;` into the break loop opened by this.
AssertionFailure();
} elseif (IS_STRING_REP(message)) {
ErrorReturnVoid("Assertion failure: %g", (Int)message, 0, "you may 'return;'");
} else {
PrintObj(message);
Pr("\n", 0, 0);
AssertionFailure();
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.