1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028 |
- ;;;; -*-scheme-*-
- ;;;;
- ;;;; Copyright (C) 2001, 2003, 2006, 2009, 2010, 2011 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 3 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
- ;;; Originally extracted from Chez Scheme Version 5.9f
- ;;; Authors: R. Kent Dybvig, Oscar Waddell, Bob Hieb, Carl Bruggeman
- ;;; 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.
- ;;; 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
- ;;; Modified by Andy Wingo <wingo@pobox.com> according to the Git
- ;;; revision control logs corresponding to this file: 2009, 2010.
- ;;; This file defines the syntax-case expander, macroexpand, and a set
- ;;; of associated syntactic forms and procedures. Of these, the
- ;;; following are documented in The Scheme Programming Language,
- ;;; Fourth Edition (R. Kent Dybvig, MIT Press, 2009), and in the
- ;;; R6RS:
- ;;;
- ;;; bound-identifier=?
- ;;; datum->syntax
- ;;; define-syntax
- ;;; syntax-parameterize
- ;;; free-identifier=?
- ;;; generate-temporaries
- ;;; identifier?
- ;;; identifier-syntax
- ;;; let-syntax
- ;;; letrec-syntax
- ;;; syntax
- ;;; syntax-case
- ;;; syntax->datum
- ;;; syntax-rules
- ;;; with-syntax
- ;;;
- ;;; Additionally, the expander provides definitions for a number of core
- ;;; Scheme syntactic bindings, such as `let', `lambda', and the like.
- ;;; The remaining exports are listed below:
- ;;;
- ;;; (macroexpand datum)
- ;;; if datum represents a valid expression, macroexpand 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-violation who message form [subform])
- ;;; used to report errors found during expansion
- ;;; ($sc-dispatch e p)
- ;;; used by expanded code to handle syntax-case matching
- ;;; This file is shipped along with an expanded version of itself,
- ;;; psyntax-pp.scm, which is loaded when psyntax.scm has not yet been
- ;;; compiled. In this way, psyntax bootstraps off of an expanded
- ;;; version of itself.
- ;;; This implementation of the expander sometimes uses 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 the 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. This will be true of
- ;;; Guile as well, once we implement a proper inliner.
- ;;; Implementation notes:
- ;;; 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.
- ;;; 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.
- ;;; 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 source location associated with incoming expressions is tracked
- ;;; via the source-properties mechanism, a weak map from expression to
- ;;; source information. At times the source is separated from the
- ;;; expression; see the note below about "efficiency and confusion".
- ;;; 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.
- (eval-when (compile)
- (set-current-module (resolve-module '(guile))))
- (let ()
- (define-syntax define-expansion-constructors
- (lambda (x)
- (syntax-case x ()
- ((_)
- (let lp ((n 0) (out '()))
- (if (< n (vector-length %expanded-vtables))
- (lp (1+ n)
- (let* ((vtable (vector-ref %expanded-vtables n))
- (stem (struct-ref vtable (+ vtable-offset-user 0)))
- (fields (struct-ref vtable (+ vtable-offset-user 2)))
- (sfields (map (lambda (f) (datum->syntax x f)) fields))
- (ctor (datum->syntax x (symbol-append 'make- stem))))
- (cons #`(define (#,ctor #,@sfields)
- (make-struct (vector-ref %expanded-vtables #,n) 0
- #,@sfields))
- out)))
- #`(begin #,@(reverse out))))))))
- (define-syntax define-expansion-accessors
- (lambda (x)
- (syntax-case x ()
- ((_ stem field ...)
- (let lp ((n 0))
- (let ((vtable (vector-ref %expanded-vtables n))
- (stem (syntax->datum #'stem)))
- (if (eq? (struct-ref vtable (+ vtable-offset-user 0)) stem)
- #`(begin
- (define (#,(datum->syntax x (symbol-append stem '?)) x)
- (and (struct? x)
- (eq? (struct-vtable x)
- (vector-ref %expanded-vtables #,n))))
- #,@(map
- (lambda (f)
- (let ((get (datum->syntax x (symbol-append stem '- f)))
- (set (datum->syntax x (symbol-append 'set- stem '- f '!)))
- (idx (list-index (struct-ref vtable
- (+ vtable-offset-user 2))
- f)))
- #`(begin
- (define (#,get x)
- (struct-ref x #,idx))
- (define (#,set x v)
- (struct-set! x #,idx v)))))
- (syntax->datum #'(field ...))))
- (lp (1+ n)))))))))
- (define-syntax define-structure
- (lambda (x)
- (define construct-name
- (lambda (template-identifier . args)
- (datum->syntax
- template-identifier
- (string->symbol
- (apply string-append
- (map (lambda (x)
- (if (string? x)
- x
- (symbol->string (syntax->datum x))))
- args))))))
- (syntax-case x ()
- ((_ (name id1 ...))
- (and-map identifier? #'(name id1 ...))
- (with-syntax
- ((constructor (construct-name #'name "make-" #'name))
- (predicate (construct-name #'name #'name "?"))
- ((access ...)
- (map (lambda (x) (construct-name x #'name "-" x))
- #'(id1 ...)))
- ((assign ...)
- (map (lambda (x)
- (construct-name x "set-" #'name "-" x "!"))
- #'(id1 ...)))
- (structure-length
- (+ (length #'(id1 ...)) 1))
- ((index ...)
- (let f ((i 1) (ids #'(id1 ...)))
- (if (null? ids)
- '()
- (cons i (f (+ i 1) (cdr ids)))))))
- #'(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-expansion-constructors)
- (define-expansion-accessors lambda meta)
- ;; hooks to nonportable run-time helpers
- (begin
- (define-syntax fx+ (identifier-syntax +))
- (define-syntax fx- (identifier-syntax -))
- (define-syntax fx= (identifier-syntax =))
- (define-syntax fx< (identifier-syntax <))
- (define top-level-eval-hook
- (lambda (x mod)
- (primitive-eval x)))
- (define local-eval-hook
- (lambda (x mod)
- (primitive-eval x)))
-
- (define-syntax-rule (gensym-hook)
- (gensym))
- (define put-global-definition-hook
- (lambda (symbol type val)
- (module-define! (current-module)
- symbol
- (make-syntax-transformer symbol type val))))
-
- (define get-global-definition-hook
- (lambda (symbol module)
- (if (and (not module) (current-module))
- (warn "module system is booted, we should have a module" symbol))
- (let ((v (module-variable (if module
- (resolve-module (cdr module))
- (current-module))
- symbol)))
- (and v (variable-bound? v)
- (let ((val (variable-ref v)))
- (and (macro? val) (macro-type val)
- (cons (macro-type val)
- (macro-binding val)))))))))
- (define (decorate-source e s)
- (if (and (pair? e) s)
- (set-source-properties! e s))
- e)
- (define (maybe-name-value! name val)
- (if (lambda? val)
- (let ((meta (lambda-meta val)))
- (if (not (assq 'name meta))
- (set-lambda-meta! val (acons 'name name meta))))))
- ;; output constructors
- (define build-void
- (lambda (source)
- (make-void source)))
- (define build-call
- (lambda (source fun-exp arg-exps)
- (make-call source fun-exp arg-exps)))
-
- (define build-conditional
- (lambda (source test-exp then-exp else-exp)
- (make-conditional source test-exp then-exp else-exp)))
-
- (define build-dynlet
- (lambda (source fluids vals body)
- (make-dynlet source fluids vals body)))
-
- (define build-lexical-reference
- (lambda (type source name var)
- (make-lexical-ref source name var)))
-
- (define build-lexical-assignment
- (lambda (source name var exp)
- (maybe-name-value! name exp)
- (make-lexical-set source name var exp)))
-
- (define (analyze-variable mod var modref-cont bare-cont)
- (if (not mod)
- (bare-cont var)
- (let ((kind (car mod))
- (mod (cdr mod)))
- (case kind
- ((public) (modref-cont mod var #t))
- ((private) (if (not (equal? mod (module-name (current-module))))
- (modref-cont mod var #f)
- (bare-cont var)))
- ((bare) (bare-cont var))
- ((hygiene) (if (and (not (equal? mod (module-name (current-module))))
- (module-variable (resolve-module mod) var))
- (modref-cont mod var #f)
- (bare-cont var)))
- (else (syntax-violation #f "bad module kind" var mod))))))
- (define build-global-reference
- (lambda (source var mod)
- (analyze-variable
- mod var
- (lambda (mod var public?)
- (make-module-ref source mod var public?))
- (lambda (var)
- (make-toplevel-ref source var)))))
- (define build-global-assignment
- (lambda (source var exp mod)
- (maybe-name-value! var exp)
- (analyze-variable
- mod var
- (lambda (mod var public?)
- (make-module-set source mod var public? exp))
- (lambda (var)
- (make-toplevel-set source var exp)))))
- (define build-global-definition
- (lambda (source var exp)
- (maybe-name-value! var exp)
- (make-toplevel-define source var exp)))
- (define build-simple-lambda
- (lambda (src req rest vars meta exp)
- (make-lambda src
- meta
- ;; hah, a case in which kwargs would be nice.
- (make-lambda-case
- ;; src req opt rest kw inits vars body else
- src req #f rest #f '() vars exp #f))))
- (define build-case-lambda
- (lambda (src meta body)
- (make-lambda src meta body)))
- (define build-lambda-case
- ;; req := (name ...)
- ;; opt := (name ...) | #f
- ;; rest := name | #f
- ;; kw := (allow-other-keys? (keyword name var) ...) | #f
- ;; inits: (init ...)
- ;; vars: (sym ...)
- ;; vars map to named arguments in the following order:
- ;; required, optional (positional), rest, keyword.
- ;; the body of a lambda: anything, already expanded
- ;; else: lambda-case | #f
- (lambda (src req opt rest kw inits vars body else-case)
- (make-lambda-case src req opt rest kw inits vars body else-case)))
- (define build-primcall
- (lambda (src name args)
- (make-primcall src name args)))
-
- (define build-primref
- (lambda (src name)
- (make-primitive-ref src name)))
-
- (define (build-data src exp)
- (make-const src exp))
- (define build-sequence
- (lambda (src exps)
- (if (null? (cdr exps))
- (car exps)
- (make-seq src (car exps) (build-sequence #f (cdr exps))))))
- (define build-let
- (lambda (src ids vars val-exps body-exp)
- (for-each maybe-name-value! ids val-exps)
- (if (null? vars)
- body-exp
- (make-let src ids vars val-exps body-exp))))
- (define build-named-let
- (lambda (src ids vars val-exps body-exp)
- (let ((f (car vars))
- (f-name (car ids))
- (vars (cdr vars))
- (ids (cdr ids)))
- (let ((proc (build-simple-lambda src ids #f vars '() body-exp)))
- (maybe-name-value! f-name proc)
- (for-each maybe-name-value! ids val-exps)
- (make-letrec
- src #f
- (list f-name) (list f) (list proc)
- (build-call src (build-lexical-reference 'fun src f-name f)
- val-exps))))))
- (define build-letrec
- (lambda (src in-order? ids vars val-exps body-exp)
- (if (null? vars)
- body-exp
- (begin
- (for-each maybe-name-value! ids val-exps)
- (make-letrec src in-order? ids vars val-exps body-exp)))))
- ;; FIXME: use a faster gensym
- (define-syntax-rule (build-lexical-var src id)
- (gensym (string-append (symbol->string id) " ")))
- (define-structure (syntax-object expression wrap module))
- (define-syntax no-source (identifier-syntax #f))
- (define source-annotation
- (lambda (x)
- (cond
- ((syntax-object? x)
- (source-annotation (syntax-object-expression x)))
- ((pair? x) (let ((props (source-properties x)))
- (if (pair? props)
- props
- #f)))
- (else #f))))
- (define-syntax-rule (arg-check pred? e who)
- (let ((x e))
- (if (not (pred? x)) (syntax-violation 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
- ;; resolve-identifier when it finds no other bindings.
- ;; <environment> ::= ((<label> . <binding>)*)
- ;; identifier bindings include a type and a value
- ;; <binding> ::= (macro . <procedure>) macros
- ;; (syntax-parameter . (<procedure>)) syntax parameters
- ;; (core . <procedure>) core forms
- ;; (module-ref . <procedure>) @ or @@
- ;; (begin) begin
- ;; (define) define
- ;; (define-syntax) define-syntax
- ;; (define-syntax-parameter) define-syntax-parameter
- ;; (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,
- ;; define-syntax-parameter, 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-syntax-rule (binding-type x)
- (car x))
- (define-syntax-rule (binding-value x)
- (cdr x))
- (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 (memq (cadr a) '(macro syntax-parameter))
- (cons a (macros-only-env (cdr r)))
- (macros-only-env (cdr r)))))))
- (define global-extend
- (lambda (type sym val)
- (put-global-definition-hook sym 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? (syntax-object-expression x)))))
- (define id?
- (lambda (x)
- (cond
- ((symbol? x) #t)
- ((syntax-object? x) (symbol? (syntax-object-expression x)))
- (else #f))))
- (define-syntax-rule (id-sym-name e)
- (let ((x e))
- (if (syntax-object? x)
- (syntax-object-expression x)
- x)))
- (define id-sym-name&marks
- (lambda (x w)
- (if (syntax-object? x)
- (values
- (syntax-object-expression x)
- (join-marks (wrap-marks w) (wrap-marks (syntax-object-wrap x))))
- (values x (wrap-marks w)))))
- ;; syntax object wraps
- ;; <wrap> ::= ((<mark> ...) . (<subst> ...))
- ;; <subst> ::= <shift> | <subs>
- ;; <subs> ::= #(<old name> <label> (<mark> ...))
- ;; <shift> ::= positive fixnum
- (define-syntax make-wrap (identifier-syntax cons))
- (define-syntax wrap-marks (identifier-syntax car))
- (define-syntax wrap-subst (identifier-syntax cdr))
- (define-syntax subst-rename? (identifier-syntax vector?))
- (define-syntax-rule (rename-old x) (vector-ref x 0))
- (define-syntax-rule (rename-new x) (vector-ref x 1))
- (define-syntax-rule (rename-marks x) (vector-ref x 2))
- (define-syntax-rule (make-rename old new marks)
- (vector old new marks))
- ;; labels must be comparable with "eq?", have read-write invariance,
- ;; and distinct from symbols.
- (define gen-label
- (lambda () (symbol->string (gensym "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-rule (top-marked? 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-rule (new-mark)
- (gensym "m"))
- ;; make-empty-ribcage and extend-ribcage maintain list-based ribcages for
- ;; internal definitions, in which the ribcages are built incrementally
- (define-syntax-rule (make-empty-ribcage)
- (make-ribcage '() '() '()))
- (define extend-ribcage!
- ;; must receive ids with complete wraps
- (lambda (ribcage id label)
- (set-ribcage-symnames! ribcage
- (cons (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
- ;; Syntax objects use wraps to associate names with marked
- ;; identifiers. This function returns the name corresponding to
- ;; the given identifier and wrap, or the original identifier if no
- ;; corresponding name was found.
- ;;
- ;; The name may be a string created by gen-label, indicating a
- ;; lexical binding, or another syntax object, indicating a
- ;; reference to a top-level definition created during a previous
- ;; macroexpansion.
- ;;
- ;; For lexical variables, finding a label simply amounts to
- ;; looking for an entry with the same symbolic name and the same
- ;; marks. Finding a toplevel definition is the same, except we
- ;; also have to compare modules, hence the `mod' parameter.
- ;; Instead of adding a separate entry in the ribcage for modules,
- ;; which wouldn't be used for lexicals, we arrange for the entry
- ;; for the name entry to be a pair with the module in its car, and
- ;; the name itself in the cdr. So if the name that we find is a
- ;; pair, we have to check modules.
- ;;
- ;; The identifer may be passed in wrapped or unwrapped. In any
- ;; case, this routine returns either a symbol, a syntax object, or
- ;; a string label.
- ;;
- (lambda (id w mod)
- (define-syntax-rule (first e)
- ;; Rely on Guile's multiple-values truncation.
- e)
- (define search
- (lambda (sym subst marks mod)
- (if (null? subst)
- (values #f marks)
- (let ((fst (car subst)))
- (if (eq? fst 'shift)
- (search sym (cdr subst) (cdr marks) mod)
- (let ((symnames (ribcage-symnames fst)))
- (if (vector? symnames)
- (search-vector-rib sym subst marks symnames fst mod)
- (search-list-rib sym subst marks symnames fst mod))))))))
- (define search-list-rib
- (lambda (sym subst marks symnames ribcage mod)
- (let f ((symnames symnames) (i 0))
- (cond
- ((null? symnames) (search sym (cdr subst) marks mod))
- ((and (eq? (car symnames) sym)
- (same-marks? marks (list-ref (ribcage-marks ribcage) i)))
- (let ((n (list-ref (ribcage-labels ribcage) i)))
- (if (pair? n)
- (if (equal? mod (car n))
- (values (cdr n) marks)
- (f (cdr symnames) (fx+ i 1)))
- (values n marks))))
- (else (f (cdr symnames) (fx+ i 1)))))))
- (define search-vector-rib
- (lambda (sym subst marks symnames ribcage mod)
- (let ((n (vector-length symnames)))
- (let f ((i 0))
- (cond
- ((fx= i n) (search sym (cdr subst) marks mod))
- ((and (eq? (vector-ref symnames i) sym)
- (same-marks? marks (vector-ref (ribcage-marks ribcage) i)))
- (let ((n (vector-ref (ribcage-labels ribcage) i)))
- (if (pair? n)
- (if (equal? mod (car n))
- (values (cdr n) marks)
- (f (fx+ i 1)))
- (values n marks))))
- (else (f (fx+ i 1))))))))
- (cond
- ((symbol? id)
- (or (first (search id (wrap-subst w) (wrap-marks w) mod)) id))
- ((syntax-object? id)
- (let ((id (syntax-object-expression id))
- (w1 (syntax-object-wrap id))
- (mod (syntax-object-module id)))
- (let ((marks (join-marks (wrap-marks w) (wrap-marks w1))))
- (call-with-values (lambda () (search id (wrap-subst w) marks mod))
- (lambda (new-id marks)
- (or new-id
- (first (search id (wrap-subst w1) marks mod))
- id))))))
- (else (syntax-violation 'id-var-name "invalid id" id)))))
- ;; Returns three values: binding type, binding value, the module (for
- ;; resolving toplevel vars).
- (define (resolve-identifier id w r mod resolve-syntax-parameters?)
- (define (resolve-syntax-parameters b)
- (if (and resolve-syntax-parameters?
- (eq? (binding-type b) 'syntax-parameter))
- (or (assq-ref r (binding-value b))
- (make-binding 'macro (car (binding-value b))))
- b))
- (define (resolve-global var mod)
- (let ((b (resolve-syntax-parameters
- (or (get-global-definition-hook var mod)
- (make-binding 'global)))))
- (if (eq? (binding-type b) 'global)
- (values 'global var mod)
- (values (binding-type b) (binding-value b) mod))))
- (define (resolve-lexical label mod)
- (let ((b (resolve-syntax-parameters
- (or (assq-ref r label)
- (make-binding 'displaced-lexical)))))
- (values (binding-type b) (binding-value b) mod)))
- (let ((n (id-var-name id w mod)))
- (cond
- ((syntax-object? n)
- ;; Recursing allows syntax-parameterize to override
- ;; macro-introduced syntax parameters.
- (resolve-identifier n w r mod resolve-syntax-parameters?))
- ((symbol? n)
- (resolve-global n (if (syntax-object? id)
- (syntax-object-module id)
- mod)))
- ((string? n)
- (resolve-lexical n (if (syntax-object? id)
- (syntax-object-module id)
- mod)))
- (else
- (error "unexpected id-var-name" id w n)))))
- ;; 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)
- (let* ((mi (and (syntax-object? i) (syntax-object-module i)))
- (mj (and (syntax-object? j) (syntax-object-module j)))
- (ni (id-var-name i empty-wrap mi))
- (nj (id-var-name j empty-wrap mj)))
- (define (id-module-binding id mod)
- (module-variable
- (if mod
- ;; The normal case.
- (resolve-module (cdr mod))
- ;; Either modules have not been booted, or we have a
- ;; raw symbol coming in, which is possible.
- (current-module))
- (id-sym-name id)))
- (cond
- ((syntax-object? ni) (free-id=? ni j))
- ((syntax-object? nj) (free-id=? i nj))
- ((symbol? ni)
- ;; `i' is not lexically bound. Assert that `j' is free,
- ;; and if so, compare their bindings, that they are either
- ;; bound to the same variable, or both unbound and have
- ;; the same name.
- (and (eq? nj (id-sym-name j))
- (let ((bi (id-module-binding i mi)))
- (if bi
- (eq? bi (id-module-binding j mj))
- (and (not (id-module-binding j mj))
- (eq? ni nj))))
- (eq? (id-module-binding i mi) (id-module-binding j mj))))
- (else
- ;; Otherwise `i' is bound, so check that `j' is bound, and
- ;; bound to the same thing.
- (equal? ni nj))))))
-
- ;; 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? (syntax-object-expression i)
- (syntax-object-expression j))
- (same-marks? (wrap-marks (syntax-object-wrap i))
- (wrap-marks (syntax-object-wrap j))))
- (eq? i 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 defmod)
- (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))
- (syntax-object-module x)))
- ((null? x) x)
- (else (make-syntax-object x w defmod)))))
- (define source-wrap
- (lambda (x w s defmod)
- (wrap (decorate-source x s) w defmod)))
- ;; expanding
- (define chi-sequence
- (lambda (body r w s mod)
- (build-sequence s
- (let dobody ((body body) (r r) (w w) (mod mod))
- (if (null? body)
- '()
- (let ((first (chi (car body) r w mod)))
- (cons first (dobody (cdr body) r w mod))))))))
- ;; At top-level, we allow mixed definitions and expressions. Like
- ;; chi-body we expand in two passes.
- ;;
- ;; First, from left to right, we expand just enough to know what
- ;; expressions are definitions, syntax definitions, and splicing
- ;; statements (`begin'). If we anything needs evaluating at
- ;; expansion-time, it is expanded directly.
- ;;
- ;; Otherwise we collect expressions to expand, in thunks, and then
- ;; expand them all at the end. This allows all syntax expanders
- ;; visible in a toplevel sequence to be visible during the
- ;; expansions of all normal definitions and expressions in the
- ;; sequence.
- ;;
- (define chi-top-sequence
- (lambda (body r w s m esew mod)
- (let* ((r (cons '("placeholder" . (placeholder)) r))
- (ribcage (make-empty-ribcage))
- (w (make-wrap (wrap-marks w) (cons ribcage (wrap-subst w)))))
- (define (record-definition! id var)
- (let ((mod (cons 'hygiene (module-name (current-module)))))
- ;; Ribcages map symbol+marks to names, mostly for
- ;; resolving lexicals. Here to add a mapping for toplevel
- ;; definitions we also need to match the module. So, we
- ;; put it in the name instead, and make id-var-name handle
- ;; the special case of names that are pairs. See the
- ;; comments in id-var-name for more.
- (extend-ribcage! ribcage id
- (cons (syntax-object-module id)
- (wrap var top-wrap mod)))))
- (define (macro-introduced-identifier? id)
- (not (equal? (wrap-marks (syntax-object-wrap id)) '(top))))
- (define (fresh-derived-name id orig-form)
- (symbol-append
- (syntax-object-expression id)
- '-
- (string->symbol
- ;; FIXME: `hash' currently stops descending into nested
- ;; data at some point, so it's less unique than we would
- ;; like. Also this encodes hash values into the ABI of
- ;; compiled modules; a problem?
- (number->string
- (hash (syntax->datum orig-form) most-positive-fixnum)
- 16))))
- (define (parse body r w s m esew mod)
- (let lp ((body body) (exps '()))
- (if (null? body)
- exps
- (lp (cdr body)
- (append (parse1 (car body) r w s m esew mod)
- exps)))))
- (define (parse1 x r w s m esew mod)
- (call-with-values
- (lambda ()
- (syntax-type x r w (source-annotation x) ribcage mod #f))
- (lambda (type value e w s mod)
- (case type
- ((define-form)
- (let* ((id (wrap value w mod))
- (label (gen-label))
- (var (if (macro-introduced-identifier? id)
- (fresh-derived-name id x)
- (syntax-object-expression id))))
- (record-definition! id var)
- (list
- (if (eq? m 'c&e)
- (let ((x (build-global-definition s var (chi e r w mod))))
- (top-level-eval-hook x mod)
- (lambda () x))
- (lambda ()
- (build-global-definition s var (chi e r w mod)))))))
- ((define-syntax-form define-syntax-parameter-form)
- (let* ((id (wrap value w mod))
- (label (gen-label))
- (var (if (macro-introduced-identifier? id)
- (fresh-derived-name id x)
- (syntax-object-expression id))))
- (record-definition! id var)
- (case m
- ((c)
- (cond
- ((memq 'compile esew)
- (let ((e (chi-install-global var type (chi e r w mod))))
- (top-level-eval-hook e mod)
- (if (memq 'load esew)
- (list (lambda () e))
- '())))
- ((memq 'load esew)
- (list (lambda ()
- (chi-install-global var type (chi e r w mod)))))
- (else '())))
- ((c&e)
- (let ((e (chi-install-global var type (chi e r w mod))))
- (top-level-eval-hook e mod)
- (list (lambda () e))))
- (else
- (if (memq 'eval esew)
- (top-level-eval-hook
- (chi-install-global var type (chi e r w mod))
- mod))
- '()))))
- ((begin-form)
- (syntax-case e ()
- ((_ e1 ...)
- (parse #'(e1 ...) r w s m esew mod))))
- ((local-syntax-form)
- (chi-local-syntax value e r w s mod
- (lambda (forms r w s mod)
- (parse forms r w s m esew mod))))
- ((eval-when-form)
- (syntax-case e ()
- ((_ (x ...) e1 e2 ...)
- (let ((when-list (chi-when-list e #'(x ...) w))
- (body #'(e1 e2 ...)))
- (define (recurse m esew)
- (parse body r w s m esew mod))
- (cond
- ((eq? m 'e)
- (if (memq 'eval when-list)
- (recurse (if (memq 'expand when-list) 'c&e 'e)
- '(eval))
- (begin
- (if (memq 'expand when-list)
- (top-level-eval-hook
- (chi-top-sequence body r w s 'e '(eval) mod)
- mod))
- '())))
- ((memq 'load when-list)
- (if (or (memq 'compile when-list)
- (memq 'expand when-list)
- (and (eq? m 'c&e) (memq 'eval when-list)))
- (recurse 'c&e '(compile load))
- (if (memq m '(c c&e))
- (recurse 'c '(load))
- '())))
- ((or (memq 'compile when-list)
- (memq 'expand when-list)
- (and (eq? m 'c&e) (memq 'eval when-list)))
- (top-level-eval-hook
- (chi-top-sequence body r w s 'e '(eval) mod)
- mod)
- '())
- (else
- '()))))))
- (else
- (list
- (if (eq? m 'c&e)
- (let ((x (chi-expr type value e r w s mod)))
- (top-level-eval-hook x mod)
- (lambda () x))
- (lambda ()
- (chi-expr type value e r w s mod)))))))))
- (let ((exps (map (lambda (x) (x))
- (reverse (parse body r w s m esew mod)))))
- (if (null? exps)
- (build-void s)
- (build-sequence s exps))))))
-
- (define chi-install-global
- (lambda (name type e)
- (build-global-definition
- no-source
- name
- (build-primcall
- no-source
- 'make-syntax-transformer
- (if (eq? type 'define-syntax-parameter-form)
- (list (build-data no-source name)
- (build-data no-source 'syntax-parameter)
- (build-primcall no-source 'list (list e)))
- (list (build-data no-source name)
- (build-data no-source 'macro)
- e))))))
-
- (define chi-when-list
- (lambda (e when-list w)
- ;; `when-list' is syntax'd version of list of situations. We
- ;; could match these keywords lexically, via free-id=?, but then
- ;; we twingle the definition of eval-when to the bindings of
- ;; eval, load, expand, and compile, which is totally unintended.
- ;; So do a symbolic match instead.
- (let f ((when-list when-list) (situations '()))
- (if (null? when-list)
- situations
- (f (cdr when-list)
- (cons (let ((x (syntax->datum (car when-list))))
- (if (memq x '(compile load eval expand))
- x
- (syntax-violation 'eval-when
- "invalid situation"
- e (wrap (car when-list) w #f))))
- situations))))))
- ;; syntax-type returns six values: type, value, e, w, s, and mod. The
- ;; first two are described in the table below.
- ;;
- ;; type value explanation
- ;; -------------------------------------------------------------------
- ;; core procedure core singleton
- ;; core-form procedure core form
- ;; module-ref procedure @ or @@ singleton
- ;; lexical name lexical variable reference
- ;; global name global variable reference
- ;; begin none begin keyword
- ;; define none define keyword
- ;; define-syntax none define-syntax keyword
- ;; define-syntax-parameter none define-syntax-parameter 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
- ;; define-syntax-parameter-form id syntax parameter definition
- ;; local-syntax-form rec? syntax definition
- ;; eval-when-form none eval-when form
- ;; constant none self-evaluating datum
- ;; other none anything else
- ;;
- ;; For definition forms (define-form, define-syntax-parameter-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. mod is the module for e.
- ;;
- ;; syntax-type expands macros and unwraps as necessary to get to one
- ;; of the forms above. It also parses definition forms, although
- ;; perhaps this should be done by the consumer.
- (define syntax-type
- (lambda (e r w s rib mod for-car?)
- (cond
- ((symbol? e)
- (call-with-values (lambda () (resolve-identifier e w r mod #t))
- (lambda (type value mod*)
- (case type
- ((macro)
- (if for-car?
- (values type value e w s mod)
- (syntax-type (chi-macro value e r w s rib mod)
- r empty-wrap s rib mod #f)))
- ((global)
- ;; Toplevel definitions may resolve to bindings with
- ;; different names or in different modules.
- (values type value value w s mod*))
- (else (values type value e w s mod))))))
- ((pair? e)
- (let ((first (car e)))
- (call-with-values
- (lambda () (syntax-type first r w s rib mod #t))
- (lambda (ftype fval fe fw fs fmod)
- (case ftype
- ((lexical)
- (values 'lexical-call fval e w s mod))
- ((global)
- ;; If we got here via an (@@ ...) expansion, we need to
- ;; make sure the fmod information is propagated back
- ;; correctly -- hence this consing.
- (values 'global-call (make-syntax-object fval w fmod)
- e w s mod))
- ((macro)
- (syntax-type (chi-macro fval e r w s rib mod)
- r empty-wrap s rib mod for-car?))
- ((module-ref)
- (call-with-values (lambda () (fval e r w))
- (lambda (e r w s mod)
- (syntax-type e r w s rib mod for-car?))))
- ((core)
- (values 'core-form fval e w s mod))
- ((local-syntax)
- (values 'local-syntax-form fval e w s mod))
- ((begin)
- (values 'begin-form #f e w s mod))
- ((eval-when)
- (values 'eval-when-form #f e w s mod))
- ((define)
- (syntax-case e ()
- ((_ name val)
- (id? #'name)
- (values 'define-form #'name #'val w s mod))
- ((_ (name . args) e1 e2 ...)
- (and (id? #'name)
- (valid-bound-ids? (lambda-var-list #'args)))
- ;; need lambda here...
- (values 'define-form (wrap #'name w mod)
- (decorate-source
- (cons #'lambda (wrap #'(args e1 e2 ...) w mod))
- s)
- empty-wrap s mod))
- ((_ name)
- (id? #'name)
- (values 'define-form (wrap #'name w mod)
- #'(if #f #f)
- empty-wrap s mod))))
- ((define-syntax)
- (syntax-case e ()
- ((_ name val)
- (id? #'name)
- (values 'define-syntax-form #'name #'val w s mod))))
- ((define-syntax-parameter)
- (syntax-case e ()
- ((_ name val)
- (id? #'name)
- (values 'define-syntax-parameter-form #'name #'val w s mod))))
- (else
- (values 'call #f e w s mod)))))))
- ((syntax-object? e)
- (syntax-type (syntax-object-expression e)
- r
- (join-wraps w (syntax-object-wrap e))
- (or (source-annotation e) s) rib
- (or (syntax-object-module e) mod) for-car?))
- ((self-evaluating? e) (values 'constant #f e w s mod))
- (else (values 'other #f e w s mod)))))
- (define chi
- (lambda (e r w mod)
- (call-with-values
- (lambda () (syntax-type e r w (source-annotation e) #f mod #f))
- (lambda (type value e w s mod)
- (chi-expr type value e r w s mod)))))
- (define chi-expr
- (lambda (type value e r w s mod)
- (case type
- ((lexical)
- (build-lexical-reference 'value s e value))
- ((core core-form)
- ;; apply transformer
- (value e r w s mod))
- ((module-ref)
- (call-with-values (lambda () (value e r w))
- (lambda (e r w s mod)
- (chi e r w mod))))
- ((lexical-call)
- (chi-call
- (let ((id (car e)))
- (build-lexical-reference 'fun (source-annotation id)
- (if (syntax-object? id)
- (syntax->datum id)
- id)
- value))
- e r w s mod))
- ((global-call)
- (chi-call
- (build-global-reference (source-annotation (car e))
- (if (syntax-object? value)
- (syntax-object-expression value)
- value)
- (if (syntax-object? value)
- (syntax-object-module value)
- mod))
- e r w s mod))
- ((constant) (build-data s (strip (source-wrap e w s mod) empty-wrap)))
- ((global) (build-global-reference s value mod))
- ((call) (chi-call (chi (car e) r w mod) e r w s mod))
- ((begin-form)
- (syntax-case e ()
- ((_ e1 e2 ...) (chi-sequence #'(e1 e2 ...) r w s mod))))
- ((local-syntax-form)
- (chi-local-syntax value e r w s mod chi-sequence))
- ((eval-when-form)
- (syntax-case e ()
- ((_ (x ...) e1 e2 ...)
- (let ((when-list (chi-when-list e #'(x ...) w)))
- (if (memq 'eval when-list)
- (chi-sequence #'(e1 e2 ...) r w s mod)
- (chi-void))))))
- ((define-form define-syntax-form define-syntax-parameter-form)
- (syntax-violation #f "definition in expression context"
- e (wrap value w mod)))
- ((syntax)
- (syntax-violation #f "reference to pattern variable outside syntax form"
- (source-wrap e w s mod)))
- ((displaced-lexical)
- (syntax-violation #f "reference to identifier outside its scope"
- (source-wrap e w s mod)))
- (else (syntax-violation #f "unexpected syntax"
- (source-wrap e w s mod))))))
- (define chi-call
- (lambda (x e r w s mod)
- (syntax-case e ()
- ((e0 e1 ...)
- (build-call s x
- (map (lambda (e) (chi e r w mod)) #'(e1 ...)))))))
- ;; (What follows is my interpretation of what's going on here -- Andy)
- ;;
- ;; A macro takes an expression, a tree, the leaves of which are identifiers
- ;; and datums. Identifiers are symbols along with a wrap and a module. For
- ;; efficiency, subtrees that share wraps and modules may be grouped as one
- ;; syntax object.
- ;;
- ;; Going into the expansion, the expression is given an anti-mark, which
- ;; logically propagates to all leaves. Then, in the new expression returned
- ;; from the transfomer, if we see an expression with an anti-mark, we know it
- ;; pertains to the original expression; conversely, expressions without the
- ;; anti-mark are known to be introduced by the transformer.
- ;;
- ;; OK, good until now. We know this algorithm does lexical scoping
- ;; appropriately because it's widely known in the literature, and psyntax is
- ;; widely used. But what about modules? Here we're on our own. What we do is
- ;; to mark the module of expressions produced by a macro as pertaining to the
- ;; module that was current when the macro was defined -- that is, free
- ;; identifiers introduced by a macro are scoped in the macro's module, not in
- ;; the expansion's module. Seems to work well.
- ;;
- ;; The only wrinkle is when we want a macro to expand to code in another
- ;; module, as is the case for the r6rs `library' form -- the body expressions
- ;; should be scoped relative the the new module, the one defined by the macro.
- ;; For that, use `(@@ mod-name body)'.
- ;;
- ;; Part of the macro output will be from the site of the macro use and part
- ;; from the macro definition. We allow source information from the macro use
- ;; to pass through, but we annotate the parts coming from the macro with the
- ;; source location information corresponding to the macro use. It would be
- ;; really nice if we could also annotate introduced expressions with the
- ;; locations corresponding to the macro definition, but that is not yet
- ;; possible.
- (define chi-macro
- (lambda (p e r w s rib mod)
- (define rebuild-macro-output
- (lambda (x m)
- (cond ((pair? x)
- (decorate-source
- (cons (rebuild-macro-output (car x) m)
- (rebuild-macro-output (cdr x) m))
- s))
- ((syntax-object? x)
- (let ((w (syntax-object-wrap x)))
- (let ((ms (wrap-marks w)) (s (wrap-subst w)))
- (if (and (pair? ms) (eq? (car ms) the-anti-mark))
- ;; output is from original text
- (make-syntax-object
- (syntax-object-expression x)
- (make-wrap (cdr ms) (if rib (cons rib (cdr s)) (cdr s)))
- (syntax-object-module x))
- ;; output introduced by macro
- (make-syntax-object
- (decorate-source (syntax-object-expression x) s)
- (make-wrap (cons m ms)
- (if rib
- (cons rib (cons 'shift s))
- (cons 'shift s)))
- (syntax-object-module x))))))
-
- ((vector? x)
- (let* ((n (vector-length x))
- (v (decorate-source (make-vector n) x)))
- (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-violation #f "encountered raw symbol in macro output"
- (source-wrap e w (wrap-subst w) mod) x))
- (else (decorate-source x s)))))
- (rebuild-macro-output (p (source-wrap e (anti-mark w) s mod))
- (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 mod)
- (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 mod))) body))
- (ids '()) (labels '())
- (var-ids '()) (vars '()) (vals '()) (bindings '()))
- (if (null? body)
- (syntax-violation #f "no expressions in body" outer-form)
- (let ((e (cdar body)) (er (caar body)))
- (call-with-values
- (lambda () (syntax-type e er empty-wrap (source-annotation er) ribcage mod #f))
- (lambda (type value e w s mod)
- (case type
- ((define-form)
- (let ((id (wrap value w mod)) (label (gen-label)))
- (let ((var (gen-var id)))
- (extend-ribcage! ribcage id label)
- (parse (cdr body)
- (cons id ids) (cons label labels)
- (cons id var-ids)
- (cons var vars) (cons (cons er (wrap e w mod)) vals)
- (cons (make-binding 'lexical var) bindings)))))
- ((define-syntax-form define-syntax-parameter-form)
- (let ((id (wrap value w mod)) (label (gen-label)))
- (extend-ribcage! ribcage id label)
- (parse (cdr body)
- (cons id ids) (cons label labels)
- var-ids vars vals
- (cons (make-binding
- (if (eq? type 'define-syntax-parameter-form)
- 'syntax-parameter
- 'macro)
- (cons er (wrap e w mod)))
- bindings))))
- ((begin-form)
- (syntax-case e ()
- ((_ e1 ...)
- (parse (let f ((forms #'(e1 ...)))
- (if (null? forms)
- (cdr body)
- (cons (cons er (wrap (car forms) w mod))
- (f (cdr forms)))))
- ids labels var-ids vars vals bindings))))
- ((local-syntax-form)
- (chi-local-syntax value e er w s mod
- (lambda (forms er w s mod)
- (parse (let f ((forms forms))
- (if (null? forms)
- (cdr body)
- (cons (cons er (wrap (car forms) w mod))
- (f (cdr forms)))))
- ids labels var-ids 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 mod))
- (cons (cons er (source-wrap e w s mod))
- (cdr body))))
- (begin
- (if (not (valid-bound-ids? ids))
- (syntax-violation
- #f "invalid or duplicate identifier in definition"
- outer-form))
- (let loop ((bs bindings) (er-cache #f) (r-cache #f))
- (if (not (null? bs))
- (let* ((b (car bs)))
- (if (memq (car b) '(macro syntax-parameter))
- (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 mod)
- mod))
- (if (eq? (car b) 'syntax-parameter)
- (set-cdr! b (list (cdr b))))
- (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 #t
- (reverse (map syntax->datum var-ids))
- (reverse vars)
- (map (lambda (x)
- (chi (cdr x) (car x) empty-wrap mod))
- (reverse vals))
- (build-sequence no-source
- (map (lambda (x)
- (chi (cdr x) (car x) empty-wrap mod))
- (cons (cons er (source-wrap e w s mod))
- (cdr body)))))))))))))))))
- (define chi-local-syntax
- (lambda (rec? e r w s mod k)
- (syntax-case e ()
- ((_ ((id val) ...) e1 e2 ...)
- (let ((ids #'(id ...)))
- (if (not (valid-bound-ids? ids))
- (syntax-violation #f "duplicate bound keyword" e)
- (let ((labels (gen-labels ids)))
- (let ((new-w (make-binding-wrap ids labels w)))
- (k #'(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 mod)
- mod)))
- #'(val ...)))
- r)
- new-w
- s
- mod))))))
- (_ (syntax-violation #f "bad local syntax definition"
- (source-wrap e w s mod))))))
- (define eval-local-transformer
- (lambda (expanded mod)
- (let ((p (local-eval-hook expanded mod)))
- (if (procedure? p)
- p
- (syntax-violation #f "nonprocedure transformer" p)))))
- (define chi-void
- (lambda ()
- (build-void no-source)))
- (define ellipsis?
- (lambda (x)
- (and (nonsymbol-id? x)
- (free-id=? x #'(... ...)))))
- (define lambda-formals
- (lambda (orig-args)
- (define (req args rreq)
- (syntax-case args ()
- (()
- (check (reverse rreq) #f))
- ((a . b) (id? #'a)
- (req #'b (cons #'a rreq)))
- (r (id? #'r)
- (check (reverse rreq) #'r))
- (else
- (syntax-violation 'lambda "invalid argument list" orig-args args))))
- (define (check req rest)
- (cond
- ((distinct-bound-ids? (if rest (cons rest req) req))
- (values req #f rest #f))
- (else
- (syntax-violation 'lambda "duplicate identifier in argument list"
- orig-args))))
- (req orig-args '())))
- (define chi-simple-lambda
- (lambda (e r w s mod req rest meta body)
- (let* ((ids (if rest (append req (list rest)) req))
- (vars (map gen-var ids))
- (labels (gen-labels ids)))
- (build-simple-lambda
- s
- (map syntax->datum req) (and rest (syntax->datum rest)) vars
- meta
- (chi-body body (source-wrap e w s mod)
- (extend-var-env labels vars r)
- (make-binding-wrap ids labels w)
- mod)))))
- (define lambda*-formals
- (lambda (orig-args)
- (define (req args rreq)
- (syntax-case args ()
- (()
- (check (reverse rreq) '() #f '()))
- ((a . b) (id? #'a)
- (req #'b (cons #'a rreq)))
- ((a . b) (eq? (syntax->datum #'a) #:optional)
- (opt #'b (reverse rreq) '()))
- ((a . b) (eq? (syntax->datum #'a) #:key)
- (key #'b (reverse rreq) '() '()))
- ((a b) (eq? (syntax->datum #'a) #:rest)
- (rest #'b (reverse rreq) '() '()))
- (r (id? #'r)
- (rest #'r (reverse rreq) '() '()))
- (else
- (syntax-violation 'lambda* "invalid argument list" orig-args args))))
- (define (opt args req ropt)
- (syntax-case args ()
- (()
- (check req (reverse ropt) #f '()))
- ((a . b) (id? #'a)
- (opt #'b req (cons #'(a #f) ropt)))
- (((a init) . b) (id? #'a)
- (opt #'b req (cons #'(a init) ropt)))
- ((a . b) (eq? (syntax->datum #'a) #:key)
- (key #'b req (reverse ropt) '()))
- ((a b) (eq? (syntax->datum #'a) #:rest)
- (rest #'b req (reverse ropt) '()))
- (r (id? #'r)
- (rest #'r req (reverse ropt) '()))
- (else
- (syntax-violation 'lambda* "invalid optional argument list"
- orig-args args))))
- (define (key args req opt rkey)
- (syntax-case args ()
- (()
- (check req opt #f (cons #f (reverse rkey))))
- ((a . b) (id? #'a)
- (with-syntax ((k (symbol->keyword (syntax->datum #'a))))
- (key #'b req opt (cons #'(k a #f) rkey))))
- (((a init) . b) (id? #'a)
- (with-syntax ((k (symbol->keyword (syntax->datum #'a))))
- (key #'b req opt (cons #'(k a init) rkey))))
- (((a init k) . b) (and (id? #'a)
- (keyword? (syntax->datum #'k)))
- (key #'b req opt (cons #'(k a init) rkey)))
- ((aok) (eq? (syntax->datum #'aok) #:allow-other-keys)
- (check req opt #f (cons #t (reverse rkey))))
- ((aok a b) (and (eq? (syntax->datum #'aok) #:allow-other-keys)
- (eq? (syntax->datum #'a) #:rest))
- (rest #'b req opt (cons #t (reverse rkey))))
- ((aok . r) (and (eq? (syntax->datum #'aok) #:allow-other-keys)
- (id? #'r))
- (rest #'r req opt (cons #t (reverse rkey))))
- ((a b) (eq? (syntax->datum #'a) #:rest)
- (rest #'b req opt (cons #f (reverse rkey))))
- (r (id? #'r)
- (rest #'r req opt (cons #f (reverse rkey))))
- (else
- (syntax-violation 'lambda* "invalid keyword argument list"
- orig-args args))))
- (define (rest args req opt kw)
- (syntax-case args ()
- (r (id? #'r)
- (check req opt #'r kw))
- (else
- (syntax-violation 'lambda* "invalid rest argument"
- orig-args args))))
- (define (check req opt rest kw)
- (cond
- ((distinct-bound-ids?
- (append req (map car opt) (if rest (list rest) '())
- (if (pair? kw) (map cadr (cdr kw)) '())))
- (values req opt rest kw))
- (else
- (syntax-violation 'lambda* "duplicate identifier in argument list"
- orig-args))))
- (req orig-args '())))
- (define chi-lambda-case
- (lambda (e r w s mod get-formals clauses)
- (define (expand-req req opt rest kw body)
- (let ((vars (map gen-var req))
- (labels (gen-labels req)))
- (let ((r* (extend-var-env labels vars r))
- (w* (make-binding-wrap req labels w)))
- (expand-opt (map syntax->datum req)
- opt rest kw body (reverse vars) r* w* '() '()))))
- (define (expand-opt req opt rest kw body vars r* w* out inits)
- (cond
- ((pair? opt)
- (syntax-case (car opt) ()
- ((id i)
- (let* ((v (gen-var #'id))
- (l (gen-labels (list v)))
- (r** (extend-var-env l (list v) r*))
- (w** (make-binding-wrap (list #'id) l w*)))
- (expand-opt req (cdr opt) rest kw body (cons v vars)
- r** w** (cons (syntax->datum #'id) out)
- (cons (chi #'i r* w* mod) inits))))))
- (rest
- (let* ((v (gen-var rest))
- (l (gen-labels (list v)))
- (r* (extend-var-env l (list v) r*))
- (w* (make-binding-wrap (list rest) l w*)))
- (expand-kw req (if (pair? out) (reverse out) #f)
- (syntax->datum rest)
- (if (pair? kw) (cdr kw) kw)
- body (cons v vars) r* w*
- (if (pair? kw) (car kw) #f)
- '() inits)))
- (else
- (expand-kw req (if (pair? out) (reverse out) #f) #f
- (if (pair? kw) (cdr kw) kw)
- body vars r* w*
- (if (pair? kw) (car kw) #f)
- '() inits))))
- (define (expand-kw req opt rest kw body vars r* w* aok out inits)
- (cond
- ((pair? kw)
- (syntax-case (car kw) ()
- ((k id i)
- (let* ((v (gen-var #'id))
- (l (gen-labels (list v)))
- (r** (extend-var-env l (list v) r*))
- (w** (make-binding-wrap (list #'id) l w*)))
- (expand-kw req opt rest (cdr kw) body (cons v vars)
- r** w** aok
- (cons (list (syntax->datum #'k)
- (syntax->datum #'id)
- v)
- out)
- (cons (chi #'i r* w* mod) inits))))))
- (else
- (expand-body req opt rest
- (if (or aok (pair? out)) (cons aok (reverse out)) #f)
- body (reverse vars) r* w* (reverse inits) '()))))
- (define (expand-body req opt rest kw body vars r* w* inits meta)
- (syntax-case body ()
- ((docstring e1 e2 ...) (string? (syntax->datum #'docstring))
- (expand-body req opt rest kw #'(e1 e2 ...) vars r* w* inits
- (append meta
- `((documentation
- . ,(syntax->datum #'docstring))))))
- ((#((k . v) ...) e1 e2 ...)
- (expand-body req opt rest kw #'(e1 e2 ...) vars r* w* inits
- (append meta (syntax->datum #'((k . v) ...)))))
- ((e1 e2 ...)
- (values meta req opt rest kw inits vars
- (chi-body #'(e1 e2 ...) (source-wrap e w s mod)
- r* w* mod)))))
- (syntax-case clauses ()
- (() (values '() #f))
- (((args e1 e2 ...) (args* e1* e2* ...) ...)
- (call-with-values (lambda () (get-formals #'args))
- (lambda (req opt rest kw)
- (call-with-values (lambda ()
- (expand-req req opt rest kw #'(e1 e2 ...)))
- (lambda (meta req opt rest kw inits vars body)
- (call-with-values
- (lambda ()
- (chi-lambda-case e r w s mod get-formals
- #'((args* e1* e2* ...) ...)))
- (lambda (meta* else*)
- (values
- (append meta meta*)
- (build-lambda-case s req opt rest kw inits vars
- body else*))))))))))))
- ;; data
- ;; strips syntax-objects down to top-wrap
- ;;
- ;; 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)
- 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)))
- ;; inlined and-map with two args
- (let lp ((l1 old) (l2 new))
- (if (null? l1)
- x
- (if (eq? (car l1) (car l2))
- (lp (cdr l1) (cdr l2))
- (list->vector new)))))))
- (else x))))))
- ;; lexical variables
- (define gen-var
- (lambda (id)
- (let ((id (if (syntax-object? id) (syntax-object-expression id) id)))
- (build-lexical-var no-source id))))
- ;; appears to return a reversed list
- (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 #f) ls) w))
- ((id? vars) (cons (wrap vars w #f) ls))
- ((null? vars) ls)
- ((syntax-object? vars)
- (lvl (syntax-object-expression vars)
- ls
- (join-wraps w (syntax-object-wrap vars))))
- ;; 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 'syntax-parameterize
- (lambda (e r w s mod)
- (syntax-case e ()
- ((_ ((var val) ...) e1 e2 ...)
- (valid-bound-ids? #'(var ...))
- (let ((names
- (map (lambda (x)
- (call-with-values
- (lambda () (resolve-identifier x w r mod #f))
- (lambda (type value mod)
- (case type
- ((displaced-lexical)
- (syntax-violation 'syntax-parameterize
- "identifier out of context"
- e
- (source-wrap x w s mod)))
- ((syntax-parameter)
- value)
- (else
- (syntax-violation 'syntax-parameterize
- "invalid syntax parameter"
- e
- (source-wrap x w s mod)))))))
- #'(var ...)))
- (bindings
- (let ((trans-r (macros-only-env r)))
- (map (lambda (x)
- (make-binding
- 'macro
- (eval-local-transformer (chi x trans-r w mod) mod)))
- #'(val ...)))))
- (chi-body #'(e1 e2 ...)
- (source-wrap e w s mod)
- (extend-env names bindings r)
- w
- mod)))
- (_ (syntax-violation 'syntax-parameterize "bad syntax"
- (source-wrap e w s mod))))))
- (global-extend 'core 'quote
- (lambda (e r w s mod)
- (syntax-case e ()
- ((_ e) (build-data s (strip #'e w)))
- (_ (syntax-violation 'quote "bad syntax"
- (source-wrap e w s mod))))))
- (global-extend
- 'core 'syntax
- (let ()
- (define gen-syntax
- (lambda (src e r maps ellipsis? mod)
- (if (id? e)
- (call-with-values (lambda ()
- (resolve-identifier e empty-wrap r mod #f))
- (lambda (type value mod)
- (case type
- ((syntax)
- (call-with-values
- (lambda () (gen-ref src (car value) (cdr value) maps))
- (lambda (var maps)
- (values `(ref ,var) maps))))
- (else
- (if (ellipsis? e)
- (syntax-violation 'syntax "misplaced ellipsis" src)
- (values `(quote ,e) maps))))))
- (syntax-case e ()
- ((dots e)
- (ellipsis? #'dots)
- (gen-syntax src #'e r maps (lambda (x) #f) mod))
- ((x dots . y)
- ;; this could be about a dozen lines of code, except that we
- ;; choose to handle #'(x ... ...) forms
- (ellipsis? #'dots)
- (let f ((y #'y)
- (k (lambda (maps)
- (call-with-values
- (lambda ()
- (gen-syntax src #'x r
- (cons '() maps) ellipsis? mod))
- (lambda (x maps)
- (if (null? (car maps))
- (syntax-violation 'syntax "extra ellipsis"
- src)
- (values (gen-map x (car maps))
- (cdr maps))))))))
- (syntax-case y ()
- ((dots . y)
- (ellipsis? #'dots)
- (f #'y
- (lambda (maps)
- (call-with-values
- (lambda () (k (cons '() maps)))
- (lambda (x maps)
- (if (null? (car maps))
- (syntax-violation 'syntax "extra ellipsis" src)
- (values (gen-mappend x (car maps))
- (cdr maps))))))))
- (_ (call-with-values
- (lambda () (gen-syntax src y r maps ellipsis? mod))
- (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 #'x r maps ellipsis? mod))
- (lambda (x maps)
- (call-with-values
- (lambda () (gen-syntax src #'y r maps ellipsis? mod))
- (lambda (y maps) (values (gen-cons x y) maps))))))
- (#(e1 e2 ...)
- (call-with-values
- (lambda ()
- (gen-syntax src #'(e1 e2 ...) r maps ellipsis? mod))
- (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-violation 'syntax "missing ellipsis" src)
- (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))
- ((and-map
- (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) (cadr x)))
- ((primitive) (build-primref no-source (cadr x)))
- ((quote) (build-data no-source (cadr x)))
- ((lambda)
- (if (list? (cadr x))
- (build-simple-lambda no-source (cadr x) #f (cadr x) '() (regen (caddr x)))
- (error "how did we get here" x)))
- (else (build-primcall no-source (car x) (map regen (cdr x)))))))
- (lambda (e r w s mod)
- (let ((e (source-wrap e w s mod)))
- (syntax-case e ()
- ((_ x)
- (call-with-values
- (lambda () (gen-syntax e #'x r '() ellipsis? mod))
- (lambda (e maps) (regen e))))
- (_ (syntax-violation 'syntax "bad `syntax' form" e)))))))
- (global-extend 'core 'lambda
- (lambda (e r w s mod)
- (syntax-case e ()
- ((_ args e1 e2 ...)
- (call-with-values (lambda () (lambda-formals #'args))
- (lambda (req opt rest kw)
- (let lp ((body #'(e1 e2 ...)) (meta '()))
- (syntax-case body ()
- ((docstring e1 e2 ...) (string? (syntax->datum #'docstring))
- (lp #'(e1 e2 ...)
- (append meta
- `((documentation
- . ,(syntax->datum #'docstring))))))
- ((#((k . v) ...) e1 e2 ...)
- (lp #'(e1 e2 ...)
- (append meta (syntax->datum #'((k . v) ...)))))
- (_ (chi-simple-lambda e r w s mod req rest meta body)))))))
- (_ (syntax-violation 'lambda "bad lambda" e)))))
-
- (global-extend 'core 'lambda*
- (lambda (e r w s mod)
- (syntax-case e ()
- ((_ args e1 e2 ...)
- (call-with-values
- (lambda ()
- (chi-lambda-case e r w s mod
- lambda*-formals #'((args e1 e2 ...))))
- (lambda (meta lcase)
- (build-case-lambda s meta lcase))))
- (_ (syntax-violation 'lambda "bad lambda*" e)))))
- (global-extend 'core 'case-lambda
- (lambda (e r w s mod)
- (syntax-case e ()
- ((_ (args e1 e2 ...) (args* e1* e2* ...) ...)
- (call-with-values
- (lambda ()
- (chi-lambda-case e r w s mod
- lambda-formals
- #'((args e1 e2 ...) (args* e1* e2* ...) ...)))
- (lambda (meta lcase)
- (build-case-lambda s meta lcase))))
- (_ (syntax-violation 'case-lambda "bad case-lambda" e)))))
- (global-extend 'core 'case-lambda*
- (lambda (e r w s mod)
- (syntax-case e ()
- ((_ (args e1 e2 ...) (args* e1* e2* ...) ...)
- (call-with-values
- (lambda ()
- (chi-lambda-case e r w s mod
- lambda*-formals
- #'((args e1 e2 ...) (args* e1* e2* ...) ...)))
- (lambda (meta lcase)
- (build-case-lambda s meta lcase))))
- (_ (syntax-violation 'case-lambda "bad case-lambda*" e)))))
- (global-extend 'core 'let
- (let ()
- (define (chi-let e r w s mod constructor ids vals exps)
- (if (not (valid-bound-ids? ids))
- (syntax-violation 'let "duplicate bound variable" e)
- (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
- (map syntax->datum ids)
- new-vars
- (map (lambda (x) (chi x r w mod)) vals)
- (chi-body exps (source-wrap e nw s mod)
- nr nw mod))))))
- (lambda (e r w s mod)
- (syntax-case e ()
- ((_ ((id val) ...) e1 e2 ...)
- (and-map id? #'(id ...))
- (chi-let e r w s mod
- build-let
- #'(id ...)
- #'(val ...)
- #'(e1 e2 ...)))
- ((_ f ((id val) ...) e1 e2 ...)
- (and (id? #'f) (and-map id? #'(id ...)))
- (chi-let e r w s mod
- build-named-let
- #'(f id ...)
- #'(val ...)
- #'(e1 e2 ...)))
- (_ (syntax-violation 'let "bad let" (source-wrap e w s mod)))))))
- (global-extend 'core 'letrec
- (lambda (e r w s mod)
- (syntax-case e ()
- ((_ ((id val) ...) e1 e2 ...)
- (and-map id? #'(id ...))
- (let ((ids #'(id ...)))
- (if (not (valid-bound-ids? ids))
- (syntax-violation 'letrec "duplicate bound variable" e)
- (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 #f
- (map syntax->datum ids)
- new-vars
- (map (lambda (x) (chi x r w mod)) #'(val ...))
- (chi-body #'(e1 e2 ...)
- (source-wrap e w s mod) r w mod)))))))
- (_ (syntax-violation 'letrec "bad letrec" (source-wrap e w s mod))))))
- (global-extend 'core 'letrec*
- (lambda (e r w s mod)
- (syntax-case e ()
- ((_ ((id val) ...) e1 e2 ...)
- (and-map id? #'(id ...))
- (let ((ids #'(id ...)))
- (if (not (valid-bound-ids? ids))
- (syntax-violation 'letrec* "duplicate bound variable" e)
- (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 #t
- (map syntax->datum ids)
- new-vars
- (map (lambda (x) (chi x r w mod)) #'(val ...))
- (chi-body #'(e1 e2 ...)
- (source-wrap e w s mod) r w mod)))))))
- (_ (syntax-violation 'letrec* "bad letrec*" (source-wrap e w s mod))))))
- (global-extend
- 'core 'set!
- (lambda (e r w s mod)
- (syntax-case e ()
- ((_ id val)
- (id? #'id)
- (call-with-values
- (lambda () (resolve-identifier #'id w r mod #t))
- (lambda (type value id-mod)
- (case type
- ((lexical)
- (build-lexical-assignment s (syntax->datum #'id) value
- (chi #'val r w mod)))
- ((global)
- (build-global-assignment s value (chi #'val r w mod) id-mod))
- ((macro)
- (if (procedure-property value 'variable-transformer)
- ;; As syntax-type does, call chi-macro with
- ;; the mod of the expression. Hmm.
- (chi (chi-macro value e r w s #f mod) r empty-wrap mod)
- (syntax-violation 'set! "not a variable transformer"
- (wrap e w mod)
- (wrap #'id w id-mod))))
- ((displaced-lexical)
- (syntax-violation 'set! "identifier out of context"
- (wrap #'id w mod)))
- (else
- (syntax-violation 'set! "bad set!" (source-wrap e w s mod)))))))
- ((_ (head tail ...) val)
- (call-with-values
- (lambda () (syntax-type #'head r empty-wrap no-source #f mod #t))
- (lambda (type value ee ww ss modmod)
- (case type
- ((module-ref)
- (let ((val (chi #'val r w mod)))
- (call-with-values (lambda () (value #'(head tail ...) r w))
- (lambda (e r w s* mod)
- (syntax-case e ()
- (e (id? #'e)
- (build-global-assignment s (syntax->datum #'e)
- val mod)))))))
- (else
- (build-call s
- (chi #'(setter head) r w mod)
- (map (lambda (e) (chi e r w mod))
- #'(tail ... val))))))))
- (_ (syntax-violation 'set! "bad set!" (source-wrap e w s mod))))))
- (global-extend 'module-ref '@
- (lambda (e r w)
- (syntax-case e ()
- ((_ (mod ...) id)
- (and (and-map id? #'(mod ...)) (id? #'id))
- (values (syntax->datum #'id) r w #f
- (syntax->datum
- #'(public mod ...)))))))
- (global-extend 'module-ref '@@
- (lambda (e r w)
- (define remodulate
- (lambda (x mod)
- (cond ((pair? x)
- (cons (remodulate (car x) mod)
- (remodulate (cdr x) mod)))
- ((syntax-object? x)
- (make-syntax-object
- (remodulate (syntax-object-expression x) mod)
- (syntax-object-wrap x)
- ;; hither the remodulation
- mod))
- ((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 (remodulate (vector-ref x i) mod)))))
- (else x))))
- (syntax-case e ()
- ((_ (mod ...) exp)
- (and-map id? #'(mod ...))
- (let ((mod (syntax->datum #'(private mod ...))))
- (values (remodulate #'exp mod)
- r w (source-annotation #'exp)
- mod))))))
-
- (global-extend 'core 'if
- (lambda (e r w s mod)
- (syntax-case e ()
- ((_ test then)
- (build-conditional
- s
- (chi #'test r w mod)
- (chi #'then r w mod)
- (build-void no-source)))
- ((_ test then else)
- (build-conditional
- s
- (chi #'test r w mod)
- (chi #'then r w mod)
- (chi #'else r w mod))))))
- (global-extend 'core 'with-fluids
- (lambda (e r w s mod)
- (syntax-case e ()
- ((_ ((fluid val) ...) b b* ...)
- (build-dynlet
- s
- (map (lambda (x) (chi x r w mod)) #'(fluid ...))
- (map (lambda (x) (chi x r w mod)) #'(val ...))
- (chi-body #'(b b* ...)
- (source-wrap e w s mod) r w mod))))))
-
- (global-extend 'begin 'begin '())
- (global-extend 'define 'define '())
- (global-extend 'define-syntax 'define-syntax '())
- (global-extend 'define-syntax-parameter 'define-syntax-parameter '())
- (global-extend 'eval-when 'eval-when '())
- (global-extend 'core 'syntax-case
- (let ()
- (define convert-pattern
- ;; accepts pattern & keys
- ;; returns $sc-dispatch pattern & ids
- (lambda (pattern keys)
- (define cvt*
- (lambda (p* n ids)
- (if (not (pair? p*))
- (cvt p* n ids)
- (call-with-values
- (lambda () (cvt* (cdr p*) n ids))
- (lambda (y ids)
- (call-with-values
- (lambda () (cvt (car p*) n ids))
- (lambda (x ids)
- (values (cons x y) ids))))))))
-
- (define (v-reverse x)
- (let loop ((r '()) (x x))
- (if (not (pair? x))
- (values r x)
- (loop (cons (car x) r) (cdr x)))))
- (define cvt
- (lambda (p n ids)
- (if (id? p)
- (cond
- ((bound-id-member? p keys)
- (values (vector 'free-id p) ids))
- ((free-id=? p #'_)
- (values '_ ids))
- (else
- (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 dots . ys)
- (ellipsis? (syntax dots))
- (call-with-values
- (lambda () (cvt* (syntax ys) n ids))
- (lambda (ys ids)
- (call-with-values
- (lambda () (cvt (syntax x) (+ n 1) ids))
- (lambda (x ids)
- (call-with-values
- (lambda () (v-reverse ys))
- (lambda (ys e)
- (values `#(each+ ,x ,ys ,e)
- 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))))))
- (cvt pattern 0 '())))
- (define build-dispatch-call
- (lambda (pvars exp y r mod)
- (let ((ids (map car pvars)) (levels (map cdr pvars)))
- (let ((labels (gen-labels ids)) (new-vars (map gen-var ids)))
- (build-primcall
- no-source
- 'apply
- (list (build-simple-lambda no-source (map syntax->datum ids) #f 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)
- mod))
- y))))))
- (define gen-clause
- (lambda (x keys clauses r pat fender exp mod)
- (call-with-values
- (lambda () (convert-pattern pat keys))
- (lambda (p pvars)
- (cond
- ((not (distinct-bound-ids? (map car pvars)))
- (syntax-violation 'syntax-case "duplicate pattern variable" pat))
- ((not (and-map (lambda (x) (not (ellipsis? (car x)))) pvars))
- (syntax-violation 'syntax-case "misplaced ellipsis" pat))
- (else
- (let ((y (gen-var 'tmp)))
- ;; fat finger binding and references to temp variable y
- (build-call no-source
- (build-simple-lambda no-source (list 'tmp) #f (list y) '()
- (let ((y (build-lexical-reference 'value no-source
- 'tmp y)))
- (build-conditional no-source
- (syntax-case fender ()
- (#t y)
- (_ (build-conditional no-source
- y
- (build-dispatch-call pvars fender y r mod)
- (build-data no-source #f))))
- (build-dispatch-call pvars exp y r mod)
- (gen-syntax-case x keys clauses r mod))))
- (list (if (eq? p 'any)
- (build-primcall no-source 'list (list x))
- (build-primcall no-source '$sc-dispatch
- (list x (build-data no-source p)))))))))))))
- (define gen-syntax-case
- (lambda (x keys clauses r mod)
- (if (null? clauses)
- (build-primcall no-source 'syntax-violation
- (list (build-data no-source #f)
- (build-data no-source
- "source expression failed to match any pattern")
- x))
- (syntax-case (car clauses) ()
- ((pat exp)
- (if (and (id? #'pat)
- (and-map (lambda (x) (not (free-id=? #'pat x)))
- (cons #'(... ...) keys)))
- (if (free-id=? #'pad #'_)
- (chi #'exp r empty-wrap mod)
- (let ((labels (list (gen-label)))
- (var (gen-var #'pat)))
- (build-call no-source
- (build-simple-lambda
- no-source (list (syntax->datum #'pat)) #f (list var)
- '()
- (chi #'exp
- (extend-env labels
- (list (make-binding 'syntax `(,var . 0)))
- r)
- (make-binding-wrap #'(pat)
- labels empty-wrap)
- mod))
- (list x))))
- (gen-clause x keys (cdr clauses) r
- #'pat #t #'exp mod)))
- ((pat fender exp)
- (gen-clause x keys (cdr clauses) r
- #'pat #'fender #'exp mod))
- (_ (syntax-violation 'syntax-case "invalid clause"
- (car clauses)))))))
- (lambda (e r w s mod)
- (let ((e (source-wrap e w s mod)))
- (syntax-case e ()
- ((_ val (key ...) m ...)
- (if (and-map (lambda (x) (and (id? x) (not (ellipsis? x))))
- #'(key ...))
- (let ((x (gen-var 'tmp)))
- ;; fat finger binding and references to temp variable x
- (build-call s
- (build-simple-lambda no-source (list 'tmp) #f (list x) '()
- (gen-syntax-case (build-lexical-reference 'value no-source
- 'tmp x)
- #'(key ...) #'(m ...)
- r
- mod))
- (list (chi #'val r empty-wrap mod))))
- (syntax-violation 'syntax-case "invalid literals list" e))))))))
- ;; The portable macroexpand 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! macroexpand
- (lambda* (x #:optional (m 'e) (esew '(eval)))
- (chi-top-sequence (list x) null-env top-wrap #f m esew
- (cons 'hygiene (module-name (current-module))))))
- (set! identifier?
- (lambda (x)
- (nonsymbol-id? x)))
- (set! datum->syntax
- (lambda (id datum)
- (make-syntax-object datum (syntax-object-wrap id)
- (syntax-object-module id))))
- (set! syntax->datum
- ;; accepts any object, since syntax objects may consist partially
- ;; or entirely of unwrapped, nonsymbolic data
- (lambda (x)
- (strip x empty-wrap)))
- (set! syntax-source
- (lambda (x) (source-annotation x)))
- (set! generate-temporaries
- (lambda (ls)
- (arg-check list? ls 'generate-temporaries)
- (let ((mod (cons 'hygiene (module-name (current-module)))))
- (map (lambda (x) (wrap (gensym-hook) top-wrap mod)) 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-violation
- (lambda* (who message form #:optional subform)
- (arg-check (lambda (x) (or (not x) (string? x) (symbol? x)))
- who 'syntax-violation)
- (arg-check string? message 'syntax-violation)
- (throw 'syntax-error who message
- (source-annotation (or form subform))
- (strip form empty-wrap)
- (and subform (strip subform empty-wrap)))))
- ;; $sc-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>*)
- ;; #(each+ p1 (p2_1 ... p2_n) p3) (p1* (p2_n ... p2_1) . p3)
- ;; #(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 mod)
- (cond
- ((pair? e)
- (let ((first (match (car e) p w '() mod)))
- (and first
- (let ((rest (match-each (cdr e) p w mod)))
- (and rest (cons first rest))))))
- ((null? e) '())
- ((syntax-object? e)
- (match-each (syntax-object-expression e)
- p
- (join-wraps w (syntax-object-wrap e))
- (syntax-object-module e)))
- (else #f))))
- (define match-each+
- (lambda (e x-pat y-pat z-pat w r mod)
- (let f ((e e) (w w))
- (cond
- ((pair? e)
- (call-with-values (lambda () (f (cdr e) w))
- (lambda (xr* y-pat r)
- (if r
- (if (null? y-pat)
- (let ((xr (match (car e) x-pat w '() mod)))
- (if xr
- (values (cons xr xr*) y-pat r)
- (values #f #f #f)))
- (values
- '()
- (cdr y-pat)
- (match (car e) (car y-pat) w r mod)))
- (values #f #f #f)))))
- ((syntax-object? e)
- (f (syntax-object-expression e) (join-wraps w e)))
- (else
- (values '() y-pat (match e z-pat w r mod)))))))
- (define match-each-any
- (lambda (e w mod)
- (cond
- ((pair? e)
- (let ((l (match-each-any (cdr e) w mod)))
- (and l (cons (wrap (car e) w mod) l))))
- ((null? e) '())
- ((syntax-object? e)
- (match-each-any (syntax-object-expression e)
- (join-wraps w (syntax-object-wrap e))
- mod))
- (else #f))))
- (define match-empty
- (lambda (p r)
- (cond
- ((null? p) r)
- ((eq? 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))
- ((each+) (match-empty (vector-ref p 1)
- (match-empty
- (reverse (vector-ref p 2))
- (match-empty (vector-ref p 3) r))))
- ((free-id atom) r)
- ((vector) (match-empty (vector-ref p 1) r)))))))
- (define combine
- (lambda (r* r)
- (if (null? (car r*))
- r
- (cons (map car r*) (combine (map cdr r*) r)))))
- (define match*
- (lambda (e p w r mod)
- (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 mod)
- mod)))
- ((eq? p 'each-any)
- (let ((l (match-each-any e w mod))) (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 mod)))
- (and l
- (let collect ((l l))
- (if (null? (car l))
- r
- (cons (map car l) (collect (map cdr l)))))))))
- ((each+)
- (call-with-values
- (lambda ()
- (match-each+ e (vector-ref p 1) (vector-ref p 2) (vector-ref p 3) w r mod))
- (lambda (xr* y-pat r)
- (and r
- (null? y-pat)
- (if (null? xr*)
- (match-empty (vector-ref p 1) r)
- (combine xr* r))))))
- ((free-id) (and (id? e) (free-id=? (wrap e w mod) (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 mod))))))))
- (define match
- (lambda (e p w r mod)
- (cond
- ((not r) #f)
- ((eq? p '_) r)
- ((eq? p 'any) (cons (wrap e w mod) r))
- ((syntax-object? e)
- (match*
- (syntax-object-expression e)
- p
- (join-wraps w (syntax-object-wrap e))
- r
- (syntax-object-module e)))
- (else (match* e p w r mod)))))
- (set! $sc-dispatch
- (lambda (e p)
- (cond
- ((eq? p 'any) (list e))
- ((eq? p '_) '())
- ((syntax-object? e)
- (match* (syntax-object-expression e)
- p (syntax-object-wrap e) '() (syntax-object-module e)))
- (else (match* e p empty-wrap '() #f))))))))
- (define-syntax with-syntax
- (lambda (x)
- (syntax-case x ()
- ((_ () e1 e2 ...)
- #'(let () e1 e2 ...))
- ((_ ((out in)) e1 e2 ...)
- #'(syntax-case in ()
- (out (let () e1 e2 ...))))
- ((_ ((out in) ...) e1 e2 ...)
- #'(syntax-case (list in ...) ()
- ((out ...) (let () e1 e2 ...)))))))
- (define-syntax syntax-rules
- (lambda (x)
- (syntax-case x ()
- ((_ (k ...) ((keyword . pattern) template) ...)
- #'(lambda (x)
- ;; embed patterns as procedure metadata
- #((macro-type . syntax-rules)
- (patterns pattern ...))
- (syntax-case x (k ...)
- ((_ . pattern) #'template)
- ...)))
- ((_ (k ...) docstring ((keyword . pattern) template) ...)
- (string? (syntax->datum #'docstring))
- #'(lambda (x)
- ;; the same, but allow a docstring
- docstring
- #((macro-type . syntax-rules)
- (patterns pattern ...))
- (syntax-case x (k ...)
- ((_ . pattern) #'template)
- ...))))))
- (define-syntax define-syntax-rule
- (lambda (x)
- (syntax-case x ()
- ((_ (name . pattern) template)
- #'(define-syntax name
- (syntax-rules ()
- ((_ . pattern) template))))
- ((_ (name . pattern) docstring template)
- (string? (syntax->datum #'docstring))
- #'(define-syntax name
- (syntax-rules ()
- docstring
- ((_ . pattern) template)))))))
- (define-syntax let*
- (lambda (x)
- (syntax-case x ()
- ((let* ((x v) ...) e1 e2 ...)
- (and-map identifier? #'(x ...))
- (let f ((bindings #'((x v) ...)))
- (if (null? bindings)
- #'(let () e1 e2 ...)
- (with-syntax ((body (f (cdr bindings)))
- (binding (car bindings)))
- #'(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) #'e)
- (_ (syntax-violation
- 'do "bad step expression"
- orig-x s))))
- #'(var ...)
- #'(step ...))))
- (syntax-case #'(e1 ...) ()
- (() #'(let doloop ((var init) ...)
- (if (not e0)
- (begin c ... (doloop step ...)))))
- ((e1 e2 ...)
- #'(let doloop ((var init) ...)
- (if e0
- (begin e1 e2 ...)
- (begin c ... (doloop step ...)))))))))))
- (define-syntax quasiquote
- (let ()
- (define (quasi p lev)
- (syntax-case p (unquote quasiquote)
- ((unquote p)
- (if (= lev 0)
- #'("value" p)
- (quasicons #'("quote" unquote) (quasi #'(p) (- lev 1)))))
- ((quasiquote p) (quasicons #'("quote" quasiquote) (quasi #'(p) (+ lev 1))))
- ((p . q)
- (syntax-case #'p (unquote unquote-splicing)
- ((unquote p ...)
- (if (= lev 0)
- (quasilist* #'(("value" p) ...) (quasi #'q lev))
- (quasicons
- (quasicons #'("quote" unquote) (quasi #'(p ...) (- lev 1)))
- (quasi #'q lev))))
- ((unquote-splicing p ...)
- (if (= lev 0)
- (quasiappend #'(("value" p) ...) (quasi #'q lev))
- (quasicons
- (quasicons #'("quote" unquote-splicing) (quasi #'(p ...) (- lev 1)))
- (quasi #'q lev))))
- (_ (quasicons (quasi #'p lev) (quasi #'q lev)))))
- (#(x ...) (quasivector (vquasi #'(x ...) lev)))
- (p #'("quote" p))))
- (define (vquasi p lev)
- (syntax-case p ()
- ((p . q)
- (syntax-case #'p (unquote unquote-splicing)
- ((unquote p ...)
- (if (= lev 0)
- (quasilist* #'(("value" p) ...) (vquasi #'q lev))
- (quasicons
- (quasicons #'("quote" unquote) (quasi #'(p ...) (- lev 1)))
- (vquasi #'q lev))))
- ((unquote-splicing p ...)
- (if (= lev 0)
- (quasiappend #'(("value" p) ...) (vquasi #'q lev))
- (quasicons
- (quasicons
- #'("quote" unquote-splicing)
- (quasi #'(p ...) (- lev 1)))
- (vquasi #'q lev))))
- (_ (quasicons (quasi #'p lev) (vquasi #'q lev)))))
- (() #'("quote" ()))))
- (define (quasicons x y)
- (with-syntax ((x x) (y y))
- (syntax-case #'y ()
- (("quote" dy)
- (syntax-case #'x ()
- (("quote" dx) #'("quote" (dx . dy)))
- (_ (if (null? #'dy) #'("list" x) #'("list*" x y)))))
- (("list" . stuff) #'("list" x . stuff))
- (("list*" . stuff) #'("list*" x . stuff))
- (_ #'("list*" x y)))))
- (define (quasiappend x y)
- (syntax-case y ()
- (("quote" ())
- (cond
- ((null? x) #'("quote" ()))
- ((null? (cdr x)) (car x))
- (else (with-syntax (((p ...) x)) #'("append" p ...)))))
- (_
- (cond
- ((null? x) y)
- (else (with-syntax (((p ...) x) (y y)) #'("append" p ... y)))))))
- (define (quasilist* x y)
- (let f ((x x))
- (if (null? x)
- y
- (quasicons (car x) (f (cdr x))))))
- (define (quasivector x)
- (syntax-case x ()
- (("quote" (x ...)) #'("quote" #(x ...)))
- (_
- (let f ((y x) (k (lambda (ls) #`("vector" #,@ls))))
- (syntax-case y ()
- (("quote" (y ...)) (k #'(("quote" y) ...)))
- (("list" y ...) (k #'(y ...)))
- (("list*" y ... z) (f #'z (lambda (ls) (k (append #'(y ...) ls)))))
- (else #`("list->vector" #,x)))))))
- (define (emit x)
- (syntax-case x ()
- (("quote" x) #''x)
- (("list" x ...) #`(list #,@(map emit #'(x ...))))
- ;; could emit list* for 3+ arguments if implementation supports
- ;; list*
- (("list*" x ... y)
- (let f ((x* #'(x ...)))
- (if (null? x*)
- (emit #'y)
- #`(cons #,(emit (car x*)) #,(f (cdr x*))))))
- (("append" x ...) #`(append #,@(map emit #'(x ...))))
- (("vector" x ...) #`(vector #,@(map emit #'(x ...))))
- (("list->vector" x) #`(list->vector #,(emit #'x)))
- (("value" x) #'x)))
- (lambda (x)
- (syntax-case x ()
- ;; convert to intermediate language, combining introduced (but
- ;; not unquoted source) quote expressions where possible and
- ;; choosing optimal construction code otherwise, then emit
- ;; Scheme code corresponding to the intermediate language forms.
- ((_ e) (emit (quasi #'e 0)))))))
- (define-syntax include
- (lambda (x)
- (define read-file
- (lambda (fn k)
- (let ((p (open-input-file fn)))
- (let f ((x (read p))
- (result '()))
- (if (eof-object? x)
- (begin
- (close-input-port p)
- (reverse result))
- (f (read p)
- (cons (datum->syntax k x) result)))))))
- (syntax-case x ()
- ((k filename)
- (let ((fn (syntax->datum #'filename)))
- (with-syntax (((exp ...) (read-file fn #'filename)))
- #'(begin exp ...)))))))
- (define-syntax include-from-path
- (lambda (x)
- (syntax-case x ()
- ((k filename)
- (let ((fn (syntax->datum #'filename)))
- (with-syntax ((fn (datum->syntax
- #'filename
- (or (%search-load-path fn)
- (syntax-violation 'include-from-path
- "file not found in path"
- x #'filename)))))
- #'(include fn)))))))
- (define-syntax unquote
- (lambda (x)
- (syntax-violation 'unquote
- "expression not valid outside of quasiquote"
- x)))
- (define-syntax unquote-splicing
- (lambda (x)
- (syntax-violation 'unquote-splicing
- "expression not valid outside of quasiquote"
- x)))
- (define-syntax case
- (lambda (x)
- (syntax-case x ()
- ((_ e m1 m2 ...)
- (with-syntax
- ((body (let f ((clause #'m1) (clauses #'(m2 ...)))
- (if (null? clauses)
- (syntax-case clause (else)
- ((else e1 e2 ...) #'(begin e1 e2 ...))
- (((k ...) e1 e2 ...)
- #'(if (memv t '(k ...)) (begin e1 e2 ...)))
- (_ (syntax-violation 'case "bad clause" x clause)))
- (with-syntax ((rest (f (car clauses) (cdr clauses))))
- (syntax-case clause (else)
- (((k ...) e1 e2 ...)
- #'(if (memv t '(k ...))
- (begin e1 e2 ...)
- rest))
- (_ (syntax-violation 'case "bad clause" x
- clause))))))))
- #'(let ((t e)) body))))))
- (define (make-variable-transformer proc)
- (if (procedure? proc)
- (let ((trans (lambda (x)
- #((macro-type . variable-transformer))
- (proc x))))
- (set-procedure-property! trans 'variable-transformer #t)
- trans)
- (error "variable transformer not a procedure" proc)))
- (define-syntax identifier-syntax
- (lambda (x)
- (syntax-case x (set!)
- ((_ e)
- #'(lambda (x)
- #((macro-type . identifier-syntax))
- (syntax-case x ()
- (id
- (identifier? #'id)
- #'e)
- ((_ x (... ...))
- #'(e x (... ...))))))
- ((_ (id exp1) ((set! var val) exp2))
- (and (identifier? #'id) (identifier? #'var))
- #'(make-variable-transformer
- (lambda (x)
- #((macro-type . variable-transformer))
- (syntax-case x (set!)
- ((set! var val) #'exp2)
- ((id x (... ...)) #'(exp1 x (... ...)))
- (id (identifier? #'id) #'exp1))))))))
- (define-syntax define*
- (lambda (x)
- (syntax-case x ()
- ((_ (id . args) b0 b1 ...)
- #'(define id (lambda* args b0 b1 ...)))
- ((_ id val) (identifier? #'x)
- #'(define id val)))))
|