~ chicken-core (chicken-5) /compiler-syntax.scm
Trap1;;;; compiler-syntax.scm - compiler syntax used internally2;3; Copyright (c) 2009-2022, The CHICKEN Team4; All rights reserved.5;6; Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following7; conditions are met:8;9; Redistributions of source code must retain the above copyright notice, this list of conditions and the following10; disclaimer.11; Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following12; disclaimer in the documentation and/or other materials provided with the distribution.13; Neither the name of the author nor the names of its contributors may be used to endorse or promote14; products derived from this software without specific prior written permission.15;16; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS17; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY18; AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR19; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR20; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR21; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY22; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR23; OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE24; POSSIBILITY OF SUCH DAMAGE.252627(declare28 (unit compiler-syntax)29 (uses expand extras support compiler))3031(module chicken.compiler.compiler-syntax32 (compiler-syntax-statistics)3334(import scheme35 chicken.base36 chicken.compiler.support37 chicken.compiler.core38 chicken.fixnum39 chicken.format40 chicken.syntax)4142(include "tweaks.scm")43(include "mini-srfi-1.scm")444546;;; Compiler macros (that operate in the expansion phase)4748(define compiler-syntax-statistics '())4950(set! ##sys#compiler-syntax-hook51 (lambda (name result)52 (let ((a (alist-ref name compiler-syntax-statistics eq? 0)))53 (set! compiler-syntax-statistics54 (alist-update! name (add1 a) compiler-syntax-statistics)))))5556(define (r-c-s names transformer se)57 (let ((t (cons (##sys#ensure-transformer58 (##sys#er-transformer transformer)59 (car names))60 (append se ##sys#default-macro-environment))))61 (for-each62 (lambda (name)63 (##sys#put! name '##compiler#compiler-syntax t) )64 names) ) )6566(define-syntax define-internal-compiler-syntax67 (syntax-rules ()68 ((_ (names . llist) se . body)69 (r-c-s 'names (lambda llist . body) se))))7071(define-internal-compiler-syntax ((scheme#for-each ##sys#for-each) x r c)72 '((pair? . scheme#pair?))73 (let ((%let (r 'let))74 (%if (r 'if))75 (%loop (r 'for-each-loop))76 (%proc (gensym))77 (%begin (r 'begin))78 (%quote (r 'quote))79 (%and (r 'and))80 (%pair? (r 'pair?))81 (%lambda (r 'lambda))82 (lsts (cddr x)))83 (if (and (memq 'scheme#for-each standard-bindings) ; we have to check this because the db (and thus84 (> (length+ x) 2)) ; intrinsic marks) isn't set up yet85 (let ((vars (map (lambda _ (gensym)) lsts)))86 `(,%let ((,%proc ,(cadr x))87 ,@(map list vars lsts))88 ,@(map (lambda (var)89 `(##core#check (##sys#check-list ,var (,%quote for-each))))90 vars)91 (,%let ,%loop ,(map list vars vars)92 (,%if (,%and ,@(map (lambda (v) `(,%pair? ,v)) vars))93 (,%begin94 (,%proc95 ,@(map (lambda (v) `(##sys#slot ,v 0)) vars))96 (##core#app97 ,%loop98 ,@(map (lambda (v) `(##sys#slot ,v 1)) vars) ) )))))99 x)))100101(define-internal-compiler-syntax ((scheme#map ##sys#map) x r c)102 '((pair? . scheme#pair?) (cons . scheme#cons))103 (let ((%let (r 'let))104 (%if (r 'if))105 (%loop (r 'map-loop))106 (%res (gensym))107 (%cons (r 'cons))108 (%set! (r 'set!))109 (%result (gensym))110 (%node (gensym))111 (%proc (gensym))112 (%quote (r 'quote))113 (%begin (r 'begin))114 (%lambda (r 'lambda))115 (%and (r 'and))116 (%pair? (r 'pair?))117 (lsts (cddr x)))118 (if (and (memq 'scheme#map standard-bindings) ; s.a.119 (> (length+ x) 2))120 (let ((vars (map (lambda _ (gensym)) lsts)))121 `(,%let ((,%node (,%cons (##core#undefined) (,%quote ()))))122 (,%let ((,%result ,%node)123 (,%proc ,(cadr x))124 ,@(map list vars lsts))125 ,@(map (lambda (var)126 `(##core#check (##sys#check-list ,var (,%quote map))))127 vars)128 (,%let ,%loop ,(map list vars vars)129 (,%if (,%and ,@(map (lambda (v) `(,%pair? ,v)) vars))130 (,%let ((,%res131 (,%cons132 (,%proc133 ,@(map (lambda (v) `(##sys#slot ,v 0)) vars))134 (,%quote ()))))135 (##sys#setslot ,%node 1 ,%res)136 (,%set! ,%node ,%res)137 (##core#app138 ,%loop139 ,@(map (lambda (v) `(##sys#slot ,v 1)) vars)))140 (##sys#slot ,%result 1))))))141 x)))142143(define-internal-compiler-syntax ((chicken.base#o) x r c) '()144 (if (and (fx> (length x) 1)145 (memq 'chicken.base#o extended-bindings)) ; s.a.146 (let ((%tmp (r 'tmp)))147 `(,(r 'lambda) (,%tmp) ,(foldr list %tmp (cdr x))))148 x))149150(define-internal-compiler-syntax ((chicken.format#sprintf chicken.format#format) x r c)151 `((display . scheme#display)152 (write . scheme#write)153 (number->string . scheme#number->string)154 (write-char . scheme#write-char)155 (open-output-string . chicken.base#open-output-string)156 (get-output-string . chicken.base#get-output-string))157 (let* ((out (gensym 'out))158 (code (compile-format-string159 (if (eq? (car x) 'chicken.format#sprintf) 'sprintf 'format)160 out x (cdr x) r c)))161 (if code162 `(,(r 'let) ((,out (,(r 'open-output-string))))163 ,code164 (,(r 'get-output-string) ,out))165 x)))166167(define-internal-compiler-syntax ((chicken.format#fprintf) x r c)168 '((display . scheme#display)169 (write . scheme#write)170 (number->string . scheme#number->string)171 (write-char . scheme#write-char)172 (open-output-string . chicken.base#open-output-string)173 (get-output-string . chicken.base#get-output-string))174 (if (>= (length x) 3)175 (let ((code (compile-format-string 'fprintf (cadr x) x (cddr x) r c)))176 (or code x))177 x))178179(define-internal-compiler-syntax ((chicken.format#printf) x r c)180 '((display . scheme#display)181 (write . scheme#write)182 (number->string . scheme#number->string)183 (write-char . scheme#write-char)184 (open-output-string . chicken.base#open-output-string)185 (get-output-string . chicken.base#get-output-string))186 (let ((code (compile-format-string 'printf '##sys#standard-output x (cdr x) r c)))187 (or code x)))188189(define (compile-format-string func out x args r c)190 (call/cc191 (lambda (return)192 (and (>= (length args) 1)193 (memq (symbol-append 'chicken.format# func) extended-bindings) ; s.a.194 (or (string? (car args))195 (and (list? (car args))196 (c (r 'quote) (caar args))197 (string? (cadar args))))198 (let ((fstr (if (string? (car args)) (car args) (cadar args)))199 (args (cdr args)))200 (define (fail ret? msg . args)201 (let ((ln (get-line-number x)))202 (warning203 (sprintf "~a`~a', in format string ~s, ~?"204 (if ln (sprintf "(~a) " ln) "")205 func fstr206 msg args) ))207 (when ret? (return #f)))208 (let ((code '())209 (index 0)210 (len (string-length fstr))211 (%out (r 'out))212 (%let (r 'let))213 (%number->string (r 'number->string)))214 (define (fetch)215 (let ((c (string-ref fstr index)))216 (set! index (fx+ index 1))217 c) )218 (define (next)219 (if (null? args)220 (fail #t "too few arguments to formatted output procedure")221 (let ((x (car args)))222 (set! args (cdr args))223 x) ) )224 (define (endchunk chunk)225 (when (pair? chunk)226 (push227 (if (= 1 (length chunk))228 `(##sys#write-char-0 ,(car chunk) ,%out)229 `(##sys#print ,(##sys#reverse-list->string chunk) #f ,%out)))))230 (define (push exp)231 (set! code (cons exp code)))232 (let loop ((chunk '()))233 (cond ((>= index len)234 (unless (null? args)235 (fail #f "too many arguments to formatted output procedure"))236 (endchunk chunk)237 `(,%let ((,%out ,out))238 (##sys#check-output-port ,%out #t ',func)239 ,@(reverse code)))240 (else241 (let ((c (fetch)))242 (if (eq? c #\~)243 (let ((dchar (fetch)))244 (endchunk chunk)245 (case (char-upcase dchar)246 ((#\S) (push `(##sys#print ,(next) #t ,%out)))247 ((#\A) (push `(##sys#print ,(next) #f ,%out)))248 ((#\C) (push `(##sys#write-char-0 ,(next) ,%out)))249 ((#\B)250 (push251 `(##sys#print (,%number->string ,(next) 2)252 #f ,%out)))253 ((#\O)254 (push255 `(##sys#print (,%number->string ,(next) 8)256 #f ,%out)))257 ((#\X)258 (push259 `(##sys#print (,%number->string ,(next) 16)260 #f ,%out)))261 ((#\!) (push `(##sys#flush-output ,%out)))262 ((#\?)263 (let* ([fstr (next)]264 [lst (next)] )265 (push `(##sys#apply chicken.format#fprintf ,%out ,fstr ,lst))))266 ((#\~) (push `(##sys#write-char-0 #\~ ,%out)))267 ((#\% #\N) (push `(##sys#write-char-0 #\newline ,%out)))268 (else269 (if (char-whitespace? dchar)270 (let skip ((c (fetch)))271 (if (char-whitespace? c)272 (skip (fetch))273 (set! index (sub1 index))))274 (fail #t "illegal format-string character `~c'" dchar) ) ) )275 (loop '()) )276 (loop (cons c chunk)))))))))))))277278(define-internal-compiler-syntax ((chicken.base#foldr) x r c)279 '((pair? . scheme#pair?))280 (if (and (fx= (length x) 4)281 (memq 'chicken.base#foldr extended-bindings) ) ; s.a.282 (let ((f (cadr x))283 (z (caddr x))284 (lst (cadddr x))285 (%let* (r 'let*))286 (%let (r 'let))287 (%pair? (r 'pair?))288 (%if (r 'if))289 (loopvar (gensym "foldr"))290 (lstvar (gensym)))291 `(,%let* ((,lstvar ,lst))292 (##core#check (##sys#check-list ,lstvar (##core#quote foldr)))293 (,%let ,loopvar ((,lstvar ,lstvar))294 (,%if (,%pair? ,lstvar)295 (,f (##sys#slot ,lstvar 0)296 (##core#app ,loopvar (##sys#slot ,lstvar 1)))297 ,z))))298 x))299300(define-internal-compiler-syntax ((chicken.base#foldl) x r c)301 '((pair? . scheme#pair?))302 (if (and (fx= (length x) 4)303 (memq 'chicken.base#foldl extended-bindings) ) ; s.a.304 (let ((f (cadr x))305 (z (caddr x))306 (lst (cadddr x))307 (%let* (r 'let*))308 (%let (r 'let))309 (%if (r 'if))310 (%pair? (r 'pair?))311 (zvar (gensym))312 (loopvar (gensym "foldl"))313 (lstvar (gensym)))314 `(,%let* ((,zvar ,z)315 (,lstvar ,lst))316 (##core#check (##sys#check-list ,lstvar (##core#quote foldl)))317 (,%let ,loopvar ((,lstvar ,lstvar) (,zvar ,zvar))318 (,%if (,%pair? ,lstvar)319 (##core#app320 ,loopvar321 (##sys#slot ,lstvar 1)322 (,f ,zvar (##sys#slot ,lstvar 0)))323 ,zvar))))324 x))325)