Module: internal Author: Jonathan Bachrach Copyright: Original Code is Copyright (c) 1995-2004 Functional Objects, Inc. All rights reserved. License: Functional Objects Library Public License Version 1.0 Dual-license: GNU Lesser General Public License Warranty: Distributed WITHOUT WARRANTY OF ANY KIND //// HANDLERS define primary class () constant slot handler-type, init-keyword: type:; constant slot handler-function, init-keyword: function:; constant slot handler-test, init-keyword: test:; constant slot handler-init-arguments, init-keyword: init-arguments:; end class ; define sealed domain make (singleton()); define sealed domain initialize (); define variable *current-handlers* :: = #(); define variable *last-handlers* :: = #(); define variable *last-handler* :: false-or() = #f; // ---*** maintained for patching define function add-last-handler (_handler :: ) => () *last-handlers* := pair(_handler, *last-handlers*) end function; define function remove-last-handler () unless (empty?(*last-handlers*)) *last-handlers* := tail(*last-handlers*) end unless; end function; define inline function make-handler (type, function, #key test, init-arguments) make(, type: type, function: function, test: test, init-arguments: init-arguments | #[]) end function make-handler; //// //// CONDITION CLASSES. //// define open abstract class () end class ; define generic signal (cond-or-string, #rest arguments); define generic error (cond-or-string, #rest arguments) => (will-never-return :: ); define open generic default-handler (condition :: ); /// CONDITIONS define open abstract primary class () constant slot condition-format-string, init-keyword: format-string:, init-value: ""; constant slot condition-format-arguments, init-keyword: format-arguments:, init-value: #[]; end class ; define constant = ; define method signal (condition :: , #rest noise) unless (empty?(noise)) error("Can only supply format arguments when supplying a format string.") end unless; let done-last? = #f; iterate search (handlers = *current-handlers*) if (empty?(handlers)) if (done-last?) default-handler(condition) else done-last? := #t; search(*last-handlers*) end if; else let _handler = head(handlers); let remaining = tail(handlers); if (handler-matches?(_handler, condition)) handler-function(_handler) (condition, method () search(remaining) end method) else search(remaining) end if end if end iterate end method signal; define method handler-matches? (_handler :: , condition :: ) => (matches? :: ) instance?(condition, handler-type(_handler)) & begin let test = handler-test(_handler); ~test | test(condition) end end method handler-matches?; define method error (condition :: , #rest noise) => (will-never-return :: ) unless (noise.empty?) error("Can only supply format arguments when supplying a format string.") end unless; signal(condition); // (invoke-debugger cond) error("Error may not return"); end method error; define method default-handler (condition :: ) #f end method default-handler; /// SERIOUS CONDITIONS define open abstract class () end class ; define method default-handler (condition :: ) condition.invoke-debugger; #f end method default-handler; /// ERRORS define open abstract class () end class ; define open class (, ) end class ; define method error (string :: , #rest arguments) => (will-never-return :: ) error(make(, format-string: string, format-arguments: arguments)) end method error; /// WARNINGS define open abstract class () end class ; define open class (, ) end class ; define method signal (string :: , #rest arguments) signal(make(, format-string: string, format-arguments: arguments)) end method signal; /// LAST-HANDLER /// /// ---*** put in "*last-handler* := #f;" for patching define macro last-handler-definer { define last-handler (?condition:expression, ?args:*) = ?handler:expression } => { *last-handler* := #f; add-last-handler(make-last-handler(?condition, ?handler, ?args)) } { define last-handler ?condition:* = ?handler:expression } => { *last-handler* := #f; add-last-handler(make-last-handler(?condition, ?handler)) } { define last-handler } => { *last-handler* := #f; remove-last-handler() } condition: // hack to avoid eating "=" and RHS { ?expression:expression } => { ?expression } end macro last-handler-definer; define function default-last-handler-test (condition :: ) => (handle? :: ) ignore(condition); ~inside-debugger?() end function default-last-handler-test; define function make-last-handler (type, function, #key test = default-last-handler-test, init-arguments) make-handler(type, function, test: test, init-arguments: init-arguments) end function make-last-handler; // EOF