12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213 |
- ;;;; -*-scheme-*-
- ;;;;
- ;;;; Copyright (C) 2001, 2003, 2006 Free Software Foundation, Inc.
- ;;;;
- ;;;; This library is free software; you can redistribute it and/or
- ;;;; modify it under the terms of the GNU Lesser General Public
- ;;;; License as published by the Free Software Foundation; either
- ;;;; version 2.1 of the License, or (at your option) any later version.
- ;;;;
- ;;;; This library is distributed in the hope that it will be useful,
- ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
- ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- ;;;; Lesser General Public License for more details.
- ;;;;
- ;;;; You should have received a copy of the GNU Lesser General Public
- ;;;; License along with this library; if not, write to the Free Software
- ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- ;;;;
- ;;; Portable implementation of syntax-case
- ;;; Extracted from Chez Scheme Version 5.9f
- ;;; Authors: R. Kent Dybvig, Oscar Waddell, Bob Hieb, Carl Bruggeman
- ;;; Modified by Mikael Djurfeldt <djurfeldt@nada.kth.se> according
- ;;; to the ChangeLog distributed in the same directory as this file:
- ;;; 1997-08-19, 1997-09-03, 1997-09-10, 2000-08-13, 2000-08-24,
- ;;; 2000-09-12, 2001-03-08
- ;;; Copyright (c) 1992-1997 Cadence Research Systems
- ;;; Permission to copy this software, in whole or in part, to use this
- ;;; software for any lawful purpose, and to redistribute this software
- ;;; is granted subject to the restriction that all copies made of this
- ;;; software must include this copyright notice in full. This software
- ;;; is provided AS IS, with NO WARRANTY, EITHER EXPRESS OR IMPLIED,
- ;;; INCLUDING BUT NOT LIMITED TO IMPLIED WARRANTIES OF MERCHANTABILITY
- ;;; OR FITNESS FOR ANY PARTICULAR PURPOSE. IN NO EVENT SHALL THE
- ;;; AUTHORS BE LIABLE FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES OF ANY
- ;;; NATURE WHATSOEVER.
- ;;; Before attempting to port this code to a new implementation of
- ;;; Scheme, please read the notes below carefully.
- ;;; This file defines the syntax-case expander, sc-expand, and a set
- ;;; of associated syntactic forms and procedures. Of these, the
- ;;; following are documented in The Scheme Programming Language,
- ;;; Second Edition (R. Kent Dybvig, Prentice Hall, 1996). Most are
- ;;; also documented in the R4RS and draft R5RS.
- ;;;
- ;;; bound-identifier=?
- ;;; datum->syntax-object
- ;;; define-syntax
- ;;; fluid-let-syntax
- ;;; free-identifier=?
- ;;; generate-temporaries
- ;;; identifier?
- ;;; identifier-syntax
- ;;; let-syntax
- ;;; letrec-syntax
- ;;; syntax
- ;;; syntax-case
- ;;; syntax-object->datum
- ;;; syntax-rules
- ;;; with-syntax
- ;;;
- ;;; All standard Scheme syntactic forms are supported by the expander
- ;;; or syntactic abstractions defined in this file. Only the R4RS
- ;;; delay is omitted, since its expansion is implementation-dependent.
- ;;; The remaining exports are listed below:
- ;;;
- ;;; (sc-expand datum)
- ;;; if datum represents a valid expression, sc-expand returns an
- ;;; expanded version of datum in a core language that includes no
- ;;; syntactic abstractions. The core language includes begin,
- ;;; define, if, lambda, letrec, quote, and set!.
- ;;; (eval-when situations expr ...)
- ;;; conditionally evaluates expr ... at compile-time or run-time
- ;;; depending upon situations (see the Chez Scheme System Manual,
- ;;; Revision 3, for a complete description)
- ;;; (syntax-error object message)
- ;;; used to report errors found during expansion
- ;;; (install-global-transformer symbol value)
- ;;; used by expanded code to install top-level syntactic abstractions
- ;;; (syntax-dispatch e p)
- ;;; used by expanded code to handle syntax-case matching
- ;;; The following nonstandard procedures must be provided by the
- ;;; implementation for this code to run.
- ;;;
- ;;; (void)
- ;;; returns the implementation's cannonical "unspecified value". This
- ;;; usually works: (define void (lambda () (if #f #f))).
- ;;;
- ;;; (andmap proc list1 list2 ...)
- ;;; returns true if proc returns true when applied to each element of list1
- ;;; along with the corresponding elements of list2 ....
- ;;; The following definition works but does no error checking:
- ;;;
- ;;; (define andmap
- ;;; (lambda (f first . rest)
- ;;; (or (null? first)
- ;;; (if (null? rest)
- ;;; (let andmap ((first first))
- ;;; (let ((x (car first)) (first (cdr first)))
- ;;; (if (null? first)
- ;;; (f x)
- ;;; (and (f x) (andmap first)))))
- ;;; (let andmap ((first first) (rest rest))
- ;;; (let ((x (car first))
- ;;; (xr (map car rest))
- ;;; (first (cdr first))
- ;;; (rest (map cdr rest)))
- ;;; (if (null? first)
- ;;; (apply f (cons x xr))
- ;;; (and (apply f (cons x xr)) (andmap first rest)))))))))
- ;;;
- ;;; The following nonstandard procedures must also be provided by the
- ;;; implementation for this code to run using the standard portable
- ;;; hooks and output constructors. They are not used by expanded code,
- ;;; and so need be present only at expansion time.
- ;;;
- ;;; (eval x)
- ;;; where x is always in the form ("noexpand" expr).
- ;;; returns the value of expr. the "noexpand" flag is used to tell the
- ;;; evaluator/expander that no expansion is necessary, since expr has
- ;;; already been fully expanded to core forms.
- ;;;
- ;;; eval will not be invoked during the loading of psyntax.pp. After
- ;;; psyntax.pp has been loaded, the expansion of any macro definition,
- ;;; whether local or global, will result in a call to eval. If, however,
- ;;; sc-expand has already been registered as the expander to be used
- ;;; by eval, and eval accepts one argument, nothing special must be done
- ;;; to support the "noexpand" flag, since it is handled by sc-expand.
- ;;;
- ;;; (error who format-string why what)
- ;;; where who is either a symbol or #f, format-string is always "~a ~s",
- ;;; why is always a string, and what may be any object. error should
- ;;; signal an error with a message something like
- ;;;
- ;;; "error in <who>: <why> <what>"
- ;;;
- ;;; (gensym)
- ;;; returns a unique symbol each time it's called
- ;;;
- ;;; (putprop symbol key value)
- ;;; (getprop symbol key)
- ;;; key is always the symbol *sc-expander*; value may be any object.
- ;;; putprop should associate the given value with the given symbol in
- ;;; some way that it can be retrieved later with getprop.
- ;;; When porting to a new Scheme implementation, you should define the
- ;;; procedures listed above, load the expanded version of psyntax.ss
- ;;; (psyntax.pp, which should be available whereever you found
- ;;; psyntax.ss), and register sc-expand as the current expander (how
- ;;; you do this depends upon your implementation of Scheme). You may
- ;;; change the hooks and constructors defined toward the beginning of
- ;;; the code below, but to avoid bootstrapping problems, do so only
- ;;; after you have a working version of the expander.
- ;;; Chez Scheme allows the syntactic form (syntax <template>) to be
- ;;; abbreviated to #'<template>, just as (quote <datum>) may be
- ;;; abbreviated to '<datum>. The #' syntax makes programs written
- ;;; using syntax-case shorter and more readable and draws out the
- ;;; intuitive connection between syntax and quote.
- ;;; If you find that this code loads or runs slowly, consider
- ;;; switching to faster hardware or a faster implementation of
- ;;; Scheme. In Chez Scheme on a 200Mhz Pentium Pro, expanding,
- ;;; compiling (with full optimization), and loading this file takes
- ;;; between one and two seconds.
- ;;; In the expander implementation, we sometimes use syntactic abstractions
- ;;; when procedural abstractions would suffice. For example, we define
- ;;; top-wrap and top-marked? as
- ;;; (define-syntax top-wrap (identifier-syntax '((top))))
- ;;; (define-syntax top-marked?
- ;;; (syntax-rules ()
- ;;; ((_ w) (memq 'top (wrap-marks w)))))
- ;;; rather than
- ;;; (define top-wrap '((top)))
- ;;; (define top-marked?
- ;;; (lambda (w) (memq 'top (wrap-marks w))))
- ;;; On ther other hand, we don't do this consistently; we define make-wrap,
- ;;; wrap-marks, and wrap-subst simply as
- ;;; (define make-wrap cons)
- ;;; (define wrap-marks car)
- ;;; (define wrap-subst cdr)
- ;;; In Chez Scheme, the syntactic and procedural forms of these
- ;;; abstractions are equivalent, since the optimizer consistently
- ;;; integrates constants and small procedures. Some Scheme
- ;;; implementations, however, may benefit from more consistent use
- ;;; of one form or the other.
- ;;; implementation information:
- ;;; "begin" is treated as a splicing construct at top level and at
- ;;; the beginning of bodies. Any sequence of expressions that would
- ;;; be allowed where the "begin" occurs is allowed.
- ;;; "let-syntax" and "letrec-syntax" are also treated as splicing
- ;;; constructs, in violation of the R4RS appendix and probably the R5RS
- ;;; when it comes out. A consequence, let-syntax and letrec-syntax do
- ;;; not create local contours, as do let and letrec. Although the
- ;;; functionality is greater as it is presently implemented, we will
- ;;; probably change it to conform to the R4RS/expected R5RS.
- ;;; Objects with no standard print syntax, including objects containing
- ;;; cycles and syntax object, are allowed in quoted data as long as they
- ;;; are contained within a syntax form or produced by datum->syntax-object.
- ;;; Such objects are never copied.
- ;;; All identifiers that don't have macro definitions and are not bound
- ;;; lexically are assumed to be global variables
- ;;; Top-level definitions of macro-introduced identifiers are allowed.
- ;;; This may not be appropriate for implementations in which the
- ;;; model is that bindings are created by definitions, as opposed to
- ;;; one in which initial values are assigned by definitions.
- ;;; Top-level variable definitions of syntax keywords is not permitted.
- ;;; Any solution allowing this would be kludgey and would yield
- ;;; surprising results in some cases. We can provide an undefine-syntax
- ;;; form. The questions is, should define be an implicit undefine-syntax?
- ;;; We've decided no for now.
- ;;; Identifiers and syntax objects are implemented as vectors for
- ;;; portability. As a result, it is possible to "forge" syntax
- ;;; objects.
- ;;; The implementation of generate-temporaries assumes that it is possible
- ;;; to generate globally unique symbols (gensyms).
- ;;; The input to sc-expand may contain "annotations" describing, e.g., the
- ;;; source file and character position from where each object was read if
- ;;; it was read from a file. These annotations are handled properly by
- ;;; sc-expand only if the annotation? hook (see hooks below) is implemented
- ;;; properly and the operators make-annotation, annotation-expression,
- ;;; annotation-source, annotation-stripped, and set-annotation-stripped!
- ;;; are supplied. If annotations are supplied, the proper annotation
- ;;; source is passed to the various output constructors, allowing
- ;;; implementations to accurately correlate source and expanded code.
- ;;; Contact one of the authors for details if you wish to make use of
- ;;; this feature.
- ;;; Bootstrapping:
- ;;; When changing syntax-object representations, it is necessary to support
- ;;; both old and new syntax-object representations in id-var-name. It
- ;;; should be sufficient to recognize old representations and treat
- ;;; them as not lexically bound.
- (let ()
- (define-syntax define-structure
- (lambda (x)
- (define construct-name
- (lambda (template-identifier . args)
- (datum->syntax-object
- template-identifier
- (string->symbol
- (apply string-append
- (map (lambda (x)
- (if (string? x)
- x
- (symbol->string (syntax-object->datum x))))
- args))))))
- (syntax-case x ()
- ((_ (name id1 ...))
- (andmap identifier? (syntax (name id1 ...)))
- (with-syntax
- ((constructor (construct-name (syntax name) "make-" (syntax name)))
- (predicate (construct-name (syntax name) (syntax name) "?"))
- ((access ...)
- (map (lambda (x) (construct-name x (syntax name) "-" x))
- (syntax (id1 ...))))
- ((assign ...)
- (map (lambda (x)
- (construct-name x "set-" (syntax name) "-" x "!"))
- (syntax (id1 ...))))
- (structure-length
- (+ (length (syntax (id1 ...))) 1))
- ((index ...)
- (let f ((i 1) (ids (syntax (id1 ...))))
- (if (null? ids)
- '()
- (cons i (f (+ i 1) (cdr ids)))))))
- (syntax (begin
- (define constructor
- (lambda (id1 ...)
- (vector 'name id1 ... )))
- (define predicate
- (lambda (x)
- (and (vector? x)
- (= (vector-length x) structure-length)
- (eq? (vector-ref x 0) 'name))))
- (define access
- (lambda (x)
- (vector-ref x index)))
- ...
- (define assign
- (lambda (x update)
- (vector-set! x index update)))
- ...)))))))
- (let ()
- (define noexpand "noexpand")
- ;;; hooks to nonportable run-time helpers
- (begin
- (define fx+ +)
- (define fx- -)
- (define fx= =)
- (define fx< <)
- (define annotation? (lambda (x) #f))
- (define top-level-eval-hook
- (lambda (x)
- (eval `(,noexpand ,x) (interaction-environment))))
- (define local-eval-hook
- (lambda (x)
- (eval `(,noexpand ,x) (interaction-environment))))
- (define error-hook
- (lambda (who why what)
- (error who "~a ~s" why what)))
- (define-syntax gensym-hook
- (syntax-rules ()
- ((_) (gensym))))
- (define put-global-definition-hook
- (lambda (symbol binding)
- (putprop symbol '*sc-expander* binding)))
- (define get-global-definition-hook
- (lambda (symbol)
- (getprop symbol '*sc-expander*)))
- )
- ;;; output constructors
- (begin
- (define-syntax build-application
- (syntax-rules ()
- ((_ source fun-exp arg-exps)
- `(,fun-exp . ,arg-exps))))
- (define-syntax build-conditional
- (syntax-rules ()
- ((_ source test-exp then-exp else-exp)
- `(if ,test-exp ,then-exp ,else-exp))))
- (define-syntax build-lexical-reference
- (syntax-rules ()
- ((_ type source var)
- var)))
- (define-syntax build-lexical-assignment
- (syntax-rules ()
- ((_ source var exp)
- `(set! ,var ,exp))))
- (define-syntax build-global-reference
- (syntax-rules ()
- ((_ source var)
- var)))
- (define-syntax build-global-assignment
- (syntax-rules ()
- ((_ source var exp)
- `(set! ,var ,exp))))
- (define-syntax build-global-definition
- (syntax-rules ()
- ((_ source var exp)
- `(define ,var ,exp))))
- (define-syntax build-lambda
- (syntax-rules ()
- ((_ src vars exp)
- `(lambda ,vars ,exp))))
- (define-syntax build-primref
- (syntax-rules ()
- ((_ src name) name)
- ((_ src level name) name)))
- (define (build-data src exp)
- (if (and (self-evaluating? exp)
- (not (vector? exp)))
- exp
- (list 'quote exp)))
- (define build-sequence
- (lambda (src exps)
- (if (null? (cdr exps))
- (car exps)
- `(begin ,@exps))))
- (define build-let
- (lambda (src vars val-exps body-exp)
- (if (null? vars)
- body-exp
- `(let ,(map list vars val-exps) ,body-exp))))
- (define build-named-let
- (lambda (src vars val-exps body-exp)
- (if (null? vars)
- body-exp
- `(let ,(car vars) ,(map list (cdr vars) val-exps) ,body-exp))))
- (define build-letrec
- (lambda (src vars val-exps body-exp)
- (if (null? vars)
- body-exp
- `(letrec ,(map list vars val-exps) ,body-exp))))
- (define-syntax build-lexical-var
- (syntax-rules ()
- ((_ src id) (gensym (symbol->string id)))))
- )
- (define-structure (syntax-object expression wrap))
- (define-syntax unannotate
- (syntax-rules ()
- ((_ x)
- (let ((e x))
- (if (annotation? e)
- (annotation-expression e)
- e)))))
- (define-syntax no-source (identifier-syntax #f))
- (define source-annotation
- (lambda (x)
- (cond
- ((annotation? x) (annotation-source x))
- ((syntax-object? x) (source-annotation (syntax-object-expression x)))
- (else no-source))))
- (define-syntax arg-check
- (syntax-rules ()
- ((_ pred? e who)
- (let ((x e))
- (if (not (pred? x)) (error-hook who "invalid argument" x))))))
- ;;; compile-time environments
- ;;; wrap and environment comprise two level mapping.
- ;;; wrap : id --> label
- ;;; env : label --> <element>
- ;;; environments are represented in two parts: a lexical part and a global
- ;;; part. The lexical part is a simple list of associations from labels
- ;;; to bindings. The global part is implemented by
- ;;; {put,get}-global-definition-hook and associates symbols with
- ;;; bindings.
- ;;; global (assumed global variable) and displaced-lexical (see below)
- ;;; do not show up in any environment; instead, they are fabricated by
- ;;; lookup when it finds no other bindings.
- ;;; <environment> ::= ((<label> . <binding>)*)
- ;;; identifier bindings include a type and a value
- ;;; <binding> ::= (macro . <procedure>) macros
- ;;; (core . <procedure>) core forms
- ;;; (external-macro . <procedure>) external-macro
- ;;; (begin) begin
- ;;; (define) define
- ;;; (define-syntax) define-syntax
- ;;; (local-syntax . rec?) let-syntax/letrec-syntax
- ;;; (eval-when) eval-when
- ;;; (syntax . (<var> . <level>)) pattern variables
- ;;; (global) assumed global variable
- ;;; (lexical . <var>) lexical variables
- ;;; (displaced-lexical) displaced lexicals
- ;;; <level> ::= <nonnegative integer>
- ;;; <var> ::= variable returned by build-lexical-var
- ;;; a macro is a user-defined syntactic-form. a core is a system-defined
- ;;; syntactic form. begin, define, define-syntax, and eval-when are
- ;;; treated specially since they are sensitive to whether the form is
- ;;; at top-level and (except for eval-when) can denote valid internal
- ;;; definitions.
- ;;; a pattern variable is a variable introduced by syntax-case and can
- ;;; be referenced only within a syntax form.
- ;;; any identifier for which no top-level syntax definition or local
- ;;; binding of any kind has been seen is assumed to be a global
- ;;; variable.
- ;;; a lexical variable is a lambda- or letrec-bound variable.
- ;;; a displaced-lexical identifier is a lexical identifier removed from
- ;;; it's scope by the return of a syntax object containing the identifier.
- ;;; a displaced lexical can also appear when a letrec-syntax-bound
- ;;; keyword is referenced on the rhs of one of the letrec-syntax clauses.
- ;;; a displaced lexical should never occur with properly written macros.
- (define-syntax make-binding
- (syntax-rules (quote)
- ((_ type value) (cons type value))
- ((_ 'type) '(type))
- ((_ type) (cons type '()))))
- (define binding-type car)
- (define binding-value cdr)
- (define-syntax null-env (identifier-syntax '()))
- (define extend-env
- (lambda (labels bindings r)
- (if (null? labels)
- r
- (extend-env (cdr labels) (cdr bindings)
- (cons (cons (car labels) (car bindings)) r)))))
- (define extend-var-env
- ; variant of extend-env that forms "lexical" binding
- (lambda (labels vars r)
- (if (null? labels)
- r
- (extend-var-env (cdr labels) (cdr vars)
- (cons (cons (car labels) (make-binding 'lexical (car vars))) r)))))
- ;;; we use a "macros only" environment in expansion of local macro
- ;;; definitions so that their definitions can use local macros without
- ;;; attempting to use other lexical identifiers.
- (define macros-only-env
- (lambda (r)
- (if (null? r)
- '()
- (let ((a (car r)))
- (if (eq? (cadr a) 'macro)
- (cons a (macros-only-env (cdr r)))
- (macros-only-env (cdr r)))))))
- (define lookup
- ; x may be a label or a symbol
- ; although symbols are usually global, we check the environment first
- ; anyway because a temporary binding may have been established by
- ; fluid-let-syntax
- (lambda (x r)
- (cond
- ((assq x r) => cdr)
- ((symbol? x)
- (or (get-global-definition-hook x) (make-binding 'global)))
- (else (make-binding 'displaced-lexical)))))
- (define global-extend
- (lambda (type sym val)
- (put-global-definition-hook sym (make-binding type val))))
- ;;; Conceptually, identifiers are always syntax objects. Internally,
- ;;; however, the wrap is sometimes maintained separately (a source of
- ;;; efficiency and confusion), so that symbols are also considered
- ;;; identifiers by id?. Externally, they are always wrapped.
- (define nonsymbol-id?
- (lambda (x)
- (and (syntax-object? x)
- (symbol? (unannotate (syntax-object-expression x))))))
- (define id?
- (lambda (x)
- (cond
- ((symbol? x) #t)
- ((syntax-object? x) (symbol? (unannotate (syntax-object-expression x))))
- ((annotation? x) (symbol? (annotation-expression x)))
- (else #f))))
- (define-syntax id-sym-name
- (syntax-rules ()
- ((_ e)
- (let ((x e))
- (unannotate (if (syntax-object? x) (syntax-object-expression x) x))))))
- (define id-sym-name&marks
- (lambda (x w)
- (if (syntax-object? x)
- (values
- (unannotate (syntax-object-expression x))
- (join-marks (wrap-marks w) (wrap-marks (syntax-object-wrap x))))
- (values (unannotate x) (wrap-marks w)))))
- ;;; syntax object wraps
- ;;; <wrap> ::= ((<mark> ...) . (<subst> ...))
- ;;; <subst> ::= <shift> | <subs>
- ;;; <subs> ::= #(<old name> <label> (<mark> ...))
- ;;; <shift> ::= positive fixnum
- (define make-wrap cons)
- (define wrap-marks car)
- (define wrap-subst cdr)
- (define-syntax subst-rename? (identifier-syntax vector?))
- (define-syntax rename-old (syntax-rules () ((_ x) (vector-ref x 0))))
- (define-syntax rename-new (syntax-rules () ((_ x) (vector-ref x 1))))
- (define-syntax rename-marks (syntax-rules () ((_ x) (vector-ref x 2))))
- (define-syntax make-rename
- (syntax-rules ()
- ((_ old new marks) (vector old new marks))))
- ;;; labels must be comparable with "eq?" and distinct from symbols.
- (define gen-label
- (lambda () (string #\i)))
- (define gen-labels
- (lambda (ls)
- (if (null? ls)
- '()
- (cons (gen-label) (gen-labels (cdr ls))))))
- (define-structure (ribcage symnames marks labels))
- (define-syntax empty-wrap (identifier-syntax '(())))
- (define-syntax top-wrap (identifier-syntax '((top))))
- (define-syntax top-marked?
- (syntax-rules ()
- ((_ w) (memq 'top (wrap-marks w)))))
- ;;; Marks must be comparable with "eq?" and distinct from pairs and
- ;;; the symbol top. We do not use integers so that marks will remain
- ;;; unique even across file compiles.
- (define-syntax the-anti-mark (identifier-syntax #f))
- (define anti-mark
- (lambda (w)
- (make-wrap (cons the-anti-mark (wrap-marks w))
- (cons 'shift (wrap-subst w)))))
- (define-syntax new-mark
- (syntax-rules ()
- ((_) (string #\m))))
- ;;; make-empty-ribcage and extend-ribcage maintain list-based ribcages for
- ;;; internal definitions, in which the ribcages are built incrementally
- (define-syntax make-empty-ribcage
- (syntax-rules ()
- ((_) (make-ribcage '() '() '()))))
- (define extend-ribcage!
- ; must receive ids with complete wraps
- (lambda (ribcage id label)
- (set-ribcage-symnames! ribcage
- (cons (unannotate (syntax-object-expression id))
- (ribcage-symnames ribcage)))
- (set-ribcage-marks! ribcage
- (cons (wrap-marks (syntax-object-wrap id))
- (ribcage-marks ribcage)))
- (set-ribcage-labels! ribcage
- (cons label (ribcage-labels ribcage)))))
- ;;; make-binding-wrap creates vector-based ribcages
- (define make-binding-wrap
- (lambda (ids labels w)
- (if (null? ids)
- w
- (make-wrap
- (wrap-marks w)
- (cons
- (let ((labelvec (list->vector labels)))
- (let ((n (vector-length labelvec)))
- (let ((symnamevec (make-vector n)) (marksvec (make-vector n)))
- (let f ((ids ids) (i 0))
- (if (not (null? ids))
- (call-with-values
- (lambda () (id-sym-name&marks (car ids) w))
- (lambda (symname marks)
- (vector-set! symnamevec i symname)
- (vector-set! marksvec i marks)
- (f (cdr ids) (fx+ i 1))))))
- (make-ribcage symnamevec marksvec labelvec))))
- (wrap-subst w))))))
- (define smart-append
- (lambda (m1 m2)
- (if (null? m2)
- m1
- (append m1 m2))))
- (define join-wraps
- (lambda (w1 w2)
- (let ((m1 (wrap-marks w1)) (s1 (wrap-subst w1)))
- (if (null? m1)
- (if (null? s1)
- w2
- (make-wrap
- (wrap-marks w2)
- (smart-append s1 (wrap-subst w2))))
- (make-wrap
- (smart-append m1 (wrap-marks w2))
- (smart-append s1 (wrap-subst w2)))))))
- (define join-marks
- (lambda (m1 m2)
- (smart-append m1 m2)))
- (define same-marks?
- (lambda (x y)
- (or (eq? x y)
- (and (not (null? x))
- (not (null? y))
- (eq? (car x) (car y))
- (same-marks? (cdr x) (cdr y))))))
- (define id-var-name
- (lambda (id w)
- (define-syntax first
- (syntax-rules ()
- ((_ e) (call-with-values (lambda () e) (lambda (x . ignore) x)))))
- (define search
- (lambda (sym subst marks)
- (if (null? subst)
- (values #f marks)
- (let ((fst (car subst)))
- (if (eq? fst 'shift)
- (search sym (cdr subst) (cdr marks))
- (let ((symnames (ribcage-symnames fst)))
- (if (vector? symnames)
- (search-vector-rib sym subst marks symnames fst)
- (search-list-rib sym subst marks symnames fst))))))))
- (define search-list-rib
- (lambda (sym subst marks symnames ribcage)
- (let f ((symnames symnames) (i 0))
- (cond
- ((null? symnames) (search sym (cdr subst) marks))
- ((and (eq? (car symnames) sym)
- (same-marks? marks (list-ref (ribcage-marks ribcage) i)))
- (values (list-ref (ribcage-labels ribcage) i) marks))
- (else (f (cdr symnames) (fx+ i 1)))))))
- (define search-vector-rib
- (lambda (sym subst marks symnames ribcage)
- (let ((n (vector-length symnames)))
- (let f ((i 0))
- (cond
- ((fx= i n) (search sym (cdr subst) marks))
- ((and (eq? (vector-ref symnames i) sym)
- (same-marks? marks (vector-ref (ribcage-marks ribcage) i)))
- (values (vector-ref (ribcage-labels ribcage) i) marks))
- (else (f (fx+ i 1))))))))
- (cond
- ((symbol? id)
- (or (first (search id (wrap-subst w) (wrap-marks w))) id))
- ((syntax-object? id)
- (let ((id (unannotate (syntax-object-expression id)))
- (w1 (syntax-object-wrap id)))
- (let ((marks (join-marks (wrap-marks w) (wrap-marks w1))))
- (call-with-values (lambda () (search id (wrap-subst w) marks))
- (lambda (new-id marks)
- (or new-id
- (first (search id (wrap-subst w1) marks))
- id))))))
- ((annotation? id)
- (let ((id (unannotate id)))
- (or (first (search id (wrap-subst w) (wrap-marks w))) id)))
- (else (error-hook 'id-var-name "invalid id" id)))))
- ;;; free-id=? must be passed fully wrapped ids since (free-id=? x y)
- ;;; may be true even if (free-id=? (wrap x w) (wrap y w)) is not.
- (define free-id=?
- (lambda (i j)
- (and (eq? (id-sym-name i) (id-sym-name j)) ; accelerator
- (eq? (id-var-name i empty-wrap) (id-var-name j empty-wrap)))))
- ;;; bound-id=? may be passed unwrapped (or partially wrapped) ids as
- ;;; long as the missing portion of the wrap is common to both of the ids
- ;;; since (bound-id=? x y) iff (bound-id=? (wrap x w) (wrap y w))
- (define bound-id=?
- (lambda (i j)
- (if (and (syntax-object? i) (syntax-object? j))
- (and (eq? (unannotate (syntax-object-expression i))
- (unannotate (syntax-object-expression j)))
- (same-marks? (wrap-marks (syntax-object-wrap i))
- (wrap-marks (syntax-object-wrap j))))
- (eq? (unannotate i) (unannotate j)))))
- ;;; "valid-bound-ids?" returns #t if it receives a list of distinct ids.
- ;;; valid-bound-ids? may be passed unwrapped (or partially wrapped) ids
- ;;; as long as the missing portion of the wrap is common to all of the
- ;;; ids.
- (define valid-bound-ids?
- (lambda (ids)
- (and (let all-ids? ((ids ids))
- (or (null? ids)
- (and (id? (car ids))
- (all-ids? (cdr ids)))))
- (distinct-bound-ids? ids))))
- ;;; distinct-bound-ids? expects a list of ids and returns #t if there are
- ;;; no duplicates. It is quadratic on the length of the id list; long
- ;;; lists could be sorted to make it more efficient. distinct-bound-ids?
- ;;; may be passed unwrapped (or partially wrapped) ids as long as the
- ;;; missing portion of the wrap is common to all of the ids.
- (define distinct-bound-ids?
- (lambda (ids)
- (let distinct? ((ids ids))
- (or (null? ids)
- (and (not (bound-id-member? (car ids) (cdr ids)))
- (distinct? (cdr ids)))))))
- (define bound-id-member?
- (lambda (x list)
- (and (not (null? list))
- (or (bound-id=? x (car list))
- (bound-id-member? x (cdr list))))))
- ;;; wrapping expressions and identifiers
- (define wrap
- (lambda (x w)
- (cond
- ((and (null? (wrap-marks w)) (null? (wrap-subst w))) x)
- ((syntax-object? x)
- (make-syntax-object
- (syntax-object-expression x)
- (join-wraps w (syntax-object-wrap x))))
- ((null? x) x)
- (else (make-syntax-object x w)))))
- (define source-wrap
- (lambda (x w s)
- (wrap (if s (make-annotation x s #f) x) w)))
- ;;; expanding
- (define chi-sequence
- (lambda (body r w s)
- (build-sequence s
- (let dobody ((body body) (r r) (w w))
- (if (null? body)
- '()
- (let ((first (chi (car body) r w)))
- (cons first (dobody (cdr body) r w))))))))
- (define chi-top-sequence
- (lambda (body r w s m esew)
- (build-sequence s
- (let dobody ((body body) (r r) (w w) (m m) (esew esew))
- (if (null? body)
- '()
- (let ((first (chi-top (car body) r w m esew)))
- (cons first (dobody (cdr body) r w m esew))))))))
- (define chi-install-global
- (lambda (name e)
- (build-application no-source
- (build-primref no-source 'install-global-transformer)
- (list (build-data no-source name) e))))
- (define chi-when-list
- (lambda (e when-list w)
- ; when-list is syntax'd version of list of situations
- (let f ((when-list when-list) (situations '()))
- (if (null? when-list)
- situations
- (f (cdr when-list)
- (cons (let ((x (car when-list)))
- (cond
- ((free-id=? x (syntax compile)) 'compile)
- ((free-id=? x (syntax load)) 'load)
- ((free-id=? x (syntax eval)) 'eval)
- (else (syntax-error (wrap x w)
- "invalid eval-when situation"))))
- situations))))))
- ;;; syntax-type returns five values: type, value, e, w, and s. The first
- ;;; two are described in the table below.
- ;;;
- ;;; type value explanation
- ;;; -------------------------------------------------------------------
- ;;; core procedure core form (including singleton)
- ;;; external-macro procedure external macro
- ;;; lexical name lexical variable reference
- ;;; global name global variable reference
- ;;; begin none begin keyword
- ;;; define none define keyword
- ;;; define-syntax none define-syntax keyword
- ;;; local-syntax rec? letrec-syntax/let-syntax keyword
- ;;; eval-when none eval-when keyword
- ;;; syntax level pattern variable
- ;;; displaced-lexical none displaced lexical identifier
- ;;; lexical-call name call to lexical variable
- ;;; global-call name call to global variable
- ;;; call none any other call
- ;;; begin-form none begin expression
- ;;; define-form id variable definition
- ;;; define-syntax-form id syntax definition
- ;;; local-syntax-form rec? syntax definition
- ;;; eval-when-form none eval-when form
- ;;; constant none self-evaluating datum
- ;;; other none anything else
- ;;;
- ;;; For define-form and define-syntax-form, e is the rhs expression.
- ;;; For all others, e is the entire form. w is the wrap for e.
- ;;; s is the source for the entire form.
- ;;;
- ;;; syntax-type expands macros and unwraps as necessary to get to
- ;;; one of the forms above. It also parses define and define-syntax
- ;;; forms, although perhaps this should be done by the consumer.
- (define syntax-type
- (lambda (e r w s rib)
- (cond
- ((symbol? e)
- (let* ((n (id-var-name e w))
- (b (lookup n r))
- (type (binding-type b)))
- (case type
- ((lexical) (values type (binding-value b) e w s))
- ((global) (values type n e w s))
- ((macro)
- (syntax-type (chi-macro (binding-value b) e r w rib) r empty-wrap s rib))
- (else (values type (binding-value b) e w s)))))
- ((pair? e)
- (let ((first (car e)))
- (if (id? first)
- (let* ((n (id-var-name first w))
- (b (lookup n r))
- (type (binding-type b)))
- (case type
- ((lexical) (values 'lexical-call (binding-value b) e w s))
- ((global) (values 'global-call n e w s))
- ((macro)
- (syntax-type (chi-macro (binding-value b) e r w rib)
- r empty-wrap s rib))
- ((core external-macro) (values type (binding-value b) e w s))
- ((local-syntax)
- (values 'local-syntax-form (binding-value b) e w s))
- ((begin) (values 'begin-form #f e w s))
- ((eval-when) (values 'eval-when-form #f e w s))
- ((define)
- (syntax-case e ()
- ((_ name val)
- (id? (syntax name))
- (values 'define-form (syntax name) (syntax val) w s))
- ((_ (name . args) e1 e2 ...)
- (and (id? (syntax name))
- (valid-bound-ids? (lambda-var-list (syntax args))))
- ; need lambda here...
- (values 'define-form (wrap (syntax name) w)
- (cons (syntax lambda) (wrap (syntax (args e1 e2 ...)) w))
- empty-wrap s))
- ((_ name)
- (id? (syntax name))
- (values 'define-form (wrap (syntax name) w)
- (syntax (void))
- empty-wrap s))))
- ((define-syntax)
- (syntax-case e ()
- ((_ name val)
- (id? (syntax name))
- (values 'define-syntax-form (syntax name)
- (syntax val) w s))))
- (else (values 'call #f e w s))))
- (values 'call #f e w s))))
- ((syntax-object? e)
- ;; s can't be valid source if we've unwrapped
- (syntax-type (syntax-object-expression e)
- r
- (join-wraps w (syntax-object-wrap e))
- no-source rib))
- ((annotation? e)
- (syntax-type (annotation-expression e) r w (annotation-source e) rib))
- ((self-evaluating? e) (values 'constant #f e w s))
- (else (values 'other #f e w s)))))
- (define chi-top
- (lambda (e r w m esew)
- (define-syntax eval-if-c&e
- (syntax-rules ()
- ((_ m e)
- (let ((x e))
- (if (eq? m 'c&e) (top-level-eval-hook x))
- x))))
- (call-with-values
- (lambda () (syntax-type e r w no-source #f))
- (lambda (type value e w s)
- (case type
- ((begin-form)
- (syntax-case e ()
- ((_) (chi-void))
- ((_ e1 e2 ...)
- (chi-top-sequence (syntax (e1 e2 ...)) r w s m esew))))
- ((local-syntax-form)
- (chi-local-syntax value e r w s
- (lambda (body r w s)
- (chi-top-sequence body r w s m esew))))
- ((eval-when-form)
- (syntax-case e ()
- ((_ (x ...) e1 e2 ...)
- (let ((when-list (chi-when-list e (syntax (x ...)) w))
- (body (syntax (e1 e2 ...))))
- (cond
- ((eq? m 'e)
- (if (memq 'eval when-list)
- (chi-top-sequence body r w s 'e '(eval))
- (chi-void)))
- ((memq 'load when-list)
- (if (or (memq 'compile when-list)
- (and (eq? m 'c&e) (memq 'eval when-list)))
- (chi-top-sequence body r w s 'c&e '(compile load))
- (if (memq m '(c c&e))
- (chi-top-sequence body r w s 'c '(load))
- (chi-void))))
- ((or (memq 'compile when-list)
- (and (eq? m 'c&e) (memq 'eval when-list)))
- (top-level-eval-hook
- (chi-top-sequence body r w s 'e '(eval)))
- (chi-void))
- (else (chi-void)))))))
- ((define-syntax-form)
- (let ((n (id-var-name value w)) (r (macros-only-env r)))
- (case m
- ((c)
- (if (memq 'compile esew)
- (let ((e (chi-install-global n (chi e r w))))
- (top-level-eval-hook e)
- (if (memq 'load esew) e (chi-void)))
- (if (memq 'load esew)
- (chi-install-global n (chi e r w))
- (chi-void))))
- ((c&e)
- (let ((e (chi-install-global n (chi e r w))))
- (top-level-eval-hook e)
- e))
- (else
- (if (memq 'eval esew)
- (top-level-eval-hook
- (chi-install-global n (chi e r w))))
- (chi-void)))))
- ((define-form)
- (let* ((n (id-var-name value w))
- (type (binding-type (lookup n r))))
- (case type
- ((global)
- (eval-if-c&e m
- (build-global-definition s n (chi e r w))))
- ((displaced-lexical)
- (syntax-error (wrap value w) "identifier out of context"))
- (else
- (if (eq? type 'external-macro)
- (eval-if-c&e m
- (build-global-definition s n (chi e r w)))
- (syntax-error (wrap value w)
- "cannot define keyword at top level"))))))
- (else (eval-if-c&e m (chi-expr type value e r w s))))))))
- (define chi
- (lambda (e r w)
- (call-with-values
- (lambda () (syntax-type e r w no-source #f))
- (lambda (type value e w s)
- (chi-expr type value e r w s)))))
- (define chi-expr
- (lambda (type value e r w s)
- (case type
- ((lexical)
- (build-lexical-reference 'value s value))
- ((core external-macro) (value e r w s))
- ((lexical-call)
- (chi-application
- (build-lexical-reference 'fun (source-annotation (car e)) value)
- e r w s))
- ((global-call)
- (chi-application
- (build-global-reference (source-annotation (car e)) value)
- e r w s))
- ((constant) (build-data s (strip (source-wrap e w s) empty-wrap)))
- ((global) (build-global-reference s value))
- ((call) (chi-application (chi (car e) r w) e r w s))
- ((begin-form)
- (syntax-case e ()
- ((_ e1 e2 ...) (chi-sequence (syntax (e1 e2 ...)) r w s))))
- ((local-syntax-form)
- (chi-local-syntax value e r w s chi-sequence))
- ((eval-when-form)
- (syntax-case e ()
- ((_ (x ...) e1 e2 ...)
- (let ((when-list (chi-when-list e (syntax (x ...)) w)))
- (if (memq 'eval when-list)
- (chi-sequence (syntax (e1 e2 ...)) r w s)
- (chi-void))))))
- ((define-form define-syntax-form)
- (syntax-error (wrap value w) "invalid context for definition of"))
- ((syntax)
- (syntax-error (source-wrap e w s)
- "reference to pattern variable outside syntax form"))
- ((displaced-lexical)
- (syntax-error (source-wrap e w s)
- "reference to identifier outside its scope"))
- (else (syntax-error (source-wrap e w s))))))
- (define chi-application
- (lambda (x e r w s)
- (syntax-case e ()
- ((e0 e1 ...)
- (build-application s x
- (map (lambda (e) (chi e r w)) (syntax (e1 ...))))))))
- (define chi-macro
- (lambda (p e r w rib)
- (define rebuild-macro-output
- (lambda (x m)
- (cond ((pair? x)
- (cons (rebuild-macro-output (car x) m)
- (rebuild-macro-output (cdr x) m)))
- ((syntax-object? x)
- (let ((w (syntax-object-wrap x)))
- (let ((ms (wrap-marks w)) (s (wrap-subst w)))
- (make-syntax-object (syntax-object-expression x)
- (if (and (pair? ms) (eq? (car ms) the-anti-mark))
- (make-wrap (cdr ms)
- (if rib (cons rib (cdr s)) (cdr s)))
- (make-wrap (cons m ms)
- (if rib
- (cons rib (cons 'shift s))
- (cons 'shift s))))))))
- ((vector? x)
- (let* ((n (vector-length x)) (v (make-vector n)))
- (do ((i 0 (fx+ i 1)))
- ((fx= i n) v)
- (vector-set! v i
- (rebuild-macro-output (vector-ref x i) m)))))
- ((symbol? x)
- (syntax-error x "encountered raw symbol in macro output"))
- (else x))))
- (rebuild-macro-output (p (wrap e (anti-mark w))) (new-mark))))
- (define chi-body
- ;; In processing the forms of the body, we create a new, empty wrap.
- ;; This wrap is augmented (destructively) each time we discover that
- ;; the next form is a definition. This is done:
- ;;
- ;; (1) to allow the first nondefinition form to be a call to
- ;; one of the defined ids even if the id previously denoted a
- ;; definition keyword or keyword for a macro expanding into a
- ;; definition;
- ;; (2) to prevent subsequent definition forms (but unfortunately
- ;; not earlier ones) and the first nondefinition form from
- ;; confusing one of the bound identifiers for an auxiliary
- ;; keyword; and
- ;; (3) so that we do not need to restart the expansion of the
- ;; first nondefinition form, which is problematic anyway
- ;; since it might be the first element of a begin that we
- ;; have just spliced into the body (meaning if we restarted,
- ;; we'd really need to restart with the begin or the macro
- ;; call that expanded into the begin, and we'd have to give
- ;; up allowing (begin <defn>+ <expr>+), which is itself
- ;; problematic since we don't know if a begin contains only
- ;; definitions until we've expanded it).
- ;;
- ;; Before processing the body, we also create a new environment
- ;; containing a placeholder for the bindings we will add later and
- ;; associate this environment with each form. In processing a
- ;; let-syntax or letrec-syntax, the associated environment may be
- ;; augmented with local keyword bindings, so the environment may
- ;; be different for different forms in the body. Once we have
- ;; gathered up all of the definitions, we evaluate the transformer
- ;; expressions and splice into r at the placeholder the new variable
- ;; and keyword bindings. This allows let-syntax or letrec-syntax
- ;; forms local to a portion or all of the body to shadow the
- ;; definition bindings.
- ;;
- ;; Subforms of a begin, let-syntax, or letrec-syntax are spliced
- ;; into the body.
- ;;
- ;; outer-form is fully wrapped w/source
- (lambda (body outer-form r w)
- (let* ((r (cons '("placeholder" . (placeholder)) r))
- (ribcage (make-empty-ribcage))
- (w (make-wrap (wrap-marks w) (cons ribcage (wrap-subst w)))))
- (let parse ((body (map (lambda (x) (cons r (wrap x w))) body))
- (ids '()) (labels '()) (vars '()) (vals '()) (bindings '()))
- (if (null? body)
- (syntax-error outer-form "no expressions in body")
- (let ((e (cdar body)) (er (caar body)))
- (call-with-values
- (lambda () (syntax-type e er empty-wrap no-source ribcage))
- (lambda (type value e w s)
- (case type
- ((define-form)
- (let ((id (wrap value w)) (label (gen-label)))
- (let ((var (gen-var id)))
- (extend-ribcage! ribcage id label)
- (parse (cdr body)
- (cons id ids) (cons label labels)
- (cons var vars) (cons (cons er (wrap e w)) vals)
- (cons (make-binding 'lexical var) bindings)))))
- ((define-syntax-form)
- (let ((id (wrap value w)) (label (gen-label)))
- (extend-ribcage! ribcage id label)
- (parse (cdr body)
- (cons id ids) (cons label labels)
- vars vals
- (cons (make-binding 'macro (cons er (wrap e w)))
- bindings))))
- ((begin-form)
- (syntax-case e ()
- ((_ e1 ...)
- (parse (let f ((forms (syntax (e1 ...))))
- (if (null? forms)
- (cdr body)
- (cons (cons er (wrap (car forms) w))
- (f (cdr forms)))))
- ids labels vars vals bindings))))
- ((local-syntax-form)
- (chi-local-syntax value e er w s
- (lambda (forms er w s)
- (parse (let f ((forms forms))
- (if (null? forms)
- (cdr body)
- (cons (cons er (wrap (car forms) w))
- (f (cdr forms)))))
- ids labels vars vals bindings))))
- (else ; found a non-definition
- (if (null? ids)
- (build-sequence no-source
- (map (lambda (x)
- (chi (cdr x) (car x) empty-wrap))
- (cons (cons er (source-wrap e w s))
- (cdr body))))
- (begin
- (if (not (valid-bound-ids? ids))
- (syntax-error outer-form
- "invalid or duplicate identifier in definition"))
- (let loop ((bs bindings) (er-cache #f) (r-cache #f))
- (if (not (null? bs))
- (let* ((b (car bs)))
- (if (eq? (car b) 'macro)
- (let* ((er (cadr b))
- (r-cache
- (if (eq? er er-cache)
- r-cache
- (macros-only-env er))))
- (set-cdr! b
- (eval-local-transformer
- (chi (cddr b) r-cache empty-wrap)))
- (loop (cdr bs) er r-cache))
- (loop (cdr bs) er-cache r-cache)))))
- (set-cdr! r (extend-env labels bindings (cdr r)))
- (build-letrec no-source
- vars
- (map (lambda (x)
- (chi (cdr x) (car x) empty-wrap))
- vals)
- (build-sequence no-source
- (map (lambda (x)
- (chi (cdr x) (car x) empty-wrap))
- (cons (cons er (source-wrap e w s))
- (cdr body)))))))))))))))))
- (define chi-lambda-clause
- (lambda (e c r w k)
- (syntax-case c ()
- (((id ...) e1 e2 ...)
- (let ((ids (syntax (id ...))))
- (if (not (valid-bound-ids? ids))
- (syntax-error e "invalid parameter list in")
- (let ((labels (gen-labels ids))
- (new-vars (map gen-var ids)))
- (k new-vars
- (chi-body (syntax (e1 e2 ...))
- e
- (extend-var-env labels new-vars r)
- (make-binding-wrap ids labels w)))))))
- ((ids e1 e2 ...)
- (let ((old-ids (lambda-var-list (syntax ids))))
- (if (not (valid-bound-ids? old-ids))
- (syntax-error e "invalid parameter list in")
- (let ((labels (gen-labels old-ids))
- (new-vars (map gen-var old-ids)))
- (k (let f ((ls1 (cdr new-vars)) (ls2 (car new-vars)))
- (if (null? ls1)
- ls2
- (f (cdr ls1) (cons (car ls1) ls2))))
- (chi-body (syntax (e1 e2 ...))
- e
- (extend-var-env labels new-vars r)
- (make-binding-wrap old-ids labels w)))))))
- (_ (syntax-error e)))))
- (define chi-local-syntax
- (lambda (rec? e r w s k)
- (syntax-case e ()
- ((_ ((id val) ...) e1 e2 ...)
- (let ((ids (syntax (id ...))))
- (if (not (valid-bound-ids? ids))
- (syntax-error e "duplicate bound keyword in")
- (let ((labels (gen-labels ids)))
- (let ((new-w (make-binding-wrap ids labels w)))
- (k (syntax (e1 e2 ...))
- (extend-env
- labels
- (let ((w (if rec? new-w w))
- (trans-r (macros-only-env r)))
- (map (lambda (x)
- (make-binding 'macro
- (eval-local-transformer (chi x trans-r w))))
- (syntax (val ...))))
- r)
- new-w
- s))))))
- (_ (syntax-error (source-wrap e w s))))))
- (define eval-local-transformer
- (lambda (expanded)
- (let ((p (local-eval-hook expanded)))
- (if (procedure? p)
- p
- (syntax-error p "nonprocedure transformer")))))
- (define chi-void
- (lambda ()
- (build-application no-source (build-primref no-source 'void) '())))
- (define ellipsis?
- (lambda (x)
- (and (nonsymbol-id? x)
- (free-id=? x (syntax (... ...))))))
- ;;; data
- ;;; strips all annotations from potentially circular reader output
- (define strip-annotation
- (lambda (x parent)
- (cond
- ((pair? x)
- (let ((new (cons #f #f)))
- (when parent (set-annotation-stripped! parent new))
- (set-car! new (strip-annotation (car x) #f))
- (set-cdr! new (strip-annotation (cdr x) #f))
- new))
- ((annotation? x)
- (or (annotation-stripped x)
- (strip-annotation (annotation-expression x) x)))
- ((vector? x)
- (let ((new (make-vector (vector-length x))))
- (when parent (set-annotation-stripped! parent new))
- (let loop ((i (- (vector-length x) 1)))
- (unless (fx< i 0)
- (vector-set! new i (strip-annotation (vector-ref x i) #f))
- (loop (fx- i 1))))
- new))
- (else x))))
- ;;; strips syntax-objects down to top-wrap; if top-wrap is layered directly
- ;;; on an annotation, strips the annotation as well.
- ;;; since only the head of a list is annotated by the reader, not each pair
- ;;; in the spine, we also check for pairs whose cars are annotated in case
- ;;; we've been passed the cdr of an annotated list
- (define strip
- (lambda (x w)
- (if (top-marked? w)
- (if (or (annotation? x) (and (pair? x) (annotation? (car x))))
- (strip-annotation x #f)
- x)
- (let f ((x x))
- (cond
- ((syntax-object? x)
- (strip (syntax-object-expression x) (syntax-object-wrap x)))
- ((pair? x)
- (let ((a (f (car x))) (d (f (cdr x))))
- (if (and (eq? a (car x)) (eq? d (cdr x)))
- x
- (cons a d))))
- ((vector? x)
- (let ((old (vector->list x)))
- (let ((new (map f old)))
- (if (andmap eq? old new) x (list->vector new)))))
- (else x))))))
- ;;; lexical variables
- (define gen-var
- (lambda (id)
- (let ((id (if (syntax-object? id) (syntax-object-expression id) id)))
- (if (annotation? id)
- (build-lexical-var (annotation-source id) (annotation-expression id))
- (build-lexical-var no-source id)))))
- (define lambda-var-list
- (lambda (vars)
- (let lvl ((vars vars) (ls '()) (w empty-wrap))
- (cond
- ((pair? vars) (lvl (cdr vars) (cons (wrap (car vars) w) ls) w))
- ((id? vars) (cons (wrap vars w) ls))
- ((null? vars) ls)
- ((syntax-object? vars)
- (lvl (syntax-object-expression vars)
- ls
- (join-wraps w (syntax-object-wrap vars))))
- ((annotation? vars)
- (lvl (annotation-expression vars) ls w))
- ; include anything else to be caught by subsequent error
- ; checking
- (else (cons vars ls))))))
- ;;; core transformers
- (global-extend 'local-syntax 'letrec-syntax #t)
- (global-extend 'local-syntax 'let-syntax #f)
- (global-extend 'core 'fluid-let-syntax
- (lambda (e r w s)
- (syntax-case e ()
- ((_ ((var val) ...) e1 e2 ...)
- (valid-bound-ids? (syntax (var ...)))
- (let ((names (map (lambda (x) (id-var-name x w)) (syntax (var ...)))))
- (for-each
- (lambda (id n)
- (case (binding-type (lookup n r))
- ((displaced-lexical)
- (syntax-error (source-wrap id w s)
- "identifier out of context"))))
- (syntax (var ...))
- names)
- (chi-body
- (syntax (e1 e2 ...))
- (source-wrap e w s)
- (extend-env
- names
- (let ((trans-r (macros-only-env r)))
- (map (lambda (x)
- (make-binding 'macro
- (eval-local-transformer (chi x trans-r w))))
- (syntax (val ...))))
- r)
- w)))
- (_ (syntax-error (source-wrap e w s))))))
- (global-extend 'core 'quote
- (lambda (e r w s)
- (syntax-case e ()
- ((_ e) (build-data s (strip (syntax e) w)))
- (_ (syntax-error (source-wrap e w s))))))
- (global-extend 'core 'syntax
- (let ()
- (define gen-syntax
- (lambda (src e r maps ellipsis?)
- (if (id? e)
- (let ((label (id-var-name e empty-wrap)))
- (let ((b (lookup label r)))
- (if (eq? (binding-type b) 'syntax)
- (call-with-values
- (lambda ()
- (let ((var.lev (binding-value b)))
- (gen-ref src (car var.lev) (cdr var.lev) maps)))
- (lambda (var maps) (values `(ref ,var) maps)))
- (if (ellipsis? e)
- (syntax-error src "misplaced ellipsis in syntax form")
- (values `(quote ,e) maps)))))
- (syntax-case e ()
- ((dots e)
- (ellipsis? (syntax dots))
- (gen-syntax src (syntax e) r maps (lambda (x) #f)))
- ((x dots . y)
- ; this could be about a dozen lines of code, except that we
- ; choose to handle (syntax (x ... ...)) forms
- (ellipsis? (syntax dots))
- (let f ((y (syntax y))
- (k (lambda (maps)
- (call-with-values
- (lambda ()
- (gen-syntax src (syntax x) r
- (cons '() maps) ellipsis?))
- (lambda (x maps)
- (if (null? (car maps))
- (syntax-error src
- "extra ellipsis in syntax form")
- (values (gen-map x (car maps))
- (cdr maps))))))))
- (syntax-case y ()
- ((dots . y)
- (ellipsis? (syntax dots))
- (f (syntax y)
- (lambda (maps)
- (call-with-values
- (lambda () (k (cons '() maps)))
- (lambda (x maps)
- (if (null? (car maps))
- (syntax-error src
- "extra ellipsis in syntax form")
- (values (gen-mappend x (car maps))
- (cdr maps))))))))
- (_ (call-with-values
- (lambda () (gen-syntax src y r maps ellipsis?))
- (lambda (y maps)
- (call-with-values
- (lambda () (k maps))
- (lambda (x maps)
- (values (gen-append x y) maps)))))))))
- ((x . y)
- (call-with-values
- (lambda () (gen-syntax src (syntax x) r maps ellipsis?))
- (lambda (x maps)
- (call-with-values
- (lambda () (gen-syntax src (syntax y) r maps ellipsis?))
- (lambda (y maps) (values (gen-cons x y) maps))))))
- (#(e1 e2 ...)
- (call-with-values
- (lambda ()
- (gen-syntax src (syntax (e1 e2 ...)) r maps ellipsis?))
- (lambda (e maps) (values (gen-vector e) maps))))
- (_ (values `(quote ,e) maps))))))
- (define gen-ref
- (lambda (src var level maps)
- (if (fx= level 0)
- (values var maps)
- (if (null? maps)
- (syntax-error src "missing ellipsis in syntax form")
- (call-with-values
- (lambda () (gen-ref src var (fx- level 1) (cdr maps)))
- (lambda (outer-var outer-maps)
- (let ((b (assq outer-var (car maps))))
- (if b
- (values (cdr b) maps)
- (let ((inner-var (gen-var 'tmp)))
- (values inner-var
- (cons (cons (cons outer-var inner-var)
- (car maps))
- outer-maps)))))))))))
- (define gen-mappend
- (lambda (e map-env)
- `(apply (primitive append) ,(gen-map e map-env))))
- (define gen-map
- (lambda (e map-env)
- (let ((formals (map cdr map-env))
- (actuals (map (lambda (x) `(ref ,(car x))) map-env)))
- (cond
- ((eq? (car e) 'ref)
- ; identity map equivalence:
- ; (map (lambda (x) x) y) == y
- (car actuals))
- ((andmap
- (lambda (x) (and (eq? (car x) 'ref) (memq (cadr x) formals)))
- (cdr e))
- ; eta map equivalence:
- ; (map (lambda (x ...) (f x ...)) y ...) == (map f y ...)
- `(map (primitive ,(car e))
- ,@(map (let ((r (map cons formals actuals)))
- (lambda (x) (cdr (assq (cadr x) r))))
- (cdr e))))
- (else `(map (lambda ,formals ,e) ,@actuals))))))
- (define gen-cons
- (lambda (x y)
- (case (car y)
- ((quote)
- (if (eq? (car x) 'quote)
- `(quote (,(cadr x) . ,(cadr y)))
- (if (eq? (cadr y) '())
- `(list ,x)
- `(cons ,x ,y))))
- ((list) `(list ,x ,@(cdr y)))
- (else `(cons ,x ,y)))))
- (define gen-append
- (lambda (x y)
- (if (equal? y '(quote ()))
- x
- `(append ,x ,y))))
- (define gen-vector
- (lambda (x)
- (cond
- ((eq? (car x) 'list) `(vector ,@(cdr x)))
- ((eq? (car x) 'quote) `(quote #(,@(cadr x))))
- (else `(list->vector ,x)))))
- (define regen
- (lambda (x)
- (case (car x)
- ((ref) (build-lexical-reference 'value no-source (cadr x)))
- ((primitive) (build-primref no-source (cadr x)))
- ((quote) (build-data no-source (cadr x)))
- ((lambda) (build-lambda no-source (cadr x) (regen (caddr x))))
- ((map) (let ((ls (map regen (cdr x))))
- (build-application no-source
- (if (fx= (length ls) 2)
- (build-primref no-source 'map)
- ; really need to do our own checking here
- (build-primref no-source 2 'map)) ; require error check
- ls)))
- (else (build-application no-source
- (build-primref no-source (car x))
- (map regen (cdr x)))))))
- (lambda (e r w s)
- (let ((e (source-wrap e w s)))
- (syntax-case e ()
- ((_ x)
- (call-with-values
- (lambda () (gen-syntax e (syntax x) r '() ellipsis?))
- (lambda (e maps) (regen e))))
- (_ (syntax-error e)))))))
- (global-extend 'core 'lambda
- (lambda (e r w s)
- (syntax-case e ()
- ((_ . c)
- (chi-lambda-clause (source-wrap e w s) (syntax c) r w
- (lambda (vars body) (build-lambda s vars body)))))))
- (global-extend 'core 'let
- (let ()
- (define (chi-let e r w s constructor ids vals exps)
- (if (not (valid-bound-ids? ids))
- (syntax-error e "duplicate bound variable in")
- (let ((labels (gen-labels ids))
- (new-vars (map gen-var ids)))
- (let ((nw (make-binding-wrap ids labels w))
- (nr (extend-var-env labels new-vars r)))
- (constructor s
- new-vars
- (map (lambda (x) (chi x r w)) vals)
- (chi-body exps (source-wrap e nw s) nr nw))))))
- (lambda (e r w s)
- (syntax-case e ()
- ((_ ((id val) ...) e1 e2 ...)
- (chi-let e r w s
- build-let
- (syntax (id ...))
- (syntax (val ...))
- (syntax (e1 e2 ...))))
- ((_ f ((id val) ...) e1 e2 ...)
- (id? (syntax f))
- (chi-let e r w s
- build-named-let
- (syntax (f id ...))
- (syntax (val ...))
- (syntax (e1 e2 ...))))
- (_ (syntax-error (source-wrap e w s)))))))
- (global-extend 'core 'letrec
- (lambda (e r w s)
- (syntax-case e ()
- ((_ ((id val) ...) e1 e2 ...)
- (let ((ids (syntax (id ...))))
- (if (not (valid-bound-ids? ids))
- (syntax-error e "duplicate bound variable in")
- (let ((labels (gen-labels ids))
- (new-vars (map gen-var ids)))
- (let ((w (make-binding-wrap ids labels w))
- (r (extend-var-env labels new-vars r)))
- (build-letrec s
- new-vars
- (map (lambda (x) (chi x r w)) (syntax (val ...)))
- (chi-body (syntax (e1 e2 ...)) (source-wrap e w s) r w)))))))
- (_ (syntax-error (source-wrap e w s))))))
- (global-extend 'core 'set!
- (lambda (e r w s)
- (syntax-case e ()
- ((_ id val)
- (id? (syntax id))
- (let ((val (chi (syntax val) r w))
- (n (id-var-name (syntax id) w)))
- (let ((b (lookup n r)))
- (case (binding-type b)
- ((lexical)
- (build-lexical-assignment s (binding-value b) val))
- ((global) (build-global-assignment s n val))
- ((displaced-lexical)
- (syntax-error (wrap (syntax id) w)
- "identifier out of context"))
- (else (syntax-error (source-wrap e w s)))))))
- ((_ (getter arg ...) val)
- (build-application s
- (chi (syntax (setter getter)) r w)
- (map (lambda (e) (chi e r w))
- (syntax (arg ... val)))))
- (_ (syntax-error (source-wrap e w s))))))
- (global-extend 'begin 'begin '())
- (global-extend 'define 'define '())
- (global-extend 'define-syntax 'define-syntax '())
- (global-extend 'eval-when 'eval-when '())
- (global-extend 'core 'syntax-case
- (let ()
- (define convert-pattern
- ; accepts pattern & keys
- ; returns syntax-dispatch pattern & ids
- (lambda (pattern keys)
- (let cvt ((p pattern) (n 0) (ids '()))
- (if (id? p)
- (if (bound-id-member? p keys)
- (values (vector 'free-id p) ids)
- (values 'any (cons (cons p n) ids)))
- (syntax-case p ()
- ((x dots)
- (ellipsis? (syntax dots))
- (call-with-values
- (lambda () (cvt (syntax x) (fx+ n 1) ids))
- (lambda (p ids)
- (values (if (eq? p 'any) 'each-any (vector 'each p))
- ids))))
- ((x . y)
- (call-with-values
- (lambda () (cvt (syntax y) n ids))
- (lambda (y ids)
- (call-with-values
- (lambda () (cvt (syntax x) n ids))
- (lambda (x ids)
- (values (cons x y) ids))))))
- (() (values '() ids))
- (#(x ...)
- (call-with-values
- (lambda () (cvt (syntax (x ...)) n ids))
- (lambda (p ids) (values (vector 'vector p) ids))))
- (x (values (vector 'atom (strip p empty-wrap)) ids)))))))
- (define build-dispatch-call
- (lambda (pvars exp y r)
- (let ((ids (map car pvars)) (levels (map cdr pvars)))
- (let ((labels (gen-labels ids)) (new-vars (map gen-var ids)))
- (build-application no-source
- (build-primref no-source 'apply)
- (list (build-lambda no-source new-vars
- (chi exp
- (extend-env
- labels
- (map (lambda (var level)
- (make-binding 'syntax `(,var . ,level)))
- new-vars
- (map cdr pvars))
- r)
- (make-binding-wrap ids labels empty-wrap)))
- y))))))
- (define gen-clause
- (lambda (x keys clauses r pat fender exp)
- (call-with-values
- (lambda () (convert-pattern pat keys))
- (lambda (p pvars)
- (cond
- ((not (distinct-bound-ids? (map car pvars)))
- (syntax-error pat
- "duplicate pattern variable in syntax-case pattern"))
- ((not (andmap (lambda (x) (not (ellipsis? (car x)))) pvars))
- (syntax-error pat
- "misplaced ellipsis in syntax-case pattern"))
- (else
- (let ((y (gen-var 'tmp)))
- ; fat finger binding and references to temp variable y
- (build-application no-source
- (build-lambda no-source (list y)
- (let ((y (build-lexical-reference 'value no-source y)))
- (build-conditional no-source
- (syntax-case fender ()
- (#t y)
- (_ (build-conditional no-source
- y
- (build-dispatch-call pvars fender y r)
- (build-data no-source #f))))
- (build-dispatch-call pvars exp y r)
- (gen-syntax-case x keys clauses r))))
- (list (if (eq? p 'any)
- (build-application no-source
- (build-primref no-source 'list)
- (list x))
- (build-application no-source
- (build-primref no-source 'syntax-dispatch)
- (list x (build-data no-source p)))))))))))))
- (define gen-syntax-case
- (lambda (x keys clauses r)
- (if (null? clauses)
- (build-application no-source
- (build-primref no-source 'syntax-error)
- (list x))
- (syntax-case (car clauses) ()
- ((pat exp)
- (if (and (id? (syntax pat))
- (andmap (lambda (x) (not (free-id=? (syntax pat) x)))
- (cons (syntax (... ...)) keys)))
- (let ((labels (list (gen-label)))
- (var (gen-var (syntax pat))))
- (build-application no-source
- (build-lambda no-source (list var)
- (chi (syntax exp)
- (extend-env labels
- (list (make-binding 'syntax `(,var . 0)))
- r)
- (make-binding-wrap (syntax (pat))
- labels empty-wrap)))
- (list x)))
- (gen-clause x keys (cdr clauses) r
- (syntax pat) #t (syntax exp))))
- ((pat fender exp)
- (gen-clause x keys (cdr clauses) r
- (syntax pat) (syntax fender) (syntax exp)))
- (_ (syntax-error (car clauses) "invalid syntax-case clause"))))))
- (lambda (e r w s)
- (let ((e (source-wrap e w s)))
- (syntax-case e ()
- ((_ val (key ...) m ...)
- (if (andmap (lambda (x) (and (id? x) (not (ellipsis? x))))
- (syntax (key ...)))
- (let ((x (gen-var 'tmp)))
- ; fat finger binding and references to temp variable x
- (build-application s
- (build-lambda no-source (list x)
- (gen-syntax-case (build-lexical-reference 'value no-source x)
- (syntax (key ...)) (syntax (m ...))
- r))
- (list (chi (syntax val) r empty-wrap))))
- (syntax-error e "invalid literals list in"))))))))
- ;;; The portable sc-expand seeds chi-top's mode m with 'e (for
- ;;; evaluating) and esew (which stands for "eval syntax expanders
- ;;; when") with '(eval). In Chez Scheme, m is set to 'c instead of e
- ;;; if we are compiling a file, and esew is set to
- ;;; (eval-syntactic-expanders-when), which defaults to the list
- ;;; '(compile load eval). This means that, by default, top-level
- ;;; syntactic definitions are evaluated immediately after they are
- ;;; expanded, and the expanded definitions are also residualized into
- ;;; the object file if we are compiling a file.
- (set! sc-expand
- (let ((m 'e) (esew '(eval)))
- (lambda (x)
- (if (and (pair? x) (equal? (car x) noexpand))
- (cadr x)
- (chi-top x null-env top-wrap m esew)))))
- (set! sc-expand3
- (let ((m 'e) (esew '(eval)))
- (lambda (x . rest)
- (if (and (pair? x) (equal? (car x) noexpand))
- (cadr x)
- (chi-top x
- null-env
- top-wrap
- (if (null? rest) m (car rest))
- (if (or (null? rest) (null? (cdr rest)))
- esew
- (cadr rest)))))))
- (set! identifier?
- (lambda (x)
- (nonsymbol-id? x)))
- (set! datum->syntax-object
- (lambda (id datum)
- (make-syntax-object datum (syntax-object-wrap id))))
- (set! syntax-object->datum
- ; accepts any object, since syntax objects may consist partially
- ; or entirely of unwrapped, nonsymbolic data
- (lambda (x)
- (strip x empty-wrap)))
- (set! generate-temporaries
- (lambda (ls)
- (arg-check list? ls 'generate-temporaries)
- (map (lambda (x) (wrap (gensym-hook) top-wrap)) ls)))
- (set! free-identifier=?
- (lambda (x y)
- (arg-check nonsymbol-id? x 'free-identifier=?)
- (arg-check nonsymbol-id? y 'free-identifier=?)
- (free-id=? x y)))
- (set! bound-identifier=?
- (lambda (x y)
- (arg-check nonsymbol-id? x 'bound-identifier=?)
- (arg-check nonsymbol-id? y 'bound-identifier=?)
- (bound-id=? x y)))
- (set! syntax-error
- (lambda (object . messages)
- (for-each (lambda (x) (arg-check string? x 'syntax-error)) messages)
- (let ((message (if (null? messages)
- "invalid syntax"
- (apply string-append messages))))
- (error-hook #f message (strip object empty-wrap)))))
- (set! install-global-transformer
- (lambda (sym v)
- (arg-check symbol? sym 'define-syntax)
- (arg-check procedure? v 'define-syntax)
- (global-extend 'macro sym v)))
- ;;; syntax-dispatch expects an expression and a pattern. If the expression
- ;;; matches the pattern a list of the matching expressions for each
- ;;; "any" is returned. Otherwise, #f is returned. (This use of #f will
- ;;; not work on r4rs implementations that violate the ieee requirement
- ;;; that #f and () be distinct.)
- ;;; The expression is matched with the pattern as follows:
- ;;; pattern: matches:
- ;;; () empty list
- ;;; any anything
- ;;; (<pattern>1 . <pattern>2) (<pattern>1 . <pattern>2)
- ;;; each-any (any*)
- ;;; #(free-id <key>) <key> with free-identifier=?
- ;;; #(each <pattern>) (<pattern>*)
- ;;; #(vector <pattern>) (list->vector <pattern>)
- ;;; #(atom <object>) <object> with "equal?"
- ;;; Vector cops out to pair under assumption that vectors are rare. If
- ;;; not, should convert to:
- ;;; #(vector <pattern>*) #(<pattern>*)
- (let ()
- (define match-each
- (lambda (e p w)
- (cond
- ((annotation? e)
- (match-each (annotation-expression e) p w))
- ((pair? e)
- (let ((first (match (car e) p w '())))
- (and first
- (let ((rest (match-each (cdr e) p w)))
- (and rest (cons first rest))))))
- ((null? e) '())
- ((syntax-object? e)
- (match-each (syntax-object-expression e)
- p
- (join-wraps w (syntax-object-wrap e))))
- (else #f))))
- (define match-each-any
- (lambda (e w)
- (cond
- ((annotation? e)
- (match-each-any (annotation-expression e) w))
- ((pair? e)
- (let ((l (match-each-any (cdr e) w)))
- (and l (cons (wrap (car e) w) l))))
- ((null? e) '())
- ((syntax-object? e)
- (match-each-any (syntax-object-expression e)
- (join-wraps w (syntax-object-wrap e))))
- (else #f))))
- (define match-empty
- (lambda (p r)
- (cond
- ((null? p) r)
- ((eq? p 'any) (cons '() r))
- ((pair? p) (match-empty (car p) (match-empty (cdr p) r)))
- ((eq? p 'each-any) (cons '() r))
- (else
- (case (vector-ref p 0)
- ((each) (match-empty (vector-ref p 1) r))
- ((free-id atom) r)
- ((vector) (match-empty (vector-ref p 1) r)))))))
- (define match*
- (lambda (e p w r)
- (cond
- ((null? p) (and (null? e) r))
- ((pair? p)
- (and (pair? e) (match (car e) (car p) w
- (match (cdr e) (cdr p) w r))))
- ((eq? p 'each-any)
- (let ((l (match-each-any e w))) (and l (cons l r))))
- (else
- (case (vector-ref p 0)
- ((each)
- (if (null? e)
- (match-empty (vector-ref p 1) r)
- (let ((l (match-each e (vector-ref p 1) w)))
- (and l
- (let collect ((l l))
- (if (null? (car l))
- r
- (cons (map car l) (collect (map cdr l)))))))))
- ((free-id) (and (id? e) (free-id=? (wrap e w) (vector-ref p 1)) r))
- ((atom) (and (equal? (vector-ref p 1) (strip e w)) r))
- ((vector)
- (and (vector? e)
- (match (vector->list e) (vector-ref p 1) w r))))))))
- (define match
- (lambda (e p w r)
- (cond
- ((not r) #f)
- ((eq? p 'any) (cons (wrap e w) r))
- ((syntax-object? e)
- (match*
- (unannotate (syntax-object-expression e))
- p
- (join-wraps w (syntax-object-wrap e))
- r))
- (else (match* (unannotate e) p w r)))))
- (set! syntax-dispatch
- (lambda (e p)
- (cond
- ((eq? p 'any) (list e))
- ((syntax-object? e)
- (match* (unannotate (syntax-object-expression e))
- p (syntax-object-wrap e) '()))
- (else (match* (unannotate e) p empty-wrap '())))))
- (set! sc-chi chi)
- ))
- )
- (define-syntax with-syntax
- (lambda (x)
- (syntax-case x ()
- ((_ () e1 e2 ...)
- (syntax (begin e1 e2 ...)))
- ((_ ((out in)) e1 e2 ...)
- (syntax (syntax-case in () (out (begin e1 e2 ...)))))
- ((_ ((out in) ...) e1 e2 ...)
- (syntax (syntax-case (list in ...) ()
- ((out ...) (begin e1 e2 ...))))))))
- (define-syntax syntax-rules
- (lambda (x)
- (syntax-case x ()
- ((_ (k ...) ((keyword . pattern) template) ...)
- (syntax (lambda (x)
- (syntax-case x (k ...)
- ((dummy . pattern) (syntax template))
- ...)))))))
- (define-syntax let*
- (lambda (x)
- (syntax-case x ()
- ((let* ((x v) ...) e1 e2 ...)
- (andmap identifier? (syntax (x ...)))
- (let f ((bindings (syntax ((x v) ...))))
- (if (null? bindings)
- (syntax (let () e1 e2 ...))
- (with-syntax ((body (f (cdr bindings)))
- (binding (car bindings)))
- (syntax (let (binding) body)))))))))
- (define-syntax do
- (lambda (orig-x)
- (syntax-case orig-x ()
- ((_ ((var init . step) ...) (e0 e1 ...) c ...)
- (with-syntax (((step ...)
- (map (lambda (v s)
- (syntax-case s ()
- (() v)
- ((e) (syntax e))
- (_ (syntax-error orig-x))))
- (syntax (var ...))
- (syntax (step ...)))))
- (syntax-case (syntax (e1 ...)) ()
- (() (syntax (let doloop ((var init) ...)
- (if (not e0)
- (begin c ... (doloop step ...))))))
- ((e1 e2 ...)
- (syntax (let doloop ((var init) ...)
- (if e0
- (begin e1 e2 ...)
- (begin c ... (doloop step ...))))))))))))
- (define-syntax quasiquote
- (letrec
- ((quasicons
- (lambda (x y)
- (with-syntax ((x x) (y y))
- (syntax-case (syntax y) (quote list)
- ((quote dy)
- (syntax-case (syntax x) (quote)
- ((quote dx) (syntax (quote (dx . dy))))
- (_ (if (null? (syntax dy))
- (syntax (list x))
- (syntax (cons x y))))))
- ((list . stuff) (syntax (list x . stuff)))
- (else (syntax (cons x y)))))))
- (quasiappend
- (lambda (x y)
- (with-syntax ((x x) (y y))
- (syntax-case (syntax y) (quote)
- ((quote ()) (syntax x))
- (_ (syntax (append x y)))))))
- (quasivector
- (lambda (x)
- (with-syntax ((x x))
- (syntax-case (syntax x) (quote list)
- ((quote (x ...)) (syntax (quote #(x ...))))
- ((list x ...) (syntax (vector x ...)))
- (_ (syntax (list->vector x)))))))
- (quasi
- (lambda (p lev)
- (syntax-case p (unquote unquote-splicing quasiquote)
- ((unquote p)
- (if (= lev 0)
- (syntax p)
- (quasicons (syntax (quote unquote))
- (quasi (syntax (p)) (- lev 1)))))
- (((unquote-splicing p) . q)
- (if (= lev 0)
- (quasiappend (syntax p) (quasi (syntax q) lev))
- (quasicons (quasicons (syntax (quote unquote-splicing))
- (quasi (syntax (p)) (- lev 1)))
- (quasi (syntax q) lev))))
- ((quasiquote p)
- (quasicons (syntax (quote quasiquote))
- (quasi (syntax (p)) (+ lev 1))))
- ((p . q)
- (quasicons (quasi (syntax p) lev) (quasi (syntax q) lev)))
- (#(x ...) (quasivector (quasi (syntax (x ...)) lev)))
- (p (syntax (quote p)))))))
- (lambda (x)
- (syntax-case x ()
- ((_ e) (quasi (syntax e) 0))))))
- (define-syntax include
- (lambda (x)
- (define read-file
- (lambda (fn k)
- (let ((p (open-input-file fn)))
- (let f ((x (read p)))
- (if (eof-object? x)
- (begin (close-input-port p) '())
- (cons (datum->syntax-object k x)
- (f (read p))))))))
- (syntax-case x ()
- ((k filename)
- (let ((fn (syntax-object->datum (syntax filename))))
- (with-syntax (((exp ...) (read-file fn (syntax k))))
- (syntax (begin exp ...))))))))
- (define-syntax unquote
- (lambda (x)
- (syntax-case x ()
- ((_ e)
- (error 'unquote
- "expression ,~s not valid outside of quasiquote"
- (syntax-object->datum (syntax e)))))))
- (define-syntax unquote-splicing
- (lambda (x)
- (syntax-case x ()
- ((_ e)
- (error 'unquote-splicing
- "expression ,@~s not valid outside of quasiquote"
- (syntax-object->datum (syntax e)))))))
- (define-syntax case
- (lambda (x)
- (syntax-case x ()
- ((_ e m1 m2 ...)
- (with-syntax
- ((body (let f ((clause (syntax m1)) (clauses (syntax (m2 ...))))
- (if (null? clauses)
- (syntax-case clause (else)
- ((else e1 e2 ...) (syntax (begin e1 e2 ...)))
- (((k ...) e1 e2 ...)
- (syntax (if (memv t '(k ...)) (begin e1 e2 ...))))
- (_ (syntax-error x)))
- (with-syntax ((rest (f (car clauses) (cdr clauses))))
- (syntax-case clause (else)
- (((k ...) e1 e2 ...)
- (syntax (if (memv t '(k ...))
- (begin e1 e2 ...)
- rest)))
- (_ (syntax-error x))))))))
- (syntax (let ((t e)) body)))))))
- (define-syntax identifier-syntax
- (lambda (x)
- (syntax-case x ()
- ((_ e)
- (syntax
- (lambda (x)
- (syntax-case x ()
- (id
- (identifier? (syntax id))
- (syntax e))
- ((_ x (... ...))
- (syntax (e x (... ...)))))))))))
|