Remember: storage for macros which is persistant across compilations
(require remember) | package: remember |
This library is implemented using literate programming. The implementation details are presented in Implementation of Remember.
This module allows macros to remember some values across compilations. Values are grouped by category, so that multiple macros can use this facility without interfering with each other. The category is simply a symbol given when remembering the value.
The list of all remembered values for a given category is returned by get-remembered, and it is possible to check if a single value has been remembered using remembered?.
Values are loaded from files using remember-input-file and remember-io-file. An output file can be set with remember-output-file and remember-io-file.
When an output file has been declared, new values passed to remember-write! are marked as remembered-or-written? and appended to that file (more precisely, the expression (remembered! category value) is appended to the file, followed by a newline).
When initially created by the user, the output file should contain the code below, which will be followed by the automatically-generated (remembered! category value) statements:
#lang racket (require remember)
The remembered! macro indicates an already-remembered value, and is typically used inside input files. The for-syntax function remembered-add! can also be used instead, to mark a value as remembered? without adding it to any file (this can be useful for values which should implicitly be remembered).
for-syntax procedure
(get-remembered category) → list?
category : symbol?
for-syntax procedure
(remembered-add! category value) → void?
category : symbol? value : any/c
This for-syntax procedure is called by the remembered! macro, but can also be executed on its own.
for-syntax procedure
(remembered? category value) → boolean?
category : symbol? value : any/c
for-syntax procedure
(remembered-or-written? category value) → boolean?
category : symbol? value : any/c
for-syntax procedure
(remember-write! category value) → void?
category : symbol? value : any/c
If the value is already remembered-or-written?, then the file is left unchanged, i.e. two or more calls to remember-write! with the same category and value will only append an expression to the file the first time.
The value is also added to the set of remembered-or-written? values, so that subsequent calls to remembered-or-written? return #t for that category and value. Calls to remembered? will be unaffected, and will still return #f. If some declarations are created by a library based on the get-remembered set, it is therefore possible to check whether a value was already present, or if it was added by a subsequent remember-write!.
for-syntax procedure
(remembered-error! category stx-value) → void?
category : symbol stx-value : syntax?
This procedure just triggers the error, and is not concerned with actually adding the value to the output file.
The error is added in a lifted declaration which is inserted at the end of the current module, using syntax-local-lift-module-end-declaration. It should therefore be triggered only when the compilation reaches the end of the file, if no other error was raised before.
This allows as many remembered-error! errors as possible to be accumulated; all of these are then shown when the file is fully expanded. The goal is to be able to add all values to the output file in a single run, instead of aborting after each value which is not remembered. This would otherwise require recompiling the program once for each value which is not initially remembered.
TODO: it would be nice to factor out the delayed error mechanism into a separate package, so that multiple libraries can add errors, and all of them get reported, without one preventing the others from executing. This function would likely keep the same signature, and just delegate to the delayed-error library.
parameter
(disable-remember-immediate-error disable?) → void? disable? : boolean?
= #f
The error is still put aside, so that if a delayed error was triggered by another call to remembered-error!, the error will still be included with the other delayed errors. If no delayed error is triggered during macro-expansion, the error that was put aside will be ignored. To prevent this from happening, call lift-maybe-delayed-errors within a context where lifts are possible.
procedure
Note that when (syntax-transforming-module-expression?) returns #false, syntax-local-lift-expression is used. The lifted form is then run as part of the current expansion pass, before the contents of any let forms are expanded. This means that calls to remembered-error! must not happen within the expansion of nested let forms (with respect to the let form being expanded (if any) when lift-maybe-delayed-errors is called), as they would add delayed errors too late, i.e. after the lifted form got executed.
syntax
(remember-input-file name)
name = string?
remembered-values. Values are added to the hash via the remembered! macro. The name file should therefore require the remember library, and contain a number of calls to remembered!, each adding a new value to the mutable hash.
syntax
(remember-output-file name)
name = (or/c string? false?)
for-syntax parameter
(remember-output-file) → (or/c string? false?)
(remember-output-file name) → void? name : (or/c string? false?)
Note that if the value given to remember-write! is already registered in an input file with remembered! for the same category, it will not be appended to the output file.
For now there can only be one output file at the same time, any call to remember-output-file overrides the setting from previous calls. Future versions of this library may offer the possibility to specify an output file per category.
The special value #f indicates that there is no output file, in which case remember-write! simply marks the value as remembered-or-written? for that category, without altering any file.
This identifier exists both as a macro and a for-syntax parameter. When called without any argument, it expands to (for the macro) or returns (for the for-syntax parameter) the last value set using either the macro or by passing an argument to the for-syntax parameter.
parameter
(remember-output-file-parameter) → (or/c path-string? false?)
(remember-output-file-parameter output-file) → void? output-file : (or/c path-string? false?)
= #f
The remember-output-file macro simply sets this parameter.
syntax
(remember-io-file name)
name = string?
(remember-input-file name) (remember-output-file name)
syntax
(remembered! category value)
category = identifier?
Calls to this macro are usually present in an input file loaded with remember-input-file or remember-io-file, but can also be inserted in the main file or any other file loaded with require.