/**************************************************************************** ** ** 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 contains the functions of the statements package. ** ** The statements package is the part of the interpreter that executes ** statements for their effects and prints statements.
*/
// The next macro is used in loop bodies to handle 'break', 'continue' and // 'return' statements. Note that here, during execution, `status` can only // take on the value STATUS_BREAK, STATUS_CONTINUE, STATUS_RETURN, and // STATUS_END; while STATUS_EOF, STATUS_ERROR, STATUS_QUIT, STATUS_QQUIT are // impossible. // // The checks are arranged so that the most frequent cases (i.e. a statement // which is not break/continue/return) is handled first. #define EXEC_STAT_IN_LOOP(stat) \
{ \
ExecStatus status = EXEC_STAT(stat); \ if (status != STATUS_END) { \ if (status == STATUS_CONTINUE) \ continue; \ return (status == STATUS_RETURN) ? STATUS_RETURN : STATUS_END; \
} \
}
/**************************************************************************** ** *V ExecStatFuncs[<type>] . . . . . . executor for statements of type <type> ** ** 'ExecStatFuncs' is the dispatch table that contains for every type of ** statements a pointer to the executor for statements of this type, i.e., ** the function that should be called if a statement of that type is ** executed.
*/
ExecStatFunc ExecStatFuncs[256];
/**************************************************************************** ** *F ExecUnknownStat(<stat>) . . . . . executor for statements of unknown type ** ** 'ExecUnknownStat' is the executor that is called if an attempt is made to ** execute a statement <stat> of an unknown type. It signals an error. If ** this is ever called, then GAP is in serious trouble, such as an ** overwritten type field of a statement.
*/ static ExecStatus ExecUnknownStat(Stat stat)
{
Pr("Panic: tried to execute a statement of unknown type '%d'\n",
(Int)TNUM_STAT(stat), 0); return STATUS_END;
}
/**************************************************************************** ** *F ExecSeqStat(<stat>) . . . . . . . . . . . . execute a statement sequence ** ** 'ExecSeqStat' executes the statement sequence <stat>. ** ** This is done by executing the statements one after another. If a ** leave-statement ('break' or 'return') is executed inside one of the ** statements, then the execution of the statement sequence is terminated ** and the non-zero leave-value is returned (to tell the calling executor ** that a leave-statement was executed). If no leave-statement is executed, ** then 0 is returned. ** ** A statement sequence with <n> statements is a statement of type ** 'STAT_SEQ_STAT' with <n> slots. The first points to the first statement, ** the second points to the second statement, and so on.
*/ static ALWAYS_INLINE ExecStatus ExecSeqStatHelper(Stat stat, UInt nr)
{ // loop over the statements for (UInt i = 1; i <= nr; i++) { // execute the <i>-th statement
ExecStatus status = EXEC_STAT(READ_STAT(stat, i - 1)); if (status != STATUS_END) { return status;
}
}
return STATUS_END;
}
static ExecStatus ExecSeqStat(Stat stat)
{ // get the number of statements
UInt nr = SIZE_STAT( stat ) / sizeof(Stat); return ExecSeqStatHelper(stat, nr);
}
/**************************************************************************** ** *F ExecIf(<stat>) . . . . . . . . . . . . . . . . . execute an if-statement ** ** 'ExecIf' executes the if-statement <stat>. ** ** This is done by evaluating the conditions until one evaluates to 'true', ** and then executing the corresponding body. If a leave-statement ('break' ** or 'return') is executed inside the body, then the execution of the ** if-statement is terminated and the non-zero leave-value is returned (to ** tell the calling executor that a leave-statement was executed). If no ** leave-statement is executed, then 0 is returned. ** ** An if-statement with <n> branches is a statement of type 'STAT_IF' with ** 2*<n> slots. The first slot points to the first condition, the second ** slot points to the first body, the third slot points to the second ** condition, the fourth slot points to the second body, and so on. If the ** if-statement has an else-branch, this is represented by a branch with ** 'EXPR_TRUE' as condition.
*/ static ExecStatus ExecIf(Stat stat)
{
Expr cond; // condition
Stat body; // body
// if the condition evaluates to 'true', execute the if-branch body
cond = READ_STAT(stat, 0); if ( EVAL_BOOL_EXPR( cond ) != False ) {
// execute the if-branch body and leave
body = READ_STAT(stat, 1); return EXEC_STAT( body );
}
return STATUS_END;
}
static ExecStatus ExecIfElse(Stat stat)
{
Expr cond; // condition
Stat body; // body
// if the condition evaluates to 'true', execute the if-branch body
cond = READ_STAT(stat, 0); if ( EVAL_BOOL_EXPR( cond ) != False ) {
// execute the if-branch body and leave
body = READ_STAT(stat, 1); return EXEC_STAT( body );
}
SET_BRK_CALL_TO(stat);
// otherwise execute the else-branch body and leave
body = READ_STAT(stat, 3); return EXEC_STAT( body );
}
static ExecStatus ExecIfElif(Stat stat)
{
Expr cond; // condition
Stat body; // body
UInt nr; // number of branches
UInt i; // loop variable
// get the number of branches
nr = SIZE_STAT( stat ) / (2*sizeof(Stat));
// loop over all branches for ( i = 1; i <= nr; i++ ) {
// if the condition evaluates to 'true', execute the branch body
cond = READ_STAT(stat, 2 * (i - 1)); if ( EVAL_BOOL_EXPR( cond ) != False ) {
// execute the branch body and leave
body = READ_STAT(stat, 2 * (i - 1) + 1); return EXEC_STAT( body );
}
SET_BRK_CALL_TO(stat);
}
return STATUS_END;
}
static ExecStatus ExecIfElifElse(Stat stat)
{
Expr cond; // condition
Stat body; // body
UInt nr; // number of branches
UInt i; // loop variable
// get the number of branches
nr = SIZE_STAT( stat ) / (2*sizeof(Stat)) - 1;
// loop over all branches for ( i = 1; i <= nr; i++ ) {
// if the condition evaluates to 'true', execute the branch body
cond = READ_STAT(stat, 2 * (i - 1)); if ( EVAL_BOOL_EXPR( cond ) != False ) {
// execute the branch body and leave
body = READ_STAT(stat, 2 * (i - 1) + 1); return EXEC_STAT( body );
}
SET_BRK_CALL_TO(stat);
}
// otherwise execute the else-branch body and leave
body = READ_STAT(stat, 2 * (i - 1) + 1); return EXEC_STAT( body );
}
/**************************************************************************** ** *F ExecFor(<stat>) . . . . . . . . . . . . . . . . . . . execute a for-loop ** ** 'ExecFor' executes the for-loop <stat>. ** ** This is done by evaluating the list-expression, checking that it ** evaluates to a list, and then looping over the entries in the list, ** executing the body for each element of the list. If a leave-statement ** ('break' or 'return') is executed inside the body, then the execution of ** the for-loop is terminated and 0 is returned if the leave-statement was a ** break-statement or the non-zero leave-value is returned if the ** leave-statement was a return-statement (to tell the calling executor that ** a return-statement was executed). If no leave-statement was executed, ** then 0 is returned. ** ** A for-loop with <n> statements in its body is a statement of type ** 'STAT_FOR' with <n>+2 slots. The first slot points to an assignment bag ** for the loop variable, the second slot points to the list-expression, and ** the remaining slots points to the statements.
*/
Obj ITERATOR;
Obj IS_DONE_ITER;
Obj NEXT_ITER; static Obj STD_ITER;
static ALWAYS_INLINE ExecStatus ExecForHelper(Stat stat, UInt nr)
{
UInt var; // variable
UInt vart; // variable type
Obj list; // list to loop over
Obj elm; // one element of the list
Stat body1; // first stat. of body of loop
Stat body2; // second stat. of body of loop
Stat body3; // third stat. of body of loop
UInt i; // loop variable
GAP_ASSERT(1 <= nr && nr <= 3);
// get the variable (initialize them first to please 'lint') const Stat varstat = READ_STAT(stat, 0); if (IS_REF_LVAR(varstat)) {
var = LVAR_REF_LVAR(varstat);
vart = 'l';
} elseif (TNUM_EXPR(varstat) == EXPR_REF_HVAR) {
var = READ_EXPR(varstat, 0);
vart = 'h';
} else/* if ( TNUM_EXPR( varstat ) == EXPR_REF_GVAR ) */ {
var = READ_EXPR(varstat, 0);
vart = 'g';
}
// evaluate the list
list = EVAL_EXPR(READ_STAT(stat, 1));
// get the body
body1 = READ_STAT(stat, 2);
body2 = (nr >= 2) ? READ_STAT(stat, 3) : 0;
body3 = (nr >= 3) ? READ_STAT(stat, 4) : 0;
// special case for lists if ( IS_SMALL_LIST( list ) ) {
// loop over the list, skipping unbound entries
i = 1; while ( i <= LEN_LIST(list) ) {
// get the element and assign it to the variable
elm = ELMV0_LIST( list, i );
i++; if ( elm == 0 ) continue; if ( vart == 'l' ) ASS_LVAR( var, elm ); elseif ( vart == 'h' ) ASS_HVAR( var, elm ); elseif ( vart == 'g' ) AssGVar( var, elm );
#if !defined(HAVE_SIGNAL) // test for an interrupt if ( HaveInterrupt() ) {
ErrorReturnVoid("user interrupt", 0, 0, "you can 'return;'");
} #endif
// execute the statements in the body
EXEC_STAT_IN_LOOP(body1); if (nr >= 2)
EXEC_STAT_IN_LOOP(body2); if (nr >= 3)
EXEC_STAT_IN_LOOP(body3);
}
}
// general case else {
Obj nfun; // function for NextIterator
Obj dfun; // function for IsDoneIterator
// get the iterator
list = CALL_1ARGS( ITERATOR, list );
if (IS_PREC_OR_COMOBJ(list) && CALL_1ARGS(STD_ITER, list) == True) { // this can avoid method selection overhead on iterator
dfun = ElmPRec( list, RNamName("IsDoneIterator") );
nfun = ElmPRec( list, RNamName("NextIterator") );
} else {
dfun = IS_DONE_ITER;
nfun = NEXT_ITER;
}
// loop over the iterator while ( CALL_1ARGS( dfun, list ) == False ) {
// get the element and assign it to the variable
elm = CALL_1ARGS( nfun, list ); if ( vart == 'l' ) ASS_LVAR( var, elm ); elseif ( vart == 'h' ) ASS_HVAR( var, elm ); elseif ( vart == 'g' ) AssGVar( var, elm );
#if !defined(HAVE_SIGNAL) // test for an interrupt if ( HaveInterrupt() ) {
ErrorReturnVoid("user interrupt", 0, 0, "you can 'return;'");
} #endif
// execute the statements in the body
EXEC_STAT_IN_LOOP(body1); if (nr >= 2)
EXEC_STAT_IN_LOOP(body2); if (nr >= 3)
EXEC_STAT_IN_LOOP(body3);
}
/**************************************************************************** ** *F ExecForRange(<stat>) . . . . . . . . . . . . . . . . execute a for-loop ** ** 'ExecForRange' executes the for-loop <stat>, which is a for-loop whose ** loop variable is a local variable and whose list is a literal range ** expression. ** ** This is done by evaluating the list-expression, checking that it ** evaluates to a list, and then looping over the entries in the list, ** executing the body for each element of the list. If a leave-statement ** ('break' or 'return') is executed inside the body, then the execution of ** the for-loop is terminated and 0 is returned if the leave-statement was a ** break-statement or the non-zero leave-value is returned if the ** leave-statement was a return-statement (to tell the calling executor that ** a return-statement was executed). If no leave-statement was executed, ** then 0 is returned. ** ** A short for-loop with <n> statements in its body is a statement of type ** 'STAT_FOR_RANGE' with <n>+2 slots. The first slot points to an assignment ** bag for the loop variable, the second slot points to the list-expression, ** and the remaining slots points to the statements.
*/ static ALWAYS_INLINE ExecStatus ExecForRangeHelper(Stat stat, UInt nr)
{
UInt lvar; // local variable Int first; // first value of range Int last; // last value of range
Obj elm; // one element of the list
Stat body1; // first stat. of body of loop
Stat body2; // second stat. of body of loop
Stat body3; // third stat. of body of loop Int i; // loop variable
GAP_ASSERT(1 <= nr && nr <= 3);
// get the variable (initialize them first to please 'lint')
lvar = LVAR_REF_LVAR(READ_STAT(stat, 0));
// evaluate the range
VisitStatIfHooked(READ_STAT(stat, 1));
elm = EVAL_EXPR(READ_EXPR(READ_STAT(stat, 1), 0));
first = GetSmallIntEx("Range", elm, "");
elm = EVAL_EXPR(READ_EXPR(READ_STAT(stat, 1), 1));
last = GetSmallIntEx("Range", elm, "");
// get the body
body1 = READ_STAT(stat, 2);
body2 = (nr >= 2) ? READ_STAT(stat, 3) : 0;
body3 = (nr >= 3) ? READ_STAT(stat, 4) : 0;
// loop over the range for ( i = first; i <= last; i++ ) {
// get the element and assign it to the variable
elm = INTOBJ_INT( i );
ASS_LVAR( lvar, elm );
#if !defined(HAVE_SIGNAL) // test for an interrupt if ( HaveInterrupt() ) {
ErrorReturnVoid("user interrupt", 0, 0, "you can 'return;'");
} #endif
// execute the statements in the body
EXEC_STAT_IN_LOOP(body1); if (nr >= 2)
EXEC_STAT_IN_LOOP(body2); if (nr >= 3)
EXEC_STAT_IN_LOOP(body3);
}
j = 0; for (i = 1; i <= nrexprs; i++) {
o = EVAL_EXPR(READ_STAT(stat, 2*i)); if (IS_BAG_REF(o)) {
tolock[j] = o;
LockQual qual = INT_INTEXPR(READ_STAT(stat, 2*i-1)); if (qual == LOCK_QUAL_READWRITE)
lockmode[j] = LOCK_MODE_READWRITE; elseif (qual == LOCK_QUAL_READONLY)
lockmode[j] = LOCK_MODE_READONLY; else// if (qual == LOCK_QUAL_NONE)
lockmode[j] = LOCK_MODE_DEFAULT;
j++;
}
}
nrexprs = j;
GetLockStatus(nrexprs, tolock, lockstatus);
j = 0; for (i = 0; i < nrexprs; i++) { switch (lockstatus[i]) { case LOCK_STATUS_UNLOCKED:
tolock[j] = tolock[i];
lockmode[j] = lockmode[i];
j++; break; case LOCK_STATUS_READONLY_LOCKED: if (lockmode[i] == LOCK_MODE_READWRITE)
ErrorMayQuit("Attempt to change from read to write lock", 0, 0); break; case LOCK_STATUS_READWRITE_LOCKED: break;
}
}
lockSP = LockObjects(j, tolock, lockmode); if (lockSP >= 0) {
status = EXEC_STAT(READ_STAT(stat, 0));
PopRegionLocks(lockSP);
} else {
status = 0;
ErrorMayQuit("Cannot lock required regions", 0, 0);
} return status;
} #endif
/**************************************************************************** ** *F ExecWhile(<stat>) . . . . . . . . . . . . . . . . . execute a while-loop ** ** 'ExecWhile' executes the while-loop <stat>. ** ** This is done by executing the body while the condition evaluates to ** 'true'. If a leave-statement ('break' or 'return') is executed inside ** the body, then the execution of the while-loop is terminated and 0 is ** returned if the leave-statement was a break-statement or the non-zero ** leave-value is returned if the leave-statement was a return-statement (to ** tell the calling executor that a return-statement was executed). If no ** leave-statement was executed, then 0 is returned. ** ** A while-loop with <n> statements in its body is a statement of type ** 'STAT_WHILE' with <n>+1 slots. The first slot points to the condition, ** the second slot points to the first statement, the third slot points to ** the second statement, and so on.
*/ static ALWAYS_INLINE ExecStatus ExecWhileHelper(Stat stat, UInt nr)
{
Expr cond; // condition
Stat body1; // first stat. of body of loop
Stat body2; // second stat. of body of loop
Stat body3; // third stat. of body of loop
GAP_ASSERT(1 <= nr && nr <= 3);
// get the condition and the body
cond = READ_STAT(stat, 0);
body1 = READ_STAT(stat, 1);
body2 = (nr >= 2) ? READ_STAT(stat, 2) : 0;
body3 = (nr >= 3) ? READ_STAT(stat, 3) : 0;
// while the condition evaluates to 'true', execute the body while ( EVAL_BOOL_EXPR( cond ) != False ) {
#if !defined(HAVE_SIGNAL) // test for an interrupt if ( HaveInterrupt() ) {
ErrorReturnVoid("user interrupt", 0, 0, "you can 'return;'");
} #endif
// execute the body
EXEC_STAT_IN_LOOP(body1); if (nr >= 2)
EXEC_STAT_IN_LOOP(body2); if (nr >= 3)
EXEC_STAT_IN_LOOP(body3);
/**************************************************************************** ** *F ExecRepeat(<stat>) . . . . . . . . . . . . . . . . execute a repeat-loop ** ** 'ExecRepeat' executes the repeat-loop <stat>. ** ** This is done by executing the body until the condition evaluates to ** 'true'. If a leave-statement ('break' or 'return') is executed inside ** the body, then the execution of the repeat-loop is terminated and 0 is ** returned if the leave-statement was a break-statement or the non-zero ** leave-value is returned if the leave-statement was a return-statement (to ** tell the calling executor that a return-statement was executed). If no ** leave-statement was executed, then 0 is returned. ** ** A repeat-loop with <n> statements in its body is a statement of type ** 'STAT_REPEAT' with <n>+1 slots. The first slot points to the condition ** second slot points to the first statement, the third slot points to the ** second statement, and so on.
*/ static ALWAYS_INLINE ExecStatus ExecRepeatHelper(Stat stat, UInt nr)
{
Expr cond; // condition
Stat body1; // first stat. of body of loop
Stat body2; // second stat. of body of loop
Stat body3; // third stat. of body of loop
// get the condition and the body
cond = READ_STAT(stat, 0);
body1 = READ_STAT(stat, 1);
body2 = (nr >= 2) ? READ_STAT(stat, 2) : 0;
body3 = (nr >= 3) ? READ_STAT(stat, 3) : 0;
// execute the body until the condition evaluates to 'true' do {
#if !defined(HAVE_SIGNAL) // test for an interrupt if ( HaveInterrupt() ) {
ErrorReturnVoid("user interrupt", 0, 0, "you can 'return;'");
} #endif
// execute the body
EXEC_STAT_IN_LOOP(body1); if (nr >= 2)
EXEC_STAT_IN_LOOP(body2); if (nr >= 3)
EXEC_STAT_IN_LOOP(body3);
/**************************************************************************** ** *F ExecBreak(<stat>) . . . . . . . . . . . . . . . execute a break-statement ** ** 'ExecBreak' executes the break-statement <stat>. ** ** This is done by returning STATUS_BREAK (to tell the calling executor that ** a break-statement was executed). ** ** A break-statement is a statement of type 'STAT_BREAK' with no slots.
*/ static ExecStatus ExecBreak(Stat stat)
{ // return to the next loop return STATUS_BREAK;
}
/**************************************************************************** ** *F ExecContinue(<stat>) . . . . . . . . . . . . execute a continue-statement ** ** 'ExecContinue' executes the continue-statement <stat>. ** ** This is done by returning STATUS_CONTINUE (to tell the calling executor ** that a continue-statement was executed). ** ** A continue-statement is a statement of type 'STAT_CONTINUE' with no ** slots.
*/ static ExecStatus ExecContinue(Stat stat)
{ // return to the next loop return STATUS_CONTINUE;
}
/**************************************************************************** ** *F ExecInfo( <stat> ) . . . . . . . . . . . . . . execute an info-statement ** ** 'ExecInfo' executes the info-statement <stat>. ** ** This is done by evaluating the first two arguments, using the GAP level ** function InfoDecision to decide whether the message has to be printed. If ** it has, the other arguments are evaluated and passed to InfoDoPrint ** ** An info-statement is a statement of type 'STAT_INFO' with slots for the ** arguments.
*/ static ExecStatus ExecInfo(Stat stat)
{
Obj selectors;
Obj level;
Obj selected;
UInt narg;
UInt i;
Obj args;
Obj arg;
selected = InfoCheckLevel(selectors, level); if (selected == True) {
// Get the number of arguments to be printed
narg = NARG_SIZE_INFO(SIZE_STAT(stat)) - 2;
// set up a list
args = NEW_PLIST( T_PLIST, narg );
SET_LEN_PLIST( args, narg );
// evaluate the objects to be printed into the list for (i = 1; i <= narg; i++) {
// These two statements must not be combined into one because of // the risk of a garbage collection during the evaluation // of arg, which may happen after the pointer to args has been // extracted
arg = EVAL_EXPR(ARGI_INFO(stat, i+2));
SET_ELM_PLIST(args, i, arg);
CHANGED_BAG(args);
}
// and print them
InfoDoPrint(selectors, level, args);
} return STATUS_END;
}
/**************************************************************************** ** *F ExecAssert2Args(<stat>) . . . . . . . . . . . execute an assert-statement ** ** 'ExecAssert2Args' executes the 2 argument assert-statement <stat>. ** ** A 2 argument assert-statement is a statement of type 'STAT_ASSERT_2ARGS' ** with slots for the two arguments
*/ static ExecStatus ExecAssert2Args(Stat stat)
{
Obj level; Int lev;
Obj cond;
level = EVAL_EXPR(READ_STAT(stat, 0));
lev = GetSmallIntEx("Assert", level, "");
if (STATE(CurrentAssertionLevel) >= lev) {
cond = EVAL_EXPR(READ_STAT(stat, 1));
RequireTrueOrFalse("Assert", cond); if (cond == False) {
AssertionFailure();
}
}
return STATUS_END;
}
/**************************************************************************** ** *F ExecAssert3Args(<stat>) . . . . . . . . . . . execute an assert-statement ** ** 'ExecAssert3Args' executes the 3 argument assert-statement <stat>. ** ** A 3 argument assert-statement is a statement of type 'STAT_ASSERT_3ARGS' ** with slots for the three arguments.
*/ static ExecStatus ExecAssert3Args(Stat stat)
{
Obj level; Int lev;
Obj cond;
Obj message;
level = EVAL_EXPR(READ_STAT(stat, 0));
lev = GetSmallIntEx("Assert", level, "");
if (STATE(CurrentAssertionLevel) >= lev) {
cond = EVAL_EXPR(READ_STAT(stat, 1));
RequireTrueOrFalse("Assert", cond); if (cond == False) {
message = EVAL_EXPR(READ_STAT(stat, 2));
SET_BRK_CALL_TO( stat );
AssertionFailureWithMessage(message);
}
} return STATUS_END;
}
/**************************************************************************** ** *F ExecReturnObj(<stat>) . . . . . . . . . execute a return-value-statement ** ** 'ExecRetval' executes the return-value-statement <stat>. ** ** This is done by setting 'STATE(ReturnObjStat)' to the value of the ** return-value-statement, and returning 'STATUS_RETURN' (to tell the ** calling executor that a return-statement was executed). ** ** A return-value-statement is a statement of type 'STAT_RETURN_OBJ' with ** one slot. This slot points to the expression whose value is to be ** returned.
*/ static ExecStatus ExecReturnObj(Stat stat)
{ #if !defined(HAVE_SIGNAL) // test for an interrupt if ( HaveInterrupt() ) {
ErrorReturnVoid("user interrupt", 0, 0, "you can 'return;'");
} #endif
/**************************************************************************** ** *F ExecReturnVoid(<stat>) . . . . . . . . . execute a return-void-statement ** ** 'ExecReturnVoid' executes the return-void-statement <stat>, i.e., the ** return-statement that returns not value. ** ** This is done by setting 'STATE(ReturnObjStat)' to zero, and returning ** 'STATUS_RETURN' (to tell the calling executor that a return-statement was ** executed). ** ** A return-void-statement is a statement of type 'STAT_RETURN_VOID' with no ** slots.
*/ static ExecStatus ExecReturnVoid(Stat stat)
{ #if !defined(HAVE_SIGNAL) // test for an interrupt if ( HaveInterrupt() ) {
ErrorReturnVoid("user interrupt", 0, 0, "you can 'return;'");
} #endif
/**************************************************************************** ** *F UInt TakeInterrupt() . . . . . . . . allow user interrupts ** ** When you call this you promise that the heap is in a normal state, ** allowing GAP execution in the usual way ** ** This will do nothing (pretty quickly) if Ctrl-C has not been pressed and ** return 0. Otherwise it will respond appropriately. This may result in a ** longjmp or in returning to the caller after arbitrary execution of GAP ** code including possible garbage collection. In this case 1 is returned.
*/
/**************************************************************************** ** *F ExecIntrStat(<stat>) . . . . . . . . . . . . . . interrupt a computation ** ** 'ExecIntrStat' is called when a computation was interrupted (by a call to ** 'InterruptExecStat'). It changes the entries in the dispatch table ** 'ExecStatFuncs' back to their original value, calls 'Error', and ** redispatches after a return from the break-loop.
*/
static ExecStatus ExecIntrStat(Stat stat)
{
// change the entries in 'ExecStatFuncs' back to the original if ( BreakLoopPending() ) {
UnInterruptExecStat();
}
#ifdef HPCGAP // and now for something completely different
HandleInterrupts(1, stat); #else // ensure global interrupt flag syLastIntr is cleared
HaveInterrupt();
// and now for something completely different #ifdef USE_GASMAN if (SyStorOverrun != SY_STOR_OVERRUN_CLEAR) { Int printError = (SyStorOverrun == SY_STOR_OVERRUN_TO_REPORT);
SyStorOverrun = SY_STOR_OVERRUN_CLEAR; // reset if (printError) {
ErrorReturnVoid("reached the pre-set memory limit\n" "(change it with the -o command line option)",
0, 0, "you can 'return;'");
}
} else #endif
ErrorReturnVoid( "user interrupt", 0, 0, "you can 'return;'" ); #endif
// continue at the interrupted statement return EXEC_STAT( stat );
}
/**************************************************************************** ** *F InterruptExecStat() . . . . . . . . interrupt the execution of statements ** ** 'InterruptExecStat' interrupts the execution of statements at the next ** possible moment. It is called from 'SyAnsIntr' if an interrupt signal is ** received. It is never called on systems that do not support signals. On ** those systems the executors test 'SyIsIntr' at regular intervals. ** ** 'InterruptExecStat' changes all entries in the executor dispatch table ** 'ExecStatFuncs' to point to 'ExecIntrStat', which changes the entries ** back, calls 'Error', and redispatches after a return from the break-loop.
*/ void InterruptExecStat ( void )
{ // remember the original entries from the table 'ExecStatFuncs'
STATE(CurrExecStatFuncs) = IntrExecStatFuncs;
}
// change the entries in 'ExecStatFuncs' back to the original if ( BreakLoopPending() ) {
UnInterruptExecStat();
// check for user interrupt if ( HaveInterrupt() ) {
Pr("Noticed user interrupt, but you are back in main loop anyway.\n",
0, 0);
} #ifdef USE_GASMAN // and check if maximal memory was overrun if (SyStorOverrun != SY_STOR_OVERRUN_CLEAR) { if (SyStorOverrun == SY_STOR_OVERRUN_TO_REPORT) {
Pr("GAP has exceeded the permitted memory (-o option),\n", 0,
0);
Pr("the maximum is now enlarged to %d kB.\n", (Int)SyStorMax,
0);
}
SyStorOverrun = SY_STOR_OVERRUN_CLEAR; // reset
} #endif
}
}
/**************************************************************************** ** *V PrintStatFuncs[<type>] . . print function for statements of type <type> ** ** 'PrintStatFuncs' is the dispatching table that contains for every type of ** statements a pointer to the printer for statements of this type, i.e., ** the function that should be called to print statements of this type.
*/ static PrintStatFunc PrintStatFuncs[256];
/**************************************************************************** ** *F PrintStat(<stat>) . . . . . . . . . . . . . . . . . . . print a statement ** ** 'PrintStat' prints the statements <stat>. ** ** 'PrintStat' simply dispatches through the table 'PrintStatFuncs' to the ** appropriate printer.
*/ void PrintStat(Stat stat)
{
(*PrintStatFuncs[TNUM_STAT(stat)])(stat);
}
/**************************************************************************** ** *F PrintUnknownStat(<stat>) . . . . . . . . print statement of unknown type ** ** 'PrintUnknownStat' is the printer that is called if an attempt is made ** print a statement <stat> of an unknown type. It signals an error. If ** this is ever called, then GAP is in serious trouble, such as an ** overwritten type field of a statement.
*/ staticvoid PrintUnknownStat(Stat stat)
{
ErrorQuit("Panic: cannot print statement of type '%d'",
(Int)TNUM_STAT(stat), 0);
}
/**************************************************************************** ** *F PrintSeqStat(<stat>) . . . . . . . . . . . . print a statement sequence ** ** 'PrintSeqStat' prints the statement sequence <stat>.
*/ staticvoid PrintSeqStat(Stat stat)
{
UInt nr; // number of statements
UInt i; // loop variable
// get the number of statements
nr = SIZE_STAT( stat ) / sizeof(Stat);
// loop over the statements for ( i = 1; i <= nr; i++ ) {
// print the <i>-th statement
PrintStat(READ_STAT(stat, i - 1));
// print a line break after all but the last statement if ( i < nr ) Pr("\n", 0, 0);
}
}
/**************************************************************************** ** *F PrintIf(<stat>) . . . . . . . . . . . . . . . . . . print an if-statement ** ** 'PrIf' prints the if-statement <stat>. ** ** Linebreaks are printed after the 'then' and the statements in the bodies. ** If necessary one is preferred immediately before the 'then'.
*/ staticvoid PrintIf(Stat stat)
{
UInt i; // loop variable
UInt len; // length of loop
len = SIZE_STAT(stat) / (2 * sizeof(Stat)); // print the 'elif' branch for (i = 2; i <= len; i++) { if (i == len &&
TNUM_EXPR(READ_STAT(stat, 2 * (i - 1))) == EXPR_TRUE) {
Pr("else%4>\n", 0, 0);
} else {
Pr("elif%4> ", 0, 0);
PrintExpr(READ_EXPR(stat, 2 * (i - 1)));
Pr("%2< then%2>\n", 0, 0);
}
PrintStat(READ_STAT(stat, 2 * (i - 1) + 1));
Pr("%4<\n", 0, 0);
}
// print the 'fi'
Pr("fi;", 0, 0);
}
/**************************************************************************** ** *F PrintFor(<stat>) . . . . . . . . . . . . . . . . . . . print a for-loop ** ** 'PrintFor' prints the for-loop <stat>. ** ** Linebreaks are printed after the 'do' and the statements in the body. If ** necessary it is preferred immediately before the 'in'.
*/ staticvoid PrintFor(Stat stat)
{
UInt i; // loop variable
Pr("for%4> ", 0, 0);
PrintExpr(READ_EXPR(stat, 0));
Pr("%2< in%2> ", 0, 0);
PrintExpr(READ_EXPR(stat, 1));
Pr("%2< do%2>\n", 0, 0); for ( i = 2; i <= SIZE_STAT(stat)/sizeof(Stat)-1; i++ ) {
PrintStat(READ_STAT(stat, i)); if ( i < SIZE_STAT(stat)/sizeof(Stat)-1 ) Pr("\n", 0, 0);
}
Pr("%4<\nod;", 0, 0);
}
/**************************************************************************** ** *F PrintWhile(<stat>) . . . . . . . . . . . . . . . . . print a while loop ** ** 'PrintWhile' prints the while-loop <stat>. ** ** Linebreaks are printed after the 'do' and the statements in the body. If ** necessary one is preferred immediately before the 'do'.
*/ staticvoid PrintWhile(Stat stat)
{
UInt i; // loop variable
Pr("while%4> ", 0, 0);
PrintExpr(READ_EXPR(stat, 0));
Pr("%2< do%2>\n", 0, 0); for ( i = 1; i <= SIZE_STAT(stat)/sizeof(Stat)-1; i++ ) {
PrintStat(READ_STAT(stat, i)); if ( i < SIZE_STAT(stat)/sizeof(Stat)-1 ) Pr("\n", 0, 0);
}
Pr("%4<\nod;", 0, 0);
}
/**************************************************************************** ** *F PrintAtomic(<stat>) . . . . . . . . . . . . . . . . print an atomic loop ** ** 'PrintAtomic' prints the atomic-loop <stat>. ** ** Linebreaks are printed after the 'do' and the statements in the body. If ** necessary one is preferred immediately before the 'do'.
*/ #ifdef HPCGAP staticvoid PrintAtomic(Stat stat)
{
UInt nrexprs;
UInt i; // loop variable
Pr("atomic%4> ", 0, 0);
nrexprs = ((SIZE_STAT(stat)/sizeof(Stat))-1)/2; for (i = 1; i <= nrexprs; i++) { if (i != 1)
Pr(", ", 0, 0); switch (INT_INTEXPR(READ_STAT(stat, 2 * i - 1))) { case LOCK_QUAL_NONE: break; case LOCK_QUAL_READONLY:
Pr("readonly ", 0, 0); break; case LOCK_QUAL_READWRITE:
Pr("readwrite ", 0, 0); break;
}
PrintExpr(READ_EXPR(stat, 2 * i));
}
Pr("%2< do%2>\n", 0, 0);
PrintStat(READ_STAT(stat, 0));
Pr("%4<\nod;", 0, 0);
} #endif
/**************************************************************************** ** *F PrintRepeat(<stat>) . . . . . . . . . . . . . . . . . print a repeat-loop ** ** 'PrintRepeat' prints the repeat-loop <stat>. ** ** Linebreaks are printed after the 'repeat' and the statements in the body. ** If necessary one is preferred after the 'until'.
*/ staticvoid PrintRepeat(Stat stat)
{
UInt i; // loop variable
Pr("repeat%4>\n", 0, 0); for ( i = 1; i <= SIZE_STAT(stat)/sizeof(Stat)-1; i++ ) {
PrintStat(READ_STAT(stat, i)); if ( i < SIZE_STAT(stat)/sizeof(Stat)-1 ) Pr("\n", 0, 0);
}
Pr("%4<\nuntil%2> ", 0, 0);
PrintExpr(READ_EXPR(stat, 0));
Pr("%2<;", 0, 0);
}
// print the opening parenthesis
Pr("%<( %>", 0, 0);
// print the expressions that evaluate to the actual arguments for ( i = 1; i <= NARG_SIZE_INFO( SIZE_STAT(stat) ); i++ ) {
PrintExpr( ARGI_INFO(stat,i) ); if ( i != NARG_SIZE_INFO( SIZE_STAT(stat) ) ) {
Pr("%<, %>", 0, 0);
}
}
// print the closing parenthesis
Pr(" %2<);", 0, 0);
}
/**************************************************************************** ** *F PrintAssert2Args(<stat>) . . . . . . . . . . . . print an info-statement ** ** 'PrintAssert2Args' prints the 2 argument assert-statement <stat>.
*/ staticvoid PrintAssert2Args(Stat stat)
{ // print the keyword
Pr("%2>Assert", 0, 0);
// print the opening parenthesis
Pr("%<( %>", 0, 0);
// Print the arguments, separated by a comma
PrintExpr(READ_EXPR(stat, 0));
Pr("%<, %>", 0, 0);
PrintExpr(READ_EXPR(stat, 1));
// print the closing parenthesis
Pr(" %2<);", 0, 0);
}
/**************************************************************************** ** *F PrintAssert3Args(<stat>) . . . . . . . . . . . . print an info-statement ** ** 'PrintAssert3Args' prints the 3 argument assert-statement <stat>.
*/ staticvoid PrintAssert3Args(Stat stat)
{ // print the keyword
Pr("%2>Assert", 0, 0);
// print the opening parenthesis
Pr("%<( %>", 0, 0);
for ( i = 0; i < ARRAY_SIZE(ExecStatFuncs); i++ )
IntrExecStatFuncs[i] = ExecIntrStat; for (i = FIRST_NON_INTERRUPT_STAT; i <= LAST_NON_INTERRUPT_STAT; i++)
IntrExecStatFuncs[i] = ExecStatFuncs[i];
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.