/** * payloads/exception.c * * An exception; required three pointers, so use object of size class 3. * * (c) 2026 Simon Brooke * Licensed under GPL version 2.0, or, at your option, any later version. */ #include /* * wide characters */ #include #include #include "memory/node.h" #include "memory/pointer.h" #include "memory/pso.h" #include "memory/pso3.h" #include "memory/pso4.h" #include "memory/tags.h" #include "payloads/exception.h" #include "ops/stack_ops.h" #include "ops/truth.h" #include #include #include #include /** * @brief allocate an exception object, and, if successful, return a pointer * to it. * * (exception message meta cause) * * Throwing an exception while generating an exception is meaningless. If * allocation fails utterly (i.e. out of heap, out of page space) this will * have to return `nil`, which might give rise to hard to trace bugs. But * otherwise it will return a pointer to a new exception. * * @param message expected to be a string, but anything printable is accepted. b * @param meta metadata for this exception. Must be an assoc list, hashtable, * or `nil` * @param cause the exception that caused this exception to be `thrown`. */ struct pso_pointer make_exception( struct pso_pointer frame_pointer ) { struct pso4 *frame = pointer_to_pso4( frame_pointer ); struct pso_pointer message = fetch_arg( frame, 0 ); struct pso_pointer previous = frame->payload.stack_frame.previous; struct pso_pointer meta = fetch_arg( frame, 1 ); struct pso_pointer cause = fetch_arg( frame, 2 ); struct pso_pointer result = allocate( frame_pointer, EXCEPTIONTAG, 3 ); if ( !c_nilp( result ) && !exceptionp( result ) ) { struct pso3 *object = ( struct pso3 * ) pointer_to_object( result ); object->payload.exception.message = message; object->payload.exception.stack = stackp( frame_pointer ) ? frame_pointer : nil; object->payload.exception.meta = ( consp( meta ) || hashtabp( meta ) ) ? meta : nil; object->payload.exception.cause = exceptionp( cause ) ? cause : nil; } return result; } /** * @brief When an exception is freed, all its pointers must be decremented. * * Lisp calling conventions; one expected arg, the pointer to the object to * be destroyed. */ struct pso_pointer destroy_exception( struct pso_pointer fp ) { if ( stackp( fp ) ) { struct pso4 *frame = pointer_to_pso4( fp ); struct pso_pointer p = frame->payload.stack_frame.arg[0]; struct pso3 *object = ( struct pso3 * ) pointer_to_object( p ); dec_ref( object->payload.exception.message ); dec_ref( object->payload.exception.stack ); dec_ref( object->payload.exception.meta ); dec_ref( object->payload.exception.cause ); } return nil; }