debug.scm 21 KB

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