PageRenderTime 59ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

/SK8/07-Objects/02-Object System Core/SK8-error-system.lisp

https://bitbucket.org/pablomarx/sk8r
Lisp | 391 lines | 135 code | 32 blank | 224 comment | 1 complexity | 5ca9a7bb10b6c2f5a76401c82f81021a MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception
  1. ;;; SK8 Š 1997 by Apple Computer, Inc.
  2. ;;; The code in this file is protected under the terms of the current SK8 License.
  3. ;;; For information on this license, see http://sk8.research.apple.com
  4. ;;; Apple Computer, Inc. -- Apple Research Laboratories
  5. (in-package :SK8DEV)
  6. #|
  7. Implementation of the SK8 error (condition) system:
  8. The CommonLisp spec says that error conditions are supposed to be signaled via a call
  9. to error, and not simply by calling signal. MCL gives us a hook for calls to error
  10. that are not handled, by letting us define an application-error method on our application
  11. class. If we assume that error conditions we are interested in are always signaled via error
  12. and that the MCL code that is running will not set up any handlers, then we can implement
  13. a SK8 condition system as follows:
  14. In application-error, look up the condition being passed in to find the corresponding
  15. SK8 condition object. If one is found, SK8-Signal that SK8 condition, passing it the
  16. Lisp condition instance.
  17. The lookup can be done by setting up a hash table that maps Lisp conditions to their
  18. corresponding SK8 conditions. The table is fixed and is built at SK8 build time. Only
  19. those SK8 condition objects will take a Lisp condition instance as an argument to
  20. SK8-Signal and each will have a definition of a method that copies property values from
  21. the Lisp condition instance to the SK8 condition object.
  22. SK8-Signal looks a lot like the MCL implementation of Signal. It goes through a list in
  23. a global (like %handlers%) popping items and looking for one that refers to a condition
  24. that is an ancestor of the one being signalled. The elements of the list are unique conses
  25. that are catch tags, set where the condition handler is defined. The first one that is
  26. found is thrown to.
  27. The on error form sets up a catch and pushes the catch tag on the global that is used
  28. for the purpose. To make threads work, the global must be separately bound in each thread.
  29. A SK8Script on error form compiles into code similar to handler-case. The generated code
  30. produces a cons containing the symbol name of the condition, binds the global, pushes it
  31. on the global and sets up a catch with the cons as the tag. It isn't necessary for the
  32. condition object to exist at SK8Script compile time if the name will be used as the
  33. object name.
  34. |#
  35. #| Here is the error hierarchy as was defined in SK8 0.9, for reference
  36. (SK8::Error SK8::Condition errorID)
  37. (SK8::GeneralError SK8::Error strings objects)
  38. (SK8::ScriptSyntaxError SK8::Error input errorPosition description)
  39. (SK8::ArithmeticError SK8::Error operation operands)
  40. (SK8::ProgrammaticError SK8::Error )
  41. (SK8::GeneralProgrammaticError SK8::ProgrammaticError )
  42. (SK8::DisposedObjectError SK8::ProgrammaticError object)
  43. (SK8::EventModeError SK8::ProgrammaticError eventMode)
  44. (SK8::TypeMismatchError SK8::ProgrammaticError object expectedType)
  45. (SK8::PropertyTypeMismatchError SK8::TypeMismatchError ownerObject propertyName)
  46. (SK8::ArgumentTypeMismatchError SK8::TypeMismatchError handlerName argumentName)
  47. (SK8::FileSystemError SK8::Error )
  48. (SK8::FileError SK8::FileSystemError file)
  49. (SK8::ProjectImproperlyClosedError SK8::FileError )
  50. (SK8::SystemError SK8::Error )
  51. (SK8::ConditionSystemError SK8::SystemError originalCondition response #~errorCause)
  52. (SK8::MemoryFullError SK8::SystemError )
  53. (SK8::UnknownError SK8::SystemError arguments)
  54. (SK8::CompilationError SK8::Error )))
  55. (SK8::UnboundVariableError SK8::ProgrammaticError variableName)
  56. (SK8::UndefinedHandlerError SK8::ProgrammaticError handlerName arguments)
  57. (SK8::IncorrectArgumentsError SK8::ProgrammaticError arguments handlerName)
  58. (SK8::IncorrectSubscriptsError SK8::ProgrammaticError array rank)
  59. (SK8::IndexOutOfBoundsError SK8::ProgrammaticError index array
  60. (SK8::CoercionError SK8::ProgrammaticError object type)
  61. (SK8::NotAHandlerError SK8::ProgrammaticError object)
  62. (SK8::CantChangeConstantError SK8::ProgrammaticError constantName)
  63. (SK8::DivisionByZeroError SK8::ArithmeticError )
  64. (SK8::ArithmeticOverflowError SK8::ArithmeticError )
  65. (SK8::OSHeapFullError SK8::MemoryFullError )
  66. (SK8::FileMemoryFullError SK8::MemoryFullError )
  67. (SK8::SK8HeapFullError SK8::MemoryFullError )
  68. (SK8::StackOverflowError SK8::MemoryFullError )
  69. (SK8::NumberMemoryFullError SK8::MemoryFullError )
  70. (SK8::FileNotFoundError SK8::FileError file)
  71. (SK8::EndOfFileError SK8::FileError file)
  72. (SK8::IllegalFilenameError SK8::FileError file)
  73. (SK8::IODriverError SK8::SystemError )
  74. (SK8::DiskError SK8::FileSystemError disk)
  75. (SK8::ClockError SK8::SystemError )
  76. (SK8::SerialPortError SK8::SystemError )
  77. (SK8::AppleTalkError SK8::SystemError )
  78. (SK8::ScrapManagerError SK8::SystemError )
  79. (SK8::MemoryManagerError SK8::SystemError )
  80. (SK8::DirectoryError SK8::FileSystemError SK8::directory)
  81. (SK8::MenuManagerError SK8::SystemError )
  82. (SK8::ResourceError SK8::SystemError )
  83. (SK8::SoundManagerError SK8::SystemError )
  84. (SK8::PPCToolboxError SK8::SystemError )
  85. (SK8::AppleEventError SK8::SystemError oserr)
  86. (SK8::MovieError SK8::SystemError )
  87. (SK8::MovieDataHandlerError SK8::MovieError )
  88. (SK8::ComponentManagerError SK8::SystemError )
  89. (SK8::ImageCompressionError SK8::SystemError )
  90. (SK8::MovieSequenceGrabberError SK8::MovieError )
  91. (SK8::MovieControllerError SK8::MovieError )
  92. |#
  93. ;; define the condition system
  94. (new object :objectname "Condition" :project sk8 :properties '(sk8::MCLCondition))
  95. (new SK8:Condition :objectname "Error" :project SK8)
  96. (new SK8:Error :objectname "GeneralError" :project SK8 :properties '(sk8::strings sk8::objects))
  97. (new SK8:Error :objectname "ArithmeticError" :project SK8 :properties '(sk8::operation sk8::operands))
  98. (new SK8:GeneralError :objectname "ProgrammaticError" :project SK8)
  99. (new SK8:ProgrammaticError :objectname "GeneralProgrammaticError" :project SK8)
  100. (new SK8:ProgrammaticError :objectname "DisposedObjectError" :project SK8 :properties '(sk8::object))
  101. (new SK8:ProgrammaticError :objectname "EventModeError" :project SK8 :properties '(sk8::eventMode))
  102. (new SK8:ProgrammaticError :objectname "TypeMismatchError" :project SK8 :properties '(sk8::object sk8::expectedType))
  103. (new SK8:TypeMismatchError :objectname "PropertyTypeMismatchError" :project SK8 :properties '(sk8::ownerObject sk8::propertyName))
  104. (new SK8:TypeMismatchError :objectname "ArgumentTypeMismatchError" :project SK8 :properties '(sk8::handlerName sk8::argumentName))
  105. (new SK8:Error :objectname "FileSystemError" :project SK8)
  106. (new SK8:FileSystemError :objectname "FileError" :project SK8 :properties '(sk8::file))
  107. (new SK8:FileError :objectname "ProjectImproperlyClosedError" :project SK8)
  108. (new SK8:Error :objectname "SystemError" :project SK8)
  109. (new SK8:SystemError :objectname "MemoryFullError" :project SK8)
  110. (new SK8:SystemError :objectname "UnknownError" :project SK8 :properties '(sk8::arguments))
  111. (new SK8:Error :objectname "CompilationError" :project SK8)
  112. (new SK8:ProgrammaticError :objectname "UnboundVariableError" :project SK8 :properties '(sk8::variableName))
  113. (new SK8:ProgrammaticError :objectname "UndefinedHandlerError" :project SK8 :properties '(sk8::handlerName sk8::arguments))
  114. (new SK8:ProgrammaticError :objectname "IncorrectArgumentsError" :project SK8 :properties '(sk8::arguments sk8::handlerName))
  115. (new SK8:ProgrammaticError :objectname "IncorrectSubscriptsError" :project SK8 :properties '(sk8::array sk8::rank))
  116. (new SK8:ProgrammaticError :objectname "IndexOutOfBoundsError" :project SK8 :properties '(sk8::index sk8::array))
  117. (new SK8:ProgrammaticError :objectname "CoercionError" :project SK8 :properties '(sk8::object sk8::type))
  118. (new SK8:ProgrammaticError :objectname "NotAHandlerError" :project SK8)
  119. (new SK8:ProgrammaticError :objectname "CantChangeConstantError" :project SK8 :properties '(sk8::constantName))
  120. (new SK8:ArithmeticError :objectname "DivisionByZeroError" :project SK8)
  121. (new SK8:ArithmeticError :objectname "ArithmeticOverflowError" :project SK8)
  122. (new SK8:MemoryFullError :objectname "OSHeapFullError" :project SK8)
  123. (new SK8:MemoryFullError :objectname "FileMemoryFullError" :project SK8)
  124. (new SK8:MemoryFullError :objectname "SK8HeapFullError" :project SK8)
  125. (new SK8:MemoryFullError :objectname "StackOverflowError" :project SK8)
  126. (new SK8:MemoryFullError :objectname "NumberMemoryFullError" :project SK8)
  127. (new SK8:FileError :objectname "FileNotFoundError" :project SK8)
  128. (new SK8:FileError :objectname "EndOfFileError" :project SK8)
  129. (new SK8:FileError :objectname "IllegalFilenameError" :project SK8)
  130. (new SK8:SystemError :objectname "IODriverError" :project SK8)
  131. (new SK8:FileSystemError :objectname "DiskError" :project SK8 :properties '(sk8::disk))
  132. (new SK8:SystemError :objectname "ClockError" :project SK8)
  133. (new SK8:SystemError :objectname "SerialPortError" :project SK8)
  134. (new SK8:SystemError :objectname "AppleTalkError" :project SK8)
  135. (new SK8:SystemError :objectname "ScrapManagerError" :project SK8)
  136. (new SK8:SystemError :objectname "MemoryManagerError" :project SK8)
  137. (new SK8:FileSystemError :objectname "DirectoryError" :project SK8 :properties '(SK8::directory))
  138. (new SK8:SystemError :objectname "MenuManagerError" :project SK8)
  139. (new SK8:SystemError :objectname "ResourceError" :project SK8)
  140. (new SK8:SystemError :objectname "SoundManagerError" :project SK8)
  141. (new SK8:SystemError :objectname "PPCToolboxError" :project SK8)
  142. (new SK8:SystemError :objectname "AppleEventError" :project SK8 :properties '(sk8::oserr))
  143. (new SK8:SystemError :objectname "MovieError" :project SK8)
  144. (new SK8:MovieError :objectname "MovieDataHandlerError" :project SK8)
  145. (new SK8:SystemError :objectname "ComponentManagerError" :project SK8)
  146. (new SK8:SystemError :objectname "ImageCompressionError" :project SK8)
  147. (new SK8:MovieError :objectname "MovieSequenceGrabberError" :project SK8)
  148. (new SK8:MovieError :objectname "MovieControllerError" :project SK8)
  149. ;; map MCL conditions to corresponding SK8 conditions.
  150. ;; The simplest way is to just set the MCLCondition property. That's enough to cause the SK8 error handling
  151. ;; system to catch the error properly and to use the MCL report-condition to generate the error message.
  152. ;; If you want the SK8Script error handler to have access to the condition's properties, you also have
  153. ;; to set them from the MCL condition's corresponding instance variables.
  154. ;; If that is not done in any of the following it is simply because I did not take the time to do it all.
  155. ;; Feel free to contribute.
  156. (defmethod condition-to-sk8-condition ((c error))
  157. (new sk8:error :project sk8 :MCLCondition c))
  158. (defmethod condition-to-sk8-condition ((c type-error))
  159. (new sk8:TypeMismatchError :project sk8 :MCLCondition c))
  160. (defmethod condition-to-sk8-condition ((c program-error))
  161. (new sk8:ProgrammaticError :project sk8 :MCLCondition c))
  162. (defmethod condition-to-sk8-condition ((c simple-error))
  163. (new sk8:GeneralError :project sk8 :MCLCondition c))
  164. (defmethod condition-to-sk8-condition ((c simple-type-error))
  165. (new sk8:TypeMismatchError :project sk8 :MCLCondition c))
  166. (defmethod condition-to-sk8-condition ((c ccl::simple-program-error))
  167. (new sk8:ProgrammaticError :project sk8 :MCLCondition c))
  168. (defmethod condition-to-sk8-condition ((c ccl::compile-time-error))
  169. (new sk8:CompilationError :project sk8 :MCLCondition c))
  170. (defmethod condition-to-sk8-condition ((c end-of-file))
  171. (new sk8:EndOfFileError :project sk8 :MCLCondition c))
  172. (defmethod condition-to-sk8-condition ((c file-error))
  173. (new sk8:FileSystemError :project sk8 :MCLCondition c))
  174. (defmethod condition-to-sk8-condition ((c unbound-variable))
  175. (new sk8:UnboundVariableError :project sk8 :MCLCondition c))
  176. (defmethod condition-to-sk8-condition ((c undefined-function))
  177. (new sk8:UndefinedHandlerError :project sk8 :MCLCondition c))
  178. (defmethod condition-to-sk8-condition ((c ccl::undefined-function-call))
  179. (new sk8:UndefinedHandlerError :project sk8 :MCLCondition c))
  180. (defmethod condition-to-sk8-condition ((c arithmetic-error))
  181. (new sk8:ArithmeticError :project sk8 :MCLCondition c))
  182. (defmethod condition-to-sk8-condition ((c division-by-zero))
  183. (new sk8:DivisionByZeroError :project sk8 :MCLCondition c))
  184. (defmethod condition-to-sk8-condition ((c floating-point-overflow))
  185. (new sk8:ArithmeticOverflowError :project sk8 :MCLCondition c))
  186. (defmethod condition-to-sk8-condition ((c appleevent-error))
  187. (new sk8:AppleEventError :project sk8 :MCLCondition c))
  188. #|
  189. type-error TypeMismatchError
  190. program-error ProgrammaticError
  191. simple-error GeneralError
  192. simple-type-error TypeMismatchError
  193. ccl::simple-program-error ProgrammaticError
  194. simple-destructuring-error
  195. compile-time-program-error
  196. eval-program-error
  197. ccl::compile-time-error CompilationError
  198. control-error
  199. package-error
  200. no-such-package
  201. unintern-conflict-error
  202. import-conflict-error
  203. use-package-conflict-error
  204. export-conflict-error
  205. package-name-conflict-error simple-error
  206. stream-error
  207. end-of-file EndOfFileError
  208. modify-read-only-buffer
  209. file-error FileSystemError
  210. cell-error
  211. unbound-variable UnboundVariableError
  212. undefined-function UndefinedHandlerError
  213. ccl::undefined-function-call UndefinedHandlerError
  214. arithmetic-error ArithmeticError
  215. division-by-zero DivisionByZeroError
  216. floating-point-underflow
  217. floating-point-overflow ArithmeticOverflowError
  218. inexact-result
  219. invalid-operation
  220. appleevent-error AppleEventError
  221. eval-cant-cope
  222. simple-reader-error
  223. |#
  224. #|
  225. ;;; Build the heirarchy of condition objects.
  226. (loop for (name from-obj mcl-error)
  227. in '(("Error" SK8:Condition error)
  228. ("GeneralError" SK8:Error simple-error)
  229. ("ScriptSyntaxError" SK8:Error simple-error)
  230. ("ArithmeticError" SK8:Error arithmetic-error)
  231. ("ProgrammaticError" SK8:GeneralError simple-error)
  232. ("GeneralProgrammaticError" SK8:ProgrammaticError simple-error)
  233. ("DisposedObjectError" SK8:ProgrammaticError simple-error)
  234. ("EventModeError" SK8:ProgrammaticError simple-error)
  235. ("TypeMismatchError" SK8:ProgrammaticError type-error)
  236. ("PropertyTypeMismatchError" SK8:TypeMismatchError type-error)
  237. ("ArgumentTypeMismatchError" SK8:TypeMismatchError type-error)
  238. ("FileSystemError" SK8:Error file-error)
  239. ("FileError" SK8:FileSystemError file-error)
  240. ("ProjectImproperlyClosedError" SK8:FileError simple-error)
  241. ("SystemError" SK8:Error simple-error)
  242. ("ConditionSystemError" SK8:SystemError simple-error)
  243. ("MemoryFullError" SK8:SystemError simple-error)
  244. ("UnknownError" SK8:SystemError error)
  245. ("CompilationError" SK8:Error CCL::compile-time-error)
  246. ("UnboundVariableError" SK8:ProgrammaticError unbound-variable)
  247. ("UndefinedHandlerError" SK8:ProgrammaticError ccl::undefined-function-call)
  248. ("IncorrectArgumentsError" SK8:ProgrammaticError simple-error)
  249. ("IncorrectSubscriptsError" SK8:ProgrammaticError simple-error)
  250. ("IndexOutOfBoundsError" SK8:ProgrammaticError simple-error)
  251. ("CoercionError" SK8:ProgrammaticError simple-error)
  252. ("NotAHandlerError" SK8:ProgrammaticError CCL::undefined-function-call)
  253. ("CantChangeConstantError" SK8:ProgrammaticError simple-error)
  254. ("DivisionByZeroError" SK8:ArithmeticError division-by-zero)
  255. ("ArithmeticOverflowError" SK8:ArithmeticError floating-point-error)
  256. ("OSHeapFullError" SK8:MemoryFullError simple-error)
  257. ("FileMemoryFullError" SK8:MemoryFullError simple-error)
  258. ("SK8HeapFullError" SK8:MemoryFullError simple-error)
  259. ("StackOverflowError" SK8:MemoryFullError simple-error)
  260. ("NumberMemoryFullError" SK8:MemoryFullError simple-error)
  261. ("FileNotFoundError" SK8:FileError simple-error)
  262. ("EndOfFileError" SK8:FileError end-of-file)
  263. ("IllegalFilenameError" SK8:FileError simple-error)
  264. ("IODriverError" SK8:SystemError simple-error)
  265. ("DiskError" SK8:FileSystemError simple-error)
  266. ("ClockError" SK8:SystemError simple-error)
  267. ("SerialPortError" SK8:SystemError simple-error)
  268. ("AppleTalkError" SK8:SystemError simple-error)
  269. ("ScrapManagerError" SK8:SystemError simple-error)
  270. ("MemoryManagerError" SK8:SystemError simple-error)
  271. ("DirectoryError" SK8:FileSystemError simple-error)
  272. ("MenuManagerError" SK8:SystemError simple-error)
  273. ("ResourceError" SK8:SystemError simple-error)
  274. ("SoundManagerError" SK8:SystemError simple-error)
  275. ("PPCToolboxError" SK8:SystemError simple-error)
  276. ("AppleEventError" SK8:SystemError appleevent-error)
  277. ("MovieError" SK8:SystemError simple-error)
  278. ("MovieDataHandlerError" SK8:MovieError simple-error)
  279. ("ComponentManagerError" SK8:SystemError simple-error)
  280. ("ImageCompressionError" SK8:SystemError simple-error)
  281. ("MovieSequenceGrabberError" SK8:MovieError simple-error)
  282. ("MovieControllerError" SK8:MovieError simple-error))
  283. doing (new (symbol-value from-obj) :project sk8 :objectname name :mcl-error-class mcl-error))
  284. |#
  285. (defvar %error-handlers% nil)
  286. ;;; The SK8 user function to signal a condition.
  287. ;;; This mates with the on-condition compiler in compile-let-forms in skil-compiler.lisp.
  288. ;;;
  289. (define-handler sk8-signal (sk8:condition)
  290. (dolist (tag %error-handlers%)
  291. (loop for (cond fn) on tag by #'cddr
  292. doing
  293. (when (and (symbolp cond) (boundp cond) (sk8:inheritsfrom me (symbol-value cond)))
  294. (cond ((null fn) (throw tag me)) ;; with-sk8-error-handler with one error clause
  295. ((fixnump fn) (throw tag (cons fn me))) ;; with-sk8-error-handler with multiple error clause: generates one catch tag which dipatches on the index
  296. (t (return (funcall fn me)))) ;; copied from CLOS condition system. Not used in SK8 yet so should never execute
  297. )))
  298. ;; Okay, no SK8 signal handlers. Just return. If this is an an error, the default error handling will take it
  299. )
  300. (define-sk8-function sk8::sk8-error nil (type &rest args)
  301. (when (inheritsfrom type sk8:condition)
  302. (let ((cnd (apply #'new type :project sk8 args)))
  303. (sk8-signal cnd)
  304. ;; it is an error if it returns
  305. (error (with-output-to-string (s) (writeobject cnd s nil))))))
  306. ;; here is the form generated by the skil compiler for on error code. It is similar to handler-case
  307. (defmacro sk8::with-sk8-error-handlers (form &rest clauses)
  308. (cond ((null clauses) form)
  309. ((null (cdr clauses))
  310. (let ((block (gensym))
  311. (cluster (gensym)))
  312. (let ((type (caar clauses))
  313. (body (cdar clauses)))
  314. `(block ,block
  315. ((lambda (currentCondition) (declare (special currentCondition)) ,@body)
  316. (let* ((,cluster (list ',type))
  317. (%error-handlers% (cons ,cluster %error-handlers%)))
  318. (declare (dynamic-extent ,cluster %error-handlers%))
  319. (catch ,cluster (return-from ,block ,form))))))))
  320. (t (let ((block (gensym)) (cluster (gensym)) (val (gensym))
  321. (index -1) handlers cases)
  322. (loop (unless clauses (return nil))
  323. (setq index (1+ index))
  324. (let* ((clause (pop clauses))
  325. (type (car clause))
  326. (body (cdr clause)))
  327. (push `',type handlers)
  328. (push index handlers)
  329. (when (null clauses) (setq index t))
  330. (push `(,index ((lambda (currentCondition) (declare (special currentCondition)) ,@body) ,val)) cases)))
  331. `(block ,block
  332. (let ((,val (let* ((,cluster (list ,@(nreverse handlers)))
  333. (%error-handlers% (cons ,cluster %error-handlers%)))
  334. (declare (dynamic-extent ,cluster %error-handlers%))
  335. (catch ,cluster (return-from ,block ,form)))))
  336. (case (pop ,val)
  337. ,@(nreverse cases))))))))
  338. #|
  339. Change History (most recent last):
  340. 2 10/18/96 sidney Implement a SK8 error system
  341. 3 10/18/96 sidney create the anonymous error objects in the SK8 project. Make sk8-error an error if it returns
  342. 4 2/27/97 Hernan
  343. 5 2/27/97 Hernan
  344. |# ;(do not edit past this line!!)