comp-exp.scm 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777
  1. ; Part of Scheme 48 1.9. See file COPYING for notices and license.
  2. ; Authors: Richard Kelsey, Jonathan Rees, Martin Gasbichler, Mike Sperber
  3. ; Optimizations are marked with +++, and may be flushed if desired.
  4. (define (compile-expression node depth frame cont)
  5. (compile node depth frame cont))
  6. ; Main dispatch for compiling a single expression.
  7. (define (compile node depth frame cont)
  8. (let ((node (type-check node)))
  9. ((operator-table-ref compilators (node-operator-id node))
  10. node
  11. depth
  12. frame
  13. cont)))
  14. ; Specialists
  15. (define compilators
  16. (make-operator-table
  17. (lambda (node depth frame cont)
  18. (generate-trap depth
  19. frame
  20. cont
  21. "not valid in expression context"
  22. (schemify node)))))
  23. (define (define-compilator name type proc)
  24. (operator-define! compilators name type proc))
  25. ;----------------------------------------------------------------
  26. (define-compilator 'literal 'leaf
  27. (lambda (node depth frame cont)
  28. (compile-constant (node-form node) depth frame cont)))
  29. (define-compilator 'quote syntax-type
  30. (lambda (node depth frame cont)
  31. (compile-constant (cadr (node-form node)) depth frame cont)))
  32. (define (compile-constant obj depth frame cont)
  33. (deliver-constant-value (cond ((eq? obj #f)
  34. ;; +++ hack for bootstrap from Schemes that don't
  35. ;; distinguish #f/()
  36. (instruction (enum op false)))
  37. ((small-integer? obj)
  38. (integer-literal-instruction obj))
  39. (else
  40. (stack-indirect-instruction
  41. (template-offset frame depth)
  42. (literal->index frame obj))))
  43. cont))
  44. (define (small-integer? obj)
  45. (and (integer? obj)
  46. (exact? obj)
  47. (<= 0 (+ obj 128))
  48. (< (+ obj 128) byte-limit)))
  49. ; PreScheme does not have signed bytes so we bias OBJ
  50. (define (integer-literal-instruction obj)
  51. (instruction (enum op integer-literal)
  52. (+ obj 128)))
  53. (define-compilator 'unspecific (proc () unspecific-type)
  54. (lambda (node depth frame cont)
  55. (deliver-constant-value (instruction (enum op unspecific))
  56. cont)))
  57. (define-compilator 'unassigned (proc () unspecific-type)
  58. (lambda (node depth frame cont)
  59. (deliver-constant-value (instruction (enum op unassigned))
  60. cont)))
  61. (define (deliver-constant-value segment cont)
  62. (deliver-value (if (ignore-values-cont? cont)
  63. empty-segment
  64. segment)
  65. cont))
  66. ;----------------------------------------------------------------
  67. ; Variable reference
  68. (define-compilator 'name 'leaf
  69. (lambda (node depth frame cont)
  70. (let* ((binding (name-node-binding node))
  71. (name (node-form node)))
  72. (deliver-value
  73. (if (pair? binding)
  74. (compile-local-name node name binding depth)
  75. (let ((offset (template-offset frame depth))
  76. (index (binding->index frame binding name #f)))
  77. (instruction (enum op global)
  78. (high-byte offset)
  79. (low-byte offset)
  80. (high-byte index)
  81. (low-byte index))))
  82. cont))))
  83. (define (compile-local-name node name binding depth)
  84. (let ((stack-offset (index->offset (car binding) depth))
  85. (rest (cdr binding)))
  86. (cond ((null? rest) ; in this frame
  87. (stack-ref-instruction stack-offset))
  88. ((null? (cdr rest))
  89. (stack-indirect-instruction stack-offset (car rest)))
  90. (else
  91. (assertion-violation 'compile-local-name "variable has too many indirections"
  92. name binding)))))
  93. ;----------------------------------------------------------------
  94. ; Hacked versions of the above for peephole optimization of pushes.
  95. ; This tries to compile NODE with an implicit push instruction preceeding
  96. ; (if PRE?) or following (if not PRE?). The instructions with implicit
  97. ; pushes are:
  98. ; push-false
  99. ; push+stack-ref
  100. ; stack-ref+push
  101. ; push+stack-indirect
  102. ; stack-indirect+push
  103. ; This codes finds the cases where literals or lexical references can be
  104. ; compiled into one of these.
  105. (define (maybe-compile-with-push node depth frame pre?)
  106. (cond ((literal-node? node)
  107. (constant-with-push (node-form node) depth frame pre?))
  108. ((quote-node? node)
  109. (constant-with-push (cadr (node-form node)) depth frame pre?))
  110. ((name-node? node)
  111. (let ((binding (name-node-binding node)))
  112. (if (and (pair? binding)
  113. (not (node-ref node 'check-unassigned)))
  114. (lexical-ref-with-push binding depth pre?)
  115. #f)))
  116. (else
  117. #f)))
  118. (define (constant-with-push obj depth frame pre?)
  119. (cond ((eq? obj #f)
  120. (if pre?
  121. #f
  122. (instruction (enum op push-false))))
  123. ((small-integer? obj)
  124. ; PreScheme does not have signed bytes so we bias OBJ
  125. (instruction (if pre?
  126. (enum op push+integer-literal)
  127. (enum op integer-literal+push))
  128. (+ obj 128)))
  129. (else
  130. (push+stack-indirect-instruction (template-offset frame depth)
  131. (literal->index frame obj)
  132. pre?))))
  133. (define (lexical-ref-with-push binding depth pre?)
  134. (let ((stack-offset (index->offset (car binding) depth))
  135. (rest (cdr binding)))
  136. (cond ((null? rest) ; in this frame
  137. (push+stack-ref-instruction stack-offset pre?))
  138. ((null? (cdr rest))
  139. (push+stack-indirect-instruction stack-offset (car rest) pre?))
  140. (else
  141. #f))))
  142. (define (push+stack-ref-instruction index pre?)
  143. (if (< index byte-limit)
  144. (instruction (if pre?
  145. (enum op push+stack-ref)
  146. (enum op stack-ref+push))
  147. index)
  148. #f))
  149. (define (push+stack-indirect-instruction index-in-stack index pre?)
  150. (if (and (< index byte-limit)
  151. (< index-in-stack byte-limit))
  152. (instruction (if pre?
  153. (enum op push+stack-indirect)
  154. (enum op stack-indirect+push))
  155. index-in-stack
  156. index)
  157. #f))
  158. ;----------------------------------------------------------------
  159. ; Assignment
  160. (define-compilator 'set! syntax-type
  161. (lambda (node depth frame cont)
  162. (let* ((exp (node-form node))
  163. (lhs-node (cadr exp))
  164. (name (node-form lhs-node))
  165. (binding (name-node-binding lhs-node)))
  166. (sequentially
  167. (compile (caddr exp) depth frame (named-cont name))
  168. (deliver-value
  169. (if (pair? binding)
  170. (let ((stack-offset (index->offset (car binding) depth))
  171. (rest (cdr binding)))
  172. (if (null? rest) ; in this frame
  173. (stack-set!-instruction stack-offset)
  174. (assertion-violation 'set! "SET! on a closed-over variable" name)))
  175. (let ((offset (template-offset frame depth))
  176. (index (binding->index frame
  177. binding
  178. name
  179. #t)))
  180. (instruction (enum op set-global!)
  181. (high-byte offset)
  182. (low-byte offset)
  183. (high-byte index)
  184. (low-byte index))))
  185. cont)))))
  186. ;----------------------------------------------------------------
  187. ; IF and BEGIN
  188. (define-compilator 'if syntax-type
  189. (lambda (node depth frame cont)
  190. (let ((exp (node-form node))
  191. (alt-label (make-label))
  192. (join-label (make-label)))
  193. (sequentially
  194. ;; Test
  195. (compile (cadr exp) depth frame (fall-through-cont node 1))
  196. (instruction-using-label (enum op jump-if-false) alt-label)
  197. ;; Consequent
  198. (compile (caddr exp) depth frame cont)
  199. (if (fall-through-cont? cont)
  200. (instruction-using-label (enum op jump) join-label)
  201. empty-segment)
  202. ;; Alternate
  203. (attach-label alt-label
  204. (compile (cadddr exp) depth frame cont))
  205. (attach-label join-label
  206. empty-segment)))))
  207. (define-compilator 'begin syntax-type
  208. (lambda (node depth frame cont)
  209. (let ((exp-list (cdr (node-form node))))
  210. (if (null? exp-list)
  211. (generate-trap depth frame cont "null begin")
  212. (let ((dummy
  213. (make-node operator/begin ;For debugging database
  214. `(begin ,@exp-list))))
  215. (let loop ((exp-list exp-list) (i 1))
  216. (if (null? (cdr exp-list))
  217. (compile (car exp-list) depth frame cont)
  218. (sequentially
  219. (compile (car exp-list)
  220. depth
  221. frame
  222. (ignore-values-cont dummy i))
  223. (loop (cdr exp-list) (+ i 1))))))))))
  224. ;----------------------------------------------------------------
  225. ; Calls
  226. (define (compile-call node depth frame cont)
  227. (if (node-ref node 'type-error)
  228. (compile-unknown-call node depth frame cont)
  229. (let ((proc-node (car (node-form node))))
  230. (cond ((name-node? proc-node)
  231. (compile-name-call node proc-node depth frame cont))
  232. ((and (lambda-node? proc-node)
  233. (not (n-ary? (cadr (node-form proc-node)))))
  234. (compile-redex proc-node (cdr (node-form node))
  235. depth
  236. frame
  237. cont))
  238. ((and (literal-node? proc-node)
  239. (primop? (node-form proc-node)))
  240. (let ((primop (node-form proc-node)))
  241. (if (primop-compilator primop)
  242. ((primop-compilator primop) node depth frame cont)
  243. (assertion-violation 'compile-call
  244. "compiler bug: primop has no compilator"
  245. primop
  246. (schemify node)))))
  247. (else
  248. (compile-unknown-call node depth frame cont))))))
  249. (define-compilator 'call 'internal compile-call)
  250. (define (compile-name-call node proc-node depth frame cont)
  251. (let ((binding (name-node-binding proc-node)))
  252. (if (binding? binding)
  253. (let ((static (binding-static binding)))
  254. (cond ((primop? static)
  255. (if (primop-compilator static)
  256. ((primop-compilator static) node depth frame cont)
  257. (compile-unknown-call node depth frame cont)))
  258. ((transform? static)
  259. (let* ((form (node-form node))
  260. (new (apply-inline-transform static
  261. form
  262. (node-form proc-node))))
  263. (if (eq? new form)
  264. (compile-unknown-call node depth frame cont)
  265. (compile new depth frame cont))))
  266. (else
  267. (compile-unknown-call node depth frame cont))))
  268. (compile-unknown-call node depth frame cont))))
  269. ; Compile a call to a computed procedure.
  270. (define (compile-unknown-call node depth frame cont)
  271. (receive (before depth label after)
  272. (maybe-push-continuation depth frame cont node)
  273. (let* ((exp (node-form node))
  274. (nargs (length (cdr exp))))
  275. (sequentially before
  276. (push-arguments node depth frame)
  277. (compile (car exp)
  278. (+ depth nargs)
  279. frame
  280. (fall-through-cont node 0))
  281. (call-instruction nargs (+ depth nargs) label)
  282. after))))
  283. ; A redex is a call of the form ((lambda (x1 ... xn) body ...) e1 ... en).
  284. (define (compile-redex proc-node args depth frame cont)
  285. (let* ((proc-exp (node-form proc-node))
  286. (formals (cadr proc-exp))
  287. (body (caddr proc-exp)))
  288. (cond ((not (= (length formals)
  289. (length args)))
  290. (generate-trap depth
  291. frame
  292. cont
  293. "wrong number of arguments"
  294. (cons (schemify proc-node)
  295. (map schemify args))))
  296. ((null? formals)
  297. (compile body depth frame cont)) ;+++
  298. (else
  299. (let* ((nargs (length args))
  300. (body-depth (+ depth nargs)))
  301. (set-frame-locations! formals body-depth)
  302. (sequentially
  303. (push-all-with-names args formals depth frame)
  304. (compile-inline-body nargs
  305. (map name-node->symbol formals)
  306. body
  307. body-depth
  308. frame
  309. cont)))))))
  310. (define (compile-inline-body nargs formals body depth frame cont)
  311. (sequentially
  312. (note-environment
  313. formals
  314. (- depth nargs)
  315. (compile body depth frame cont))
  316. (if (return-cont? cont)
  317. empty-segment
  318. (deliver-value (instruction (enum op pop-n)
  319. (high-byte nargs)
  320. (low-byte nargs))
  321. cont))))
  322. ;----------------------------------------------------------------
  323. ; (PURE-LETREC ((<var> <val>) ...) (<free var> ...) <body>)
  324. ; These are LETREC's where the values are all LAMBDA's. They are produced by
  325. ; opt/flatten.scm.
  326. (define-compilator 'pure-letrec syntax-type
  327. (lambda (node depth frame cont)
  328. (let* ((exp (node-form node))
  329. (specs (cadr exp))
  330. (free-vars (caddr exp))
  331. (body (cadddr exp))
  332. (count (length specs))
  333. (old-locations (map name-node-binding free-vars)))
  334. (receive (env-code ignore-free-vars-in-order)
  335. (compile-recursive-environment free-vars
  336. depth
  337. (template-offset frame depth)
  338. (letrec-template-maker specs frame))
  339. (for-each (lambda (node location)
  340. (node-set! node 'binding location))
  341. free-vars
  342. old-locations)
  343. (set-lexical-offsets! (map car specs) depth)
  344. (depth-check! frame (+ depth 1))
  345. (sequentially
  346. env-code
  347. (instruction (enum op push))
  348. (compile-inline-body 1
  349. (list (map name-node->symbol
  350. (append (map car specs)
  351. free-vars)))
  352. body
  353. (+ depth 1)
  354. frame
  355. cont))))))
  356. ; After getting the free variable list (to pass to NOTE-ENVIRONMENT) this
  357. ; compiles the values in SPECS, all of which are lambdas. It returns the
  358. ; template indexes of the resulting templates.
  359. (define (letrec-template-maker specs frame)
  360. (lambda (free-vars-in-order)
  361. (let ((all-vars (append (map car specs)
  362. free-vars-in-order)))
  363. (map (lambda (spec)
  364. (receive (proc-code proc-frame)
  365. (compile-lambda (unflatten-form (cadr spec))
  366. all-vars
  367. (node-form (car spec))
  368. #f
  369. frame)
  370. (literal->index frame
  371. (segment->template proc-code proc-frame))))
  372. specs))))
  373. ;----------------------------------------------------------------
  374. ; We don't pass the incremented depth to MAKE-RETURN-POINT because the
  375. ; return-pointer is not included in a continuation's size.
  376. ;
  377. ; Returns before-segment new-depth label after-segment.
  378. ;
  379. ; In all of these NODE is the expression whose value will be returned to the
  380. ; continuation. It is saved for debugging assistance.
  381. (define (maybe-push-continuation depth frame cont node)
  382. (if (return-cont? cont)
  383. (values empty-segment depth #f empty-segment)
  384. (push-continuation depth frame cont node)))
  385. (define (push-continuation depth frame cont node)
  386. (if (return-cont? cont)
  387. (assertion-violation 'push-continuation "making a return point in tail position" cont))
  388. (let ((protocol (continuation-protocol (if (ignore-values-cont? cont)
  389. 0
  390. 1)
  391. (if (ignore-values-cont? cont)
  392. #t
  393. #f))))
  394. (really-push-continuation depth frame protocol node cont)))
  395. (define (push-continuation-no-protocol depth frame node cont)
  396. (really-push-continuation depth frame empty-segment node cont))
  397. (define (really-push-continuation depth frame protocol node cont)
  398. (depth-check! frame (+ depth 1))
  399. (let ((label (make-label))
  400. (protocol (if (keep-source-code?)
  401. (note-source-code (fixup-source node
  402. (cont-source-info cont))
  403. protocol
  404. frame)
  405. protocol)))
  406. (values (instruction (enum op push-false))
  407. (+ depth 1)
  408. label
  409. (sequentially (continuation-data #f depth (template-offset frame depth))
  410. (attach-label label protocol)))))
  411. (define (fixup-source node destination)
  412. ;; Abbreviate this somehow?
  413. (if node
  414. (if (pair? destination)
  415. (cons (schemify node)
  416. (cons (car destination)
  417. (schemify (cdr destination))))
  418. (list (schemify node)))
  419. #f))
  420. ;----------------------------------------------------------------
  421. ; Pushing arguments.
  422. ;
  423. ; This is a mess because we try to merge push instructions with other common
  424. ; ones. There are three entry points:
  425. (define (push-arguments node depth frame)
  426. (let ((args (cdr (node-form node))))
  427. (if (null? args)
  428. empty-segment
  429. (really-push-arguments args depth frame node #t))))
  430. (define (push-all-but-last nodes depth frame debug-info)
  431. (really-push-arguments nodes depth frame debug-info #f))
  432. (define (push-all-with-names nodes names depth frame)
  433. (really-push-arguments nodes depth frame names #t))
  434. (define (push-argument node index depth frame)
  435. (depth-check! frame (+ depth 1))
  436. (receive (code pushed?)
  437. (compile-argument (list-ref (node-form node) (+ index 1))
  438. depth
  439. frame
  440. node
  441. (+ index 1)
  442. #f
  443. #t)
  444. (if pushed?
  445. code
  446. (sequentially code push-instruction))))
  447. ; The main loop.
  448. (define (really-push-arguments nodes depth frame debug-info push-last?)
  449. (let recur ((args nodes) (i 1) (pre-push? #f))
  450. (receive (arg-code pushed?)
  451. (compile-argument (car args) (+ depth (- i 1)) frame debug-info i
  452. pre-push?
  453. (if (null? (cdr args))
  454. push-last?
  455. #t))
  456. (cond ((null? (cdr args))
  457. (depth-check! frame (+ depth (if push-last? i (- i 1))))
  458. (if (and push-last? (not pushed?))
  459. (sequentially arg-code push-instruction)
  460. arg-code))
  461. (else
  462. (sequentially arg-code
  463. (recur (cdr args) (+ i 1) (not pushed?))))))))
  464. (define (compile-argument node depth frame debug-info index before? after?)
  465. (cond ((and before? ;+++
  466. (maybe-compile-with-push node depth frame #t))
  467. => (lambda (code)
  468. (values code #f)))
  469. ((and after? ;+++
  470. (maybe-compile-with-push node depth frame #f))
  471. => (lambda (code)
  472. (values (pre-push code before?)
  473. #t)))
  474. (else
  475. (values (pre-push (compile node
  476. depth
  477. frame
  478. (if (pair? debug-info)
  479. (named-cont (node-form (car debug-info)))
  480. (fall-through-cont debug-info index)))
  481. before?)
  482. #f))))
  483. (define (pre-push code do-it?)
  484. (if do-it?
  485. (sequentially push-instruction code)
  486. code))
  487. (define push-instruction
  488. (instruction (enum op push)))
  489. ;----------------------------------------------------------------
  490. ; We have two sizes of these because the big size is very rare and
  491. ; signficantly slower (because the argument count cannot be encoded in
  492. ; the protocol).
  493. (define (call-instruction nargs depth label)
  494. (if label
  495. (if (> nargs maximum-stack-args) ;+++
  496. (instruction-using-label (enum op big-call)
  497. label
  498. (high-byte nargs)
  499. (low-byte nargs))
  500. (instruction-using-label (enum op call)
  501. label
  502. nargs))
  503. (if (> nargs maximum-stack-args) ;+++
  504. (instruction (enum op big-call)
  505. 0
  506. 0
  507. (high-byte nargs)
  508. (low-byte nargs))
  509. (instruction (enum op tail-call)
  510. nargs
  511. (high-byte depth)
  512. (low-byte depth)))))
  513. (define (stack-ref-instruction index)
  514. (if (>= index byte-limit) ;+++
  515. (instruction (enum op big-stack-ref)
  516. (high-byte index)
  517. (low-byte index))
  518. (instruction (enum op stack-ref)
  519. index)))
  520. (define (stack-set!-instruction index)
  521. (if (>= index byte-limit) ;+++
  522. (instruction (enum op big-stack-set!)
  523. (high-byte index)
  524. (low-byte index))
  525. (instruction (enum op stack-set!)
  526. index)))
  527. (define (stack-indirect-instruction index-in-stack index)
  528. (if (and (< index byte-limit) ;+++
  529. (< index-in-stack byte-limit))
  530. (instruction (enum op stack-indirect)
  531. index-in-stack
  532. index)
  533. (instruction (enum op big-stack-indirect)
  534. (high-byte index-in-stack)
  535. (low-byte index-in-stack)
  536. (high-byte index)
  537. (low-byte index))))
  538. ;----------------------------------------------------------------
  539. ; Compile-time continuations
  540. ;
  541. ; A compile-time continuation is a pair (kind . source-info).
  542. ; Kind is one of the following:
  543. ; 'return - invoke the current full continuation.
  544. ; 'fall-through - fall through to subsequent instructions.
  545. ; 'ignore-values - ignore values, then fall through.
  546. ; 'accept-values - pass values to continuation
  547. ; Source-info is one of:
  548. ; #f - we don't know anything
  549. ; symbol - value delivered to subsequent instructions will be assigned to
  550. ; a variable with this name. If the value being assigned is a lambda, we
  551. ; can give that lambda that name.
  552. ; (i . node) - the value being computed is the i'th subexpression of the node.
  553. (define (make-cont kind source-info) (cons kind source-info))
  554. (define cont-kind car)
  555. (define cont-source-info cdr)
  556. ; We could probably be able to optimize jumps to jumps.
  557. ;(define (make-jump-cont label cont)
  558. ; (if (fall-through-cont? cont)
  559. ; (make-cont label (cont-name cont))
  560. ; cont))
  561. (define (return-cont name)
  562. (make-cont 'return name))
  563. (define (return-cont? cont)
  564. (eq? (cont-kind cont) 'return))
  565. ; Fall through into next instruction while compiling the I'th part of NODE.
  566. (define (fall-through-cont node i)
  567. (make-cont 'fall-through (cons i node)))
  568. (define (plain-fall-through-cont)
  569. (make-cont 'fall-through #f))
  570. (define (fall-through-cont? cont)
  571. (not (return-cont? cont)))
  572. ; Ignore return value, then fall through
  573. (define ignore-values-segment
  574. (instruction ignore-values-protocol))
  575. (define (ignore-values-cont node i)
  576. (make-cont 'ignore-values (cons i node)))
  577. (define (ignore-values-cont? cont)
  578. (eq? (cont-kind cont) 'ignore-values))
  579. (define (accept-values-cont node i)
  580. (make-cont 'accept-values (cons i node)))
  581. (define (accept-values-cont? cont)
  582. (eq? (cont-kind cont) 'accept-values))
  583. ; Value is in *val*; deliver it to its continuation.
  584. (define (deliver-value segment cont)
  585. (if (return-cont? cont)
  586. (sequentially segment
  587. (instruction (enum op return)))
  588. segment)) ; just fall through to next instruction
  589. ; For putting names to lambda expressions:
  590. (define (named-cont name)
  591. (make-cont 'fall-through name))
  592. (define (cont-name cont)
  593. (if (pair? (cont-source-info cont))
  594. #f
  595. (cont-source-info cont)))
  596. ;----------------------------------------------------------------
  597. ; Utilities
  598. ; Find lookup result that was cached by classifier
  599. ; The binding property is either a location, a 1- or 2-element list with
  600. ; stack index and template index, or 'unbound
  601. (define (name-node-binding node)
  602. (or (node-ref node 'binding)
  603. (node-form node)))
  604. ; Produce something for source code that contains a compile-time error.
  605. (define (generate-trap depth frame cont . stuff)
  606. (apply warning 'generate-trap stuff)
  607. (sequentially
  608. (stack-indirect-instruction (template-offset frame depth)
  609. (literal->index frame (cons 'error stuff)))
  610. (deliver-value (instruction (enum op trap))
  611. cont)))
  612. ;----------------------------------------------------------------
  613. ; Type checking. This gets called on all nodes.
  614. (define (type-check node)
  615. (if *type-check?*
  616. (let ((form (node-form node)))
  617. (if (pair? form)
  618. (let ((proc-node (car form)))
  619. (if (node? proc-node)
  620. (let ((proc-type (node-type proc-node)))
  621. (cond ((procedure-type? proc-type)
  622. (if (restrictive? proc-type)
  623. (let* ((args (cdr form))
  624. (args-type (make-some-values-type
  625. (map (lambda (arg)
  626. (meet-type
  627. (node-type arg)
  628. value-type))
  629. args)))
  630. (node (make-similar-node node
  631. (cons proc-node
  632. args))))
  633. (if (not (meet? args-type
  634. (procedure-type-domain proc-type)))
  635. (diagnose-call-error node proc-type))
  636. node)
  637. node))
  638. ((not (meet? proc-type any-procedure-type))
  639. ;; Could also check args for one-valuedness.
  640. (let ((message "non-procedure in operator position"))
  641. (warning 'type-check
  642. message
  643. (schemify node)
  644. `(procedure: ,proc-type))
  645. (node-set! node 'type-error message))
  646. node)
  647. (else node)))
  648. node))
  649. node))
  650. node))
  651. (define (set-type-check?! check?)
  652. (set! *type-check?* check?))
  653. (define *type-check?* #t)
  654. (define (diagnose-call-error node proc-type)
  655. (let ((message
  656. (cond ((not (fixed-arity-procedure-type? proc-type))
  657. "invalid arguments")
  658. ((= (procedure-type-arity proc-type)
  659. (length (cdr (node-form node))))
  660. "argument type error")
  661. (else
  662. "wrong number of arguments"))))
  663. (warning 'diagnose-call-error
  664. message
  665. (schemify node)
  666. `(procedure wants:
  667. ,(rail-type->sexp (procedure-type-domain proc-type)
  668. #f))
  669. `(arguments are: ,(map (lambda (arg)
  670. (type->sexp (node-type arg) #t))
  671. (cdr (node-form node)))))
  672. (node-set! node 'type-error message)))
  673. ; Type system loophole
  674. (define-compilator 'loophole syntax-type
  675. (lambda (node depth frame cont)
  676. (compile (caddr (node-form node)) depth frame cont)))