4.2 Exception handling

Calling a built-in or user-defined routine may lead to an error or a cached status message to be dealt with in MAL. To improve error handling in MAL, an exception handling scheme based on catch-exit blocks. The catch statement identifies a (string-valued) variable, which carries the exception message from the originally failed routine or raise exception assignment. During normal processing catch-exit blocks are simply skipped. Upon receiving an exception status from a function call, we set the exception variable and skip to the first associated catch-exit block. MAL interpretation then continues until it reaches the end of the block. If no exception variable was defined, we should abandon the function alltogether searching for a catch block at a higher layer.

Exceptions raised within a linked-in function requires some care. First, the called procedure does not know anything about the MAL interpreter context. Thus, we need to return all relevant information upon leaving the linked library routine.

Second, exceptional cases can be handled deeply in the recursion, where they may also be handled, i.e. by issueing an GDKerror message. The upper layers merely receive a negative integer value to indicate occurrence of an error somewhere in the calling sequence. We then have to also look into GDKerrbuf to see if there was an error raised deeply inside the system.

The policy is to require all C-functions to return a string-pointer. Upon a successfull call, it is a NULL string. Otherwise it contains an encoding of the exceptional state encountered. This message starts with the exception identifer, followed by contextual details.

     mal_export str catchKernelException(Client cntxt, str ret);
     str catchKernelException(Client cntxt, str ret){
      str z;
      if(cntxt->errbuf && cntxt->errbuf[0] ) {
       if (ret != MAL_SUCCEED){
        z= (char*) GDKmalloc( strlen(ret)+strlen(cntxt->errbuf)+2);
        if( z ){
         strcpy(z,ret);
         if (z[strlen(z)-1] != ' n') strcat(z," n");
         strcat(z,cntxt->errbuf);
        }
       } else {
        /* trap hidden (GDK) exception */
        z= (char*) GDKmalloc( strlen("GDKerror:")+strlen(cntxt->errbuf)+2);
        if ( z )
         sprintf(z,"GDKerror:%s n",cntxt->errbuf);
       }
       /* did we eat the error away of not */
       if (z )
        cntxt->errbuf[0] = ' 0';
      } else z = ret;
      return z;
     }