;;;=============================================================================== ;;; ;;; R6RS Macros and R6RS libraries: ;;; ;;; Copyright (c) 2006 Andre van Tonder ;;; ;;; Copyright statement at srfi.schemers.org/srfi-process.html ;;; ;;;=============================================================================== ---------------------------------------------------------------------- TO RUN TESTS : execute macros-test.scm ---------------------------------------------------------------------- Tested on MzScheme and Petite Chez (for the latter, simply change define-struct -> define-record). Uses following non-r5rs properties and constructs: * assumes left-to-right evaluation of internal defines in "let". * interaction-environment eval * define-struct * records generated by define-struct must be disjoint from vectors * parameterize * let-values * pretty-print COMPATIBILITY WITH R6RS: ------------------------ SYNTAX-CASE: * PERMITTED : We use a renaming algorithm instead of the mark-antimark algorithm described in the draft. The difference will not matter for r6rs-conformant macros. * PERMITTED? : A wrapped syntax object is the same as an unwrapped syntax object, and can be directly manipulated using car, cdr, ... without syntax-case deconstruction. Do not do this if you want your macros to be portable. * CORRECTION : R(5.91)RS assigns a lexical-scope-violating semantics to many Scheme expressions. The R(5.91)RS restriction "It is a syntax violation if the keyword that identifies one of the body forms as a definition (derived or core) is redefined by the same definition or a later definition in the same body." is insufficient to avoid giving a semantics that violates lexical scoping to many Scheme expressions. This expander does the following instead: It is a syntax violation if an identifier whose meaning is needed during the left-to-right expansion of definitions is subsequently redefined by a definition in the same body. To detect this error, the expander records each identifier reference occurring during expansion of the body. Before an identifier is bound, its current binding is compared against bindings already referenced for the same (in the sense of bound-identifier=?) identifier during the expansion of the definitions. If a match is found, the binding may have already affected the expansion of the body, and a syntax violation is therefore thrown. For many examples of this issue, see macros-test.scm LIBRARIES: * PERMITTED : The phase semantics is configurable. Currently two options are provided. Both are permitted by r6rs: UNSHARED - Each phase instantiates its own set of bindings. - Visits are distinguished across different phases. - Invocations are distinguished across different phases. - Compatible with PLT Scheme model. SHARED - The value of a binding is shared between those phases into which it is imported. - A visit at any phase is treated as a visit at all phases. - An invoke at any phase is treated as an invoke at all phases. - May be more efficient. * PERMITTED : Expansion of library form is started by removing all library bindings above phase 0. * PERMITTED : A syntax violation is raised if a binding is used outside its declared levels. * PERMITTED : The phases available for an identifier are lexically determined from the identifier's source occurrence. See examples in macros-test.scm * EXTENSION : Negative import levels are allowed. For semantics, see below. For examples, see identifier-syntax in macros-derived.scm and various in macros-test.scm. * EXTENSION : A "primitives" import form is provided for directly importing primitive PROCEDURES (not macros) provided by the host implementation. See macros-derived.scm for example. * TODO : Exceptions are not yet raised if exported variables are set! or if set! variables are indirectly exported SEMANTICS OF NEGATIVE LEVELS: ----------------------------- The implementation allows libraries to be imported at negative meta-level (an extension to the draft). However, when there are no negative level imports in a program, THE SEMANTICS COINCIDES WITH THAT DESCRIBED IN THE R6RS DRAFT. To import a library at level n during expansion: * Import at level (n + k) any library that is imported by this library for (meta k) and that has not yet been imported at level (n + k). * If n >= 0, evaluate all syntax definitions in the library. * If n >= 1, evaluate all variable definitions and expressions in the library. To import a library at level n when a script is invoked: * Import at level (n + k) any library that is imported by this library for (meta k) and that has not yet been imported at level (n + k). * If n = 0, evaluate all variable definitions and expressions in the library. CHANGES SINCE VERSION OF DECEMBER 14, 2006: ------------------------------------------- - removed support for declarations - changed script -> program everywhere - changed add-prefix -> prefix everywhere - dropped the unparenthesized shorthand for library names - changed forall -> for-all everywhere - fenders have been removed from syntax-rules - added "identifier-syntax" to (r6rs base) CHANGES SINCE VERSION OF NOVEMBER 27, 2006: ------------------------------------------- - Corrected implementation and description of invocation semantics and its interaction with negative import levels. CHANGES SINCE VERSION OF NOVEMBER 5, 2006: ------------------------------------------ - Added UNSHARED semantics (see above) as a configurable option. CHANGES SINCE VERSION OF SEPTEMBER 13, 2006: -------------------------------------------- - Added support for scripts. - Quasisyntax now works with unsyntax(-splicing) instead of unquote(-splicing). - Many bug fixes and improvements in code. - Reorganized standard libraries. - Properly avoids defect in R(5.91)RS assigning lexical scope violating semantics to certain expressions. - Implemented library reference syntax.