menu.scm 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. ; Copyright (c) 1993-2008 by Richard Kelsey and Jonathan Rees. See file COPYING.
  2. ; This breaks abstractions left and right.
  3. ; Inspector state:
  4. ; menu ; cached result of (prepare-menu thing). This is a list of
  5. ; lists (<name-or-#f> <value>).
  6. ; position ; position within menu; modified by M (more) command
  7. ; stack ; list of other things
  8. ;
  9. ; The current thing being inspected is the focus object.
  10. (define (current-menu)
  11. (or (maybe-menu)
  12. (let ((menu (prepare-menu (focus-object))))
  13. (set-menu! menu)
  14. (set-menu-position! 0)
  15. menu)))
  16. (define (present-menu)
  17. (let ((menu (current-menu))) ; may set menu position
  18. (display-menu menu
  19. (menu-position)
  20. (command-output))))
  21. (define (present-more-menu)
  22. (let* ((menu (current-menu))
  23. (position (menu-position)))
  24. (if (> (menu-length menu)
  25. (+ (inspector-menu-limit) position))
  26. (begin
  27. (set-menu-position! (- (+ position
  28. (inspector-menu-limit))
  29. 1))
  30. (present-menu))
  31. (write-line "There is no more." (command-output)))))
  32. ;----------------
  33. ; These two are used by the inspector.
  34. (define (current-menu-length)
  35. (menu-length (current-menu)))
  36. (define (current-menu-ref n)
  37. (cadar (menu-refs (current-menu) n 1)))
  38. ; The menu ADT has two functions, length and refs. A menu is a list
  39. ; (<length> <refs-function>)
  40. (define (menu-length menu)
  41. (car menu))
  42. ; Return a list of the next COUNT items starting from N, where each items is
  43. ; a list (<name-or-#f> <thing>). The returned list may be shorter than N if
  44. ; there aren't N possible items, or longer, for no reason at all.
  45. (define (menu-refs menu n count)
  46. ((cadr menu) n count))
  47. (define (list->menu items)
  48. (list (length items)
  49. (lambda (i count)
  50. (list-tail items i))))
  51. (define (long-list->menu contents length)
  52. (list length
  53. (lambda (start count)
  54. (do ((i 0 (+ i 1))
  55. (contents (list-tail contents start) (cdr contents))
  56. (r '() (cons (list #f (car contents)) r)))
  57. ((or (= i count)
  58. (null? contents))
  59. (reverse r))))))
  60. (define (indexed->menu thing length ref)
  61. (list length
  62. (lambda (start count)
  63. (do ((i 0 (+ i 1))
  64. (r '() (cons (list #f (ref thing (+ start i))) r)))
  65. ((or (= i count)
  66. (= (+ i start) length))
  67. (reverse r))))))
  68. ; Get a menu for THING. We know about a fixed set of types.
  69. (define (prepare-menu thing)
  70. (cond ((vector? thing)
  71. (indexed->menu thing (vector-length thing) vector-ref))
  72. ((template? thing)
  73. (indexed->menu thing (template-length thing) template-ref))
  74. ((pair? thing)
  75. (let ((length (careful-length thing)))
  76. (if (eq? length 'improper)
  77. (list->menu `((car ,(car thing)) (cdr ,(cdr thing))))
  78. (long-list->menu thing
  79. (if (eq? length 'circular)
  80. 9999999
  81. length)))))
  82. (else
  83. (list->menu
  84. (cond ((closure? thing)
  85. (prepare-environment-menu
  86. (closure-env thing)
  87. (debug-data-env-shape (template-debug-data
  88. (closure-template thing))
  89. #f)))
  90. ((continuation? thing)
  91. (prepare-continuation-menu thing))
  92. ((record? thing)
  93. (prepare-record-menu thing))
  94. ((location? thing)
  95. `((id ,(location-id thing))
  96. (contents ,(contents thing))))
  97. ((cell? thing)
  98. `((ref ,(cell-ref thing))))
  99. ((weak-pointer? thing)
  100. `((ref ,(weak-pointer-ref thing))))
  101. (else '()))))))
  102. (define (careful-length list)
  103. (let loop ((fast list) (len 0) (slow list) (move-slow? #f))
  104. (cond ((eq? '() fast)
  105. len)
  106. ((not (pair? fast))
  107. 'improper)
  108. ((not move-slow?)
  109. (loop (cdr fast) (+ len 1) slow #t))
  110. ((eq? fast slow)
  111. 'circular)
  112. (else
  113. (loop (cdr fast) (+ len 1) (cdr slow) #f)))))
  114. ; Some values in the operand stack are vectors that represent either the
  115. ; saved environment or a newly created one for recursive procedures.
  116. ; The debug data has names for some values in the stack and for those
  117. ; in the environments.
  118. (define (prepare-continuation-menu thing)
  119. (let ((shape (debug-data-env-shape (continuation-debug-data thing)
  120. (continuation-pc thing)))
  121. (args (do ((i 0 (+ i 1))
  122. (v '() (cons (continuation-arg thing i) v)))
  123. ((= i (continuation-arg-count thing))
  124. v))))
  125. (extend-cont-menu 0 args shape '())))
  126. (define (extend-cont-menu i args shape menu)
  127. (if (null? args)
  128. menu
  129. (let ((names (assq i shape)))
  130. (if (and names
  131. (not (null? (cdr names))))
  132. (extend-cont-menu-with-names (cdr names) i args shape menu)
  133. (extend-cont-menu (+ i 1)
  134. (cdr args)
  135. shape
  136. (cons (list #f (car args))
  137. menu))))))
  138. (define (extend-cont-menu-with-names names i args shape menu)
  139. (cond ((null? names)
  140. (extend-cont-menu i args shape menu))
  141. ((pair? (car names))
  142. (let ((values (car args)))
  143. (do ((ns (car names) (cdr ns))
  144. (j 0 (+ j 1))
  145. (menu menu (cons (list (car ns) (vector-ref values j))
  146. menu)))
  147. ((null? ns)
  148. (extend-cont-menu-with-names (cdr names)
  149. (+ i 1)
  150. (cdr args)
  151. shape
  152. menu)))))
  153. (else
  154. (extend-cont-menu-with-names (cdr names)
  155. (+ i 1)
  156. (cdr args)
  157. shape
  158. (cons (list (car names) (car args))
  159. menu)))))
  160. (define (continuation-debug-data thing)
  161. (let ((template (continuation-template thing)))
  162. (if template
  163. (template-debug-data template)
  164. #f)))
  165. ; Records that have record types get printed with the names of the fields.
  166. (define (prepare-record-menu thing)
  167. (let ((rt (record-type thing))
  168. (z (record-length thing)))
  169. (if (record-type? rt)
  170. (do ((i (- z 1) (- i 1))
  171. (f (reverse (record-type-field-names rt)) (cdr f))
  172. (l '() (cons (list (car f) (record-ref thing i)) l)))
  173. ((< i 1) l))
  174. (do ((i (- z 1) (- i 1))
  175. (l '() (cons (list #f (record-ref thing i)) l)))
  176. ((< i 0) l)))))
  177. ; We may have the names (`shape') for environments, in which case they
  178. ; are used in the menus.
  179. (define (prepare-environment-menu env shape)
  180. (if (vector? env)
  181. (let ((values (rib-values env)))
  182. (if (pair? shape)
  183. (append (map list (car shape) values)
  184. (prepare-environment-menu (vector-ref env 0)
  185. (cdr shape)))
  186. (append (map (lambda (x)
  187. (list #f x))
  188. values)
  189. (prepare-environment-menu (vector-ref env 0)
  190. shape))))
  191. '()))
  192. (define (rib-values env)
  193. (let ((z (vector-length env)))
  194. (do ((i 0 (+ i 1))
  195. (l '() (cons (if (vector-unassigned? env i)
  196. 'unassigned
  197. (vector-ref env i))
  198. l)))
  199. ((>= i z)
  200. (reverse l)))))
  201. ;----------------
  202. ; Printing menus.
  203. ;
  204. ; If the current thing is a continuation we print its source code first.
  205. ; Then we step down the menu until we run out or we reach the menu limit.
  206. (define (display-menu menu start port)
  207. (newline port)
  208. (maybe-display-source (focus-object) #f)
  209. (let ((items (menu-refs menu start (+ (inspector-menu-limit) 1)))
  210. (limit (+ start (inspector-menu-limit))))
  211. (let loop ((i start) (items items))
  212. (with-limited-output
  213. (lambda ()
  214. (cond ((null? items))
  215. ((and (>= i limit)
  216. (not (null? items)))
  217. (display " [m] more..." port) (newline port))
  218. (else
  219. (let ((item (car items)))
  220. (display " [" port)
  221. (write i port)
  222. (if (car item)
  223. (begin (display ": " port)
  224. (write-carefully (car item) port)))
  225. (display "] " port)
  226. (write-carefully
  227. (value->expression (cadr item))
  228. port)
  229. (newline port)
  230. (loop (+ i 1) (cdr items))))))))))
  231. ; Exception continuations don't have source, so we get the source from
  232. ; the next continuation if it is from the same procedure invocation.
  233. (define (maybe-display-source thing vm-exception?)
  234. (cond ((not (continuation? thing))
  235. (values))
  236. ((vm-exception-continuation? thing)
  237. (let ((next (continuation-cont thing)))
  238. (if (not (eq? next (continuation-cont thing)))
  239. (maybe-display-source next #t))))
  240. (else
  241. (let ((dd (continuation-debug-data thing)))
  242. (if dd
  243. (let ((source (assoc (continuation-pc thing)
  244. (debug-data-source dd))))
  245. (if source
  246. (display-source-info (cdr source) vm-exception?))))))))
  247. ; Show the source code for a continuation, if we have it.
  248. (define (display-source-info info vm-exception?)
  249. (let ((o-port (command-output)))
  250. (if (pair? info)
  251. (let ((exp (car info)))
  252. (display (if vm-exception?
  253. "Next call is "
  254. "Waiting for ")
  255. o-port)
  256. (limited-write exp o-port
  257. (inspector-writing-depth)
  258. (inspector-writing-length))
  259. (newline o-port)
  260. (if (and (pair? (cdr info))
  261. (integer? (cadr info)))
  262. (let ((i (cadr info))
  263. (parent (cddr info)))
  264. (display " in " o-port)
  265. (limited-write (append (sublist parent 0 i)
  266. (list '^^^)
  267. (list-tail parent (+ i 1)))
  268. o-port
  269. (inspector-writing-depth)
  270. (inspector-writing-length))
  271. (newline o-port)))))))
  272. ;----------------
  273. ; Selection commands
  274. (define (selection-command? x)
  275. (or (integer? x)
  276. (memq x '(u d template))))
  277. ;----------------
  278. ; I/O Utilities
  279. (define $write-depth (make-fluid -1))
  280. (define $write-length (make-fluid -1))
  281. (define (with-limited-output thunk . limits)
  282. (let-fluids $write-length (if (pair? limits)
  283. (car limits)
  284. (inspector-writing-length))
  285. $write-depth (if (and (pair? limits)
  286. (pair? (cdr limits)))
  287. (cadr limits)
  288. (inspector-writing-depth))
  289. thunk))
  290. (define (write-carefully x port)
  291. (if (error? (ignore-errors (lambda ()
  292. (limited-write x port
  293. (fluid $write-depth)
  294. (fluid $write-length))
  295. #f)))
  296. (display "<Error while printing.>" port)))
  297. (define (write-line string port)
  298. (display string port)
  299. (newline port))