1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846 |
- ;;; -*- mode: scheme; coding: utf-8; -*-
- ;;;; Copyright (C) 1995-2014, 2016-2023 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
- ;;;;
- ;;; Commentary:
- ;;; This file is the first thing loaded into Guile. It adds many mundane
- ;;; definitions and a few that are interesting.
- ;;;
- ;;; The module system (hence the hierarchical namespace) are defined in this
- ;;; file.
- ;;;
- ;;; Code:
- ;; Before compiling, make sure any symbols are resolved in the (guile)
- ;; module, the primary location of those symbols, rather than in
- ;; (guile-user), the default module that we compile in.
- (eval-when (compile)
- (set-current-module (resolve-module '(guile))))
- ;; Prevent this file being loaded more than once in a session. Just
- ;; doesn't make sense!
- (if (current-module)
- (error "re-loading ice-9/boot-9.scm not allowed"))
- ;;; {Language primitives}
- ;;;
- ;; These are are the procedural wrappers around the primitives of
- ;; Guile's language: apply, call-with-current-continuation, etc.
- ;;
- ;; Usually, a call to a primitive is compiled specially. The compiler
- ;; knows about all these kinds of expressions. But the primitives may
- ;; be referenced not only as operators, but as values as well. These
- ;; stub procedures are the "values" of apply, dynamic-wind, and other
- ;; such primitives.
- ;;
- (define apply
- (case-lambda
- ((fun args)
- ((@@ primitive apply) fun args))
- ((fun arg1 . args)
- (letrec ((append* (lambda (tail)
- (let ((tail (car tail))
- (tail* (cdr tail)))
- (if (null? tail*)
- tail
- (cons tail (append* tail*)))))))
- (apply fun (cons arg1 (append* args)))))))
- (define (call-with-current-continuation proc)
- ((@@ primitive call-with-current-continuation) proc))
- (define (call-with-values producer consumer)
- ((@@ primitive call-with-values) producer consumer))
- (define (dynamic-wind in thunk out)
- "All three arguments must be 0-argument procedures.
- Guard @var{in} is called, then @var{thunk}, then
- guard @var{out}.
- If, any time during the execution of @var{thunk}, the
- continuation of the @code{dynamic_wind} expression is escaped
- non-locally, @var{out} is called. If the continuation of
- the dynamic-wind is re-entered, @var{in} is called. Thus
- @var{in} and @var{out} may be called any number of
- times.
- @lisp
- (define x 'normal-binding)
- @result{} x
- (define a-cont
- (call-with-current-continuation
- (lambda (escape)
- (let ((old-x x))
- (dynamic-wind
- ;; in-guard:
- ;;
- (lambda () (set! x 'special-binding))
- ;; thunk
- ;;
- (lambda () (display x) (newline)
- (call-with-current-continuation escape)
- (display x) (newline)
- x)
- ;; out-guard:
- ;;
- (lambda () (set! x old-x)))))))
- ;; Prints:
- special-binding
- ;; Evaluates to:
- @result{} a-cont
- x
- @result{} normal-binding
- (a-cont #f)
- ;; Prints:
- special-binding
- ;; Evaluates to:
- @result{} a-cont ;; the value of the (define a-cont...)
- x
- @result{} normal-binding
- a-cont
- @result{} special-binding
- @end lisp"
- ;; FIXME: Here we don't check that the out procedure is a thunk before
- ;; calling the in-guard, as dynamic-wind is called as part of loading
- ;; modules, but thunk? requires loading (system vm debug). This is in
- ;; contrast to the open-coded version of dynamic-wind, which does
- ;; currently insert an eager thunk? check (but often optimizes it
- ;; out). Not sure what the right thing to do is here -- make thunk?
- ;; callable before modules are loaded, live with this inconsistency,
- ;; or remove the thunk? check from the compiler? Questions,
- ;; questions.
- #;
- (unless (thunk? out)
- (scm-error 'wrong-type-arg "dynamic-wind" "Not a thunk: ~S"
- (list out) #f))
- (in)
- ((@@ primitive wind) in out)
- (call-with-values thunk
- (lambda vals
- ((@@ primitive unwind))
- (out)
- (apply values vals))))
- (define (with-fluid* fluid val thunk)
- "Set @var{fluid} to @var{value} temporarily, and call @var{thunk}.
- @var{thunk} must be a procedure of no arguments."
- ((@@ primitive push-fluid) fluid val)
- (call-with-values thunk
- (lambda vals
- ((@@ primitive pop-fluid))
- (apply values vals))))
- (define (with-dynamic-state state thunk)
- "Call @var{proc} while @var{state} is the current dynamic state object.
- @var{thunk} must be a procedure of no arguments."
- ((@@ primitive push-dynamic-state) state)
- (call-with-values thunk
- (lambda vals
- ((@@ primitive pop-dynamic-state))
- (apply values vals))))
- ;;; {Simple Debugging Tools}
- ;;;
- (define (peek . stuff)
- "Write arguments to the current output port, and return the last argument.
- This is handy for tracing function calls, e.g.:
- (+ 10 (troublesome-fn))
- => (+ 10 (pk 'troublesome-fn-returned (troublesome-fn)))"
- (newline)
- (display ";;; ")
- (write stuff)
- (newline)
- (car (last-pair stuff)))
- (define pk peek)
- (define (warn . stuff)
- (newline (current-warning-port))
- (display ";;; WARNING " (current-warning-port))
- (display stuff (current-warning-port))
- (newline (current-warning-port))
- (car (last-pair stuff)))
- ;;; {Features}
- ;;;
- (define (provide sym)
- (if (not (memq sym *features*))
- (set! *features* (cons sym *features*))))
- ;; In SLIB, provided? also checks to see if the module is available. We
- ;; should do that too, but don't.
- (define (provided? feature)
- "Return #t iff FEATURE is available to this Guile interpreter."
- (and (memq feature *features*) #t))
- ;;; {map and for-each}
- ;;;
- (define map
- (case-lambda
- ((f l)
- (if (not (list? l))
- (scm-error 'wrong-type-arg "map" "Not a list: ~S"
- (list l) #f))
- (let map1 ((l l))
- (if (pair? l)
- (cons (f (car l)) (map1 (cdr l)))
- '())))
- ((f l1 l2)
- (if (not (= (length l1) (length l2)))
- (scm-error 'wrong-type-arg "map" "List of wrong length: ~S"
- (list l2) #f))
- (let map2 ((l1 l1) (l2 l2))
- (if (pair? l1)
- (cons (f (car l1) (car l2))
- (map2 (cdr l1) (cdr l2)))
- '())))
- ((f l1 . rest)
- (let ((len (length l1)))
- (let mapn ((rest rest))
- (or (null? rest)
- (if (= (length (car rest)) len)
- (mapn (cdr rest))
- (scm-error 'wrong-type-arg "map" "List of wrong length: ~S"
- (list (car rest)) #f)))))
- (let mapn ((l1 l1) (rest rest))
- (if (pair? l1)
- (cons (apply f (car l1) (map car rest))
- (mapn (cdr l1) (map cdr rest)))
- '())))))
- (define map-in-order map)
- (define for-each
- (case-lambda
- ((f l)
- (if (not (list? l))
- (scm-error 'wrong-type-arg "for-each" "Not a list: ~S" (list l) #f))
- (let for-each1 ((l l))
- (if (not (null? l))
- (begin
- (f (car l))
- (for-each1 (cdr l))))))
- ((f l1 l2)
- (if (not (= (length l1) (length l2)))
- (scm-error 'wrong-type-arg "for-each" "List of wrong length: ~S"
- (list l2) #f))
- (let for-each2 ((l1 l1) (l2 l2))
- (if (not (null? l1))
- (begin
- (f (car l1) (car l2))
- (for-each2 (cdr l1) (cdr l2))))))
- ((f l1 . rest)
- (let ((len (length l1)))
- (let for-eachn ((rest rest))
- (or (null? rest)
- (if (= (length (car rest)) len)
- (for-eachn (cdr rest))
- (scm-error 'wrong-type-arg "for-each" "List of wrong length: ~S"
- (list (car rest)) #f)))))
- (let for-eachn ((l1 l1) (rest rest))
- (if (pair? l1)
- (begin
- (apply f (car l1) (map car rest))
- (for-eachn (cdr l1) (map cdr rest))))))))
- ;; Temporary definitions used by `include'; replaced later.
- (define (absolute-file-name? file-name) #t)
- (define (open-input-file str) (open-file str "r"))
- ;;; {and-map and or-map}
- ;;;
- ;;; (and-map fn lst) is like (and (fn (car lst)) (fn (cadr lst)) (fn...) ...)
- ;;; (or-map fn lst) is like (or (fn (car lst)) (fn (cadr lst)) (fn...) ...)
- ;;;
- (define (and-map f lst)
- "Apply F to successive elements of LST until exhaustion or F returns #f.
- If returning early, return #f. Otherwise, return the last value returned
- by F. If F has never been called because LST is empty, return #t."
- (let loop ((result #t)
- (l lst))
- (and result
- (or (and (null? l)
- result)
- (loop (f (car l)) (cdr l))))))
- (define (or-map f lst)
- "Apply F to successive elements of LST until exhaustion or while F returns #f.
- If returning early, return the return value of F."
- (let loop ((result #f)
- (l lst))
- (or result
- (and (not (null? l))
- (loop (f (car l)) (cdr l))))))
- ;; let format alias simple-format until the more complete version is loaded
- (define format simple-format)
- ;; this is scheme wrapping the C code so the final pred call is a tail call,
- ;; per SRFI-13 spec
- (define string-any
- (lambda* (char_pred s #:optional (start 0) (end (string-length s)))
- (if (and (procedure? char_pred)
- (> end start)
- (<= end (string-length s))) ;; let c-code handle range error
- (or (string-any-c-code char_pred s start (1- end))
- (char_pred (string-ref s (1- end))))
- (string-any-c-code char_pred s start end))))
- ;; this is scheme wrapping the C code so the final pred call is a tail call,
- ;; per SRFI-13 spec
- (define string-every
- (lambda* (char_pred s #:optional (start 0) (end (string-length s)))
- (if (and (procedure? char_pred)
- (> end start)
- (<= end (string-length s))) ;; let c-code handle range error
- (and (string-every-c-code char_pred s start (1- end))
- (char_pred (string-ref s (1- end))))
- (string-every-c-code char_pred s start end))))
- (define (substring-fill! str start end fill)
- "A variant of string-fill! that we keep for compatibility."
- (string-fill! str fill start end))
- ;; Define a minimal stub of the module API for psyntax, before modules
- ;; have booted.
- (define (module-name x)
- '(guile))
- (define (module-add! module sym var)
- (hashq-set! (%get-pre-modules-obarray) sym var))
- (define (module-define! module sym val)
- (let ((v (hashq-ref (%get-pre-modules-obarray) sym)))
- (if v
- (variable-set! v val)
- (module-add! module sym (make-variable val)))))
- (define (module-ref module sym)
- (let ((v (module-variable module sym)))
- (if v (variable-ref v) (error "badness!" (pk module) (pk sym)))))
- (define module-generate-unique-id!
- (let ((next-id 0))
- (lambda (m)
- (let ((i next-id))
- (set! next-id (+ i 1))
- i))))
- (define module-gensym gensym)
- (define (resolve-module . args)
- #f)
- ;; The definition of "include" needs read-syntax. Replaced later.
- (define (read-syntax port)
- (let ((datum (read port)))
- (if (eof-object? datum)
- datum
- (datum->syntax #f datum))))
- ;; API provided by psyntax
- (define syntax-violation #f)
- (define datum->syntax #f)
- (define syntax->datum #f)
- (define identifier? #f)
- (define generate-temporaries #f)
- (define bound-identifier=? #f)
- (define free-identifier=? #f)
- ;; $sc-dispatch is an implementation detail of psyntax. It is used by
- ;; expanded macros, to dispatch an input against a set of patterns.
- (define $sc-dispatch #f)
- ;; Load it up!
- (primitive-load-path "ice-9/psyntax-pp")
- ;; The binding for `macroexpand' has now been overridden, making psyntax the
- ;; expander now.
- (define-syntax and
- (syntax-rules ()
- ((_) #t)
- ((_ x) x)
- ;; Avoid ellipsis, which would lead to quadratic expansion time.
- ((_ x . y) (if x (and . y) #f))))
- (define-syntax or
- (syntax-rules ()
- ((_) #f)
- ((_ x) x)
- ;; Avoid ellipsis, which would lead to quadratic expansion time.
- ((_ x . y) (let ((t x)) (if t t (or . y))))))
- (include-from-path "ice-9/quasisyntax")
- (define-syntax-rule (when test stmt stmt* ...)
- (if test (let () stmt stmt* ...)))
- (define-syntax-rule (unless test stmt stmt* ...)
- (if (not test) (let () stmt stmt* ...)))
- (define-syntax else
- (lambda (x)
- (syntax-violation 'else "bad use of 'else' syntactic keyword" x x)))
- (define-syntax =>
- (lambda (x)
- (syntax-violation '=> "bad use of '=>' syntactic keyword" x x)))
- (define-syntax ...
- (lambda (x)
- (syntax-violation '... "bad use of '...' syntactic keyword" x x)))
- (define-syntax _
- (lambda (x)
- (syntax-violation '_ "bad use of '_' syntactic keyword" x x)))
- (define-syntax cond
- (lambda (whole-expr)
- (define (fold f seed xs)
- (let loop ((xs xs) (seed seed))
- (if (null? xs) seed
- (loop (cdr xs) (f (car xs) seed)))))
- (define (reverse-map f xs)
- (fold (lambda (x seed) (cons (f x) seed))
- '() xs))
- (syntax-case whole-expr ()
- ((_ clause clauses ...)
- #`(begin
- #,@(fold (lambda (clause-builder tail)
- (clause-builder tail))
- #'()
- (reverse-map
- (lambda (clause)
- (define* (bad-clause #:optional (msg "invalid clause"))
- (syntax-violation 'cond msg whole-expr clause))
- (syntax-case clause (=> else)
- ((else e e* ...)
- (lambda (tail)
- (if (null? tail)
- #'((let () e e* ...))
- (bad-clause "else must be the last clause"))))
- ((else . _) (bad-clause))
- ((test => receiver)
- (lambda (tail)
- #`((let ((t test))
- (if t
- (receiver t)
- #,@tail)))))
- ((test => receiver ...)
- (bad-clause "wrong number of receiver expressions"))
- ((generator guard => receiver)
- (lambda (tail)
- #`((call-with-values (lambda () generator)
- (lambda vals
- (if (apply guard vals)
- (apply receiver vals)
- #,@tail))))))
- ((generator guard => receiver ...)
- (bad-clause "wrong number of receiver expressions"))
- ((test)
- (lambda (tail)
- #`((let ((t test))
- (if t t #,@tail)))))
- ((test e e* ...)
- (lambda (tail)
- #`((if test
- (let () e e* ...)
- #,@tail))))
- (_ (bad-clause))))
- #'(clause clauses ...))))))))
- (define-syntax case
- (lambda (whole-expr)
- (define (fold f seed xs)
- (let loop ((xs xs) (seed seed))
- (if (null? xs) seed
- (loop (cdr xs) (f (car xs) seed)))))
- (define (fold2 f a b xs)
- (let loop ((xs xs) (a a) (b b))
- (if (null? xs) (values a b)
- (call-with-values
- (lambda () (f (car xs) a b))
- (lambda (a b)
- (loop (cdr xs) a b))))))
- (define (reverse-map-with-seed f seed xs)
- (fold2 (lambda (x ys seed)
- (call-with-values
- (lambda () (f x seed))
- (lambda (y seed)
- (values (cons y ys) seed))))
- '() seed xs))
- (syntax-case whole-expr ()
- ((_ expr clause clauses ...)
- (with-syntax ((key #'key))
- #`(let ((key expr))
- #,@(fold
- (lambda (clause-builder tail)
- (clause-builder tail))
- #'()
- (reverse-map-with-seed
- (lambda (clause seen)
- (define* (bad-clause #:optional (msg "invalid clause"))
- (syntax-violation 'case msg whole-expr clause))
- (syntax-case clause ()
- ((test . rest)
- (with-syntax
- ((clause-expr
- (syntax-case #'rest (=>)
- ((=> receiver) #'(receiver key))
- ((=> receiver ...)
- (bad-clause
- "wrong number of receiver expressions"))
- ((e e* ...) #'(let () e e* ...))
- (_ (bad-clause)))))
- (syntax-case #'test (else)
- ((datums ...)
- (let ((seen
- (fold
- (lambda (datum seen)
- (define (warn-datum type)
- ((@ (system base message)
- warning)
- type
- (append (source-properties datum)
- (source-properties
- (syntax->datum #'test)))
- datum
- (syntax->datum clause)
- (syntax->datum whole-expr)))
- (when (memv datum seen)
- (warn-datum 'duplicate-case-datum))
- (when (or (pair? datum) (array? datum))
- (warn-datum 'bad-case-datum))
- (cons datum seen))
- seen
- (map syntax->datum #'(datums ...)))))
- (values (lambda (tail)
- #`((if (memv key '(datums ...))
- clause-expr
- #,@tail)))
- seen)))
- (else (values (lambda (tail)
- (if (null? tail)
- #'(clause-expr)
- (bad-clause
- "else must be the last clause")))
- seen))
- (_ (bad-clause)))))
- (_ (bad-clause))))
- '() #'(clause clauses ...)))))))))
- (define-syntax do
- (syntax-rules ()
- ((do ((var init step ...) ...)
- (test expr ...)
- command ...)
- (letrec
- ((loop
- (lambda (var ...)
- (if test
- (begin
- (if #f #f)
- expr ...)
- (begin
- command
- ...
- (loop (do "step" var step ...)
- ...))))))
- (loop init ...)))
- ((do "step" x)
- x)
- ((do "step" x y)
- y)))
- (define-syntax define-values
- (lambda (orig-form)
- (syntax-case orig-form ()
- ((_ () expr)
- ;; XXX Work around the lack of hygienic top-level identifiers
- (with-syntax (((dummy) (generate-temporaries '(dummy))))
- #`(define dummy
- (call-with-values (lambda () expr)
- (lambda () #f)))))
- ((_ (var) expr)
- (identifier? #'var)
- #`(define var
- (call-with-values (lambda () expr)
- (lambda (v) v))))
- ((_ (var0 ... varn) expr)
- (and-map identifier? #'(var0 ... varn))
- ;; XXX Work around the lack of hygienic toplevel identifiers
- (with-syntax (((dummy) (generate-temporaries '(dummy))))
- #`(begin
- ;; Avoid mutating the user-visible variables
- (define dummy
- (call-with-values (lambda () expr)
- (lambda (var0 ... varn)
- (list var0 ... varn))))
- (define var0
- (let ((v (car dummy)))
- (set! dummy (cdr dummy))
- v))
- ...
- (define varn
- (let ((v (car dummy)))
- (set! dummy #f) ; blackhole dummy
- v)))))
- ((_ var expr)
- (identifier? #'var)
- #'(define var
- (call-with-values (lambda () expr)
- list)))
- ((_ (var0 ... . varn) expr)
- (and-map identifier? #'(var0 ... varn))
- ;; XXX Work around the lack of hygienic toplevel identifiers
- (with-syntax (((dummy) (generate-temporaries '(dummy))))
- #`(begin
- ;; Avoid mutating the user-visible variables
- (define dummy
- (call-with-values (lambda () expr)
- (lambda (var0 ... . varn)
- (list var0 ... varn))))
- (define var0
- (let ((v (car dummy)))
- (set! dummy (cdr dummy))
- v))
- ...
- (define varn
- (let ((v (car dummy)))
- (set! dummy #f) ; blackhole dummy
- v))))))))
- (define-syntax-rule (delay exp)
- (make-promise (lambda () exp)))
- (define-syntax with-fluids
- (lambda (stx)
- (define (emit-with-fluids bindings body)
- (syntax-case bindings ()
- (()
- body)
- (((f v) . bindings)
- #`(with-fluid* f v
- (lambda ()
- #,(emit-with-fluids #'bindings body))))))
- (syntax-case stx ()
- ((_ ((fluid val) ...) exp exp* ...)
- (with-syntax (((fluid-tmp ...) (generate-temporaries #'(fluid ...)))
- ((val-tmp ...) (generate-temporaries #'(val ...))))
- #`(let ((fluid-tmp fluid) ...)
- (let ((val-tmp val) ...)
- #,(emit-with-fluids #'((fluid-tmp val-tmp) ...)
- #'(let () exp exp* ...)))))))))
- (define-syntax current-source-location
- (lambda (x)
- (syntax-case x ()
- ((_)
- (with-syntax ((s (datum->syntax x (syntax-source x))))
- #''s)))))
- ;; We provide this accessor out of convenience. current-line and
- ;; current-column aren't so interesting, because they distort what they
- ;; are measuring; better to use syntax-source from a macro.
- ;;
- (define-syntax current-filename
- (lambda (x)
- "A macro that expands to the current filename: the filename that
- the (current-filename) form appears in. Expands to #f if this
- information is unavailable."
- (false-if-exception
- (canonicalize-path (assq-ref (syntax-source x) 'filename)))))
- (define-syntax-rule (define-once sym val)
- (define sym
- (if (module-locally-bound? (current-module) 'sym) sym val)))
- ;;; {Error handling}
- ;;;
- ;; Define delimited continuation operators, and implement catch and throw in
- ;; terms of them.
- (define make-prompt-tag
- (lambda* (#:optional (stem "prompt"))
- ;; The only property that prompt tags need have is uniqueness in the
- ;; sense of eq?. A one-element list will serve nicely.
- (list stem)))
- (define default-prompt-tag
- ;; Redefined later to be a parameter.
- (let ((%default-prompt-tag (make-prompt-tag)))
- (lambda ()
- %default-prompt-tag)))
- (define (call-with-prompt tag thunk handler)
- ((@@ primitive call-with-prompt) tag thunk handler))
- (define (abort-to-prompt tag . args)
- (abort-to-prompt* tag args))
- ;;; {Defmacros}
- ;;;
- (define-syntax define-macro
- (lambda (x)
- "Define a defmacro."
- (syntax-case x ()
- ((_ (macro . args) doc body1 body ...)
- (string? (syntax->datum #'doc))
- #'(define-macro macro doc (lambda args body1 body ...)))
- ((_ (macro . args) body ...)
- #'(define-macro macro #f (lambda args body ...)))
- ((_ macro transformer)
- #'(define-macro macro #f transformer))
- ((_ macro doc transformer)
- (or (string? (syntax->datum #'doc))
- (not (syntax->datum #'doc)))
- #'(define-syntax macro
- (lambda (y)
- doc
- #((macro-type . defmacro)
- (defmacro-args args))
- (syntax-case y ()
- ((_ . args)
- (let ((v (syntax->datum #'args)))
- (datum->syntax y (apply transformer v)))))))))))
- (define-syntax defmacro
- (lambda (x)
- "Define a defmacro, with the old lispy defun syntax."
- (syntax-case x ()
- ((_ macro args doc body1 body ...)
- (string? (syntax->datum #'doc))
- #'(define-macro macro doc (lambda args body1 body ...)))
- ((_ macro args body ...)
- #'(define-macro macro #f (lambda args body ...))))))
- (provide 'defmacro)
- ;;; {Deprecation}
- ;;;
- (define-syntax begin-deprecated
- (lambda (x)
- (syntax-case x ()
- ((_ form form* ...)
- (if (include-deprecated-features)
- #'(begin form form* ...)
- #'(begin))))))
- ;;; {Trivial Functions}
- ;;;
- (define (identity x) x)
- (define (compose proc . rest)
- "Compose PROC with the procedures in REST, such that the last one in
- REST is applied first and PROC last, and return the resulting procedure.
- The given procedures must have compatible arity."
- (if (null? rest)
- proc
- (let ((g (apply compose rest)))
- (lambda args
- (call-with-values (lambda () (apply g args)) proc)))))
- (define (negate proc)
- "Return a procedure with the same arity as PROC that returns the `not'
- of PROC's result."
- (lambda args
- (not (apply proc args))))
- (define (const value)
- "Return a procedure that accepts any number of arguments and returns
- VALUE."
- (lambda _
- value))
- (define (and=> value procedure)
- "When VALUE is #f, return #f. Otherwise, return (PROC VALUE)."
- (and value (procedure value)))
- (define call/cc call-with-current-continuation)
- ;;; {General Properties}
- ;;;
- ;; Properties are a lispy way to associate random info with random objects.
- ;; Traditionally properties are implemented as an alist or a plist actually
- ;; pertaining to the object in question.
- ;;
- ;; These "object properties" have the advantage that they can be associated with
- ;; any object, even if the object has no plist. Object properties are good when
- ;; you are extending pre-existing objects in unexpected ways. They also present
- ;; a pleasing, uniform procedure-with-setter interface. But if you have a data
- ;; type that always has properties, it's often still best to store those
- ;; properties within the object itself.
- (define (make-object-property)
- ;; Weak tables are thread-safe.
- (let ((prop (make-weak-key-hash-table)))
- (make-procedure-with-setter
- (lambda (obj) (hashq-ref prop obj))
- (lambda (obj val) (hashq-set! prop obj val)))))
- ;;; {Symbol Properties}
- ;;;
- ;;; Symbol properties are something you see in old Lisp code. In most current
- ;;; Guile code, symbols are not used as a data structure -- they are used as
- ;;; keys into other data structures.
- (define (symbol-property sym prop)
- (let ((pair (assoc prop (symbol-pref sym))))
- (and pair (cdr pair))))
- (define (set-symbol-property! sym prop val)
- (let ((pair (assoc prop (symbol-pref sym))))
- (if pair
- (set-cdr! pair val)
- (symbol-pset! sym (acons prop val (symbol-pref sym))))))
- (define (symbol-property-remove! sym prop)
- (let ((pair (assoc prop (symbol-pref sym))))
- (if pair
- (symbol-pset! sym (delq! pair (symbol-pref sym))))))
- ;;; {Arrays}
- ;;;
- (define (array-shape array)
- "Return a list as long as the rank of @var{array}, where each element
- is a two-element list containing the lower and upper bounds of the
- corresponding dimension.
- @lisp
- (array-dimensions (make-array 'foo '(-1 3) 5)) @result{} ((-1 3) (0 5))
- @end lisp
- See also: @code{array-dimensions}, @code{array-rank}."
- (map (lambda (ind) (if (number? ind) (list 0 (+ -1 ind)) ind))
- (array-dimensions array)))
- ;;; {Keywords}
- ;;;
- ;;; It's much better if you can use lambda* / define*, of course.
- (define (kw-arg-ref args kw)
- (let ((rem (member kw args)))
- (and rem (pair? (cdr rem)) (cadr rem))))
- ;;; {IOTA functions: generating lists of numbers}
- ;;;
- ;;; Compatible with srfi-1 so it can just be reused there.
- (define* (iota count #:optional (start 0) (step 1))
- (unless (and (integer? count) (>= count 0))
- (throw 'wrong-type-arg count))
- (let loop ((n (- count 1)) (result '()))
- (if (negative? n)
- result
- (loop (- n 1) (cons (+ start (* n step)) result)))))
- ;;; {Structs}
- ;;;
- (define (struct-layout s)
- (struct-ref (struct-vtable s) vtable-index-layout))
- ;;; {Records}
- ;;;
- ;; Printing records: by default, records are printed as
- ;;
- ;; #<type-name field1: val1 field2: val2 ...>
- ;;
- ;; You can change that by giving a custom printing function to
- ;; MAKE-RECORD-TYPE (after the list of field symbols). This function
- ;; will be called like
- ;;
- ;; (<printer> object port)
- ;;
- ;; It should print OBJECT to PORT.
- ;; 0: type-name, 1: fields, 2: constructor, 3: flags, 4: parents 5: mutable bitmask
- (define record-type-vtable
- (let ((s (make-vtable (string-append standard-vtable-fields
- "pwpwpwpwpwpw")
- (lambda (s p)
- (display "#<record-type " p)
- (display (record-type-name s) p)
- (display ">" p)))))
- (set-struct-vtable-name! s 'record-type)
- s))
- (define (record-type? obj)
- (and (struct? obj) (eq? record-type-vtable (struct-vtable obj))))
- (define (record-type-name rtd)
- (unless (record-type? rtd)
- (error 'not-a-record-type rtd))
- (struct-ref rtd vtable-offset-user))
- (define (record-type-fields rtd)
- (unless (record-type? rtd)
- (error 'not-a-record-type rtd))
- (struct-ref rtd (+ 1 vtable-offset-user)))
- (define (record-type-constructor rtd)
- (unless (record-type? rtd)
- (error 'not-a-record-type rtd))
- (struct-ref rtd (+ 2 vtable-offset-user)))
- (define (record-type-properties rtd)
- (unless (record-type? rtd)
- (error 'not-a-record-type rtd))
- (struct-ref rtd (+ 3 vtable-offset-user)))
- (define (record-type-extensible? rtd)
- (assq-ref (record-type-properties rtd) 'extensible?))
- (define (record-type-opaque? rtd)
- (assq-ref (record-type-properties rtd) 'opaque?))
- (define (record-type-uid rtd)
- (assq-ref (record-type-properties rtd) 'uid))
- (define (record-type-parents rtd)
- (unless (record-type? rtd)
- (error 'not-a-record-type rtd))
- (struct-ref rtd (+ 4 vtable-offset-user)))
- (define (record-type-parent rtd)
- (let* ((parents (record-type-parents rtd))
- (nparents (vector-length parents)))
- (and (not (zero? nparents))
- (vector-ref parents (1- nparents)))))
- (define (record-type-has-parent? rtd parent)
- (or (eq? rtd parent)
- (let ((parents (record-type-parents rtd))
- (nparents (vector-length (record-type-parents parent))))
- (and (< nparents (vector-length parents))
- (eq? (vector-ref parents nparents) parent)))))
- (define (record-type-mutable-fields rtd)
- (unless (record-type? rtd)
- (error 'not-a-record-type rtd))
- (struct-ref rtd (+ 5 vtable-offset-user)))
- (define prefab-record-types
- (make-hash-table))
- (define* (make-record-type type-name fields #:optional printer #:key
- parent uid extensible? allow-duplicate-field-names?
- (opaque? (and=> parent record-type-opaque?)))
- ;; Pre-generate constructors for nfields < 20.
- (define-syntax make-constructor
- (lambda (x)
- (define *max-static-argument-count* 20)
- (define (make-formals n)
- (let lp ((i 0))
- (if (< i n)
- (cons (datum->syntax
- x
- (string->symbol
- (string (integer->char (+ (char->integer #\a) i)))))
- (lp (1+ i)))
- '())))
- (syntax-case x ()
- ((_ rtd exp) (not (identifier? #'exp))
- #'(let ((n exp))
- (make-constructor rtd n)))
- ((_ rtd nfields)
- #`(case nfields
- #,@(let lp ((n 0))
- (if (< n *max-static-argument-count*)
- (cons (with-syntax (((formal ...) (make-formals n))
- (n n))
- #'((n)
- (lambda (formal ...)
- (make-struct/simple rtd formal ...))))
- (lp (1+ n)))
- '()))
- (else
- (lambda args
- (if (= (length args) nfields)
- (apply make-struct/no-tail rtd args)
- (scm-error 'wrong-number-of-args
- (format #f "make-~a" type-name)
- "Wrong number of arguments" '() #f)))))))))
- (define (default-record-printer s p)
- (display "#<" p)
- (display (record-type-name (record-type-descriptor s)) p)
- (let loop ((fields (record-type-fields (record-type-descriptor s)))
- (off 0))
- (cond
- ((not (null? fields))
- (display " " p)
- (display (car fields) p)
- (display ": " p)
- (write (struct-ref s off) p)
- (loop (cdr fields) (+ 1 off)))))
- (display ">" p))
- (define parents
- (cond
- ((record-type? parent)
- (unless (record-type-extensible? parent)
- (error "parent type is final"))
- (when (and (record-type-opaque? parent) (not opaque?))
- (error "can't make non-opaque subtype of opaque type"))
- (let* ((parent-parents (record-type-parents parent))
- (parent-nparents (vector-length parent-parents))
- (parents (make-vector (1+ parent-nparents))))
- (vector-move-left! parent-parents 0 parent-nparents parents 0)
- (vector-set! parents parent-nparents parent)
- parents))
- (parent
- (error "expected parent to be a record type" parent))
- (else
- #())))
- (define (check-fields fields)
- (unless (null? fields)
- (let ((field (car fields))
- (fields (cdr fields)))
- (unless (symbol? field)
- (error "expected field to be a symbol" field))
- (when (and (not allow-duplicate-field-names?) (memq field fields))
- (error "duplicate field" field))
- (check-fields fields))))
- (define (append-fields head tail)
- (if (null? head)
- tail
- (let ((field (car head))
- (tail (append-fields (cdr head) tail)))
- (when (and (not allow-duplicate-field-names?) (memq field tail))
- (error "duplicate field" field))
- (cons field tail))))
- (define computed-fields
- (let ((fields (map (lambda (field)
- (cond
- ((symbol? field) field)
- (else
- (unless (and (pair? field)
- (memq (car field) '(mutable immutable))
- (pair? (cdr field))
- (null? (cddr field)))
- (error "bad field declaration" field))
- (cadr field))))
- fields)))
- (check-fields fields)
- (if parent
- (append-fields (record-type-fields parent) fields)
- fields)))
- (define mutable-fields
- (let lp ((fields fields)
- (i (if parent (length (record-type-fields parent)) 0))
- (mutable (if parent (record-type-mutable-fields parent) 0)))
- (if (null? fields)
- mutable
- (let ((field (car fields)))
- (lp (cdr fields)
- (1+ i)
- (if (or (not (pair? field))
- (eq? (car field) 'mutable))
- (logior mutable (ash 1 i))
- mutable))))))
- (define name-sym
- (cond
- ((symbol? type-name) type-name)
- ((string? type-name)
- (issue-deprecation-warning
- "Passing a string as a type-name to make-record-type is deprecated."
- " Pass a symbol instead.")
- (string->symbol type-name))
- (else
- (error "expected a symbol for record type name" type-name))))
- (define properties
- (let ((maybe-acons (lambda (k v tail)
- (if v (acons k v tail) tail))))
- (maybe-acons 'extensible? extensible?
- (maybe-acons 'opaque? opaque?
- (maybe-acons 'uid uid
- '())))))
- (cond
- ((and uid (hashq-ref prefab-record-types uid))
- => (lambda (rtd)
- (unless (and (equal? (record-type-name rtd) name-sym)
- (equal? (record-type-fields rtd) computed-fields)
- (not printer)
- (equal? (record-type-properties rtd) properties)
- (equal? (record-type-parents rtd) parents)
- (equal? (record-type-mutable-fields rtd) mutable-fields))
- (error "prefab record type declaration incompatible with previous"
- rtd))
- rtd))
- (else
- (let ((rtd (make-struct/no-tail
- record-type-vtable
- (make-struct-layout
- (apply string-append
- (map (lambda (f) "pw") computed-fields)))
- (or printer default-record-printer)
- name-sym
- computed-fields
- #f ; Constructor initialized below.
- properties
- parents
- mutable-fields)))
- (struct-set! rtd (+ vtable-offset-user 2)
- (make-constructor rtd (length computed-fields)))
- ;; Temporary solution: Associate a name to the record type
- ;; descriptor so that the object system can create a wrapper
- ;; class for it.
- (set-struct-vtable-name! rtd name-sym)
- (when uid
- (unless (symbol? uid)
- (error "UID for prefab record type should be a symbol" uid))
- (hashq-set! prefab-record-types uid rtd))
- rtd))))
- (define record-constructor
- (case-lambda
- ((rtd)
- (record-type-constructor rtd))
- ((rtd field-names)
- (issue-deprecation-warning
- "Calling `record-constructor' with two arguments (the record type"
- " and a list of field names) is deprecated. Instead, call with just"
- " one argument, and provide a wrapper around that constructor if"
- " needed.")
- (primitive-eval
- `(lambda ,field-names
- (make-struct/no-tail ',rtd
- ,@(map (lambda (f)
- (if (memq f field-names)
- f
- #f))
- (record-type-fields rtd))))))))
- (define (record-predicate rtd)
- (unless (record-type? rtd)
- (error 'not-a-record-type rtd))
- (if (record-type-extensible? rtd)
- (let ((pos (vector-length (record-type-parents rtd))))
- ;; Extensible record types form a forest of DAGs, with each
- ;; record type recording an ordered vector of its ancestors. If
- ;; A is a subtype of B, and B has N parents, then A.parents[N]
- ;; will be B.
- (lambda (obj)
- (and (struct? obj)
- (let* ((v (struct-vtable obj)))
- (or (eq? v rtd)
- (let ((parents (record-type-parents v)))
- (and (< pos (vector-length parents))
- (eq? (vector-ref parents pos) rtd))))))))
- (lambda (obj) (and (struct? obj) (eq? rtd (struct-vtable obj))))))
- (define (record-accessor rtd field-name-or-idx)
- (define vtable-index-size 5) ; FIXME: pull from struct.h
- (define (record-nfields rtd)
- (struct-ref/unboxed rtd vtable-index-size))
- (let ((type-name (record-type-name rtd))
- (pos (cond
- ((and (exact-integer? field-name-or-idx)
- (<= 0 field-name-or-idx (record-nfields rtd)))
- field-name-or-idx)
- ((list-index (record-type-fields rtd) field-name-or-idx))
- (else (error 'no-such-field field-name-or-idx))))
- (pred (record-predicate rtd)))
- (lambda (obj)
- (unless (pred obj)
- (scm-error 'wrong-type-arg "record-accessor"
- "Wrong type argument (want `~S'): ~S"
- (list type-name obj)
- #f))
- (struct-ref obj pos))))
- (define (record-modifier rtd field-name-or-idx)
- (define vtable-index-size 5) ; FIXME: pull from struct.h
- (define (record-nfields rtd)
- (struct-ref/unboxed rtd vtable-index-size))
- (let ((type-name (record-type-name rtd))
- (pos (cond
- ((and (exact-integer? field-name-or-idx)
- (<= 0 field-name-or-idx (record-nfields rtd)))
- field-name-or-idx)
- ((list-index (record-type-fields rtd) field-name-or-idx))
- (else (error 'no-such-field field-name-or-idx))))
- (pred (record-predicate rtd)))
- (unless (logbit? pos (record-type-mutable-fields rtd))
- (error "field is immutable" rtd field-name-or-idx))
- (lambda (obj val)
- (unless (pred obj)
- (scm-error 'wrong-type-arg "record-modifier"
- "Wrong type argument (want `~S'): ~S"
- (list type-name obj)
- #f))
- (struct-set! obj pos val))))
- (define (record? obj)
- (and (struct? obj) (record-type? (struct-vtable obj))))
- (define (record-type-descriptor obj)
- (if (record? obj)
- (struct-vtable obj)
- (error 'not-a-record obj)))
- (provide 'record)
- ;;; {Parameters}
- ;;;
- (define <parameter>
- ;; Three fields: the procedure itself, the fluid, and the converter.
- (make-struct/no-tail <applicable-struct-vtable> 'pwpwpw))
- (set-struct-vtable-name! <parameter> '<parameter>)
- (define* (make-parameter init #:optional (conv (lambda (x) x)))
- "Make a new parameter.
- A parameter is a dynamically bound value, accessed through a procedure.
- To access the current value, apply the procedure with no arguments:
- (define p (make-parameter 10))
- (p) => 10
- To provide a new value for the parameter in a dynamic extent, use
- `parameterize':
- (parameterize ((p 20))
- (p)) => 20
- (p) => 10
- The value outside of the dynamic extent of the body is unaffected. To
- update the current value, apply it to one argument:
- (p 20) => 10
- (p) => 20
- As you can see, the call that updates a parameter returns its previous
- value.
- All values for the parameter are first run through the CONV procedure,
- including INIT, the initial value. The default CONV procedure is the
- identity procedure. CONV is commonly used to ensure some set of
- invariants on the values that a parameter may have."
- (let ((fluid (make-fluid (conv init))))
- (make-struct/no-tail
- <parameter>
- (case-lambda
- (() (fluid-ref fluid))
- ((x) (let ((prev (fluid-ref fluid)))
- (fluid-set! fluid (conv x))
- prev)))
- fluid conv)))
- (define (parameter? x)
- (and (struct? x) (eq? (struct-vtable x) <parameter>)))
- (define (parameter-fluid p)
- (if (parameter? p)
- (struct-ref p 1)
- (scm-error 'wrong-type-arg "parameter-fluid"
- "Not a parameter: ~S" (list p) #f)))
- (define (parameter-converter p)
- (if (parameter? p)
- (struct-ref p 2)
- (scm-error 'wrong-type-arg "parameter-fluid"
- "Not a parameter: ~S" (list p) #f)))
- (define-syntax parameterize
- (lambda (x)
- (syntax-case x ()
- ((_ ((param value) ...) body body* ...)
- (with-syntax (((p ...) (generate-temporaries #'(param ...))))
- #'(let ((p param) ...)
- (if (not (parameter? p))
- (scm-error 'wrong-type-arg "parameterize"
- "Not a parameter: ~S" (list p) #f))
- ...
- (with-fluids (((struct-ref p 1) ((struct-ref p 2) value))
- ...)
- body body* ...)))))))
- (define* (fluid->parameter fluid #:optional (conv (lambda (x) x)))
- "Make a parameter that wraps a fluid.
- The value of the parameter will be the same as the value of the fluid.
- If the parameter is rebound in some dynamic extent, perhaps via
- `parameterize', the new value will be run through the optional CONV
- procedure, as with any parameter. Note that unlike `make-parameter',
- CONV is not applied to the initial value."
- (make-struct/no-tail
- <parameter>
- (case-lambda
- (() (fluid-ref fluid))
- ((x) (let ((prev (fluid-ref fluid)))
- (fluid-set! fluid (conv x))
- prev)))
- fluid conv))
- ;;; Once parameters have booted, define the default prompt tag as being
- ;;; a parameter, and make allow-legacy-syntax-objects? a parameter.
- ;;;
- (set! default-prompt-tag (make-parameter (default-prompt-tag)))
- ;;; {Languages}
- ;;;
- ;; The language can be a symbolic name or a <language> object from
- ;; (system base language).
- ;;
- (define current-language (make-parameter 'scheme))
- ;;; {High-Level Port Routines}
- ;;;
- (define (call-with-output-string proc)
- "Calls the one-argument procedure @var{proc} with a newly created output
- port. When the function returns, the string composed of the characters
- written into the port is returned."
- (let ((port (open-output-string)))
- (proc port)
- (get-output-string port)))
- ;;; {Booleans}
- ;;;
- (define (->bool x) (not (not x)))
- ;;; {Symbols}
- ;;;
- (define (symbol-append . args)
- (string->symbol (apply string-append (map symbol->string args))))
- (define (list->symbol . args)
- (string->symbol (apply list->string args)))
- (define (symbol . args)
- (string->symbol (apply string args)))
- ;;; {Lists}
- ;;;
- (define (list-index l k)
- (let loop ((n 0)
- (l l))
- (and (not (null? l))
- (if (eq? (car l) k)
- n
- (loop (+ n 1) (cdr l))))))
- ;;; {Exceptions}
- ;;;
- (let-syntax ((define-values* (syntax-rules ()
- ((_ (id ...) body ...)
- (define-values (id ...)
- (let ()
- body ...
- (values id ...)))))))
- (define-values* (&exception
- &compound-exception
- simple-exceptions
- make-exception
- exception?
- exception-type?
- make-exception-type
- exception-predicate
- exception-accessor)
- (define &exception (make-record-type '&exception '() #:extensible? #t))
- (define simple-exception? (record-predicate &exception))
- (define &compound-exception (make-record-type '&compound-exception
- '((immutable components))))
- (define compound-exception? (record-predicate &compound-exception))
- (define make-compound-exception (record-constructor &compound-exception))
- (define compound-exception-components
- (record-accessor &compound-exception 'components))
- (define (simple-exceptions exception)
- "Return a list of the simple exceptions that compose the exception
- object @var{exception}."
- (cond ((compound-exception? exception)
- (compound-exception-components exception))
- ((simple-exception? exception)
- (list exception))
- (else
- (error "not a exception" exception))))
- (define (make-exception . exceptions)
- "Return an exception object composed of @var{exceptions}."
- (define (flatten exceptions)
- (if (null? exceptions)
- '()
- (append (simple-exceptions (car exceptions))
- (flatten (cdr exceptions)))))
- (let ((simple (flatten exceptions)))
- (if (and (pair? simple) (null? (cdr simple)))
- (car simple)
- (make-compound-exception simple))))
- (define (exception? obj)
- "Return true if @var{obj} is an exception object."
- (or (compound-exception? obj) (simple-exception? obj)))
- (define (exception-type? obj)
- "Return true if OBJ is an exception type."
- (and (record-type? obj)
- (record-type-has-parent? obj &exception)))
- (define (make-exception-type id parent field-names)
- "Return a new exception type named @var{id}, inheriting from
- @var{parent}, and with the fields whose names are listed in
- @var{field-names}. @var{field-names} must be a list of symbols and must
- not contain names already used by @var{parent} or one of its
- supertypes."
- (unless (exception-type? parent)
- (error "parent is not a exception type" parent))
- (unless (and-map symbol? field-names)
- (error "field names should be a list of symbols" field-names))
- (make-record-type id field-names #:parent parent #:extensible? #t))
- (define (exception-predicate rtd)
- "Return a procedure that will return true if its argument is a
- simple exception that is an instance of @var{rtd}, or a compound
- exception composed of such an instance."
- (let ((rtd-predicate (record-predicate rtd)))
- (lambda (obj)
- (cond ((compound-exception? obj)
- (or-map rtd-predicate (simple-exceptions obj)))
- (else (rtd-predicate obj))))))
- (define (exception-accessor rtd proc)
- "Return a procedure that will call @var{proc} on an instance of
- the exception type @var{rtd}, or on the component of a compound
- exception that is an instance of @var{rtd}."
- (let ((rtd-predicate (record-predicate rtd)))
- (lambda (obj)
- (if (rtd-predicate obj)
- (proc obj)
- (let lp ((exceptions (if (compound-exception? obj)
- (simple-exceptions obj)
- '())))
- (when (null? exceptions)
- (error "object is not an exception of the right type"
- obj rtd)) (if (rtd-predicate (car exceptions))
- (proc (car exceptions))
- (lp (cdr exceptions)))))))))
- ;; Exceptionally, these exception types are built with
- ;; make-record-type, in order to be able to mark them as sealed. This
- ;; allows boot definitions of
- (define &exception-with-kind-and-args
- (make-record-type '&exception-with-kind-and-args
- '((immutable kind) (immutable args))
- #:parent &exception #:extensible? #f))
- (define &quit-exception
- (make-record-type '&quit-exception
- '((immutable code))
- #:parent &exception #:extensible? #f))
- (define &error
- (make-exception-type '&error &exception '()))
- (define &programming-error
- (make-exception-type '&programming-error &error '()))
- (define &non-continuable
- (make-exception-type '&non-continuable &programming-error '()))
- ;; Boot definition; overridden later.
- (define-values* (make-exception-from-throw)
- (define make-exception-with-kind-and-args
- (record-constructor &exception-with-kind-and-args))
- (define make-quit-exception
- (record-constructor &quit-exception))
- (define (make-exception-from-throw key args)
- (let ((exn (make-exception-with-kind-and-args key args)))
- (case key
- ((quit)
- (let ((code (cond
- ((not (pair? args)) 0)
- ((integer? (car args)) (car args))
- ((not (car args)) 1)
- (else 0))))
- (make-exception (make-quit-exception code)
- exn)))
- (else
- exn)))))
- (define-values* (exception-kind
- exception-args
- raise-exception
- with-exception-handler
- catch
- with-throw-handler
- throw)
- (define (steal-binding! sym)
- (let ((val (module-ref (current-module) sym)))
- (hashq-remove! (%get-pre-modules-obarray) sym)
- val))
- (define %exception-handler (steal-binding! '%exception-handler))
- (define %exception-epoch (steal-binding! '%exception-epoch))
- (define %init-exceptions! (steal-binding! '%init-exceptions!))
- (%init-exceptions! &compound-exception
- &exception-with-kind-and-args
- &quit-exception)
- (define exception-with-kind-and-args?
- (exception-predicate &exception-with-kind-and-args))
- (define %exception-kind
- (exception-accessor &exception-with-kind-and-args
- (record-accessor &exception-with-kind-and-args 'kind)))
- (define %exception-args
- (exception-accessor &exception-with-kind-and-args
- (record-accessor &exception-with-kind-and-args 'args)))
- (define (exception-kind obj)
- (if (exception-with-kind-and-args? obj)
- (%exception-kind obj)
- '%exception))
- (define (exception-args obj)
- (if (exception-with-kind-and-args? obj)
- (%exception-args obj)
- (list obj)))
- (define quit-exception?
- (exception-predicate &quit-exception))
- (define quit-exception-code
- (exception-accessor &quit-exception
- (record-accessor &quit-exception 'code)))
- (define (fallback-exception-handler exn)
- (cond
- ((quit-exception? exn)
- (primitive-exit (quit-exception-code exn)))
- (else
- (display "guile: uncaught exception:\n" (current-error-port))
- (print-exception (current-error-port) #f
- (exception-kind exn) (exception-args exn))
- (primitive-exit 1))))
- (define* (raise-exception exn #:key (continuable? #f))
- "Raise an exception by invoking the current exception handler on
- @var{exn}. The handler is called with a continuation whose dynamic
- environment is that of the call to @code{raise}, except that the current
- exception handler is the one that was in place when the handler being
- called was installed.
- If @var{continuable?} is true, the handler is invoked in tail position
- relative to the @code{raise-exception} call. Otherwise if the handler
- returns, a non-continuable exception of type @code{&non-continuable} is
- raised in the same dynamic environment as the handler."
- (define (exception-has-type? exn type)
- (cond
- ((eq? type #t)
- #t)
- ((symbol? type)
- (eq? (exception-kind exn) type))
- ((exception-type? type)
- (and (exception? exn)
- ((exception-predicate type) exn)))
- (else #f)))
- (let ((current-epoch (fluid-ref %exception-epoch)))
- (let lp ((depth 0))
- ;; FIXME: fluid-ref* takes time proportional to depth, which
- ;; makes this loop quadratic.
- (let ((val (fluid-ref* %exception-handler depth)))
- ;; There are two types of exception handlers: unwinding handlers
- ;; and pre-unwind handlers. Although you can implement unwinding
- ;; handlers with pre-unwind handlers, it's better to separate them
- ;; because it allows for emergency situations like "stack
- ;; overflow" or "out of memory" to unwind the stack before calling
- ;; a handler.
- (cond
- ((not val)
- ;; No exception handlers bound; use fallback.
- (fallback-exception-handler exn))
- ((fluid? (car val))
- (let ((epoch (car val))
- (handler (cdr val)))
- (cond
- ((< (fluid-ref epoch) current-epoch)
- (with-fluids ((epoch current-epoch))
- (cond
- (continuable?
- (handler exn))
- (else
- (handler exn)
- (raise-exception
- ((record-constructor &non-continuable)))))))
- (else
- (lp (1+ depth))))))
- (else
- (let ((prompt-tag (car val))
- (type (cdr val)))
- (cond
- ((exception-has-type? exn type)
- (abort-to-prompt prompt-tag exn)
- (error "unreachable"))
- (else
- (lp (1+ depth)))))))))))
- (define* (with-exception-handler handler thunk #:key (unwind? #f)
- (unwind-for-type #t))
- "Establish @var{handler}, a procedure of one argument, as the
- current exception handler during the dynamic extent of invoking
- @var{thunk}.
- If @code{raise-exception} is called during the dynamic extent of
- invoking @var{thunk}, @var{handler} will be invoked on the argument of
- @code{raise-exception}.
- There are two kinds of exception handlers: unwinding and non-unwinding.
- By default, exception handlers are non-unwinding. If @var{unwind?} is
- false, @var{handler} will be invoked within the continuation of the
- error, without unwinding the stack. Its dynamic environment will be
- that of the @code{raise-exception} call, with the exception that the
- current exception handler won't be @var{handler}, but rather the
- \"outer\" handler (the one that was in place when
- @code{with-exception-handler} was called).
- However, it's often the case that one would like to handle an exception
- by unwinding the computation to an earlier state and running the error
- handler there. After all, unless the @code{raise-exception} call is
- continuable, the exception handler needs to abort the continuation. To
- support this use case, if @var{unwind?} is true, @code{raise-exception}
- will first unwind the stack by invoking an @dfn{escape
- continuation} (@pxref{Prompt Primitives, @code{call/ec}}), and then
- invoke the handler with the continuation of the
- @code{with-exception-handler} call.
- Finally, one more wrinkle: for unwinding exception handlers, it can be
- useful to determine whether an exception handler would indeed handle a
- particular exception or not. This is especially the case for exceptions
- raised in resource-exhaustion scenarios like @code{stack-overflow} or
- @code{out-of-memory}, where you want to immediately shrink the
- continuation before recovering. @xref{Stack Overflow}. For this
- purpose, the @var{unwind-for-type} parameter allows users to specify the
- kind of exception handled by an exception handler; if @code{#t}, all
- exceptions will be handled; if an exception type object, only exceptions
- of that type will be handled; otherwise if a symbol, only that
- exceptions with the given @code{exception-kind} will be handled."
- (unless (procedure? handler)
- (scm-error 'wrong-type-arg "with-exception-handler"
- "Wrong type argument in position ~a: ~a"
- (list 1 handler) (list handler)))
- (cond
- (unwind?
- (unless (or (eq? unwind-for-type #t)
- (symbol? unwind-for-type)
- (exception-type? unwind-for-type))
- (scm-error 'wrong-type-arg "with-exception-handler"
- "Wrong type argument for #:unwind-for-type: ~a"
- (list unwind-for-type) (list unwind-for-type)))
- (let ((tag (make-prompt-tag "exception handler")))
- (call-with-prompt
- tag
- (lambda ()
- (with-fluids ((%exception-handler (cons tag unwind-for-type)))
- (thunk)))
- (lambda (k exn)
- (handler exn)))))
- (else
- (let ((epoch (make-fluid 0)))
- (with-fluids ((%exception-handler (cons epoch handler)))
- (thunk))))))
- (define (throw key . args)
- "Invoke the catch form matching @var{key}, passing @var{args} to the
- @var{handler}.
- @var{key} is a symbol. It will match catches of the same symbol or of @code{#t}.
- If there is no handler at all, Guile prints an error and then exits."
- (unless (symbol? key)
- (throw 'wrong-type-arg "throw" "Wrong type argument in position ~a: ~a"
- (list 1 key) (list key)))
- (raise-exception (make-exception-from-throw key args)))
- (define (with-throw-handler k thunk pre-unwind-handler)
- "Add @var{handler} to the dynamic context as a throw handler
- for key @var{k}, then invoke @var{thunk}."
- (unless (or (symbol? k) (eq? k #t))
- (scm-error 'wrong-type-arg "with-throw-handler"
- "Wrong type argument in position ~a: ~a"
- (list 1 k) (list k)))
- (define running? (make-fluid))
- ;; Throw handlers have two semantic oddities.
- ;;
- ;; One is that throw handlers are not re-entrant: if one is
- ;; already active in the current continuation, it won't handle
- ;; exceptions thrown within that continuation. It's a restrictive
- ;; choice, but it does ensure progress. We ensure this property
- ;; by having a running? fluid associated with each
- ;; with-throw-handler.
- ;;
- ;; The other oddity is that any exception thrown within a throw
- ;; handler starts the whole raise-exception dispatch procedure
- ;; again from the top. This can have its uses if you want to have
- ;; handlers for multiple specific keys active at the same time,
- ;; without specifying an order between them. But, it's weird. We
- ;; ensure this property by having a %exception-epoch fluid and
- ;; also associating an epoch with each pre-unwind handler; a
- ;; handler is active if its epoch is less than the current
- ;; %exception-epoch. We increment the epoch with the extent of
- ;; the throw handler.
- (with-exception-handler
- (lambda (exn)
- (when (and (or (eq? k #t) (eq? k (exception-kind exn)))
- (not (fluid-ref running?)))
- (with-fluids ((%exception-epoch (1+ (fluid-ref %exception-epoch)))
- (running? #t))
- (apply pre-unwind-handler (exception-kind exn)
- (exception-args exn))))
- (raise-exception exn))
- thunk))
- (define* (catch k thunk handler #:optional pre-unwind-handler)
- "Invoke @var{thunk} in the dynamic context of @var{handler} for
- exceptions matching @var{key}. If thunk throws to the symbol
- @var{key}, then @var{handler} is invoked this way:
- @lisp
- (handler key args ...)
- @end lisp
- @var{key} is a symbol or @code{#t}.
- @var{thunk} takes no arguments. If @var{thunk} returns
- normally, that is the return value of @code{catch}.
- Handler is invoked outside the scope of its own @code{catch}.
- If @var{handler} again throws to the same key, a new handler
- from further up the call chain is invoked.
- If the key is @code{#t}, then a throw to @emph{any} symbol will
- match this call to @code{catch}.
- If a @var{pre-unwind-handler} is given and @var{thunk} throws
- an exception that matches @var{key}, Guile calls the
- @var{pre-unwind-handler} before unwinding the dynamic state and
- invoking the main @var{handler}. @var{pre-unwind-handler} should
- be a procedure with the same signature as @var{handler}, that
- is @code{(lambda (key . args))}. It is typically used to save
- the stack at the point where the exception occurred, but can also
- query other parts of the dynamic state at that point, such as
- fluid values.
- A @var{pre-unwind-handler} can exit either normally or non-locally.
- If it exits normally, Guile unwinds the stack and dynamic context
- and then calls the normal (third argument) handler. If it exits
- non-locally, that exit determines the continuation."
- (define (wrong-type-arg n val)
- (scm-error 'wrong-type-arg "catch"
- "Wrong type argument in position ~a: ~a"
- (list n val) (list val)))
- (unless (or (symbol? k) (eq? k #t))
- (wrong-type-arg 2 k))
- (unless (procedure? handler)
- (wrong-type-arg 3 handler))
- (unless (or (not pre-unwind-handler) (procedure? pre-unwind-handler))
- (wrong-type-arg 4 pre-unwind-handler))
- (with-exception-handler
- (lambda (exn)
- (apply handler (exception-kind exn) (exception-args exn)))
- (if pre-unwind-handler
- (lambda ()
- (with-throw-handler k thunk pre-unwind-handler))
- thunk)
- #:unwind? #t
- #:unwind-for-type k))))
- ;;;
- ;;; Extensible exception printing.
- ;;;
- (define set-exception-printer! #f)
- ;; There is already a definition of print-exception from backtrace.c
- ;; that we will override.
- (let ((exception-printers '()))
- (define (print-location frame port)
- (let ((source (and=> frame frame-source)))
- ;; source := (addr . (filename . (line . column)))
- (if source
- (let ((filename (or (cadr source) "<unnamed port>"))
- (line (caddr source))
- (col (cdddr source)))
- (format port "~a:~a:~a: " filename (1+ line) col))
- (format port "ERROR: "))))
- (set! set-exception-printer!
- (lambda (key proc)
- (set! exception-printers (acons key proc exception-printers))))
- (set! print-exception
- (lambda (port frame key args)
- (define (default-printer)
- (format port "Throw to key `~a' with args `~s'." key args))
- (when frame
- (print-location frame port)
- ;; When booting, false-if-exception isn't defined yet.
- (let ((name (catch #t
- (lambda () (frame-procedure-name frame))
- (lambda _ #f))))
- (when name
- (format port "In procedure ~a:\n" name))))
- (catch #t
- (lambda ()
- (let ((printer (assq-ref exception-printers key)))
- (if printer
- (printer port key args default-printer)
- (default-printer))))
- (lambda (k . args)
- (format port "Error while printing exception.")))
- (newline port)
- (force-output port))))
- ;;;
- ;;; Printers for those keys thrown by Guile.
- ;;;
- (let ()
- (define (scm-error-printer port key args default-printer)
- ;; Abuse case-lambda as a pattern matcher, given that we don't have
- ;; ice-9 match at this point.
- (apply (case-lambda
- ((subr msg args . rest)
- (if subr
- (format port "In procedure ~a: " subr))
- (apply format port msg (or args '())))
- (_ (default-printer)))
- args))
- (define (syntax-error-printer port key args default-printer)
- (apply (case-lambda
- ((who what where form subform . extra)
- (format port "Syntax error:\n")
- (if where
- (let ((file (or (assq-ref where 'filename) "unknown file"))
- (line (and=> (assq-ref where 'line) 1+))
- (col (assq-ref where 'column)))
- (format port "~a:~a:~a: " file line col))
- (format port "unknown location: "))
- (if who
- (format port "~a: " who))
- (format port "~a" what)
- (if subform
- (format port " in subform ~s of ~s" subform form)
- (if form
- (format port " in form ~s" form))))
- (_ (default-printer)))
- args))
- (define (keyword-error-printer port key args default-printer)
- (let ((message (cadr args))
- (faulty (car (cadddr args)))) ; I won't do it again, I promise.
- (format port "~a: ~s" message faulty)))
- (define (getaddrinfo-error-printer port key args default-printer)
- (format port "In procedure getaddrinfo: ~a" (gai-strerror (car args))))
- (set-exception-printer! 'goops-error scm-error-printer)
- (set-exception-printer! 'host-not-found scm-error-printer)
- (set-exception-printer! 'keyword-argument-error keyword-error-printer)
- (set-exception-printer! 'misc-error scm-error-printer)
- (set-exception-printer! 'no-data scm-error-printer)
- (set-exception-printer! 'no-recovery scm-error-printer)
- (set-exception-printer! 'null-pointer-error scm-error-printer)
- (set-exception-printer! 'out-of-memory scm-error-printer)
- (set-exception-printer! 'out-of-range scm-error-printer)
- (set-exception-printer! 'program-error scm-error-printer)
- (set-exception-printer! 'read-error scm-error-printer)
- (set-exception-printer! 'regular-expression-syntax scm-error-printer)
- (set-exception-printer! 'signal scm-error-printer)
- (set-exception-printer! 'stack-overflow scm-error-printer)
- (set-exception-printer! 'system-error scm-error-printer)
- (set-exception-printer! 'try-again scm-error-printer)
- (set-exception-printer! 'unbound-variable scm-error-printer)
- (set-exception-printer! 'wrong-number-of-args scm-error-printer)
- (set-exception-printer! 'wrong-type-arg scm-error-printer)
- (set-exception-printer! 'syntax-error syntax-error-printer)
- (set-exception-printer! 'getaddrinfo-error getaddrinfo-error-printer))
- ;; Load `posix.scm' even when not (provided? 'posix) so that we get the
- ;; `stat' accessors.
- (primitive-load-path "ice-9/posix")
- (if (provided? 'socket)
- (primitive-load-path "ice-9/networking"))
- ;; For reference, Emacs file-exists-p uses stat in this same way.
- (define file-exists?
- (if (provided? 'posix)
- (lambda (str)
- (->bool (stat str #f)))
- (lambda (str)
- (let ((port (catch 'system-error (lambda () (open-input-file str))
- (lambda args #f))))
- (if port (begin (close-port port) #t)
- #f)))))
- (define file-is-directory?
- (if (provided? 'posix)
- (lambda (str)
- (eq? (stat:type (stat str)) 'directory))
- (lambda (str)
- (let ((port (catch 'system-error
- (lambda ()
- (open-input-file (string-append str "/.")))
- (lambda args #f))))
- (if port (begin (close-port port) #t)
- #f)))))
- (define (system-error-errno args)
- (if (eq? (car args) 'system-error)
- (car (list-ref args 4))
- #f))
- ;;; {Error Handling}
- ;;;
- (define error
- (case-lambda
- (()
- (scm-error 'misc-error #f "?" #f #f))
- ((message . args)
- (let ((msg (string-join (cons "~A" (make-list (length args) "~S")))))
- (scm-error 'misc-error #f msg (cons message args) #f)))))
- ;;; {Include}
- ;;;
- ;;; This redefined version of call-with-include-port (first defined in
- ;;; psyntax.scm) also try to locate an included file using the
- ;;; %file-port-stripped-prefixes fluid.
- (define call-with-include-port
- (let ((syntax-dirname (lambda (stx)
- (define src (syntax-source stx))
- (define filename (and src (assq-ref src 'filename)))
- (and (string? filename)
- (dirname filename)))))
- (lambda* (filename proc #:key (dirname (syntax-dirname filename)))
- "Like @code{call-with-input-file}, except relative paths are
- searched relative to @var{dirname} instead of the current working
- directory. Also, @var{filename} can be a syntax object; in that case,
- and if @var{dirname} is not specified, the @code{syntax-source} of
- @var{filename} is used to obtain a base directory for relative file
- names. As a special case, when the @var{%file-port-stripped-prefixes}
- fluid is set, its value is searched for a directory matching the dirname
- inferred from FILENAME."
- (let* ((filename (syntax->datum filename))
- (candidates
- (cond ((absolute-file-name? filename)
- (list filename))
- (dirname ;filename is relative
- (let* ((rel-names (fluid-ref %file-port-stripped-prefixes))
- (stripped-prefix (and rel-names
- (assoc-ref rel-names dirname)))
- (fallback (and stripped-prefix
- (string-append stripped-prefix
- dirname))))
- (map (lambda (d)
- (in-vicinity d filename))
- `(,dirname ,@(if fallback
- (list fallback)
- '())))))
- (else
- (error
- "attempt to include relative file name \
- but could not determine base dir"))))
- (p (let loop ((files candidates))
- (when (null? files)
- (error "could not open any of" candidates))
- (catch 'system-error
- (lambda _
- (open-input-file (car files)))
- (lambda _
- (loop (cdr files))))))
- (enc (file-encoding p)))
- ;; Choose the input encoding deterministically.
- (set-port-encoding! p (or enc "UTF-8"))
- (call-with-values (lambda () (proc p))
- (lambda results
- (close-port p)
- (apply values results)))))))
- ;;; {Time Structures}
- ;;;
- (define (tm:sec obj) (vector-ref obj 0))
- (define (tm:min obj) (vector-ref obj 1))
- (define (tm:hour obj) (vector-ref obj 2))
- (define (tm:mday obj) (vector-ref obj 3))
- (define (tm:mon obj) (vector-ref obj 4))
- (define (tm:year obj) (vector-ref obj 5))
- (define (tm:wday obj) (vector-ref obj 6))
- (define (tm:yday obj) (vector-ref obj 7))
- (define (tm:isdst obj) (vector-ref obj 8))
- (define (tm:gmtoff obj) (vector-ref obj 9))
- (define (tm:zone obj) (vector-ref obj 10))
- (define (set-tm:sec obj val) (vector-set! obj 0 val))
- (define (set-tm:min obj val) (vector-set! obj 1 val))
- (define (set-tm:hour obj val) (vector-set! obj 2 val))
- (define (set-tm:mday obj val) (vector-set! obj 3 val))
- (define (set-tm:mon obj val) (vector-set! obj 4 val))
- (define (set-tm:year obj val) (vector-set! obj 5 val))
- (define (set-tm:wday obj val) (vector-set! obj 6 val))
- (define (set-tm:yday obj val) (vector-set! obj 7 val))
- (define (set-tm:isdst obj val) (vector-set! obj 8 val))
- (define (set-tm:gmtoff obj val) (vector-set! obj 9 val))
- (define (set-tm:zone obj val) (vector-set! obj 10 val))
- (define (tms:clock obj) (vector-ref obj 0))
- (define (tms:utime obj) (vector-ref obj 1))
- (define (tms:stime obj) (vector-ref obj 2))
- (define (tms:cutime obj) (vector-ref obj 3))
- (define (tms:cstime obj) (vector-ref obj 4))
- ;;; {C Environment}
- ;;;
- (define (setenv name value)
- (if value
- (putenv (string-append name "=" value))
- (putenv name)))
- (define (unsetenv name)
- "Remove the entry for NAME from the environment."
- (putenv name))
- ;;; {Load Paths}
- ;;;
- (let-syntax ((compile-time-case
- (lambda (stx)
- (syntax-case stx ()
- ((_ exp clauses ...)
- (let ((val (primitive-eval (syntax->datum #'exp))))
- (let next-clause ((clauses #'(clauses ...)))
- (syntax-case clauses (else)
- (()
- (syntax-violation 'compile-time-case
- "all clauses failed to match" stx))
- (((else form ...))
- #'(begin form ...))
- ((((k ...) form ...) clauses ...)
- (if (memv val (syntax->datum #'(k ...)))
- #'(begin form ...)
- (next-clause #'(clauses ...))))))))))))
- ;; emacs: (put 'compile-time-case 'scheme-indent-function 1)
- (compile-time-case (system-file-name-convention)
- ((posix)
- (define (file-name-separator? c)
- (char=? c #\/))
- (define file-name-separator-string "/")
- (define (absolute-file-name? file-name)
- (string-prefix? "/" file-name)))
- ((windows)
- (define (file-name-separator? c)
- (or (char=? c #\/)
- (char=? c #\\)))
- (define file-name-separator-string "/")
- (define (absolute-file-name? file-name)
- (define (file-name-separator-at-index? idx)
- (and (> (string-length file-name) idx)
- (file-name-separator? (string-ref file-name idx))))
- (define (unc-file-name?)
- ;; Universal Naming Convention (UNC) file-names start with \\,
- ;; and are always absolute. See:
- ;; http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#fully_qualified_vs._relative_paths
- (and (file-name-separator-at-index? 0)
- (file-name-separator-at-index? 1)))
- (define (has-drive-specifier?)
- (and (>= (string-length file-name) 2)
- (let ((drive (string-ref file-name 0)))
- (or (char<=? #\a drive #\z)
- (char<=? #\A drive #\Z)))
- (eqv? (string-ref file-name 1) #\:)))
- (or (unc-file-name?)
- (if (has-drive-specifier?)
- (file-name-separator-at-index? 2)
- (file-name-separator-at-index? 0)))))))
- (define (in-vicinity vicinity file)
- (let ((tail (let ((len (string-length vicinity)))
- (if (zero? len)
- #f
- (string-ref vicinity (- len 1))))))
- (string-append vicinity
- (if (or (not tail) (file-name-separator? tail))
- ""
- file-name-separator-string)
- file)))
- ;;; {Exception-handling helpers}
- (define-syntax false-if-exception
- (syntax-rules ()
- ((false-if-exception expr)
- (catch #t
- (lambda () expr)
- (lambda args #f)))
- ((false-if-exception expr #:warning template arg ...)
- (catch #t
- (lambda () expr)
- (lambda (key . args)
- (for-each (lambda (s)
- (if (not (string-null? s))
- (format (current-warning-port) ";;; ~a\n" s)))
- (string-split
- (call-with-output-string
- (lambda (port)
- (format port template arg ...)
- (print-exception port #f key args)))
- #\newline))
- #f)))))
- ;;; {Help for scm_shell}
- ;;;
- ;;; The argument-processing code used by Guile-based shells generates
- ;;; Scheme code based on the argument list. This page contains help
- ;;; functions for the code it generates.
- ;;;
- (define (command-line) (program-arguments))
- ;; This is mostly for the internal use of the code generated by
- ;; scm_compile_shell_switches.
- (define (load-user-init)
- (let* ((home (or (getenv "HOME")
- (false-if-exception (passwd:dir (getpwuid (getuid))))
- file-name-separator-string)) ;; fallback for cygwin etc.
- (init-file (in-vicinity home ".guile")))
- (if (file-exists? init-file)
- (primitive-load init-file))))
- ;;; {The interpreter stack}
- ;;;
- ;; %stacks defined in stacks.c
- (define (%start-stack tag thunk)
- (let ((prompt-tag (make-prompt-tag "start-stack")))
- (call-with-prompt
- prompt-tag
- (lambda ()
- (with-fluids ((%stacks (cons tag prompt-tag)))
- (thunk)))
- (lambda (k . args)
- (%start-stack tag (lambda () (apply k args)))))))
- (define-syntax-rule (start-stack tag exp)
- (%start-stack tag (lambda () exp)))
- ;;; {Loading by paths}
- ;;;
- (define (load-from-path name)
- "Load a Scheme source file named NAME, searching for it in the
- directories listed in %load-path, and applying each of the file
- name extensions listed in %load-extensions."
- (start-stack 'load-stack
- (primitive-load-path name)))
- (define-syntax-rule (add-to-load-path elt)
- "Add ELT to Guile's load path, at compile-time and at run-time."
- (eval-when (expand load eval)
- (set! %load-path (cons elt (delete elt %load-path)))))
- (define %load-verbosely #f)
- (define (assert-load-verbosity v) (set! %load-verbosely v))
- (define (%load-announce file)
- (if %load-verbosely
- (with-output-to-port (current-warning-port)
- (lambda ()
- (display ";;; ")
- (display "loading ")
- (display file)
- (newline)
- (force-output)))))
- (set! %load-hook %load-announce)
- ;;; {Reader Extensions}
- ;;;
- ;;; Reader code for various "#c" forms.
- ;;;
- (define read-hash-procedures
- (fluid->parameter %read-hash-procedures))
- (define (read-hash-procedure ch)
- (assq-ref (read-hash-procedures) ch))
- (define (read-hash-extend ch proc)
- (let ((alist (read-hash-procedures)))
- (read-hash-procedures
- (if proc
- (assq-set! alist ch proc)
- (assq-remove! alist ch)))))
- (define read-eval? (make-fluid #f))
- (read-hash-extend #\.
- (lambda (c port)
- (if (fluid-ref read-eval?)
- (eval (read port) (interaction-environment))
- (error
- "#. read expansion found and read-eval? is #f."))))
- ;;; {Low Level Modules}
- ;;;
- ;;; These are the low level data structures for modules.
- ;;;
- ;;; Every module object is of the type 'module-type', which is a record
- ;;; consisting of the following members:
- ;;;
- ;;; - declarative?: a boolean flag indicating whether this module's
- ;;; singly-defined bindings are used in a declarative way.
- ;;; Declarative definitions can be better optimized by the compiler.
- ;;; See "Declarative Modules" in the manual, for more.
- ;;;
- ;;; - obarray: a hash table that maps symbols to variable objects. In this
- ;;; hash table, the definitions are found that are local to the module (that
- ;;; is, not imported from other modules). When looking up bindings in the
- ;;; module, this hash table is searched first.
- ;;;
- ;;; - binder: either #f or a function taking a module and a symbol argument.
- ;;; If it is a function it is called after the obarray has been
- ;;; unsuccessfully searched for a binding. It then can provide bindings
- ;;; that would otherwise not be found locally in the module.
- ;;;
- ;;; - uses: a list of modules from which non-local bindings can be inherited.
- ;;; These modules are the third place queried for bindings after the obarray
- ;;; has been unsuccessfully searched and the binder function did not deliver
- ;;; a result either.
- ;;;
- ;;; - transformer: either #f or a function taking a scheme expression as
- ;;; delivered by read. If it is a function, it will be called to perform
- ;;; syntax transformations (e. g. makro expansion) on the given scheme
- ;;; expression. The output of the transformer function will then be passed
- ;;; to Guile's internal memoizer. This means that the output must be valid
- ;;; scheme code. The only exception is, that the output may make use of the
- ;;; syntax extensions provided to identify the modules that a binding
- ;;; belongs to.
- ;;;
- ;;; - name: the name of the module. This is used for all kinds of printing
- ;;; outputs. In certain places the module name also serves as a way of
- ;;; identification. When adding a module to the uses list of another
- ;;; module, it is made sure that the new uses list will not contain two
- ;;; modules of the same name.
- ;;;
- ;;; - kind: classification of the kind of module. The value is (currently?)
- ;;; only used for printing. It has no influence on how a module is treated.
- ;;; Currently the following values are used when setting the module kind:
- ;;; 'module, 'directory, 'interface, 'custom-interface. If no explicit kind
- ;;; is set, it defaults to 'module.
- ;;;
- ;;; - duplicates-handlers: a list of procedures that get called to make a
- ;;; choice between two duplicate bindings when name clashes occur. See the
- ;;; `duplicate-handlers' global variable below.
- ;;;
- ;;; - observers: a list of procedures that get called when the module is
- ;;; modified.
- ;;;
- ;;; - weak-observers: a weak-key hash table of procedures that get called
- ;;; when the module is modified. See `module-observe-weak' for details.
- ;;;
- ;;; In addition, the module may (must?) contain a binding for
- ;;; `%module-public-interface'. This variable should be bound to a module
- ;;; representing the exported interface of a module. See the
- ;;; `module-public-interface' and `module-export!' procedures.
- ;;;
- ;;; !!! warning: The interface to lazy binder procedures is going
- ;;; to be changed in an incompatible way to permit all the basic
- ;;; module ops to be virtualized.
- ;;;
- ;;; (make-module size use-list lazy-binding-proc) => module
- ;;; module-{obarray,uses,binder}[|-set!]
- ;;; (module? obj) => [#t|#f]
- ;;; (module-locally-bound? module symbol) => [#t|#f]
- ;;; (module-bound? module symbol) => [#t|#f]
- ;;; (module-symbol-locally-interned? module symbol) => [#t|#f]
- ;;; (module-symbol-interned? module symbol) => [#t|#f]
- ;;; (module-local-variable module symbol) => [#<variable ...> | #f]
- ;;; (module-variable module symbol) => [#<variable ...> | #f]
- ;;; (module-symbol-binding module symbol opt-value)
- ;;; => [ <obj> | opt-value | an error occurs ]
- ;;; (module-make-local-var! module symbol) => #<variable...>
- ;;; (module-add! module symbol var) => unspecified
- ;;; (module-remove! module symbol) => unspecified
- ;;; (module-for-each proc module) => unspecified
- ;;; (make-scm-module) => module ; a lazy copy of the symhash module
- ;;; (set-current-module module) => unspecified
- ;;; (current-module) => #<module...>
- ;;;
- ;;;
- ;;; {Printing Modules}
- ;;;
- ;; This is how modules are printed. You can re-define it.
- (define (%print-module mod port)
- (display "#<" port)
- (display (or (module-kind mod) "module") port)
- (display " " port)
- (display (module-name mod) port)
- (display " " port)
- (display (number->string (object-address mod) 16) port)
- (display ">" port))
- (letrec-syntax
- ;; Locally extend the syntax to allow record accessors to be defined at
- ;; compile-time. Cache the rtd locally to the constructor, the getters and
- ;; the setters, in order to allow for redefinition of the record type; not
- ;; relevant in the case of modules, but perhaps if we make this public, it
- ;; could matter.
- ((define-record-type
- (lambda (x)
- (define (make-id scope . fragments)
- (datum->syntax scope
- (apply symbol-append
- (map (lambda (x)
- (if (symbol? x) x (syntax->datum x)))
- fragments))))
- (define (getter rtd type-name field slot)
- (define id (make-id rtd type-name '- field))
- #`(define #,id
- (let ((rtd #,rtd))
- (lambda (#,type-name)
- (unless (eq? (struct-vtable #,type-name) rtd)
- (scm-error 'wrong-type-arg
- #,(symbol->string (syntax->datum id))
- "Wrong type argument (want `~S'): ~S"
- (list '#,type-name #,type-name)
- #f))
- (struct-ref #,type-name #,slot)))))
- (define (setter rtd type-name field slot)
- (define id (make-id rtd 'set- type-name '- field '!))
- #`(define #,id
- (let ((rtd #,rtd))
- (lambda (#,type-name val)
- (unless (eq? (struct-vtable #,type-name) rtd)
- (scm-error 'wrong-type-arg
- #,(symbol->string (syntax->datum id))
- "Wrong type argument (want `~S'): ~S"
- (list '#,type-name #,type-name)
- #f))
- (struct-set! #,type-name #,slot val)))))
- (define (accessors rtd type-name fields n exp)
- (syntax-case fields ()
- (() exp)
- (((field #:no-accessors) field* ...) (identifier? #'field)
- (accessors rtd type-name #'(field* ...) (1+ n)
- exp))
- (((field #:no-setter) field* ...) (identifier? #'field)
- (accessors rtd type-name #'(field* ...) (1+ n)
- #`(begin #,exp
- #,(getter rtd type-name #'field n))))
- (((field #:no-getter) field* ...) (identifier? #'field)
- (accessors rtd type-name #'(field* ...) (1+ n)
- #`(begin #,exp
- #,(setter rtd type-name #'field n))))
- ((field field* ...) (identifier? #'field)
- (accessors rtd type-name #'(field* ...) (1+ n)
- #`(begin #,exp
- #,(getter rtd type-name #'field n)
- #,(setter rtd type-name #'field n))))))
- (define (predicate rtd type-name fields exp)
- (accessors
- rtd type-name fields 0
- #`(begin
- #,exp
- (define (#,(make-id rtd type-name '?) obj)
- (and (struct? obj) (eq? (struct-vtable obj) #,rtd))))))
- (define (field-list fields)
- (syntax-case fields ()
- (() '())
- (((f . opts) . rest) (identifier? #'f)
- (cons #'f (field-list #'rest)))
- ((f . rest) (identifier? #'f)
- (cons #'f (field-list #'rest)))))
- (define (constructor rtd type-name fields exp)
- (let* ((ctor (make-id rtd type-name '-constructor))
- (args (field-list fields))
- (n (length fields))
- (slots (iota n)))
- (predicate rtd type-name fields
- #`(begin #,exp
- (define #,ctor
- (let ((rtd #,rtd))
- (lambda #,args
- (make-struct/simple rtd #,@args))))
- (struct-set! #,rtd (+ vtable-offset-user 2)
- #,ctor)))))
- (define (type type-name printer fields)
- (define (make-layout)
- (let lp ((fields fields) (slots '()))
- (syntax-case fields ()
- (() (datum->syntax #'here
- (make-struct-layout
- (apply string-append slots))))
- ((_ . rest) (lp #'rest (cons "pw" slots))))))
- (let ((rtd (make-id type-name type-name '-type)))
- (constructor rtd type-name fields
- #`(begin
- (define #,rtd
- (make-struct/no-tail
- record-type-vtable
- '#,(make-layout)
- #,printer
- '#,type-name
- '#,(field-list fields)
- #f ; constructor; set later
- '() ; properties
- #())) ; parents
- (set-struct-vtable-name! #,rtd '#,type-name)))))
- (syntax-case x ()
- ((_ type-name printer (field ...))
- (type #'type-name #'printer #'(field ...)))))))
- ;; module-type
- ;;
- ;; A module is characterized by an obarray in which local symbols
- ;; are interned, a list of modules, "uses", from which non-local
- ;; bindings can be inherited, and an optional lazy-binder which
- ;; is a (CLOSURE module symbol) which, as a last resort, can provide
- ;; bindings that would otherwise not be found locally in the module.
- ;;
- ;; NOTE: If you change the set of fields or their order, you also need to
- ;; change the constants in libguile/modules.h.
- ;;
- ;; NOTE: The getter `module-transformer' is defined libguile/modules.c.
- ;; NOTE: The getter `module-name' is defined later, due to boot reasons.
- ;; NOTE: The getter `module-public-interface' is used in libguile/modules.c.
- ;;
- (define-record-type module
- (lambda (obj port) (%print-module obj port))
- (obarray
- uses
- binder
- declarative?
- (transformer #:no-getter)
- (name #:no-getter)
- kind
- duplicates-handlers
- (import-obarray #:no-setter)
- observers
- (weak-observers #:no-setter)
- version
- submodules
- submodule-binder
- public-interface
- filename
- next-unique-id
- (replacements #:no-setter)
- inlinable-exports)))
- ;; make-module &opt size uses binder
- ;;
- (define* (make-module #:optional (size 0) (uses '()) (binder #f))
- "Create a new module, perhaps with a particular size of obarray,
- initial uses list, or binding procedure."
- (unless (integer? size)
- (error "Illegal size to make-module." size))
- (unless (zero? size)
- (issue-deprecation-warning
- "Passing a non-zero size argument to `make-module' is deprecated. "
- "Omit the argument or pass zero instead."))
- (unless (and (list? uses) (and-map module? uses))
- (error "Incorrect use list." uses))
- (when (and binder (not (procedure? binder)))
- (error "Lazy-binder expected to be a procedure or #f." binder))
- (module-constructor (make-hash-table size)
- uses binder #f macroexpand
- #f #f #f
- (make-hash-table)
- '()
- (make-weak-key-hash-table) #f
- (make-hash-table) #f #f #f 0
- (make-hash-table) #f))
- ;;; {Observer protocol}
- ;;;
- (define (module-observe module proc)
- (set-module-observers! module (cons proc (module-observers module)))
- (cons module proc))
- (define* (module-observe-weak module observer-id #:optional (proc observer-id))
- "Register PROC as an observer of MODULE under name OBSERVER-ID (which can
- be any Scheme object). PROC is invoked and passed MODULE any time
- MODULE is modified. PROC gets unregistered when OBSERVER-ID gets GC'd
- (thus, it is never unregistered if OBSERVER-ID is an immediate value,
- for instance).
- The two-argument version is kept for backward compatibility: when called
- with two arguments, the observer gets unregistered when closure PROC
- gets GC'd (making it impossible to use an anonymous lambda for PROC)."
- (hashq-set! (module-weak-observers module) observer-id proc))
- (define (module-unobserve token)
- (let ((module (car token))
- (id (cdr token)))
- (if (integer? id)
- (hash-remove! (module-weak-observers module) id)
- (set-module-observers! module (delq1! id (module-observers module)))))
- *unspecified*)
- ;; Hash table of module -> #t indicating modules that changed while
- ;; observers were deferred, or #f if observers are not being deferred.
- (define module-defer-observers (make-parameter #f))
- (define (module-modified m)
- (cond
- ((module-defer-observers) => (lambda (tab) (hashq-set! tab m #t)))
- (else (module-call-observers m))))
- ;;; This function can be used to delay calls to observers so that they
- ;;; can be called once only in the face of massive updating of modules.
- ;;;
- (define (call-with-deferred-observers thunk)
- (cond
- ((module-defer-observers) (thunk))
- (else
- (let ((modules (make-hash-table)))
- (dynamic-wind (lambda () #t)
- (lambda ()
- (parameterize ((module-defer-observers modules))
- (thunk)))
- (lambda ()
- (let ((changed (hash-map->list cons modules)))
- (hash-clear! modules)
- (for-each (lambda (pair)
- (module-call-observers (car pair)))
- changed))))))))
- (define (module-call-observers m)
- (for-each (lambda (proc) (proc m)) (module-observers m))
- ;; We assume that weak observers don't (un)register themselves as they are
- ;; called since this would preclude proper iteration over the hash table
- ;; elements.
- (hash-for-each (lambda (id proc) (proc m)) (module-weak-observers m)))
- ;;; {Module Searching in General}
- ;;;
- ;;; We sometimes want to look for properties of a symbol
- ;;; just within the obarray of one module. If the property
- ;;; holds, then it is said to hold ``locally'' as in, ``The symbol
- ;;; DISPLAY is locally rebound in the module `safe-guile'.''
- ;;;
- ;;;
- ;;; Other times, we want to test for a symbol property in the obarray
- ;;; of M and, if it is not found there, try each of the modules in the
- ;;; uses list of M. This is the normal way of testing for some
- ;;; property, so we state these properties without qualification as
- ;;; in: ``The symbol 'fnord is interned in module M because it is
- ;;; interned locally in module M2 which is a member of the uses list
- ;;; of M.''
- ;;;
- (define (module-search fn m v)
- "Return the first non-#f result of FN applied to M and then to
- the modules in the uses of M, and so on recursively. If all applications
- return #f, then so does this function."
- (define (loop pos)
- (and (pair? pos)
- (or (module-search fn (car pos) v)
- (loop (cdr pos)))))
- (or (fn m v)
- (loop (module-uses m))))
- ;;; {Is a symbol bound in a module?}
- ;;;
- ;;; Symbol S in Module M is bound if S is interned in M and if the binding
- ;;; of S in M has been set to some well-defined value.
- ;;;
- (define (module-locally-bound? m v)
- "Is symbol V bound (interned and defined) locally in module M?"
- (let ((var (module-local-variable m v)))
- (and var
- (variable-bound? var))))
- (define (module-bound? m v)
- "Is symbol V bound (interned and defined) anywhere in module M or its
- uses?"
- (let ((var (module-variable m v)))
- (and var
- (variable-bound? var))))
- ;;; {Is a symbol interned in a module?}
- ;;;
- ;;; Symbol S in Module M is interned if S occurs in
- ;;; of S in M has been set to some well-defined value.
- ;;;
- ;;; It is possible to intern a symbol in a module without providing
- ;;; an initial binding for the corresponding variable. This is done
- ;;; with:
- ;;; (module-add! module symbol (make-undefined-variable))
- ;;;
- ;;; In that case, the symbol is interned in the module, but not
- ;;; bound there. The unbound symbol shadows any binding for that
- ;;; symbol that might otherwise be inherited from a member of the uses list.
- ;;;
- (define (module-obarray-get-handle ob key)
- ((if (symbol? key) hashq-get-handle hash-get-handle) ob key))
- (define (module-obarray-ref ob key)
- ((if (symbol? key) hashq-ref hash-ref) ob key))
- (define (module-obarray-set! ob key val)
- ((if (symbol? key) hashq-set! hash-set!) ob key val))
- (define (module-obarray-remove! ob key)
- ((if (symbol? key) hashq-remove! hash-remove!) ob key))
- (define (module-symbol-locally-interned? m v)
- "Is symbol V interned (not neccessarily defined) locally in module M
- or its uses? Interned symbols shadow inherited bindings even if they
- are not themselves bound to a defined value."
- (not (not (module-obarray-get-handle (module-obarray m) v))))
- (define (module-symbol-interned? m v)
- "Is symbol V interned (not neccessarily defined) anywhere in module M
- or its uses? Interned symbols shadow inherited bindings even if they
- are not themselves bound to a defined value."
- (module-search module-symbol-locally-interned? m v))
- ;;; {Mapping modules x symbols --> variables}
- ;;;
- ;; module-local-variable module symbol
- ;; return the local variable associated with a MODULE and SYMBOL.
- ;;
- ;;; This function is very important. It is the only function that can
- ;;; return a variable from a module other than the mutators that store
- ;;; new variables in modules. Therefore, this function is the location
- ;;; of the "lazy binder" hack.
- ;;;
- ;;; If symbol is defined in MODULE, and if the definition binds symbol
- ;;; to a variable, return that variable object.
- ;;;
- ;;; If the symbols is not found at first, but the module has a lazy binder,
- ;;; then try the binder.
- ;;;
- ;;; If the symbol is not found at all, return #f.
- ;;;
- ;;; (This is now written in C, see `modules.c'.)
- ;;;
- ;;; {Mapping modules x symbols --> bindings}
- ;;;
- ;;; These are similar to the mapping to variables, except that the
- ;;; variable is dereferenced.
- ;;;
- (define (module-symbol-local-binding m v . opt-val)
- "Return the binding of variable V specified by name within module M,
- signalling an error if the variable is unbound. If the OPT-VALUE is
- passed, then instead of signalling an error, return OPT-VALUE."
- (let ((var (module-local-variable m v)))
- (if (and var (variable-bound? var))
- (variable-ref var)
- (if (not (null? opt-val))
- (car opt-val)
- (error "Locally unbound variable." v)))))
- (define (module-symbol-binding m v . opt-val)
- "Return the binding of variable V specified by name within module M,
- signalling an error if the variable is unbound. If the OPT-VALUE is
- passed, then instead of signalling an error, return OPT-VALUE."
- (let ((var (module-variable m v)))
- (if (and var (variable-bound? var))
- (variable-ref var)
- (if (not (null? opt-val))
- (car opt-val)
- (error "Unbound variable." v)))))
- ;;; {Adding Variables to Modules}
- ;;;
- ;; This function is used in modules.c.
- ;;
- (define (module-make-local-var! m v)
- "Ensure a variable for V in the local namespace of M.
- If no variable was already there, then create a new and uninitialized
- variable."
- (or (let ((b (module-obarray-ref (module-obarray m) v)))
- (and (variable? b)
- (begin
- ;; Mark as modified since this function is called when
- ;; the standard eval closure defines a binding
- (module-modified m)
- b)))
- ;; Create a new local variable.
- (let ((local-var (make-undefined-variable)))
- (module-add! m v local-var)
- local-var)))
- (define (module-ensure-local-variable! module symbol)
- "Ensure that there is a local variable in MODULE for SYMBOL. If
- there is no binding for SYMBOL, create a new uninitialized
- variable. Return the local variable."
- (or (module-local-variable module symbol)
- (let ((var (make-undefined-variable)))
- (module-add! module symbol var)
- var)))
- ;; module-add! module symbol var
- ;;
- (define (module-add! m v var)
- "Ensure a particular variable for V in the local namespace of M."
- (if (not (variable? var))
- (error "Bad variable to module-add!" var))
- (if (not (symbol? v))
- (error "Bad symbol to module-add!" v))
- (module-obarray-set! (module-obarray m) v var)
- (module-modified m))
- (define (module-remove! m v)
- "Make sure that symbol V is undefined in the local namespace of M."
- (module-obarray-remove! (module-obarray m) v)
- (module-modified m))
- (define (module-clear! m)
- (hash-clear! (module-obarray m))
- (module-modified m))
- ;; MODULE-FOR-EACH -- exported
- ;;
- (define (module-for-each proc module)
- "Call PROC on each symbol in MODULE, with arguments of (SYMBOL VARIABLE)."
- (hash-for-each proc (module-obarray module)))
- (define (module-map proc module)
- (hash-map->list proc (module-obarray module)))
- ;; Submodules
- ;;
- ;; Modules exist in a separate namespace from values, because you generally do
- ;; not want the name of a submodule, which you might not even use, to collide
- ;; with local variables that happen to be named the same as the submodule.
- ;;
- (define (module-ref-submodule module name)
- (or (hashq-ref (module-submodules module) name)
- (and (module-submodule-binder module)
- ((module-submodule-binder module) module name))))
- (define (module-define-submodule! module name submodule)
- (hashq-set! (module-submodules module) name submodule))
- ;;; {Module-based Loading}
- ;;;
- (define (save-module-excursion thunk)
- (let ((inner-module (current-module))
- (outer-module #f))
- (dynamic-wind (lambda ()
- (set! outer-module (current-module))
- (set-current-module inner-module)
- (set! inner-module #f))
- thunk
- (lambda ()
- (set! inner-module (current-module))
- (set-current-module outer-module)
- (set! outer-module #f)))))
- ;;; {MODULE-REF -- exported}
- ;;;
- (define (module-ref module name . rest)
- "Returns the value of a variable called NAME in MODULE or any of its
- used modules. If there is no such variable, then if the optional third
- argument DEFAULT is present, it is returned; otherwise an error is signaled."
- (let ((variable (module-variable module name)))
- (if (and variable (variable-bound? variable))
- (variable-ref variable)
- (if (null? rest)
- (error "No variable named" name 'in module)
- (car rest) ; default value
- ))))
- ;; MODULE-SET! -- exported
- ;;
- (define (module-set! module name value)
- "Sets the variable called NAME in MODULE (or in a module that MODULE uses)
- to VALUE; if there is no such variable, an error is signaled."
- (let ((variable (module-variable module name)))
- (if variable
- (variable-set! variable value)
- (error "No variable named" name 'in module))))
- ;; MODULE-DEFINE! -- exported
- ;;
- (define (module-define! module name value)
- "Sets the variable called NAME in MODULE to VALUE; if there is no such
- variable, it is added first."
- (let ((variable (module-local-variable module name)))
- (if variable
- (begin
- (variable-set! variable value)
- (module-modified module))
- (let ((variable (make-variable value)))
- (module-add! module name variable)))))
- ;; MODULE-DEFINED? -- exported
- ;;
- (define (module-defined? module name)
- "Return #t iff NAME is defined in MODULE (or in a module that MODULE
- uses)."
- (let ((variable (module-variable module name)))
- (and variable (variable-bound? variable))))
- (define (module-use! module interface)
- "Add INTERFACE to the list of interfaces used by MODULE."
- (if (not (or (eq? module interface)
- (memq interface (module-uses module))))
- (begin
- ;; Newly used modules must be appended rather than consed, so that
- ;; `module-variable' traverses the use list starting from the first
- ;; used module.
- (set-module-uses! module (append (module-uses module)
- (list interface)))
- (hash-clear! (module-import-obarray module))
- (module-modified module))))
- (define (module-use-interfaces! module interfaces)
- "Same as MODULE-USE!, but only notifies module observers after all
- interfaces are added to the inports list."
- (let* ((cur (module-uses module))
- (new (let lp ((in interfaces) (out '()))
- (if (null? in)
- (reverse out)
- (lp (cdr in)
- (let ((iface (car in)))
- (if (or (memq iface cur) (memq iface out))
- out
- (cons iface out))))))))
- (set-module-uses! module (append cur new))
- (hash-clear! (module-import-obarray module))
- (module-modified module)))
- ;;; {Recursive Namespaces}
- ;;;
- ;;; A hierarchical namespace emerges if we consider some module to be
- ;;; root, and submodules of that module to be nested namespaces.
- ;;;
- ;;; The routines here manage variable names in hierarchical namespace.
- ;;; Each variable name is a list of elements, looked up in successively nested
- ;;; modules.
- ;;;
- ;;; (nested-ref some-root-module '(foo bar baz))
- ;;; => <value of a variable named baz in the submodule bar of
- ;;; the submodule foo of some-root-module>
- ;;;
- ;;;
- ;;; There are:
- ;;;
- ;;; ;; a-root is a module
- ;;; ;; name is a list of symbols
- ;;;
- ;;; nested-ref a-root name
- ;;; nested-set! a-root name val
- ;;; nested-define! a-root name val
- ;;; nested-remove! a-root name
- ;;;
- ;;; These functions manipulate values in namespaces. For referencing the
- ;;; namespaces themselves, use the following:
- ;;;
- ;;; nested-ref-module a-root name
- ;;; nested-define-module! a-root name mod
- ;;;
- ;;; (current-module) is a natural choice for a root so for convenience there are
- ;;; also:
- ;;;
- ;;; local-ref name == nested-ref (current-module) name
- ;;; local-set! name val == nested-set! (current-module) name val
- ;;; local-define name val == nested-define! (current-module) name val
- ;;; local-remove name == nested-remove! (current-module) name
- ;;; local-ref-module name == nested-ref-module (current-module) name
- ;;; local-define-module! name m == nested-define-module! (current-module) name m
- ;;;
- (define (nested-ref root names)
- (if (null? names)
- root
- (let loop ((cur root)
- (head (car names))
- (tail (cdr names)))
- (if (null? tail)
- (module-ref cur head #f)
- (let ((cur (module-ref-submodule cur head)))
- (and cur
- (loop cur (car tail) (cdr tail))))))))
- (define (nested-set! root names val)
- (let loop ((cur root)
- (head (car names))
- (tail (cdr names)))
- (if (null? tail)
- (module-set! cur head val)
- (let ((cur (module-ref-submodule cur head)))
- (if (not cur)
- (error "failed to resolve module" names)
- (loop cur (car tail) (cdr tail)))))))
- (define (nested-define! root names val)
- (let loop ((cur root)
- (head (car names))
- (tail (cdr names)))
- (if (null? tail)
- (module-define! cur head val)
- (let ((cur (module-ref-submodule cur head)))
- (if (not cur)
- (error "failed to resolve module" names)
- (loop cur (car tail) (cdr tail)))))))
- (define (nested-remove! root names)
- (let loop ((cur root)
- (head (car names))
- (tail (cdr names)))
- (if (null? tail)
- (module-remove! cur head)
- (let ((cur (module-ref-submodule cur head)))
- (if (not cur)
- (error "failed to resolve module" names)
- (loop cur (car tail) (cdr tail)))))))
- (define (nested-ref-module root names)
- (let loop ((cur root)
- (names names))
- (if (null? names)
- cur
- (let ((cur (module-ref-submodule cur (car names))))
- (and cur
- (loop cur (cdr names)))))))
- (define (nested-define-module! root names module)
- (if (null? names)
- (error "can't redefine root module" root module)
- (let loop ((cur root)
- (head (car names))
- (tail (cdr names)))
- (if (null? tail)
- (module-define-submodule! cur head module)
- (let ((cur (or (module-ref-submodule cur head)
- (let ((m (make-module)))
- (set-module-kind! m 'directory)
- (set-module-name! m (append (module-name cur)
- (list head)))
- (module-define-submodule! cur head m)
- m))))
- (loop cur (car tail) (cdr tail)))))))
- (define (local-ref names)
- (nested-ref (current-module) names))
- (define (local-set! names val)
- (nested-set! (current-module) names val))
- (define (local-define names val)
- (nested-define! (current-module) names val))
- (define (local-remove names)
- (nested-remove! (current-module) names))
- (define (local-ref-module names)
- (nested-ref-module (current-module) names))
- (define (local-define-module names mod)
- (nested-define-module! (current-module) names mod))
- ;;; {The (guile) module}
- ;;;
- ;;; The standard module, which has the core Guile bindings. Also called the
- ;;; "root module", as it is imported by many other modules, but it is not
- ;;; necessarily the root of anything; and indeed, the module named '() might be
- ;;; better thought of as a root.
- ;;;
- ;; The root module uses the pre-modules-obarray as its obarray. This
- ;; special obarray accumulates all bindings that have been established
- ;; before the module system is fully booted.
- ;;
- ;; (The obarray continues to be used by code that has been closed over
- ;; before the module system has been booted.)
- ;;
- (define the-root-module
- (let ((m (make-module 0)))
- (set-module-obarray! m (%get-pre-modules-obarray))
- (set-module-name! m '(guile))
- ;; Inherit next-unique-id from preliminary stub of
- ;; %module-get-next-unique-id! defined above.
- (set-module-next-unique-id! m (module-generate-unique-id! #f))
- m))
- ;; The root interface is a module that uses the same obarray as the
- ;; root module. It does not allow new definitions, tho.
- ;;
- (define the-scm-module
- (let ((m (make-module 0)))
- (set-module-obarray! m (%get-pre-modules-obarray))
- (set-module-name! m '(guile))
- (set-module-kind! m 'interface)
- ;; In Guile 1.8 and earlier M was its own public interface.
- (set-module-public-interface! m m)
- m))
- (set-module-public-interface! the-root-module the-scm-module)
- ;; Now that we have a root module, even though modules aren't fully booted,
- ;; expand the definition of resolve-module.
- ;;
- (define (resolve-module name . args)
- (if (equal? name '(guile))
- the-root-module
- (error "unexpected module to resolve during module boot" name)))
- (define (module-generate-unique-id! m)
- (let ((i (module-next-unique-id m)))
- (set-module-next-unique-id! m (+ i 1))
- i))
- ;; Cheat. These bindings are needed by modules.c, but we don't want
- ;; to move their real definition here because that would be unnatural.
- ;;
- (define define-module* #f)
- (define process-use-modules #f)
- (define module-export! #f)
- (define default-duplicate-binding-procedures #f)
- ;; This boots the module system. All bindings needed by modules.c
- ;; must have been defined by now.
- ;;
- (set-current-module the-root-module)
- (define (call-with-module-autoload-lock thunk)
- ;; This binding is overridden when (ice-9 threads) is available to
- ;; implement a critical section around the call to THUNK. It must be
- ;; used anytime 'autoloads-done' and related variables are accessed
- ;; and whenever submodules are accessed (via the 'nested-'
- ;; procedures.)
- (thunk))
- ;; Now that modules are booted, give module-name its final definition.
- ;;
- (define module-name
- (let ((accessor (record-accessor module-type 'name)))
- (lambda (mod)
- (or (accessor mod)
- (let ((name (list (gensym))))
- ;; Name MOD and bind it in the module root so that it's visible to
- ;; `resolve-module'. This is important as `psyntax' stores module
- ;; names and relies on being able to `resolve-module' them.
- (set-module-name! mod name)
- (call-with-module-autoload-lock
- (lambda ()
- (nested-define-module! (resolve-module '() #f) name mod)))
- (accessor mod))))))
- (define* (module-gensym #:optional (id " mg") (m (current-module)))
- "Return a fresh symbol in the context of module M, based on ID (a
- string or symbol). As long as M is a valid module, this procedure is
- deterministic."
- (define (->string number)
- (number->string number 16))
- (if m
- (string->symbol
- (string-append id "-"
- (->string (hash (module-name m) most-positive-fixnum))
- "-"
- (->string (module-generate-unique-id! m))))
- (gensym id)))
- (define (make-modules-in module name)
- (or (nested-ref-module module name)
- (let ((m (make-module)))
- (set-module-kind! m 'directory)
- (set-module-name! m (append (module-name module) name))
- (nested-define-module! module name m)
- m)))
- (define user-modules-declarative? (make-parameter #t))
- (define (beautify-user-module! module)
- (let ((interface (module-public-interface module)))
- (if (or (not interface)
- (eq? interface module))
- (let ((interface (make-module)))
- (set-module-name! interface (module-name module))
- (set-module-version! interface (module-version module))
- (set-module-kind! interface 'interface)
- (set-module-public-interface! module interface))))
- (if (and (not (memq the-scm-module (module-uses module)))
- (not (eq? module the-root-module)))
- ;; Import the default set of bindings (from the SCM module) in MODULE.
- (module-use! module the-scm-module)))
- (define (version-matches? version-ref target)
- (define (sub-versions-match? v-refs t)
- (define (sub-version-matches? v-ref t)
- (let ((matches? (lambda (v) (sub-version-matches? v t))))
- (cond
- ((number? v-ref) (eqv? v-ref t))
- ((list? v-ref)
- (case (car v-ref)
- ((>=) (>= t (cadr v-ref)))
- ((<=) (<= t (cadr v-ref)))
- ((and) (and-map matches? (cdr v-ref)))
- ((or) (or-map matches? (cdr v-ref)))
- ((not) (not (matches? (cadr v-ref))))
- (else (error "Invalid sub-version reference" v-ref))))
- (else (error "Invalid sub-version reference" v-ref)))))
- (or (null? v-refs)
- (and (not (null? t))
- (sub-version-matches? (car v-refs) (car t))
- (sub-versions-match? (cdr v-refs) (cdr t)))))
- (let ((matches? (lambda (v) (version-matches? v target))))
- (or (null? version-ref)
- (case (car version-ref)
- ((and) (and-map matches? (cdr version-ref)))
- ((or) (or-map matches? (cdr version-ref)))
- ((not) (not (matches? (cadr version-ref))))
- (else (sub-versions-match? version-ref target))))))
- (define (make-fresh-user-module)
- (let ((m (make-module)))
- (beautify-user-module! m)
- (set-module-declarative?! m (user-modules-declarative?))
- m))
- ;; NOTE: This binding is used in libguile/modules.c.
- ;;
- (define resolve-module
- (let ((root (make-module)))
- (set-module-name! root '())
- ;; Define the-root-module as '(guile).
- (module-define-submodule! root 'guile the-root-module)
- (lambda* (name #:optional (autoload #t) (version #f) #:key (ensure #t))
- (call-with-module-autoload-lock
- (lambda ()
- (let ((already (nested-ref-module root name)))
- (cond
- ((and already
- (or (not autoload) (module-public-interface already)))
- ;; A hit, a palpable hit.
- (if (and version
- (not (version-matches? version (module-version already))))
- (error "incompatible module version already loaded" name))
- already)
- (autoload
- ;; Try to autoload the module, and recurse.
- (try-load-module name version)
- (resolve-module name #f #:ensure ensure))
- (else
- ;; No module found (or if one was, it had no public interface), and
- ;; we're not autoloading. Make an empty module if #:ensure is true.
- (or already
- (and ensure
- (make-modules-in root name)))))))))))
- (define (try-load-module name version)
- (try-module-autoload name version))
- (define (reload-module m)
- "Revisit the source file corresponding to the module @var{m}."
- (let ((f (module-filename m)))
- (if f
- (save-module-excursion
- (lambda ()
- ;; Re-set the initial environment, as in try-module-autoload.
- (set-current-module (make-fresh-user-module))
- (primitive-load-path f)
- m))
- ;; Though we could guess, we *should* know it.
- (error "unknown file name for module" m))))
- (define (purify-module! module)
- "Removes bindings in MODULE which are inherited from the (guile) module."
- (let ((use-list (module-uses module)))
- (if (and (pair? use-list)
- (eq? (car (last-pair use-list)) the-scm-module))
- (set-module-uses! module (reverse (cdr (reverse use-list)))))))
- (define* (resolve-interface name #:key
- (select #f)
- (hide '())
- (prefix #f)
- (renamer (if prefix
- (symbol-prefix-proc prefix)
- identity))
- version)
- "Return a module that is an interface to the module designated by
- NAME.
- `resolve-interface' takes four keyword arguments:
- #:select SELECTION
- SELECTION is a list of binding-specs to be imported; A binding-spec
- is either a symbol or a pair of symbols (ORIG . SEEN), where ORIG
- is the name in the used module and SEEN is the name in the using
- module. Note that SEEN is also passed through RENAMER, below. The
- default is to select all bindings. If you specify no selection but
- a renamer, only the bindings that already exist in the used module
- are made available in the interface. Bindings that are added later
- are not picked up.
- #:hide BINDINGS
- BINDINGS is a list of bindings which should not be imported.
- #:prefix PREFIX
- PREFIX is a symbol that will be appended to each exported name.
- The default is to not perform any renaming.
- #:renamer RENAMER
- RENAMER is a procedure that takes a symbol and returns its new
- name. The default is not perform any renaming.
- Signal \"no code for module\" error if module name is not resolvable
- or its public interface is not available. Signal \"no binding\"
- error if selected binding does not exist in the used module."
- (let* ((module (resolve-module name #t version #:ensure #f))
- (public-i (and module (module-public-interface module))))
- (unless public-i
- (error "no code for module" name))
- (if (and (not select) (null? hide) (eq? renamer identity))
- public-i
- (let ((selection (or select (module-map (lambda (sym var) sym)
- public-i)))
- (custom-i (make-module)))
- (set-module-kind! custom-i 'custom-interface)
- (set-module-name! custom-i name)
- ;; Check that we are not hiding bindings which don't exist
- (for-each (lambda (binding)
- (unless (module-local-variable public-i binding)
- (error
- (simple-format
- #f "no binding `~A' to hide in module ~A"
- binding name))))
- hide)
- (define (maybe-export! src dst var)
- (unless (memq src hide)
- (let ((name (renamer dst)))
- (when (hashq-ref (module-replacements public-i) src)
- (hashq-set! (module-replacements custom-i) name #t))
- (module-add! custom-i name var))))
- (cond
- (select
- (for-each
- (lambda (bspec)
- (let* ((direct? (symbol? bspec))
- (orig (if direct? bspec (car bspec)))
- (seen (if direct? bspec (cdr bspec)))
- (var (module-local-variable public-i orig)))
- (unless var
- (scm-error 'unbound-variable "resolve-interface"
- "no binding `~A' in module ~A" (list orig name)
- #f))
- (maybe-export! orig seen var)))
- select))
- (else
- ;; FIXME: Use a lazy binder so that changes to the used
- ;; module are picked up automatically.
- (module-for-each (lambda (sym var)
- (maybe-export! sym sym var))
- public-i)))
- custom-i))))
- (define (symbol-prefix-proc prefix)
- (lambda (symbol)
- (symbol-append prefix symbol)))
- ;; This function is called from "modules.c". If you change it, be
- ;; sure to update "modules.c" as well.
- (define* (define-module* name
- #:key filename pure version (imports '()) (exports '())
- (replacements '()) (re-exports '()) (re-export-replacements '())
- (autoloads '()) (duplicates #f) transformer declarative?
- inlinable-exports)
- (define (list-of pred l)
- (or (null? l)
- (and (pair? l) (pred (car l)) (list-of pred (cdr l)))))
- (define (valid-import? x)
- (list? x))
- (define (valid-export? x)
- (or (symbol? x) (and (pair? x) (symbol? (car x)) (symbol? (cdr x)))))
- (define (valid-autoload? x)
- (and (pair? x) (list-of symbol? (car x)) (list-of symbol? (cdr x))))
- ;; We could add a #:no-check arg, set by the define-module macro, if
- ;; these checks are taking too much time.
- ;;
- (let ((module (resolve-module name #f)))
- (beautify-user-module! module)
- (set-module-declarative?! module declarative?)
- (when filename
- (set-module-filename! module filename))
- (when pure
- (purify-module! module))
- (when version
- (unless (list-of integer? version)
- (error "expected list of integers for version"))
- (set-module-version! module version)
- (set-module-version! (module-public-interface module) version))
- (call-with-deferred-observers
- (lambda ()
- (unless (list-of valid-import? imports)
- (error "expected imports to be a list of import specifications"))
- (unless (list-of valid-export? exports)
- (error "expected exports to be a list of symbols or symbol pairs"))
- (unless (list-of valid-export? replacements)
- (error "expected replacements to be a list of symbols or symbol pairs"))
- (unless (list-of valid-export? re-exports)
- (error "expected re-exports to be a list of symbols or symbol pairs"))
- (module-export! module exports)
- (module-replace! module replacements)
- (unless (null? imports)
- (let ((imports (map (lambda (import-spec)
- (apply resolve-interface import-spec))
- imports)))
- (module-use-interfaces! module imports)))
- (module-re-export! module re-exports)
- (module-re-export! module re-export-replacements #:replace? #t)
- ;; FIXME: Avoid use of `apply'.
- (apply module-autoload! module autoloads)
- (let ((duplicates (or duplicates
- ;; Avoid stompling a previously installed
- ;; duplicates handlers if possible.
- (and (not (module-duplicates-handlers module))
- ;; Note: If you change this default,
- ;; change it also in
- ;; `default-duplicate-binding-procedures'.
- '(replace warn-override-core warn last)))))
- (when duplicates
- (let ((handlers (lookup-duplicates-handlers duplicates)))
- (set-module-duplicates-handlers! module handlers))))))
- (when transformer
- (unless (and (pair? transformer) (list-of symbol? transformer))
- (error "expected transformer to be a module name" transformer))
- (let ((iface (resolve-interface transformer))
- (sym (car (last-pair transformer))))
- (set-module-transformer! module (module-ref iface sym))))
- (when inlinable-exports
- (unless (procedure? inlinable-exports)
- (error "expected inlinable-exports to be a procedure" inlinable-exports))
- (set-module-inlinable-exports! (module-public-interface module)
- inlinable-exports))
- (run-hook module-defined-hook module)
- module))
- ;; `module-defined-hook' is a hook that is run whenever a new module
- ;; is defined. Its members are called with one argument, the new
- ;; module.
- (define module-defined-hook (make-hook 1))
- ;;; {Autoload}
- ;;;
- (define (make-autoload-interface module name bindings)
- (let ((b (lambda (a sym definep)
- (false-if-exception
- (and (memq sym bindings)
- (let ((i (resolve-interface name #:select bindings)))
- (unless i
- (error "missing interface for module" name))
- (let ((uses (memq a (module-uses module))))
- (when uses
- ;; Replace autoload-interface with actual
- ;; interface.
- (set-car! uses i)))
- (for-each
- (lambda (name)
- (when (hashq-ref (module-replacements i) name)
- (hashq-set! (module-replacements a) name #t)))
- bindings)
- (or (module-local-variable i sym)
- (error "binding not presentin module" name sym))))
- #:warning "Failed to autoload ~a in ~a:\n" sym name))))
- (module-constructor (make-hash-table 0) '() b #f #f name 'autoload #f
- (make-hash-table 0) '() (make-weak-value-hash-table) #f
- (make-hash-table 0) #f #f #f 0 (make-hash-table 0) #f)))
- (define (module-autoload! module . args)
- "Have @var{module} automatically load the module named @var{name} when one
- of the symbols listed in @var{bindings} is looked up. @var{args} should be a
- list of module-name/binding-list pairs, e.g., as in @code{(module-autoload!
- module '(ice-9 q) '(make-q q-length))}."
- (let loop ((args args))
- (cond ((null? args)
- #t)
- ((null? (cdr args))
- (error "invalid name+binding autoload list" args))
- (else
- (let ((name (car args))
- (bindings (cadr args)))
- (module-use! module (make-autoload-interface module
- name bindings))
- (loop (cddr args)))))))
- ;;; {Autoloading modules}
- ;;;
- (define autoloads-in-progress '())
- ;; This function is called from scm_load_scheme_module in
- ;; "deprecated.c". Please do not change its interface.
- ;;
- (define* (try-module-autoload module-name #:optional version)
- "Try to load a module of the given name. If it is not found, return
- #f. Otherwise return #t. May raise an exception if a file is found,
- but it fails to load."
- (let* ((reverse-name (reverse module-name))
- (name (symbol->string (car reverse-name)))
- (dir-hint-module-name (reverse (cdr reverse-name)))
- (dir-hint (apply string-append
- (map (lambda (elt)
- (string-append (symbol->string elt)
- file-name-separator-string))
- dir-hint-module-name))))
- (resolve-module dir-hint-module-name #f)
- (call-with-module-autoload-lock
- (lambda ()
- (and (not (autoload-done-or-in-progress? dir-hint name))
- (let ((didit #f))
- (dynamic-wind
- (lambda () (autoload-in-progress! dir-hint name))
- (lambda ()
- (with-fluids ((current-reader #f))
- (save-module-excursion
- (lambda ()
- (define (call/ec proc)
- (let ((tag (make-prompt-tag)))
- (call-with-prompt
- tag
- (lambda ()
- (proc (lambda () (abort-to-prompt tag))))
- (lambda (k) (values)))))
- ;; The initial environment when loading a module is a fresh
- ;; user module.
- (set-current-module (make-fresh-user-module))
- ;; Here we could allow some other search strategy (other than
- ;; primitive-load-path), for example using versions encoded
- ;; into the file system -- but then we would have to figure
- ;; out how to locate the compiled file, do auto-compilation,
- ;; etc. Punt for now, and don't use versions when locating
- ;; the file.
- (call/ec
- (lambda (abort)
- (primitive-load-path (in-vicinity dir-hint name)
- abort)
- (set! didit #t)))))))
- (lambda () (set-autoloaded! dir-hint name didit)))
- didit))))))
- ;;; {Dynamic linking of modules}
- ;;;
- (define autoloads-done '((guile . guile)))
- (define (autoload-done-or-in-progress? p m)
- (let ((n (cons p m)))
- (->bool (or (member n autoloads-done)
- (member n autoloads-in-progress)))))
- (define (autoload-done! p m)
- (let ((n (cons p m)))
- (set! autoloads-in-progress
- (delete! n autoloads-in-progress))
- (or (member n autoloads-done)
- (set! autoloads-done (cons n autoloads-done)))))
- (define (autoload-in-progress! p m)
- (let ((n (cons p m)))
- (set! autoloads-done
- (delete! n autoloads-done))
- (set! autoloads-in-progress (cons n autoloads-in-progress))))
- (define (set-autoloaded! p m done?)
- (if done?
- (autoload-done! p m)
- (let ((n (cons p m)))
- (set! autoloads-done (delete! n autoloads-done))
- (set! autoloads-in-progress (delete! n autoloads-in-progress)))))
- ;;; {Run-time options}
- ;;;
- (define-syntax define-option-interface
- (syntax-rules ()
- ((_ (interface (options enable disable) (option-set!)))
- (begin
- (define options
- (case-lambda
- (() (interface))
- ((arg)
- (if (list? arg)
- (begin (interface arg) (interface))
- (for-each
- (lambda (option)
- (apply (lambda (name value documentation)
- (display name)
- (let ((len (string-length (symbol->string name))))
- (when (< len 16)
- (display #\tab)
- (when (< len 8)
- (display #\tab))))
- (display #\tab)
- (display value)
- (display #\tab)
- (display documentation)
- (newline))
- option))
- (interface #t))))))
- (define (enable . flags)
- (interface (append flags (interface)))
- (interface))
- (define (disable . flags)
- (let ((options (interface)))
- (for-each (lambda (flag) (set! options (delq! flag options)))
- flags)
- (interface options)
- (interface)))
- (define-syntax-rule (option-set! opt val)
- (eval-when (expand load eval)
- (options (append (options) (list 'opt val)))))))))
- (define-option-interface
- (debug-options-interface
- (debug-options debug-enable debug-disable)
- (debug-set!)))
- (define-option-interface
- (read-options-interface
- (read-options read-enable read-disable)
- (read-set!)))
- (define-option-interface
- (print-options-interface
- (print-options print-enable print-disable)
- (print-set!)))
- ;;; {The Unspecified Value}
- ;;;
- ;;; Currently Guile represents unspecified values via one particular value,
- ;;; which may be obtained by evaluating (if #f #f). It would be nice in the
- ;;; future if we could replace this with a return of 0 values, though.
- ;;;
- (define-syntax *unspecified*
- (identifier-syntax (if #f #f)))
- (define (unspecified? v) (eq? v *unspecified*))
- ;;; {Running Repls}
- ;;;
- (define *repl-stack* (make-fluid '()))
- ;; Programs can call `batch-mode?' to see if they are running as part of a
- ;; script or if they are running interactively. REPL implementations ensure that
- ;; `batch-mode?' returns #f during their extent.
- ;;
- (define (batch-mode?)
- (null? (fluid-ref *repl-stack*)))
- ;; Programs can re-enter batch mode, for example after a fork, by calling
- ;; `ensure-batch-mode!'. It's not a great interface, though; it would be better
- ;; to abort to the outermost prompt, and call a thunk there.
- ;;
- (define (ensure-batch-mode!)
- (set! batch-mode? (lambda () #t)))
- (define (quit . args)
- (apply throw 'quit args))
- (define exit quit)
- (define (gc-run-time)
- (cdr (assq 'gc-time-taken (gc-stats))))
- (define abort-hook (make-hook))
- (define before-error-hook (make-hook))
- (define after-error-hook (make-hook))
- (define before-backtrace-hook (make-hook))
- (define after-backtrace-hook (make-hook))
- (define before-read-hook (make-hook))
- (define after-read-hook (make-hook))
- (define before-eval-hook (make-hook 1))
- (define after-eval-hook (make-hook 1))
- (define before-print-hook (make-hook 1))
- (define after-print-hook (make-hook 1))
- ;;; This hook is run at the very end of an interactive session.
- ;;;
- (define exit-hook (make-hook))
- ;;; The default repl-reader function. We may override this if we've
- ;;; the readline library.
- (define repl-reader
- (lambda* (prompt #:optional (reader (fluid-ref current-reader)))
- (if (not (char-ready?))
- (begin
- (display (if (string? prompt) prompt (prompt)))
- ;; An interesting situation. The printer resets the column to
- ;; 0 by printing a newline, but we then advance it by printing
- ;; the prompt. However the port-column of the output port
- ;; does not typically correspond with the actual column on the
- ;; screen, because the input is echoed back! Since the
- ;; input is line-buffered and thus ends with a newline, the
- ;; output will really start on column zero. So, here we zero
- ;; it out. See bug 9664.
- ;;
- ;; Note that for similar reasons, the output-line will not
- ;; reflect the actual line on the screen. But given the
- ;; possibility of multiline input, the fix is not as
- ;; straightforward, so we don't bother.
- ;;
- ;; Also note that the readline implementation papers over
- ;; these concerns, because it's readline itself printing the
- ;; prompt, and not Guile.
- (set-port-column! (current-output-port) 0)))
- (force-output)
- (run-hook before-read-hook)
- ((or reader read) (current-input-port))))
- ;;; {While}
- ;;;
- ;;; with `continue' and `break'.
- ;;;
- ;; The inliner will remove the prompts at compile-time if it finds that
- ;; `continue' or `break' are not used.
- ;;
- (define-syntax while
- (lambda (x)
- (syntax-case x ()
- ((while cond body ...)
- #`(let ((break-tag (make-prompt-tag "break"))
- (continue-tag (make-prompt-tag "continue")))
- (call-with-prompt
- break-tag
- (lambda ()
- (define-syntax #,(datum->syntax #'while 'break)
- (lambda (x)
- (syntax-case x ()
- ((_ arg (... ...))
- #'(abort-to-prompt break-tag arg (... ...)))
- (_
- #'(lambda args
- (apply abort-to-prompt break-tag args))))))
- (let lp ()
- (call-with-prompt
- continue-tag
- (lambda ()
- (define-syntax #,(datum->syntax #'while 'continue)
- (lambda (x)
- (syntax-case x ()
- ((_)
- #'(abort-to-prompt continue-tag))
- ((_ . args)
- (syntax-violation 'continue "too many arguments" x))
- (_
- #'(lambda ()
- (abort-to-prompt continue-tag))))))
- (do () ((not cond) #f) body ...))
- (lambda (k) (lp)))))
- (lambda (k . args)
- (if (null? args)
- #t
- (apply values args)))))))))
- ;;; {Module System Macros}
- ;;;
- ;; Return a list of expressions that evaluate to the appropriate
- ;; arguments for resolve-interface according to SPEC.
- (eval-when (expand)
- (if (memq 'prefix (read-options))
- (error "boot-9 must be compiled with #:kw, not :kw")))
- (define (keyword-like-symbol->keyword sym)
- (symbol->keyword (string->symbol (substring (symbol->string sym) 1))))
- (define-syntax define-module
- (lambda (x)
- (define (keyword-like? stx)
- (let ((dat (syntax->datum stx)))
- (and (symbol? dat)
- (eqv? (string-ref (symbol->string dat) 0) #\:))))
- (define (->keyword sym)
- (symbol->keyword (string->symbol (substring (symbol->string sym) 1))))
- (define (parse-iface args)
- (let loop ((in args) (out '()))
- (syntax-case in ()
- (() (reverse! out))
- ;; The user wanted #:foo, but wrote :foo. Fix it.
- ((sym . in) (keyword-like? #'sym)
- (loop #`(#,(->keyword (syntax->datum #'sym)) . in) out))
- ((kw . in) (not (keyword? (syntax->datum #'kw)))
- (syntax-violation 'define-module "expected keyword arg" x #'kw))
- ((#:renamer renamer . in)
- (loop #'in (cons* #',renamer #:renamer out)))
- ((kw val . in)
- (loop #'in (cons* #'val #'kw out))))))
- (define (parse args imp exp rex rep rxp aut dec)
- ;; Just quote everything except #:use-module and #:use-syntax. We
- ;; need to know about all arguments regardless since we want to turn
- ;; symbols that look like keywords into real keywords, and the
- ;; keyword args in a define-module form are not regular
- ;; (i.e. no-backtrace doesn't take a value).
- (syntax-case args ()
- (()
- (let ((imp (if (null? imp) '() #`(#:imports `#,imp)))
- (exp (if (null? exp) '() #`(#:exports '#,exp)))
- (rex (if (null? rex) '() #`(#:re-exports '#,rex)))
- (rep (if (null? rep) '() #`(#:replacements '#,rep)))
- (rxp (if (null? rxp) '() #`(#:re-export-replacements '#,rxp)))
- (aut (if (null? aut) '() #`(#:autoloads '#,aut)))
- (dec (if dec '() #`(#:declarative?
- #,(user-modules-declarative?)))))
- #`(#,@imp #,@exp #,@rex #,@rep #,@rxp #,@aut #,@dec)))
- ;; The user wanted #:foo, but wrote :foo. Fix it.
- ((sym . args) (keyword-like? #'sym)
- (parse #`(#,(->keyword (syntax->datum #'sym)) . args)
- imp exp rex rep rxp aut dec))
- ((kw . args) (not (keyword? (syntax->datum #'kw)))
- (syntax-violation 'define-module "expected keyword arg" x #'kw))
- ((#:no-backtrace . args)
- ;; Ignore this one.
- (parse #'args imp exp rex rep rxp aut dec))
- ((#:pure . args)
- #`(#:pure #t . #,(parse #'args imp exp rex rep rxp aut dec)))
- ((kw)
- (syntax-violation 'define-module "keyword arg without value" x #'kw))
- ((#:version (v ...) . args)
- #`(#:version '(v ...) . #,(parse #'args imp exp rex rep rxp aut dec)))
- ((#:duplicates (d ...) . args)
- #`(#:duplicates '(d ...) . #,(parse #'args imp exp rex rep rxp aut dec)))
- ((#:filename f . args)
- #`(#:filename 'f . #,(parse #'args imp exp rex rep rxp aut dec)))
- ((#:declarative? d . args)
- #`(#:declarative? 'd . #,(parse #'args imp exp rex rep rxp aut #t)))
- ((#:use-module (name name* ...) . args)
- (and (and-map symbol? (syntax->datum #'(name name* ...))))
- (parse #'args #`(#,@imp ((name name* ...))) exp rex rep rxp aut dec))
- ((#:use-syntax (name name* ...) . args)
- (and (and-map symbol? (syntax->datum #'(name name* ...))))
- #`(#:transformer '(name name* ...)
- . #,(parse #'args #`(#,@imp ((name name* ...))) exp rex
- rep rxp aut dec)))
- ((#:use-module ((name name* ...) arg ...) . args)
- (and (and-map symbol? (syntax->datum #'(name name* ...))))
- (parse #'args
- #`(#,@imp ((name name* ...) #,@(parse-iface #'(arg ...))))
- exp rex rep rxp aut dec))
- ((#:export (ex ...) . args)
- (parse #'args imp #`(#,@exp ex ...) rex rep rxp aut dec))
- ((#:export-syntax (ex ...) . args)
- (parse #'args imp #`(#,@exp ex ...) rex rep rxp aut dec))
- ((#:re-export (re ...) . args)
- (parse #'args imp exp #`(#,@rex re ...) rep rxp aut dec))
- ((#:re-export-syntax (re ...) . args)
- (parse #'args imp exp #`(#,@rex re ...) rep rxp aut dec))
- ((#:replace (r ...) . args)
- (parse #'args imp exp rex #`(#,@rep r ...) rxp aut dec))
- ((#:replace-syntax (r ...) . args)
- (parse #'args imp exp rex #`(#,@rep r ...) rxp aut dec))
- ((#:re-export-and-replace (r ...) . args)
- (parse #'args imp exp rex rep #`(#,@rxp r ...) aut dec))
- ((#:autoload name bindings . args)
- (parse #'args imp exp rex rep rxp #`(#,@aut name bindings) dec))
- ((kw val . args)
- (syntax-violation 'define-module "unknown keyword or bad argument"
- #'kw #'val))))
- (syntax-case x ()
- ((_ (name name* ...) arg ...)
- (and-map symbol? (syntax->datum #'(name name* ...)))
- (with-syntax (((quoted-arg ...)
- (parse #'(arg ...) '() '() '() '() '() '() #f))
- ;; Ideally the filename is either a string or #f;
- ;; this hack is to work around a case in which
- ;; port-filename returns a symbol (`socket') for
- ;; sockets.
- (filename (let ((f (assq-ref (or (syntax-source x) '())
- 'filename)))
- (and (string? f) f))))
- #'(eval-when (expand load eval)
- (let ((m (define-module* '(name name* ...)
- #:filename filename quoted-arg ...)))
- (set-current-module m)
- m)))))))
- ;; The guts of the use-modules macro. Add the interfaces of the named
- ;; modules to the use-list of the current module, in order.
- ;; This function is called by "modules.c". If you change it, be sure
- ;; to change scm_c_use_module as well.
- (define (process-use-modules module-interface-args)
- (let ((interfaces (map (lambda (mif-args)
- (or (apply resolve-interface mif-args)
- (error "no such module" mif-args)))
- module-interface-args)))
- (call-with-deferred-observers
- (lambda ()
- (module-use-interfaces! (current-module) interfaces)))))
- (define-syntax use-modules
- (lambda (x)
- (define (keyword-like? stx)
- (let ((dat (syntax->datum stx)))
- (and (symbol? dat)
- (eqv? (string-ref (symbol->string dat) 0) #\:))))
- (define (->keyword sym)
- (symbol->keyword (string->symbol (substring (symbol->string sym) 1))))
- (define (quotify-iface args)
- (let loop ((in args) (out '()))
- (syntax-case in ()
- (() (reverse! out))
- ;; The user wanted #:foo, but wrote :foo. Fix it.
- ((sym . in) (keyword-like? #'sym)
- (loop #`(#,(->keyword (syntax->datum #'sym)) . in) out))
- ((kw . in) (not (keyword? (syntax->datum #'kw)))
- (syntax-violation 'define-module "expected keyword arg" x #'kw))
- ((#:renamer renamer . in)
- (loop #'in (cons* #'renamer #:renamer out)))
- ((kw val . in)
- (loop #'in (cons* #''val #'kw out))))))
- (define (quotify specs)
- (let lp ((in specs) (out '()))
- (syntax-case in ()
- (() (reverse out))
- (((name name* ...) . in)
- (and-map symbol? (syntax->datum #'(name name* ...)))
- (lp #'in (cons #''((name name* ...)) out)))
- ((((name name* ...) arg ...) . in)
- (and-map symbol? (syntax->datum #'(name name* ...)))
- (with-syntax (((quoted-arg ...) (quotify-iface #'(arg ...))))
- (lp #'in (cons #`(list '(name name* ...) quoted-arg ...)
- out)))))))
- (syntax-case x ()
- ((_ spec ...)
- (with-syntax (((quoted-args ...) (quotify #'(spec ...))))
- #'(eval-when (expand load eval)
- (process-use-modules (list quoted-args ...))
- *unspecified*))))))
- ;;; This is defined early because ice-9/r7rs-libraries makes use of
- ;;; the R7RS features, which requires it to be defined.
- (define %cond-expand-features
- ;; This should contain only features that are present in core Guile,
- ;; before loading any modules. Modular features are handled by
- ;; placing 'cond-expand-provide' in the relevant module.
- '(guile
- guile-2
- guile-2.2
- guile-3
- guile-3.0
- r5rs
- r6rs
- r7rs
- exact-closed ieee-float full-unicode ratios ;; R7RS features.
- srfi-0 ;; cond-expand itself
- srfi-4 ;; homogeneous numeric vectors
- srfi-6 ;; string ports
- srfi-13 ;; string library
- srfi-14 ;; character sets
- srfi-16 ;; case-lambda
- srfi-23 ;; `error` procedure
- srfi-30 ;; nested multi-line comments
- srfi-39 ;; parameterize
- srfi-46 ;; basic syntax-rules extensions
- srfi-55 ;; require-extension
- srfi-61 ;; general cond clause
- srfi-62 ;; s-expression comments
- srfi-87 ;; => in case clauses
- srfi-105 ;; curly infix expressions
- ))
- (include-from-path "ice-9/r6rs-libraries")
- (include-from-path "ice-9/r7rs-libraries")
- (define-syntax-rule (define-private foo bar)
- (define foo bar))
- (define-syntax define-public
- (syntax-rules ()
- ((_ (name . args) . body)
- (begin
- (define (name . args) . body)
- (export name)))
- ((_ name val)
- (begin
- (define name val)
- (export name)))))
- (define-syntax-rule (defmacro-public name args body ...)
- (begin
- (defmacro name args body ...)
- (export-syntax name)))
- ;; And now for the most important macro.
- (define-syntax-rule (λ formals body ...)
- (lambda formals body ...))
- ;; This function is called from "modules.c". If you change it, be
- ;; sure to update "modules.c" as well.
- (define* (module-export! m names #:key replace?)
- "Export a local variable."
- (let ((public-i (module-public-interface m)))
- (for-each (lambda (name)
- (let* ((internal-name (if (pair? name) (car name) name))
- (external-name (if (pair? name) (cdr name) name))
- (var (module-ensure-local-variable! m internal-name)))
- (when replace?
- (hashq-set! (module-replacements public-i) external-name #t))
- (module-add! public-i external-name var)))
- names)))
- (define (module-replace! m names)
- (module-export! m names #:replace? #t))
- (define (module-export-all! mod)
- "Export all local variables from a module."
- (define (fresh-interface!)
- (let ((iface (make-module)))
- (set-module-name! iface (module-name mod))
- (set-module-version! iface (module-version mod))
- (set-module-kind! iface 'interface)
- (set-module-public-interface! mod iface)
- iface))
- (let ((iface (or (module-public-interface mod)
- (fresh-interface!))))
- (set-module-obarray! iface (module-obarray mod))))
- (define* (module-re-export! m names #:key replace?)
- "Re-export an imported variable."
- (let ((public-i (module-public-interface m)))
- (for-each
- (lambda (name)
- (let* ((internal-name (if (pair? name) (car name) name))
- (external-name (if (pair? name) (cdr name) name))
- (var (module-variable m internal-name)))
- (cond
- ((not var)
- (error "Undefined variable:" internal-name))
- ((eq? var (module-local-variable m internal-name))
- (error "re-exporting local variable:" internal-name))
- (else
- (when replace?
- (hashq-set! (module-replacements public-i) external-name #t))
- (module-add! public-i external-name var)))))
- names)))
- (define-syntax-rule (export name ...)
- (eval-when (expand load eval)
- (call-with-deferred-observers
- (lambda ()
- (module-export! (current-module) '(name ...))))))
- (define-syntax-rule (re-export name ...)
- (eval-when (expand load eval)
- (call-with-deferred-observers
- (lambda ()
- (module-re-export! (current-module) '(name ...))))))
- (define-syntax-rule (export! name ...)
- (eval-when (expand load eval)
- (call-with-deferred-observers
- (lambda ()
- (module-replace! (current-module) '(name ...))))))
- (define-syntax-rule (export-syntax name ...)
- (export name ...))
- (define-syntax-rule (re-export-syntax name ...)
- (re-export name ...))
- ;;; {Parameters}
- ;;;
- (define* (make-mutable-parameter init #:optional (converter identity))
- (let ((fluid (make-fluid (converter init))))
- (case-lambda
- (() (fluid-ref fluid))
- ((val) (fluid-set! fluid (converter val))))))
- ;;; {Handling of duplicate imported bindings}
- ;;;
- ;; Duplicate handlers take the following arguments:
- ;;
- ;; module importing module
- ;; name conflicting name
- ;; int1 old interface where name occurs
- ;; val1 value of binding in old interface
- ;; int2 new interface where name occurs
- ;; val2 value of binding in new interface
- ;; var previous resolution or #f
- ;; val value of previous resolution
- ;;
- ;; A duplicate handler can take three alternative actions:
- ;;
- ;; 1. return #f => leave responsibility to next handler
- ;; 2. exit with an error
- ;; 3. return a variable resolving the conflict
- ;;
- (define duplicate-handlers
- (let ((m (make-module)))
- (define (check module name int1 val1 int2 val2 var val)
- (scm-error 'misc-error
- #f
- "~A: `~A' imported from both ~A and ~A"
- (list (module-name module)
- name
- (module-name int1)
- (module-name int2))
- #f))
- (define (warn module name int1 val1 int2 val2 var val)
- (format (current-warning-port)
- "WARNING: ~A: `~A' imported from both ~A and ~A\n"
- (module-name module)
- name
- (module-name int1)
- (module-name int2))
- #f)
- (define (replace module name int1 val1 int2 val2 var val)
- (let* ((replace1 (hashq-ref (module-replacements int1) name))
- (replace2 (hashq-ref (module-replacements int2) name))
- (old (or (and replace1 var)
- (module-variable int1 name)))
- (new (module-variable int2 name)))
- (if replace1
- (and (or (eq? old new) (not replace2))
- old)
- (and replace2 new))))
- (define (warn-override-core module name int1 val1 int2 val2 var val)
- (and (eq? int1 the-scm-module)
- (begin
- (format (current-warning-port)
- "WARNING: ~A: imported module ~A overrides core binding `~A'\n"
- (module-name module)
- (module-name int2)
- name)
- (module-variable int2 name))))
- (define (first module name int1 val1 int2 val2 var val)
- (or var (module-variable int1 name)))
- (define (last module name int1 val1 int2 val2 var val)
- (module-variable int2 name))
- (define (noop module name int1 val1 int2 val2 var val)
- #f)
- (set-module-name! m 'duplicate-handlers)
- (set-module-kind! m 'interface)
- (module-define! m 'check check)
- (module-define! m 'warn warn)
- (module-define! m 'replace replace)
- (module-define! m 'warn-override-core warn-override-core)
- (module-define! m 'first first)
- (module-define! m 'last last)
- (module-define! m 'merge-generics noop)
- (module-define! m 'merge-accessors noop)
- m))
- (define (lookup-duplicates-handlers handler-names)
- (and handler-names
- (map (lambda (handler-name)
- (or (module-symbol-local-binding
- duplicate-handlers handler-name #f)
- (error "invalid duplicate handler name:"
- handler-name)))
- (if (list? handler-names)
- handler-names
- (list handler-names)))))
- (define default-duplicate-binding-procedures
- (case-lambda
- (()
- (or (module-duplicates-handlers (current-module))
- ;; Note: If you change this default, change it also in
- ;; `define-module*'.
- (lookup-duplicates-handlers
- '(replace warn-override-core warn last))))
- ((procs)
- (set-module-duplicates-handlers! (current-module) procs))))
- (define default-duplicate-binding-handler
- (case-lambda
- (()
- (map procedure-name (default-duplicate-binding-procedures)))
- ((handlers)
- (default-duplicate-binding-procedures
- (lookup-duplicates-handlers handlers)))))
- ;;; {`load'.}
- ;;;
- ;;; Load is tricky when combined with relative file names, compilation,
- ;;; and the file system. If a file name is relative, what is it
- ;;; relative to? The name of the source file at the time it was
- ;;; compiled? The name of the compiled file? What if both or either
- ;;; were installed? And how do you get that information? Tricky, I
- ;;; say.
- ;;;
- ;;; To get around all of this, we're going to do something nasty, and
- ;;; turn `load' into a macro. That way it can know the name of the
- ;;; source file with respect to which it was invoked, so it can resolve
- ;;; relative file names with respect to the original source file.
- ;;;
- ;;; There is an exception, and that is that if the source file was in
- ;;; the load path when it was compiled, instead of looking up against
- ;;; the absolute source location, we load-from-path against the relative
- ;;; source location.
- ;;;
- (define %auto-compilation-options
- ;; Default `compile-file' option when auto-compiling.
- '(#:warnings (shadowed-toplevel use-before-definition arity-mismatch
- format duplicate-case-datum bad-case-datum
- non-idempotent-definition)))
- (define* (load-in-vicinity dir file-name #:optional reader)
- "Load source file FILE-NAME in vicinity of directory DIR. Use a
- pre-compiled version of FILE-NAME when available, and auto-compile one
- when none is available, reading FILE-NAME with READER."
- ;; The auto-compilation code will residualize a .go file in the cache
- ;; dir: by default, $HOME/.cache/guile/2.0/ccache/PATH.go. This
- ;; function determines the PATH to use as a key into the compilation
- ;; cache.
- (define (canonical->suffix canon)
- (cond
- ((and (not (string-null? canon))
- (file-name-separator? (string-ref canon 0)))
- canon)
- ((and (eq? (system-file-name-convention) 'windows)
- (absolute-file-name? canon))
- ;; An absolute file name that doesn't start with a separator
- ;; starts with a drive component. Transform the drive component
- ;; to a file name element: c:\foo -> \c\foo.
- (string-append file-name-separator-string
- (substring canon 0 1)
- (substring canon 2)))
- (else canon)))
- (define compiled-extension
- ;; File name extension of compiled files.
- (cond ((or (null? %load-compiled-extensions)
- (string-null? (car %load-compiled-extensions)))
- (warn "invalid %load-compiled-extensions"
- %load-compiled-extensions)
- ".go")
- (else (car %load-compiled-extensions))))
- (define (more-recent? stat1 stat2)
- ;; Return #t when STAT1 has an mtime greater than that of STAT2.
- (or (> (stat:mtime stat1) (stat:mtime stat2))
- (and (= (stat:mtime stat1) (stat:mtime stat2))
- (>= (stat:mtimensec stat1)
- (stat:mtimensec stat2)))))
- (define (fallback-file-name canon-file-name)
- ;; Return the in-cache compiled file name for source file
- ;; CANON-FILE-NAME.
- ;; FIXME: would probably be better just to append
- ;; SHA1(canon-file-name) to the %compile-fallback-path, to avoid
- ;; deep directory stats.
- (and %compile-fallback-path
- (string-append %compile-fallback-path
- (canonical->suffix canon-file-name)
- compiled-extension)))
- (define (compile file)
- ;; Compile source FILE, lazily loading the compiler.
- ((module-ref (resolve-interface '(system base compile))
- 'compile-file)
- file
- #:opts %auto-compilation-options
- #:env (current-module)))
- (define (load-thunk-from-file file)
- (let ((loader (resolve-interface '(system vm loader))))
- ((module-ref loader 'load-thunk-from-file) file)))
- ;; Returns a thunk loaded from the .go file corresponding to `name'.
- ;; Does not search load paths, only the fallback path. If the .go
- ;; file is missing or out of date, and auto-compilation is enabled,
- ;; will try auto-compilation, just as primitive-load-path does
- ;; internally. primitive-load is unaffected. Returns #f if
- ;; auto-compilation failed or was disabled.
- ;;
- ;; NB: Unless we need to compile the file, this function should not
- ;; cause (system base compile) to be loaded up. For that reason
- ;; compiled-file-name partially duplicates functionality from (system
- ;; base compile).
- (define (fresh-compiled-thunk name scmstat go-file-name)
- ;; Return GO-FILE-NAME after making sure that it contains a freshly
- ;; compiled version of source file NAME with stat SCMSTAT; return #f
- ;; on failure.
- (false-if-exception
- (let ((gostat (and (not %fresh-auto-compile)
- (stat go-file-name #f))))
- (if (and gostat (more-recent? gostat scmstat))
- (load-thunk-from-file go-file-name)
- (begin
- (when gostat
- (format (current-warning-port)
- ";;; note: source file ~a\n;;; newer than compiled ~a\n"
- name go-file-name))
- (cond
- (%load-should-auto-compile
- (%warn-auto-compilation-enabled)
- (format (current-warning-port) ";;; compiling ~a\n" name)
- (let ((cfn (compile name)))
- (format (current-warning-port) ";;; compiled ~a\n" cfn)
- (load-thunk-from-file cfn)))
- (else #f)))))
- #:warning "WARNING: compilation of ~a failed:\n" name))
- (define (sans-extension file)
- (let ((dot (string-rindex file #\.)))
- (if dot
- (substring file 0 dot)
- file)))
- (define (load-absolute abs-file-name)
- ;; Load from ABS-FILE-NAME, using a compiled file or auto-compiling
- ;; if needed.
- (define scmstat
- (false-if-exception
- (stat abs-file-name)
- #:warning "Stat of ~a failed:\n" abs-file-name))
- (define (pre-compiled)
- (or-map
- (lambda (dir)
- (or-map
- (lambda (ext)
- (let ((candidate (string-append (in-vicinity dir file-name) ext)))
- (let ((gostat (stat candidate #f)))
- (and gostat
- (more-recent? gostat scmstat)
- (false-if-exception
- (load-thunk-from-file candidate)
- #:warning "WARNING: failed to load compiled file ~a:\n"
- candidate)))))
- %load-compiled-extensions))
- %load-compiled-path))
- (define (fallback)
- (and=> (false-if-exception (canonicalize-path abs-file-name))
- (lambda (canon)
- (and=> (fallback-file-name canon)
- (lambda (go-file-name)
- (fresh-compiled-thunk abs-file-name
- scmstat
- go-file-name))))))
- (let ((compiled (and scmstat (or (pre-compiled) (fallback)))))
- (if compiled
- (begin
- (if %load-hook
- (%load-hook abs-file-name))
- (compiled))
- (start-stack 'load-stack
- (primitive-load abs-file-name)))))
- (save-module-excursion
- (lambda ()
- (with-fluids ((current-reader reader)
- (%file-port-name-canonicalization 'relative))
- (cond
- ((absolute-file-name? file-name)
- (load-absolute file-name))
- ((absolute-file-name? dir)
- (load-absolute (in-vicinity dir file-name)))
- (else
- (load-from-path (in-vicinity dir file-name))))))))
- (define-syntax load
- (make-variable-transformer
- (lambda (x)
- (let* ((src (syntax-source x))
- (file (and src (assq-ref src 'filename)))
- (dir (and (string? file) (dirname file))))
- ;; A module that uses `load' is not declarative.
- (when (module-declarative? (current-module))
- (format (current-warning-port)
- "WARNING: Use of `load' in declarative module ~A. ~A\n"
- (module-name (current-module))
- "Add #:declarative? #f to your define-module invocation.")
- (set-module-declarative?! (current-module) #f))
- (syntax-case x ()
- ((_ arg ...)
- #`(load-in-vicinity #,(or dir #'(getcwd)) arg ...))
- (id
- (identifier? #'id)
- #`(lambda args
- (apply load-in-vicinity #,(or dir #'(getcwd)) args))))))))
- ;;; {`cond-expand' for SRFI-0 support.}
- ;;;
- ;;; This syntactic form expands into different commands or
- ;;; definitions, depending on the features provided by the Scheme
- ;;; implementation.
- ;;;
- ;;; Syntax:
- ;;;
- ;;; <cond-expand>
- ;;; --> (cond-expand <cond-expand-clause>+)
- ;;; | (cond-expand <cond-expand-clause>* (else <command-or-definition>))
- ;;; <cond-expand-clause>
- ;;; --> (<feature-requirement> <command-or-definition>*)
- ;;; <feature-requirement>
- ;;; --> <feature-identifier>
- ;;; | (and <feature-requirement>*)
- ;;; | (or <feature-requirement>*)
- ;;; | (not <feature-requirement>)
- ;;; <feature-identifier>
- ;;; --> <a symbol which is the name or alias of a SRFI>
- ;;;
- ;;; Additionally, this implementation provides the
- ;;; <feature-identifier>s `guile' and `r5rs', so that programs can
- ;;; determine the implementation type and the supported standard.
- ;;;
- ;;; Remember to update the features list when adding more SRFIs.
- ;;;
- ;; This table maps module public interfaces to the list of features.
- ;;
- (define %cond-expand-table (make-hash-table))
- ;; Add one or more features to the `cond-expand' feature list of the
- ;; module `module'.
- ;;
- (define (cond-expand-provide module features)
- (let ((mod (module-public-interface module)))
- (and mod
- (hashq-set! %cond-expand-table mod
- (append (hashq-ref %cond-expand-table mod '())
- features)))))
- (define-syntax cond-expand
- (lambda (x)
- (define (module-has-feature? mod sym)
- (or-map (lambda (mod)
- (memq sym (hashq-ref %cond-expand-table mod '())))
- (module-uses mod)))
- (define (condition-matches? condition)
- (syntax-case condition (and or not)
- ((and c ...)
- (and-map condition-matches? #'(c ...)))
- ((or c ...)
- (or-map condition-matches? #'(c ...)))
- ((not c)
- (if (condition-matches? #'c) #f #t))
- (c
- (identifier? #'c)
- (let ((sym (syntax->datum #'c)))
- (if (memq sym %cond-expand-features)
- #t
- (module-has-feature? (current-module) sym))))))
- (define (match clauses alternate)
- (syntax-case clauses ()
- (((condition form ...) . rest)
- (if (condition-matches? #'condition)
- #'(begin form ...)
- (match #'rest alternate)))
- (() (alternate))))
- (syntax-case x (else)
- ((_ clause ... (else form ...))
- (match #'(clause ...)
- (lambda ()
- #'(begin form ...))))
- ((_ clause ...)
- (match #'(clause ...)
- (lambda ()
- (syntax-violation 'cond-expand "unfulfilled cond-expand" x)))))))
- ;; This procedure gets called from the startup code with a list of
- ;; numbers, which are the numbers of the SRFIs to be loaded on startup.
- ;;
- (define (use-srfis srfis)
- (process-use-modules
- (map (lambda (num)
- (list (list 'srfi (string->symbol
- (string-append "srfi-" (number->string num))))))
- srfis)))
- ;;; srfi-55: require-extension
- ;;;
- (define-syntax require-extension
- (lambda (x)
- (syntax-case x (srfi)
- ((_ (srfi n ...))
- (and-map integer? (syntax->datum #'(n ...)))
- (with-syntax
- (((srfi-n ...)
- (map (lambda (n)
- (datum->syntax x (symbol-append 'srfi- n)))
- (map string->symbol
- (map number->string (syntax->datum #'(n ...)))))))
- #'(use-modules (srfi srfi-n) ...)))
- ((_ (type arg ...))
- (identifier? #'type)
- (syntax-violation 'require-extension "Not a recognized extension type"
- x)))))
- ;;; Defining transparently inlinable procedures
- ;;;
- (define-syntax define-inlinable
- ;; Define a macro and a procedure such that direct calls are inlined, via
- ;; the macro expansion, whereas references in non-call contexts refer to
- ;; the procedure. Inspired by the `define-integrable' macro by Dybvig et al.
- (lambda (x)
- ;; Use a space in the prefix to avoid potential -Wunused-toplevel
- ;; warning
- (define prefix (string->symbol "% "))
- (define (make-procedure-name name)
- (datum->syntax name
- (symbol-append prefix (syntax->datum name)
- '-procedure)))
- (syntax-case x ()
- ((_ (name formals ...) body0 body ...)
- (identifier? #'name)
- (with-syntax ((proc-name (make-procedure-name #'name))
- ((args ...) (generate-temporaries #'(formals ...))))
- #`(begin
- (define (proc-name formals ...)
- #((maybe-unused))
- (syntax-parameterize ((name (identifier-syntax proc-name)))
- body0 body ...))
- (define-syntax-parameter name
- (lambda (x)
- (syntax-case x ()
- ((_ args ...)
- #'((syntax-parameterize ((name (identifier-syntax proc-name)))
- (lambda (formals ...)
- body0 body ...))
- args ...))
- ((_ a (... ...))
- (syntax-violation 'name "Wrong number of arguments" x))
- (_
- (identifier? x)
- #'proc-name))))))))))
- (define using-readline?
- (let ((using-readline? (make-fluid)))
- (make-procedure-with-setter
- (lambda () (fluid-ref using-readline?))
- (lambda (v) (fluid-set! using-readline? v)))))
- ;;; {R6RS and R7RS}
- ;;;
- (define (install-r6rs!)
- "Make changes to the default environment to better conform to the
- R6RS. @xref{R6RS Incompatibilities} in the manual."
- (set! %load-extensions
- (cons* ".guile.sls" ".sls"
- (delete ".guile.sls" (delete ".sls" %load-extensions))))
- (read-enable 'r6rs-hex-escapes)
- (read-enable 'hungry-eol-escapes))
- (define (install-r7rs!)
- "Make changes to the default environment to better conform to the
- R7RS."
- (install-r6rs!)
- (set! %load-extensions
- (cons* ".guile.sld" ".sld"
- (delete ".guile.sld" (delete ".sld" (delete ".guile.sls" (delete ".sls" %load-extensions))))))
- (read-enable 'r7rs-symbols))
- ;;; {Deprecated stuff}
- ;;;
- (begin-deprecated
- (module-use! the-scm-module (resolve-interface '(ice-9 deprecated))))
- ;;; {Ports}
- ;;;
- ;; Allow code in (guile) to use port bindings.
- (module-use! the-root-module (resolve-interface '(ice-9 ports)))
- ;; Allow users of (guile) to see port bindings.
- (module-use! the-scm-module (resolve-interface '(ice-9 ports)))
- ;;; {`read' implementation in Scheme.}
- ;;;
- ;;;
- (call-with-values (lambda ()
- ;; Capture syntax? binding, later removed from root
- ;; module.
- (let ((syntax? syntax?))
- (include-from-path "ice-9/read.scm")
- (values read read-syntax)))
- (lambda (read* read-syntax*)
- (set! read read*)
- (set! read-syntax read-syntax*)))
- ;;; {Threads}
- ;;;
- ;; Load (ice-9 threads), initializing some internal data structures.
- (resolve-interface '(ice-9 threads))
- ;;; {Exceptions}
- ;;;
- ;; Load (ice-9 exceptions), initializing some internal data structures.
- (resolve-interface '(ice-9 exceptions))
- ;;; SRFI-4 in the default environment. FIXME: we should figure out how
- ;;; to deprecate this.
- ;;;
- ;; FIXME:
- (module-use! the-scm-module (resolve-interface '(srfi srfi-4)))
- ;;; make-soft-port in the default environment. FIXME: Deprecate, make
- ;;; callers import (ice-9 soft-port).
- ;;;
- (define (make-soft-port pv modes)
- ((module-ref (resolve-interface '(ice-9 soft-ports))
- 'deprecated-make-soft-port)
- pv modes))
- ;;; A few identifiers that need to be defined in this file are really
- ;;; internal implementation details. We shove them off into internal
- ;;; modules, removing them from the (guile) module.
- ;;;
- (define-module (system syntax internal))
- (let ()
- (define (steal-bindings! from to ids)
- (for-each
- (lambda (sym)
- (let ((v (module-local-variable from sym)))
- (module-remove! from sym)
- (module-add! to sym v)))
- ids)
- (module-export! to ids))
- (steal-bindings! the-root-module (resolve-module '(system syntax internal))
- '(syntax?
- syntax-local-binding
- %syntax-module
- syntax-locally-bound-identifiers
- syntax-session-id
- make-syntax
- syntax-expression
- syntax-wrap
- syntax-module
- syntax-sourcev)))
- ;;; Place the user in the guile-user module.
- ;;;
- ;; Set filename to #f to prevent reload.
- (define-module (guile-user)
- #:autoload (system base compile) (compile compile-file)
- #:filename #f
- #:declarative? #f)
- ;; Remain in the `(guile)' module at compilation-time so that the
- ;; `-Wunused-toplevel' warning works as expected.
- (eval-when (compile) (set-current-module the-root-module))
- ;;; boot-9.scm ends here
|