• Places
    • Home
    • Graphs
    • Prefixes
  • Admin
    • Users
    • Settings
    • Plugins
    • Statistics
  • Repository
    • Load local file
    • Load from HTTP
    • Load from library
    • Remove triples
    • Clear repository
    • RDF quality heuristics
  • Query
    • YASGUI SPARQL Editor
    • Simple Form
    • SWISH Prolog shell
  • Help
    • Documentation
    • Tutorial
    • Roadmap
    • HTTP Services
  • Login

12.4 The Foreign Include File
AllApplicationManualNameSummaryHelp

  • Documentation
    • Reference manual
      • Foreign Language Interface
        • The Foreign Include File
          • Argument Passing and Control
          • Atoms and functors
          • Analysing Terms via the Foreign Interface
          • Constructing Terms
          • Unifying data
          • Convenient functions to generate Prolog exceptions
          • Serializing and deserializing Prolog terms
          • BLOBS: Using atoms to store arbitrary binary data
          • Exchanging GMP numbers
          • Calling Prolog from C
          • Discarding Data
          • String buffering
          • Foreign Code and Modules
          • Prolog exceptions in foreign code
            • PL_raise_exception()
            • PL_throw()
            • PL_exception()
            • PL_clear_exception()
          • Catching Signals (Software Interrupts)
          • Miscellaneous
          • Errors and warnings
          • Environment Control from Foreign Code
          • Querying Prolog
          • Registering Foreign Predicates
          • Foreign Code Hooks
          • Storing foreign data
          • Embedding SWI-Prolog in other applications
    • Packages

12.4.14 Prolog exceptions in foreign code

This section discusses PL_exception(), PL_throw() and PL_raise_exception(), the interface functions to detect and generate Prolog exceptions from C code. PL_throw() and PL_raise_exception() from the C interface raise an exception from foreign code. PL_throw() exploits the C function longjmp() to return immediately to the innermost PL_next_solution(). PL_raise_exception() registers the exception term and returns FALSE. If a foreign predicate returns FALSE, while an exception term is registered, a Prolog exception will be raised by the virtual machine.

Calling these functions outside the context of a function implementing a foreign predicate results in undefined behaviour.

PL_exception() may be used after a call to PL_next_solution() fails, and returns a term reference to an exception term if an exception was raised, and 0 otherwise.

If a C function implementing a predicate calls Prolog and detects an exception using PL_exception(), it can handle this exception or return with the exception. Some caution is required though. It is not allowed to call PL_close_query() or PL_discard_foreign_frame() afterwards, as this will invalidate the exception term. Below is the code that calls a Prolog-defined arithmetic function (see arithmetic_function/1).

If PL_next_solution() succeeds, the result is analysed and translated to a number, after which the query is closed and all Prolog data created after PL_open_foreign_frame() is destroyed. On the other hand, if PL_next_solution() fails and if an exception was raised, just pass it. Otherwise generate an exception (PL_error() is an internal call for building the standard error terms and calling PL_raise_exception()). After this, the Prolog environment should be discarded using PL_cut_query() and PL_close_foreign_frame() to avoid invalidating the exception term.

static int
prologFunction(ArithFunction f, term_t av, Number r)
{ int arity = f->proc->definition->functor->arity;
  fid_t fid = PL_open_foreign_frame();
  qid_t qid;
  int rval;

  qid = PL_open_query(NULL, PL_Q_NORMAL, f->proc, av);

  if ( PL_next_solution(qid) )
  { rval = valueExpression(av+arity-1, r);
    PL_close_query(qid);
    PL_discard_foreign_frame(fid);
  } else
  { term_t except;

    if ( (except = PL_exception(qid)) )
    { rval = PL_throw(except);          /* pass exception */
    } else
    { char *name = stringAtom(f->proc->definition->functor->name);

                                        /* generate exception */
      rval = PL_error(name, arity-1, NULL, ERR_FAILED, f->proc);
    }

    PL_cut_query(qid);                  /* do not destroy data */
    PL_close_foreign_frame(fid);        /* same */
  }

  return rval;
}
int PL_raise_exception(term_t exception)
Generate an exception (as throw/1) and return FALSE. Below is an example returning an exception from a foreign predicate:
foreign_t
pl_hello(term_t to)
{ char *s;

  if ( PL_get_atom_chars(to, &s) )
  { Sprintf("Hello \"%s\"\n", s);

    PL_succeed;
  } else
  { term_t except = PL_new_term_ref();

    PL_unify_term(except,
                  PL_FUNCTOR_CHARS, "type_error", 2,
                    PL_CHARS, "atom",
                    PL_TERM, to);

    return PL_raise_exception(except);
  }
}
int PL_throw(term_t exception)
Similar to PL_raise_exception(), but returns using the C longjmp() function to the innermost PL_next_solution().
term_t PL_exception(qid_t qid)
If PL_next_solution() fails, this can be due to normal failure of the Prolog call, or because an exception was raised using throw/1. This function returns a handle to the exception term if an exception was raised, or 0 if the Prolog goal simply failed. If there is an exception, PL_exception() allocates a term-handle using PL_new_term_ref() that is used to return the exception term.

Additionally, PL_exception(0) returns the pending exception in the current query or 0 if no exception is pending. This can be used to check the error status after a failing call to, e.g., one of the unification functions.

void PL_clear_exception(void)
Tells Prolog that the encountered exception must be ignored. This function must be called if control remains in C after a previous API call fails with an exception.197This feature is non-portable. Other Prolog systems (e.g., YAP) have no facilities to ignore raised exceptions, and the design of YAP's exception handling does not support such a facility.

ClioPatria (version V3.1.1-40-g9d9e003)