www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

remember.scrbl (11150B)


      1 #lang scribble/manual
      2 @require[@for-label[remember
      3                     racket/base]]
      4 
      5 @title{Remember: storage for macros which is persistant across compilations}
      6 @author[@author+email["Suzanne Soy" "racket@suzanne.soy"]]
      7 
      8 @defmodule[remember]
      9 
     10 This library is implemented using literate programming. The
     11 implementation details are presented in 
     12 @other-doc['(lib "remember/remember-implementation.hl.rkt")].
     13 
     14 This module allows macros to remember some values across
     15 compilations. Values are grouped by @racket[_category], so
     16 that multiple macros can use this facility without
     17 interfering with each other. The @racket[_category] is
     18 simply a symbol given when remembering the value.
     19 
     20 The list of all remembered values for a given 
     21 @racket[_category] is returned by @racket[get-remembered],
     22 and it is possible to check if a single value has been
     23 remembered using @racket[remembered?].
     24 
     25 Values are loaded from files using 
     26 @racket[remember-input-file] and @racket[remember-io-file].
     27 An output file can be set with 
     28 @racket[remember-output-file] and 
     29 @racket[remember-io-file].
     30 
     31 When an output file has been declared, new values passed to
     32 @racket[remember-write!] are marked as 
     33 @racket[remembered-or-written?] and appended to that file
     34 (more precisely, the expression 
     35 @racket[(remembered! _category _value)] is appended to the
     36 file, followed by a newline).
     37 
     38 When initially created by the user, the output file should
     39 contain the code below, which will be followed by the
     40 automatically-generated 
     41 @racket[(remembered! _category _value)] statements:
     42 
     43 @codeblock[#:keep-lang-line? #t]|{
     44             #lang racket
     45             (require remember)}|
     46 
     47 The @racket[remembered!] macro indicates an
     48 already-remembered value, and is typically used inside input
     49 files. The @racket[for-syntax] function 
     50 @racket[remembered-add!] can also be used instead, to mark a
     51 value as @racket[remembered?] without adding it to any file
     52 (this can be useful for values which should implicitly be
     53 remembered).
     54 
     55 @defproc[#:kind "for-syntax procedure"
     56          (get-remembered [category symbol?]) list?]{
     57  Returns a list of all values that have been remembered for
     58  the given @racket[category] (i.e. all values passed as the
     59  second argument to @racket[remembered-add!], 
     60  @racket[remember-write!] or @racket[remembered!], with the given
     61  category as the first argument).}
     62 
     63 @defproc[#:kind "for-syntax procedure"
     64          (remembered-add! [category symbol?] [value any/c]) void?]{
     65  Marks the given @racket[value] as remembered in the given 
     66  @racket[category]. If the same value is remembered twice
     67  for the same category, the second occurrence is ignored
     68  (i.e. values are stored in a distinct @racket[set] for each
     69  category).
     70  
     71  This @racket[for-syntax] procedure is called by the 
     72  @racket[remembered!] macro, but can also be executed on its
     73  own.}
     74 
     75 @defproc[#:kind "for-syntax procedure"
     76          (remembered? [category symbol?] [value any/c]) boolean?]{
     77  Checks whether the given @racket[value] has already been
     78  added to the set of remembered values for the given 
     79  @racket[category].}
     80 
     81 @defproc[#:kind "for-syntax procedure"
     82          (remembered-or-written? [category symbol?] [value any/c]) boolean?]{
     83  Checks whether the given @racket[value] has already been
     84  added to the set of remembered values for the given 
     85  @racket[category], or if it was freshly written to a file
     86  during the current expansion.}
     87 
     88 @defproc[#:kind "for-syntax procedure"
     89          (remember-write! [category symbol?] [value any/c]) void?]{
     90  Adds the given @racket[value] to the current 
     91  @racket[remember-output-file] for the given category. More
     92  precisely, the expression 
     93  @racket[(remembered! category value)] is appended to the
     94  file, followed by a newline.
     95  
     96  If the value is already @racket[remembered-or-written?],
     97  then the file is left unchanged, i.e. two or more calls to
     98  @racket[remember-write!] with the same @racket[category]
     99  and @racket[value] will only append an expression to the
    100  file the first time.
    101  
    102  The value is also added to the set of 
    103  @racket[remembered-or-written?] values, so that subsequent
    104  calls to @racket[remembered-or-written?] return 
    105  @racket[#t] for that category and value. Calls to 
    106  @racket[remembered?] will be unaffected, and will still
    107  return @racket[#f]. If some declarations are created by a
    108  library based on the @racket[get-remembered] set, it is
    109  therefore possible to check whether a value was already
    110  present, or if it was added by a subsequent 
    111  @racket[remember-write!].}
    112 
    113 @defproc[#:kind "for-syntax procedure"
    114          (remembered-error! [category symbol] [stx-value syntax?]) void?]{
    115  Produces a delayed error indicating that this value has
    116  not been remembered, but was added to the output file.
    117  
    118  This procedure just triggers the error, and is not
    119  concerned with actually adding the value to the output
    120  file.
    121  
    122  The error is added in a lifted declaration which is
    123  inserted at the end of the current module, using 
    124  @racket[syntax-local-lift-module-end-declaration]. It
    125  should therefore be triggered only when the compilation
    126  reaches the end of the file, if no other error was raised
    127  before.
    128  
    129  This allows as many @racket[remembered-error!] errors as
    130  possible to be accumulated; all of these are then shown
    131  when the file is fully expanded. The goal is to be able to
    132  add all values to the output file in a single run, instead
    133  of aborting after each value which is not remembered. This
    134  would otherwise require recompiling the program once for
    135  each value which is not initially remembered.
    136 
    137  TODO: it would be nice to factor out the delayed error
    138  mechanism into a separate package, so that multiple
    139  libraries can add errors, and all of them get reported,
    140  without one preventing the others from executing. This
    141  function would likely keep the same signature, and just
    142  delegate to the delayed-error library.}
    143 
    144 @defparam[disable-remember-immediate-error disable? boolean? #:value #f]{
    145  The @racket[disable-remember-immediate-error] parameter allows code to
    146  temporarily prevent @racket[remembered-error!] from lifting a delayed error.
    147  This can be useful for example when calling @racket[remembered-error!] from a
    148  context where @racket[(syntax-local-lift-context)] is @racket[#false], e.g.
    149  outside of the expansion of a macro, but within a @racket[begin-for-syntax]
    150  block.
    151 
    152  The error is still put aside, so that if a delayed error was triggered by
    153  another call to @racket[remembered-error!], the error will still be included
    154  with the other delayed errors. If no delayed error is triggered during
    155  macro-expansion, the error that was put aside will be ignored. To prevent
    156  this from happening, call @racket[lift-maybe-delayed-errors] within a context
    157  where lifts are possible.}
    158 
    159 @defproc[(lift-maybe-delayed-errors) void?]{
    160  Uses @racket[syntax-local-lift-module-end-declaration] or
    161  @racket[syntax-local-lift-expression], depending on the context, to lift an
    162  expression which will trigger delayed errors, if any. If no delayed errors
    163  have been recorded by @racket[remembered-error!] when the lifted form is
    164  executed, then nothing will happen and expansion will proceed.
    165 
    166  Note that when @racket[(syntax-transforming-module-expression?)] returns
    167  @racket[#false], @racket[syntax-local-lift-expression] is used. The lifted
    168  form is then run as part of the current expansion pass, before the contents of
    169  any @racket[let] forms are expanded. This means that calls to
    170  @racket[remembered-error!] must not happen within the expansion of nested
    171  @racket[let] forms (with respect to the @racket[let] form being expanded (if
    172  any) when @racket[lift-maybe-delayed-errors] is called), as they would add
    173  delayed errors too late, i.e. after the lifted form got executed.}
    174 
    175 @defform[(remember-input-file name)
    176          #:grammar ([name string?])]{
    177  The file is loaded with @racket[require], but no
    178  identifier is imported from that module. Instead, 
    179  @racket[remembered?] relies on its internal mutable 
    180  @racket[for-syntax] hash table which stores remembered
    181  values associated to their category.
    182  
    183  @racket[remembered-values]. Values are added to the hash
    184  via the @racket[remembered!] macro. The @racket[name] file
    185  should therefore @racket[require] the 
    186  @racketmodname[remember] library, and contain a number of
    187  calls to @racket[remembered!], each adding a new value to
    188  the mutable hash.}
    189 
    190 @deftogether[
    191  (@defform*[((remember-output-file)
    192              (remember-output-file name))
    193            #:grammar ([name (or/c string? false?)])]
    194   @defproc*[#:kind "for-syntax parameter"
    195             #:link-target? #f 
    196             ([(remember-output-file) (or/c string? false?)]
    197              [(remember-output-file [name (or/c string? false?)]) void?])]
    198    )]{
    199  Indicates that new values added via 
    200  @racket[remember-write!] should be appended to the file 
    201  @racket[name]. More precisely, the expression 
    202  @racket[(remembered! _category _value)] is appended to the
    203  file, followed by a newline.
    204  
    205  Note that if the @racket[_value] given to 
    206  @racket[remember-write!] is already registered in an input
    207  file with @racket[remembered!] for the same category, it
    208  will not be appended to the output file.
    209  
    210  For now there can only be one @racket[output] file at the
    211  same time, any call to @racket[remember-output-file]
    212  overrides the setting from previous calls. Future versions
    213  of this library may offer the possibility to specify an
    214  output file per @racket[_category].
    215 
    216  The special value @racket[#f] indicates that there is no
    217  output file, in which case @racket[remember-write!] simply
    218  marks the @racket[value] as 
    219  @racket[remembered-or-written?] for that category, without
    220  altering any file.
    221  
    222  This identifier exists both as a macro and a for-syntax
    223  parameter. When called without any argument, it expands to
    224  (for the macro) or returns (for the for-syntax parameter)
    225  the last value set using either the macro or by passing an
    226  argument to the for-syntax parameter.}
    227 
    228 @defparam[remember-output-file-parameter output-file
    229           (or/c path-string? false?)
    230           #:value #f]{
    231  This for-syntax parameter that new values added via @racket[remember-write!]
    232  should be appended to the file whose name is stored within the parameter.
    233 
    234  The @racket[remember-output-file] macro simply sets this parameter.}
    235 
    236 @defform[(remember-io-file name)
    237          #:grammar ([name string?])]{
    238  Indicates that calls to @racket[remembered!] in this file
    239  should be taken into account, and that new values added
    240  with @racket[remember-write!] should be appended to this
    241  file.
    242  
    243  It is equivalent to:
    244  @racketblock[(remember-input-file name)
    245               (remember-output-file name)]}
    246 
    247 @defform[(remembered! category value)
    248          #:grammar ([category identifier?])]{
    249  Marks the given @racket[value] as remembered in the given 
    250  @racket[category]. If the same value is remembered twice
    251  for the same category, the second occurrence is ignored
    252  (i.e. values are stored in a distinct @racket[set] for each
    253  category).
    254  
    255  Calls to this macro are usually present in an input file
    256  loaded with @racket[remember-input-file] or 
    257  @racket[remember-io-file], but can also be inserted in the
    258  main file or any other file loaded with @racket[require].}