debug.scm 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779
  1. ; Copyright (c) 1993-2008 by Richard Kelsey and Jonathan Rees. See file COPYING.
  2. ; Commands for debugging.
  3. ; translate
  4. (define-command-syntax 'translate "<from> <to>"
  5. "establish file name translation"
  6. '(filename filename))
  7. (define translate set-translation!)
  8. ; preview -- show continuations
  9. (define (preview)
  10. (let ((cont (command-continuation)))
  11. (if cont
  12. (display-preview (continuation-preview cont)
  13. (command-output)))))
  14. (define (display-preview preview port)
  15. (for-each (lambda (info+pc)
  16. (if (not (fluid-let-continuation-info? (car info+pc)))
  17. (display-template-names (car info+pc) port)))
  18. preview))
  19. (define (display-template-names info port)
  20. (let ((names (debug-data-names info)))
  21. (display " " port)
  22. (if (null? names)
  23. (begin (display "unnamed " port)
  24. (write `(id ,(if (debug-data? info)
  25. (debug-data-uid info)
  26. info))
  27. port))
  28. (let loop ((names names))
  29. (if (car names)
  30. (write (car names) port)
  31. (display "unnamed" port))
  32. (if (and (not (null? (cdr names)))
  33. (cadr names))
  34. (begin (display " in " port)
  35. (loop (cdr names))))))
  36. (newline port)))
  37. (define fluid-let-continuation-info? ;Incestuous!
  38. (let ((id (let-fluid (make-fluid #f) #f
  39. (lambda ()
  40. (primitive-catch (lambda (k)
  41. (let ((template (continuation-template k)))
  42. (if template
  43. (template-id template)
  44. #f))))))))
  45. (lambda (info)
  46. (eqv? (if (debug-data? info)
  47. (debug-data-uid info)
  48. info)
  49. id))))
  50. (define-command-syntax 'preview ""
  51. "show pending continuations (stack trace)"
  52. '())
  53. ; Proceed
  54. (define (really-proceed vals)
  55. (let* ((level (command-level))
  56. (condition (command-level-condition level)))
  57. (if (ok-to-proceed? condition)
  58. (apply proceed-with-command-level (cadr (command-levels)) vals)
  59. (begin
  60. (write-line "No way to proceed from here." (command-output))
  61. (write condition (command-output))
  62. (newline (command-output))))))
  63. (define-command-syntax 'proceed "<exp>" "proceed after an interrupt or error"
  64. '(&rest expression))
  65. (define (proceed . exps)
  66. (really-proceed (map (lambda (exp)
  67. (eval exp (environment-for-commands)))
  68. exps)))
  69. ; Scrutinize the condition to ensure that it's safe to return from the
  70. ; call to RAISE.
  71. (define (ok-to-proceed? condition)
  72. (and condition
  73. (if (serious-condition? condition)
  74. (and (vm-exception? condition)
  75. (let ((opcode (vm-exception-opcode condition)))
  76. (or (= opcode (enum op global))
  77. (>= opcode (enum op eq?)))))
  78. #t)))
  79. (define (breakpoint . rest)
  80. (command-loop (conditions:condition (make-breakpoint-condition)
  81. (make-who-condition 'breakpoint)
  82. (make-irritants-condition rest))))
  83. (define-condition-type &breakpoint &condition
  84. make-breakpoint-condition breakpoint-condition?)
  85. ; push
  86. (define-command-syntax 'push "" "push command level" '())
  87. (define (push)
  88. (command-loop (if (command-level? (focus-object))
  89. (command-level-condition (focus-object))
  90. #f)))
  91. ; pop (same as ^D (= end-of-file))
  92. (define-command-syntax 'pop "" "pop command level" '())
  93. (define (pop)
  94. (pop-command-level))
  95. ; reset
  96. (define (reset . maybe-level)
  97. (if (null? maybe-level)
  98. (abort-to-command-level (top-command-level))
  99. (go-to-level (car maybe-level))))
  100. (define-command-syntax 'reset "[<number>]"
  101. "restart command level (default level is 0)"
  102. '(&opt expression))
  103. (define (go-to-level n)
  104. (let ((level (find-level n)))
  105. (if level
  106. (abort-to-command-level level)
  107. (write-line "invalid command level" (command-output)))))
  108. ; Old ,level command retained for compatibility.
  109. ; Has no help strings s it won't show up in the ,? list.
  110. (define-command-syntax 'level #f #f '(expression))
  111. (define level go-to-level)
  112. ; Find the Nth command level.
  113. (define (find-level n)
  114. (let ((levels (reverse (command-levels))))
  115. (if (and (integer? n)
  116. (>= n 0)
  117. (< n (length levels)))
  118. (list-ref levels n)
  119. #f)))
  120. ; resume
  121. ; Same as ,reset except that we don't restart the level.
  122. (define (resume . maybe-level)
  123. (let ((level (if (null? maybe-level)
  124. (top-command-level)
  125. (find-level (car maybe-level)))))
  126. (if level
  127. (begin
  128. (if (command-level-paused-thread level)
  129. (kill-paused-thread! level))
  130. (proceed-with-command-level level))
  131. (write-line "invalid command level" (command-output)))))
  132. (define-command-syntax 'resume "[<number>]"
  133. "resume specific command level (default is 0)"
  134. '(&opt expression))
  135. (define-command-syntax 'condition ""
  136. "select an object that describes the current error condition"
  137. '())
  138. (define (condition)
  139. (let ((c (command-level-condition (command-level))))
  140. (if c
  141. (set-command-results! (list c) #t)
  142. (write-line "no condition" (command-output)))))
  143. ; Toggling various boolean flags.
  144. (define-command-syntax 'set "<setting> [<on-or-off-or-literal-or-?>]"
  145. "set the value of a setting (? lists settings)"
  146. '(name &opt literal))
  147. (define-command-syntax 'unset "<setting>"
  148. "set boolean setting to off"
  149. '(name))
  150. (define (set name . maybe-value)
  151. (if (eq? name '?)
  152. (list-settings)
  153. (let* ((setting (lookup-setting name))
  154. (value (cond ((not setting)
  155. (assertion-violation 'set "setting not found" name))
  156. ((null? maybe-value)
  157. (if (setting-boolean? setting)
  158. #t
  159. (assertion-violation 'set "no value specified")))
  160. ((eq? (car maybe-value) '?)
  161. (if (setting-boolean? setting)
  162. (display (if (setting-value setting)
  163. "on, "
  164. "off, ")
  165. (command-output)))
  166. (setting-value setting))
  167. ((setting-boolean? setting)
  168. (case (car maybe-value)
  169. ((off) #f)
  170. ((on) #t)
  171. (else
  172. (assertion-violation
  173. 'set
  174. "invalid value for boolean setting; should be on or off"))))
  175. (else
  176. (car maybe-value))))
  177. (out (command-output)))
  178. (setting-set! setting value)
  179. (display (setting-doc setting) out)
  180. (if (not (setting-boolean? setting))
  181. (begin
  182. (display " is " (command-output))
  183. (write value (command-output))))
  184. (newline out))))
  185. (define (unset name)
  186. (let ((setting (lookup-setting name))
  187. (out (command-output)))
  188. (if (not setting)
  189. (assertion-violation 'unset "setting not found" name)
  190. (setting-set! setting #f))
  191. (display (setting-doc setting) out)
  192. (newline out)))
  193. ; The actual settings.
  194. (define (positive-integer? n)
  195. (and (integer? n)
  196. (exact? n)
  197. (positive? n)))
  198. (add-setting 'batch #t
  199. batch-mode?
  200. set-batch-mode?!
  201. "will not prompt and will exit on errors"
  202. "will prompt and will not exit on errors")
  203. (add-setting 'inline-values #t
  204. (lambda ()
  205. (package-integrate? (environment-for-commands)))
  206. (lambda (b)
  207. (set-package-integrate?! (environment-for-commands) b))
  208. "will compile some calls in line"
  209. "will not compile calls in line")
  210. (add-setting 'break-on-warnings #t
  211. break-on-warnings?
  212. set-break-on-warnings?!
  213. "will enter breakpoint on warnings"
  214. "will not enter breakpoint on warnings")
  215. (add-setting 'load-noisily #t
  216. load-noisily?
  217. set-load-noisily?!
  218. "will notify when loading modules and files"
  219. "will not notify when loading modules and files")
  220. ;(add-setting 'form-preferred #t
  221. ; form-preferred?
  222. ; set-form-preferred?!
  223. ; "commas are required before commands"
  224. ; "commas are not required before commands")
  225. (add-setting 'levels #t
  226. push-command-levels?
  227. set-push-command-levels?!
  228. "will push command level on errors"
  229. "will not push command level on errors")
  230. (add-setting 'inspector-menu-limit positive-integer?
  231. inspector-menu-limit
  232. set-inspector-menu-limit!
  233. "maximum number of menu entries in inspector")
  234. (add-setting 'inspector-writing-depth positive-integer?
  235. inspector-writing-depth
  236. set-inspector-writing-depth!
  237. "maximum writing depth in inspector")
  238. (add-setting 'inspector-writing-length positive-integer?
  239. inspector-writing-length
  240. set-inspector-writing-length!
  241. "maximum writing length in inspector")
  242. (add-setting 'condition-writing-length positive-integer?
  243. condition-writing-length
  244. set-condition-writing-length!
  245. "maximum writing length for conditions")
  246. (add-setting 'condition-writing-depth positive-integer?
  247. condition-writing-depth
  248. set-condition-writing-depth!
  249. "maximum writing depth for conditions")
  250. ; Old toggling commands retained for compatibility
  251. ; These have no help strings.
  252. (define (define-toggle-syntax name help)
  253. (define-command-syntax name #f #f '(&opt name)))
  254. (define (toggle-command name)
  255. (lambda maybe-value
  256. (set name (if (null? maybe-value)
  257. (if (setting-value (or (lookup-setting name)
  258. (assertion-violation 'toggle "setting not found" name)))
  259. 'off
  260. 'on)
  261. (car maybe-value)))))
  262. (define-toggle-syntax 'batch
  263. "enable/disable batch mode (no prompt, errors exit)")
  264. (define batch (toggle-command 'batch))
  265. (define-toggle-syntax 'bench
  266. "enable/disable inlining of primitives")
  267. (define bench (toggle-command 'inline-values))
  268. (define-toggle-syntax 'break-on-warnings
  269. "treat warnings as errors")
  270. (define break-on-warnings (toggle-command 'break-on-warnings))
  271. ;(define-toggle-syntax 'form-preferred
  272. ; "enable/disable form-preferred command processor mode")
  273. ;
  274. ;(define form-preferred (toggle-command 'form-preferred))
  275. (define-toggle-syntax 'levels
  276. "disable/enable command levels")
  277. (define levels (toggle-command 'levels))
  278. ; Flush debug data base
  279. (define-command-syntax 'flush "[<kind> ...]"
  280. "start forgetting debug information
  281. Kind should be one of: names maps files source tabulate
  282. location-names file-packages"
  283. '(&rest name))
  284. (define (flush . kinds)
  285. (cond ((null? kinds)
  286. (write-line "Flushing location names and tabulated debug info"
  287. (command-output))
  288. (flush-location-names)
  289. ((debug-flag-modifier 'table) (make-table)))
  290. (else
  291. (for-each (lambda (kind)
  292. (cond ((memq kind debug-flag-names)
  293. ((debug-flag-modifier kind)
  294. (if (eq? kind 'table) (make-table) #f)))
  295. ((eq? kind 'location-names)
  296. (flush-location-names))
  297. ((eq? kind 'file-packages)
  298. (forget-file-environments))
  299. (else
  300. (write-line "Unrecognized debug flag"
  301. (command-output)))))
  302. kinds))))
  303. ; Control retention of debugging information
  304. (define-command-syntax 'keep "[<kind> ...]"
  305. "start remembering debug information
  306. Kind should be one of: names maps files source tabulate"
  307. '(&rest name))
  308. (define (keep . kinds)
  309. (let ((port (command-output)))
  310. (if (null? kinds)
  311. (for-each (lambda (kind)
  312. (if (not (eq? kind 'table))
  313. (begin
  314. (display (if ((debug-flag-accessor kind))
  315. "+ " "- ")
  316. port)
  317. (display kind port)
  318. (newline port))))
  319. debug-flag-names)
  320. (for-each (lambda (kind)
  321. (if (and (memq kind debug-flag-names)
  322. (not (eq? kind 'table)))
  323. ((debug-flag-modifier kind) #t)
  324. (write-line "Unrecognized debug flag"
  325. port)))
  326. kinds))))
  327. ; Collect some garbage
  328. (define (collect)
  329. (let ((port (command-output))
  330. (available-before (available-memory))
  331. (heap-size-before (heap-size)))
  332. (primitives:collect)
  333. (let ((available-after (available-memory))
  334. (heap-size-after (heap-size)))
  335. (display "Before: " port)
  336. (write available-before port)
  337. (display " out of " port)
  338. (display heap-size-before port)
  339. (display" words available" port)
  340. (newline port)
  341. (display "After: " port)
  342. (write available-after port)
  343. (display " out of " port)
  344. (display heap-size-after port)
  345. (display " words available" port)
  346. (newline port))))
  347. (define (available-memory)
  348. (primitives:memory-status (enum memory-status-option available)
  349. #f))
  350. (define (heap-size)
  351. (primitives:memory-status (enum memory-status-option heap-size)
  352. #f))
  353. (define-command-syntax 'collect "" "invoke the garbage collector" '())
  354. ; Undefined (this is sort of pointless now that NOTING-UNDEFINED-VARIABLES
  355. ; exists)
  356. ;
  357. ;(define (show-undefined-variables)
  358. ; (let ((out (command-output))
  359. ; (undef (undefined-variables (environment-for-commands))))
  360. ; (if (not (null? undef))
  361. ; (begin (display "Undefined: " out)
  362. ; (write undef out)
  363. ; (newline out)))))
  364. ;
  365. ;(define-command-syntax 'undefined "" "list undefined variables"
  366. ; '() show-undefined-variables)
  367. ; Trace and untrace
  368. (define traced-procedures
  369. (user-context-accessor 'traced (lambda () '())))
  370. (define set-traced-procedures!
  371. (user-context-modifier 'traced))
  372. (define (trace . names)
  373. (if (null? names)
  374. (let ((port (command-output)))
  375. (write (map car (traced-procedures)) port)
  376. (newline port))
  377. (for-each trace-1 names)))
  378. (define-command-syntax 'trace "<name> ..."
  379. "trace calls to given procedure(s)"
  380. '(&rest name))
  381. (define (untrace . names)
  382. (if (null? names)
  383. (for-each untrace-1 (map car (traced-procedures)))
  384. (for-each untrace-1 names)))
  385. (define-command-syntax 'untrace "<name> ..." "stop tracing calls"
  386. '(&rest name))
  387. (add-setting 'trace-writing-depth positive-integer?
  388. trace-writing-depth
  389. set-trace-writing-depth!
  390. "writing depth for traces")
  391. ; Trace internals
  392. (define (trace-1 name)
  393. (let* ((env (environment-for-commands))
  394. (proc (environment-ref env name))
  395. (traced (make-traced proc name)))
  396. (set-traced-procedures!
  397. (cons (list name traced proc env)
  398. (traced-procedures)))
  399. (environment-define! env name traced))) ;was environment-set!
  400. ; Should be doing clookup's here -- avoid creating new locations
  401. (define (untrace-1 name)
  402. (let ((probe (assq name (traced-procedures))))
  403. (if probe
  404. (let* ((traced (cadr probe))
  405. (proc (caddr probe))
  406. (env (cadddr probe)))
  407. (if (eq? (environment-ref env name) traced)
  408. (environment-set! env name proc)
  409. (let ((out (command-output)))
  410. (display "Value of " out)
  411. (write name out)
  412. (display " changed since ,trace; not restoring it." out)
  413. (newline out)))
  414. (set-traced-procedures!
  415. (filter (lambda (x)
  416. (not (eq? (car x) name)))
  417. (traced-procedures))))
  418. (write-line "?" (command-output)))))
  419. (define (make-traced proc name)
  420. (lambda args
  421. (apply-traced proc name args)))
  422. (define (apply-traced proc name args)
  423. (let ((port (command-output)))
  424. (dynamic-wind
  425. (lambda ()
  426. (display "[" port))
  427. (lambda ()
  428. (let ((depth (trace-writing-depth)))
  429. (with-limited-output
  430. (lambda ()
  431. (display "Enter " port)
  432. (write-carefully (error-form name args) port)
  433. (newline port))
  434. depth depth)
  435. (call-with-values (lambda ()
  436. (apply proc args))
  437. (lambda results
  438. (with-limited-output
  439. (lambda ()
  440. (display " Leave " port)
  441. (write-carefully name port)
  442. (for-each (lambda (result)
  443. (display " " port)
  444. (write-carefully (value->expression result) port))
  445. results))
  446. depth
  447. (- depth 1))
  448. (apply values results)))))
  449. (lambda ()
  450. (display "]" port)
  451. (newline port)))))
  452. ; Timer stuff.
  453. (define (time command)
  454. (let ((thunk (if (eq? (car command) 'run)
  455. (eval `(lambda () ,(cadr command))
  456. (environment-for-commands))
  457. (lambda () (execute-command command))))
  458. (port (command-output)))
  459. (let ((start-run-time (run-time))
  460. (start-real-time (real-time)))
  461. (call-with-values thunk
  462. (lambda results
  463. (let ((stop-run-time (run-time))
  464. (stop-real-time (real-time)))
  465. (display "Run time: " port)
  466. (write-hundredths (- stop-run-time start-run-time) port)
  467. (display " seconds; Elapsed time: " port)
  468. (write-hundredths (- stop-real-time start-real-time) port)
  469. (display " seconds" port)
  470. (newline port)
  471. (set-command-results! results)))))))
  472. ; N is in milliseconds
  473. (define (write-hundredths n port)
  474. (let ((n (round (quotient n 10))))
  475. (write (quotient n 100) port)
  476. (write-char #\. port)
  477. (let ((r (remainder n 100)))
  478. (if (< r 10)
  479. (write-char #\0 port))
  480. (write r port))))
  481. ; Copied from rts/time.scm to avoid a dependency.
  482. (define (real-time)
  483. (primitives:time (enum time-option real-time) #f))
  484. (define (run-time)
  485. (primitives:time (enum time-option run-time) #f))
  486. (define-command-syntax 'time "<command>" "measure execution time"
  487. '(command))
  488. ; Support for stuffing things from Emacs.
  489. (define-command-syntax 'from-file #f #f ;"<filename>" "editor support"
  490. '(&opt filename))
  491. (define-command-syntax 'end #f #f
  492. '())
  493. (define (from-file . maybe-filename)
  494. (let* ((filename (if (null? maybe-filename) #f (car maybe-filename)))
  495. (env (let ((probe (if filename
  496. (get-file-environment filename)
  497. #f))
  498. (c (environment-for-commands)))
  499. (if (and probe (not (eq? probe c)))
  500. (let ((port (command-output)))
  501. (newline port)
  502. (display filename port)
  503. (display " => " port)
  504. (write probe port)
  505. (display " " port) ;dots follow
  506. probe)
  507. c)))
  508. (in (command-input))
  509. (forms (let recur ()
  510. (let ((command (read-command #f #t in)))
  511. (if (eof-object? command)
  512. '()
  513. (case (car command)
  514. ((end) '())
  515. ((#f run) (cons (cadr command) (recur)))
  516. (else
  517. (assertion-violation 'from-file
  518. "unusual command in ,from-file ... ,end"
  519. command))))))))
  520. (if (package? env)
  521. (with-interaction-environment env
  522. (lambda ()
  523. (noting-undefined-variables env
  524. (lambda ()
  525. (eval-from-file forms env (if (null? maybe-filename)
  526. #f
  527. (car maybe-filename)))))
  528. (newline (command-output))))
  529. (for-each (lambda (form) (eval form env)) ;Foo
  530. env))))
  531. ; Filename -> environment map.
  532. (define file-environments
  533. (user-context-accessor 'file-environments (lambda () '())))
  534. (define set-file-environments!
  535. (user-context-modifier 'file-environments))
  536. (define (forget-file-environments)
  537. (set-file-environments! '()))
  538. (define (note-file-environment! filename env)
  539. (if (maybe-user-context)
  540. (let* ((translated (filenames:translate filename))
  541. (envs (file-environments))
  542. (probe (or (assoc filename envs) ;What to do?
  543. (assoc translated envs))))
  544. (if probe
  545. (if (not (eq? env (weak-pointer-ref (cdr probe))))
  546. (let ((port (command-output)))
  547. (newline port)
  548. (display "Changing default package for file " port)
  549. (display filename port)
  550. (display " from" port)
  551. (newline port)
  552. (write (weak-pointer-ref (cdr probe)) port)
  553. (display " to " port)
  554. (write env port)
  555. (newline port)
  556. (set-cdr! probe (make-weak-pointer env))))
  557. (set-file-environments!
  558. (cons (cons filename (make-weak-pointer env))
  559. envs))))))
  560. ; Temporary hack until we get default values for unhandled upcalls.
  561. ; This gets called during the building of, say scheme48.image, while
  562. ; there's still the REALLY-SIGNAL-CONDITION from EXCEPTIONS
  563. ; installed---so we make sure we get the right ones.
  564. (define (maybe-user-context)
  565. (call-with-current-continuation
  566. (lambda (exit)
  567. (with-handler (lambda (condition punt)
  568. (if (serious-condition? condition)
  569. (exit #f)
  570. (punt)))
  571. user-context))))
  572. (define (get-file-environment filename)
  573. (let ((probe (assoc filename (file-environments)))) ;translate ?
  574. (if probe
  575. (weak-pointer-ref (cdr probe))
  576. #f)))
  577. (fluid-cell-set! $note-file-package note-file-environment!)
  578. (define-command-syntax 'forget "<filename>"
  579. "forget file/package association"
  580. '(filename))
  581. (define (forget filename)
  582. (note-file-environment! filename #f))
  583. ; ,bound? <name>
  584. (define-command-syntax 'bound? "<name>"
  585. "display binding of name, if any"
  586. '(name))
  587. (define (bound? name)
  588. (let ((port (command-output))
  589. (probe (package-lookup (environment-for-commands) name)))
  590. (if probe
  591. (begin (display "Bound to " port)
  592. (cond ((binding? probe)
  593. (describe-binding probe port))
  594. (else
  595. (write probe port)
  596. (newline port)))
  597. (set-focus-object! probe))
  598. (write-line "Not bound" port))))
  599. (define (describe-binding binding port)
  600. (let ((type (binding-type binding))
  601. (location (binding-place binding))
  602. (static (binding-static binding)))
  603. (display (binding-type-description binding) port)
  604. (write-char #\space port)
  605. (write location port)
  606. (newline port)
  607. (display " Type " port)
  608. (write (type->sexp type #t) port)
  609. (newline port)
  610. (cond (static (display " Static " port)
  611. (write static port)
  612. (newline port)))))
  613. (define (binding-type-description binding)
  614. (let ((type (binding-type binding))
  615. (static (binding-static binding)))
  616. (cond ((variable-type? type) "mutable variable")
  617. ((eq? type undeclared-type) "unknown denotation")
  618. ((subtype? type syntax-type)
  619. (if (transform? static) "macro" "special operator"))
  620. ((primop? static) "primitive procedure")
  621. ((transform? static) "integrated procedure")
  622. (else "variable"))))
  623. ; ,expand <form>
  624. (define-command-syntax 'expand "[<form>]"
  625. "macro-expand a form"
  626. '(&opt expression))
  627. ; Doesn't work - the current syntax interface doesn't have anything that only
  628. ; expands once.
  629. ;(define-command-syntax 'expand-once "[<form>]"
  630. ; "macro-expand a form once"
  631. ; '(&opt expression))
  632. (define (expand . maybe-exp)
  633. (do-expand maybe-exp syntactic:expand-form))
  634. (define (expand-once . maybe-exp)
  635. (do-expand maybe-exp syntactic:expand))
  636. (define (do-expand maybe-exp expander)
  637. (let ((exp (if (null? maybe-exp)
  638. (focus-object)
  639. (car maybe-exp)))
  640. (env (package->environment (environment-for-commands))))
  641. (set-command-results!
  642. (list (schemify (expander exp env)
  643. env)))))