m3core/src/runtime/common/RTException.m3


 Copyright 1996-2000, Critical Mass, Inc.  All rights reserved. 
 See file COPYRIGHT-CMASS for details. 

UNSAFE MODULE RTException;

IMPORT RT0, RuntimeError, RTError, M3toC;

TYPE  RTE = RuntimeError.T;
CONST ArgMap = ARRAY BOOLEAN(*raises*) OF RTE {
                   RTE.UnhandledException, RTE.BlockedException };

VAR cur_backstop: Backstop := NIL;

PROCEDURE SetBackstop (h: Backstop): Backstop =
  VAR old := cur_backstop;
  BEGIN
    cur_backstop := h;
    RETURN old;
  END SetBackstop;

PROCEDURE InvokeBackstop (VAR a: RT0.RaiseActivation;
                          raises: BOOLEAN)  RAISES ANY =
  BEGIN
    IF (cur_backstop = NIL)
      THEN DefaultBackstop (a, raises);
      ELSE cur_backstop (a, raises);
    END;
  END InvokeBackstop;

PROCEDURE DefaultBackstop (VAR a: RT0.RaiseActivation;
                           raises: BOOLEAN) RAISES ANY =
  VAR
    err := RuntimeError.Self ();
    arg := LOOPHOLE (ORD (ArgMap [raises]), ADDRESS);
    not_arg := LOOPHOLE (ORD (ArgMap [NOT raises]), ADDRESS);
  BEGIN
    IF (a.exception = err) AND (a.arg = arg) THEN
      (* We're already raising the "Unhandled exception" exception! *)
      Crash (a, raises, err);
    ELSIF (a.exception = err) AND (a.arg = not_arg) THEN
      Crash (a, NOT raises, err);
    ELSE
      a.un_except := a.exception;
      a.un_arg    := a.arg;
      a.exception := err;
      a.arg       := arg;
      Raise (a);
    END;
  END DefaultBackstop;

PROCEDURE Crash (VAR a: RT0.RaiseActivation;  raises: BOOLEAN;  rte: ADDRESS) =
  CONST
    Pre  = ARRAY BOOLEAN OF TEXT { "Unhandled exception: ",  "Exception \"" };
    Post = ARRAY BOOLEAN OF TEXT { "",              "\" not in RAISES list" };
  VAR
    ex    := a.un_except;
    exarg := LOOPHOLE (a.un_arg, INTEGER);
    pre   : TEXT    := NIL;
    ename : TEXT    := NIL;
    post  : TEXT    := NIL;
    file  : ADDRESS := NIL;
  BEGIN
    IF (a.module # NIL) THEN file := a.module.file; END;
    IF (ex # rte) OR (exarg < 0) OR (NUMBER (RTE) <= exarg) THEN
      pre   := Pre[raises];
      ename := M3toC.StoT (LOOPHOLE (ex.name, ADDRESS));
      post  := Post[raises];
    ELSIF (exarg = ORD (RTE.AssertFailed))  AND (a.info0 # NIL) THEN
      pre   := "<*ASSERT*> failed: ";
      ename := LOOPHOLE (a.info0, TEXT);
      post  := "";
    ELSE
      pre   := "";
      ename := RuntimeError.Tag (VAL (exarg, RuntimeError.T));
      post  := "";
    END;
    IF (file = NIL) AND (a.pc # NIL)
      THEN RTError.MsgPC (LOOPHOLE (a.pc, INTEGER), pre, ename, post);
      ELSE RTError.MsgS (file, a.line, pre, ename, post);
    END;
  END Crash;

BEGIN
END RTException.