/* Copyright Per Bothner 1987. Read the file Q-INFO */
#ifndef _EXCEPTIONS_H_
/*#pragma once*/
#pragma interface
#define _EXCEPTIONS_H_
#include "config.h"
#define NEW_DEP
#define NEW_SAVE
#ifdef __cplusplus
#include <expression.h>
#endif
#ifndef NEWTYPE_H
#include <newtype.h>
#endif NEWTYPE_H
extern struct ExceptionClass Any_exception[1];
extern RootPtr LastRaiseParameter;

#define DefExceptionClass(name, super, level)\
  struct ExceptionClass name[1] = {{#name, super, NULL, level}};

#define RaiseDomainError(x) RAISE(Bad_arg_type, x)
#define RAISE(signal, parameter) _Raise_(signal, parameter)
#define False(a) (a == NULL || MemGetType(a)==ExceptionT)
#define Succeeds(e) (!False(e))

/* CATCH(ex, exception, catcher) means:
 * Evaluate 'ex'. If an exception matching 'exception' is raised,
 * then (and only then) evaluate 'catcher'.
 * The variable 'signal' points to the ExceptionClass of the signal.
 */
#define CATCH(ex, exception, catcher) \
  { struct ExceptionClass *signal = (struct ExceptionClass*)(ex), \
	*__signal = signal, *__except = (exception); \
    Object parameter = NoValue; \
    while (__signal->level > __except->level) __signal = __signal->super; \
    if (__signal == __except) {catcher}; }
#define RE_RAISE RAISE(signal, parameter) /* can be used in a CATCH */
#define CATCH_AND_PASS(ex) CATCH(ex, Any_exception, RE_RAISE)

/*#define VarIsLast 1*/
#define VarIsAssignable 2
#define VarIsCombination 4
/*#define VarIsBound 8*/
#define VarIsAssigned 16
#define VarIsInverse 32
#define VarIsTentative 64
#define VarIsSum 128
#define VarHasCoercion 256
#define VarIsFuture 512
#define VarHasName 1024
#define VarIsDependency 2048
#define VarIsUnknown 0x8000

/*#define IsUnknown(v) (!(((struct PlainVar*)(v)).flags & VarIsBound))*/
#define AnyIsVar(v) HasAType(v,VariableT)
#define IsBound(var) (*(long*)(var) >= 0) /* sign-bit clear */

#define IsAssignable(var) (HasHType(var, Variable) \
  && (((struct Variable*)(var))->flags & VarIsAssignable))

#include <setjmp.h>

#ifndef USE_EXCEPTIONS
extern jmp_buf main_jmp_buf;
#endif

typedef struct _HandlerDesc_ {
    HandlerDesc *next;
    union _Undo_ *undo_trail; /* how many variable bindings etc to undo */
#ifdef USE_LONGJMP
    jmp_buf jump_buf;
#else
    long save_regs[CONT_SAVE_REGS];
#endif
    char *handler_PC; /* the continuation label to jump to on a _Raise_ */
    HandlerDesc **prev;
 /* remaining fields only needed for backtracking "|" - not for "if" */
#if 0 /* OLD: #ifdef M68K */
    char *filler1; // WAS: char *patched_FP; // NULL if "if" instead of "|"
    char *filler2; /*WAS: char *patched_RL; *the real return link of patched_FP
	(or a pointer to anothner patch subroutine) */
#endif
    short kind; /* 0 == Invalid; 1 == Normal; 2 == Backtracking */
} Continuation;
EXTERN volatile Object _Raise_(struct ExceptionClass *, void *);
extern Continuation InteractiveHandler[1], NullHandler[1];
#ifdef MULTI_PROCESS
#define _Handler_ (PerProcess->_handler_)
#define UndoTrail (PerProcess->undoTrail)
#else
extern HandlerDesc *_Handler_;
extern union _Undo_ *UndoTrail; /* chronolical list of constraints */
#endif
#define RealHandler(h) ((h) != NullHandler && (h) != InteractiveHandler)

#ifdef __cplusplus
struct Condition : public Root {
    DECLARE_MEMBERS(Condition)
    virtual void printon(ostream&) const;
};
struct GenericCondition : public Condition {
    char* message;
    GenericCondition(char*s) : message(s) {}
    virtual void printon(ostream&) const;
};
struct SysSignal : public Condition {
    int sig;
    SysSignal(int s) { sig = s; }
    virtual void printon(ostream&) const;
};
struct CellError : public Condition {
    Root *cell; // 
    CellError(Root *c) { cell = c; }
};
struct UnboundVariable : CellError {
    virtual void printon(ostream&) const;
    UnboundVariable(Symbol *sym) : CellError(sym) { }
};
struct CoercionFail : public Condition {
    const Root *value;
    const Type *type;
    CoercionFail(const Root *v, const Type *t) { value = v; type = t; }
    virtual void printon(ostream&) const;
};
struct MissingCondition : public Condition {
    MissingCondition() { }
    virtual void printon(ostream&) const;
};
extern MissingCondition MissingElement;
struct CompareFail : public Condition {
    const Root *left;
    const Root *right;
    const char *op;
    CompareFail(const char *o, const Root *l, const Root *r)
	: op(o), left(l), right(r) { }
    virtual void printon(ostream&) const;
};
struct ProgramExitFailure : public Condition {
    // An sub-process returned with a non-zero exit code.
    char* program_name;
    int pid;
    int return_code;
    ProgramExitFailure(char*pn, int p, int rc)
	{ program_name = pn; pid = p; return_code = rc; }
    virtual void printon(ostream&) const;
};
struct BadSyscall : public Condition {
    char *format;
    char *name1;
    char *name2;
    int err_number;
    BadSyscall(char *f, char* n, int e)
	{ format= f; name1=n; name2=NULL; err_number= e; }
    BadSyscall(char *f, char* n1, char* n2, int e)
	{ format= f; name1=n1; name2=n2; err_number= e; }
    virtual void printon(ostream&) const;
};
struct ParameterFail : public CoercionFail {
    DECLARE_MEMBERS(ParameterFail)
    const StringC* name;
    const StringC* param_name() const { return name; }
    const Type* param_type() const { return type; }
    const Root* param_value() const { return value; }
    ParameterFail(Formal* f, const Root* a)
	: name(f->u.id->fname()->Str()), CoercionFail(a, f->u.id->ftype()) { }
    ParameterFail(const Root* v, const Type *t, const StringC* n) 
	: name(n), CoercionFail(v, t) { }
    virtual void printon(ostream&) const;
};
struct UnimplementedOp : public Condition {
    const char* operator_name;
    const Type* operand_type;
    UnimplementedOp(const char* on, const Type* ot=0)
	{ operator_name= on; operand_type = ot; }
    virtual void printon(ostream&) const;
};
struct BadAssignment : public Condition {
    Root* var;
    Root* new_val;
    BadAssignment(Root* vr, Root* vl) { var = vr; new_val = vl; }
    virtual void printon(ostream&) const;
};
extern volatile void Signal(Condition*);
extern Condition* LastRaiseCondition;
#endif
#endif _EXCEPTIONS_H_
