Squashed commits
This commit is contained in:
commit
dfa5f22627
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
*~
|
||||
\#*
|
||||
.\#*
|
||||
.DS_Store
|
||||
compiled/
|
||||
/doc/
|
31
.travis.yml
Normal file
31
.travis.yml
Normal file
|
@ -0,0 +1,31 @@
|
|||
language: c
|
||||
sudo: false
|
||||
|
||||
env:
|
||||
global:
|
||||
# RACKET_DIR is an argument to install-racket.sh
|
||||
- RACKET_DIR=~/racket
|
||||
- PATH="$RACKET_DIR/bin:$PATH"
|
||||
matrix:
|
||||
# RACKET_VERSION is an argument to install-racket.sh
|
||||
- RACKET_VERSION=6.5
|
||||
- RACKET_VERSION=6.6
|
||||
- RACKET_VERSION=6.7
|
||||
- RACKET_VERSION=6.8
|
||||
- RACKET_VERSION=RELEASE
|
||||
- RACKET_VERSION=HEAD
|
||||
|
||||
before_install:
|
||||
- curl -L https://raw.githubusercontent.com/greghendershott/travis-racket/master/install-racket.sh | bash
|
||||
- raco pkg install --deps search-auto doc-coverage cover cover-codecov # or cover-coveralls
|
||||
|
||||
install:
|
||||
- raco pkg install --deps search-auto -j 2
|
||||
|
||||
script:
|
||||
- raco test -x -p "$(basename "$TRAVIS_BUILD_DIR")"
|
||||
- raco setup --check-pkg-deps --no-zo --no-launcher --no-install --no-post-install --no-docs --pkgs "$(basename "$TRAVIS_BUILD_DIR")"
|
||||
- raco doc-coverage "$(basename "$TRAVIS_BUILD_DIR")"
|
||||
- raco cover -s main -s test -s doc -f codecov -f html -d ~/coverage . || true
|
||||
# TODO: add an option to cover to run the "outer" module too, not just the submodules.
|
||||
# TODO: deploy the coverage info.
|
28
LICENSE-more.md
Normal file
28
LICENSE-more.md
Normal file
|
@ -0,0 +1,28 @@
|
|||
remember
|
||||
|
||||
Parts of this this software were initially written as part of a project
|
||||
at Cortus, S.A.S. which can be reached at 97 Rue de Freyr, 34000
|
||||
Montpellier, France. I got their permission to redistribute the code in
|
||||
the Public Domain.
|
||||
|
||||
|
||||
|
||||
This package is in distributed under the Creative Commons CC0 license
|
||||
https://creativecommons.org/publicdomain/zero/1.0/, as specified by
|
||||
the LICENSE.txt file.
|
||||
|
||||
|
||||
|
||||
The CC0 license is equivalent to a dedication to the Public Domain
|
||||
in most countries, but is also effective in countries which do not
|
||||
recognize explicit dedications to the Public Domain.
|
||||
|
||||
|
||||
|
||||
In order to avoid any potential licensing issues, this package is explicitly
|
||||
distributed under the Creative Commons CC0 license
|
||||
https://creativecommons.org/publicdomain/zero/1.0/, or under the GNU Lesser
|
||||
General Public License (LGPL) https://opensource.org/licenses/LGPL-3.0, or
|
||||
under the Apache License Version 2.0
|
||||
https://opensource.org/licenses/Apache-2.0, or under the MIT license
|
||||
https://opensource.org/licenses/MIT, at your option.
|
116
LICENSE.txt
Normal file
116
LICENSE.txt
Normal file
|
@ -0,0 +1,116 @@
|
|||
CC0 1.0 Universal
|
||||
|
||||
Statement of Purpose
|
||||
|
||||
The laws of most jurisdictions throughout the world automatically confer
|
||||
exclusive Copyright and Related Rights (defined below) upon the creator and
|
||||
subsequent owner(s) (each and all, an "owner") of an original work of
|
||||
authorship and/or a database (each, a "Work").
|
||||
|
||||
Certain owners wish to permanently relinquish those rights to a Work for the
|
||||
purpose of contributing to a commons of creative, cultural and scientific
|
||||
works ("Commons") that the public can reliably and without fear of later
|
||||
claims of infringement build upon, modify, incorporate in other works, reuse
|
||||
and redistribute as freely as possible in any form whatsoever and for any
|
||||
purposes, including without limitation commercial purposes. These owners may
|
||||
contribute to the Commons to promote the ideal of a free culture and the
|
||||
further production of creative, cultural and scientific works, or to gain
|
||||
reputation or greater distribution for their Work in part through the use and
|
||||
efforts of others.
|
||||
|
||||
For these and/or other purposes and motivations, and without any expectation
|
||||
of additional consideration or compensation, the person associating CC0 with a
|
||||
Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
|
||||
and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
|
||||
and publicly distribute the Work under its terms, with knowledge of his or her
|
||||
Copyright and Related Rights in the Work and the meaning and intended legal
|
||||
effect of CC0 on those rights.
|
||||
|
||||
1. Copyright and Related Rights. A Work made available under CC0 may be
|
||||
protected by copyright and related or neighboring rights ("Copyright and
|
||||
Related Rights"). Copyright and Related Rights include, but are not limited
|
||||
to, the following:
|
||||
|
||||
i. the right to reproduce, adapt, distribute, perform, display, communicate,
|
||||
and translate a Work;
|
||||
|
||||
ii. moral rights retained by the original author(s) and/or performer(s);
|
||||
|
||||
iii. publicity and privacy rights pertaining to a person's image or likeness
|
||||
depicted in a Work;
|
||||
|
||||
iv. rights protecting against unfair competition in regards to a Work,
|
||||
subject to the limitations in paragraph 4(a), below;
|
||||
|
||||
v. rights protecting the extraction, dissemination, use and reuse of data in
|
||||
a Work;
|
||||
|
||||
vi. database rights (such as those arising under Directive 96/9/EC of the
|
||||
European Parliament and of the Council of 11 March 1996 on the legal
|
||||
protection of databases, and under any national implementation thereof,
|
||||
including any amended or successor version of such directive); and
|
||||
|
||||
vii. other similar, equivalent or corresponding rights throughout the world
|
||||
based on applicable law or treaty, and any national implementations thereof.
|
||||
|
||||
2. Waiver. To the greatest extent permitted by, but not in contravention of,
|
||||
applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
|
||||
unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
|
||||
and Related Rights and associated claims and causes of action, whether now
|
||||
known or unknown (including existing as well as future claims and causes of
|
||||
action), in the Work (i) in all territories worldwide, (ii) for the maximum
|
||||
duration provided by applicable law or treaty (including future time
|
||||
extensions), (iii) in any current or future medium and for any number of
|
||||
copies, and (iv) for any purpose whatsoever, including without limitation
|
||||
commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
|
||||
the Waiver for the benefit of each member of the public at large and to the
|
||||
detriment of Affirmer's heirs and successors, fully intending that such Waiver
|
||||
shall not be subject to revocation, rescission, cancellation, termination, or
|
||||
any other legal or equitable action to disrupt the quiet enjoyment of the Work
|
||||
by the public as contemplated by Affirmer's express Statement of Purpose.
|
||||
|
||||
3. Public License Fallback. Should any part of the Waiver for any reason be
|
||||
judged legally invalid or ineffective under applicable law, then the Waiver
|
||||
shall be preserved to the maximum extent permitted taking into account
|
||||
Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
|
||||
is so judged Affirmer hereby grants to each affected person a royalty-free,
|
||||
non transferable, non sublicensable, non exclusive, irrevocable and
|
||||
unconditional license to exercise Affirmer's Copyright and Related Rights in
|
||||
the Work (i) in all territories worldwide, (ii) for the maximum duration
|
||||
provided by applicable law or treaty (including future time extensions), (iii)
|
||||
in any current or future medium and for any number of copies, and (iv) for any
|
||||
purpose whatsoever, including without limitation commercial, advertising or
|
||||
promotional purposes (the "License"). The License shall be deemed effective as
|
||||
of the date CC0 was applied by Affirmer to the Work. Should any part of the
|
||||
License for any reason be judged legally invalid or ineffective under
|
||||
applicable law, such partial invalidity or ineffectiveness shall not
|
||||
invalidate the remainder of the License, and in such case Affirmer hereby
|
||||
affirms that he or she will not (i) exercise any of his or her remaining
|
||||
Copyright and Related Rights in the Work or (ii) assert any associated claims
|
||||
and causes of action with respect to the Work, in either case contrary to
|
||||
Affirmer's express Statement of Purpose.
|
||||
|
||||
4. Limitations and Disclaimers.
|
||||
|
||||
a. No trademark or patent rights held by Affirmer are waived, abandoned,
|
||||
surrendered, licensed or otherwise affected by this document.
|
||||
|
||||
b. Affirmer offers the Work as-is and makes no representations or warranties
|
||||
of any kind concerning the Work, express, implied, statutory or otherwise,
|
||||
including without limitation warranties of title, merchantability, fitness
|
||||
for a particular purpose, non infringement, or the absence of latent or
|
||||
other defects, accuracy, or the present or absence of errors, whether or not
|
||||
discoverable, all to the greatest extent permissible under applicable law.
|
||||
|
||||
c. Affirmer disclaims responsibility for clearing rights of other persons
|
||||
that may apply to the Work or any use thereof, including without limitation
|
||||
any person's Copyright and Related Rights in the Work. Further, Affirmer
|
||||
disclaims responsibility for obtaining any necessary consents, permissions
|
||||
or other rights required for any use of the Work.
|
||||
|
||||
d. Affirmer understands and acknowledges that Creative Commons is not a
|
||||
party to this document and has no duty or obligation with respect to this
|
||||
CC0 or use of the Work.
|
||||
|
||||
For more information, please see
|
||||
<http://creativecommons.org/publicdomain/zero/1.0/>
|
49
README.md
Normal file
49
README.md
Normal file
|
@ -0,0 +1,49 @@
|
|||
[](https://travis-ci.org/jsmaniac/remember)
|
||||
[](https://codecov.io/gh/jsmaniac/remember)
|
||||
[](http://jsmaniac.github.io/travis-stats/#jsmaniac/remember)
|
||||
[](http://docs.racket-lang.org/remember/)
|
||||
[](https://github.com/jsmaniac/remember/issues)
|
||||
[](https://creativecommons.org/publicdomain/zero/1.0/)
|
||||
|
||||
remember
|
||||
========
|
||||
|
||||
This Racket library provides a compile-time memoize feature. It allows
|
||||
remembering a value with `(remember-write! 'category 'value)`. In subsequent
|
||||
compilations, `(get-remembered 'category)` will return a set of all
|
||||
previously-remembered values.
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
raco pkg install remember
|
||||
|
||||
Example use case: the `phc-adt` library
|
||||
=======================================
|
||||
|
||||
This library is used to implement "interned" structure and constructor types
|
||||
in the [`phc-adt`](https://github.com/jsmaniac/phc-adt) library. The `phc-adt`
|
||||
library needs to know the set of all structure and constructor types used in
|
||||
the program, and uses `remember` to automatically memoize structure
|
||||
descriptors and constructor names.
|
||||
|
||||
When the `structure` macro defined in
|
||||
[`structure.hl.rkt`](https://github.com/jsmaniac/phc-adt/blob/refactor/structure.hl.rkt)
|
||||
encounters an unknown list of field names, it uses the `remember` library to
|
||||
append the tuple of field names to a user-specified file. That file is loaded
|
||||
in subsequent compilations, so that the tuple of fields is known to `phc-adt`.
|
||||
|
||||
The memoized descriptors are used to know all possible structs that can
|
||||
contain a field with the desired name when accessing it with `(get instance
|
||||
field-name)`. The `get` macro can then retrieve the field's value using the
|
||||
right accessor (for example `(struct123-fieldname instance)`). Knowing all
|
||||
existing structures allows `get` to perform some kind of dynamic dispatch to
|
||||
obtain the appropriate accessor, for example using a `cond` which tests for
|
||||
all possible types.
|
||||
|
||||
The `constructor` macro defined in
|
||||
[`constructor.hl.rkt`](https://github.com/jsmaniac/phc-adt/blob/refactor/constructor.hl.rkt)
|
||||
works in the same way, but remembers the name of the constructor's tag instead
|
||||
of field names. The memoization feature is used so that all uses of a
|
||||
constructor with a given name are equivalent, across all files.
|
||||
|
22
info.rkt
Normal file
22
info.rkt
Normal file
|
@ -0,0 +1,22 @@
|
|||
#lang info
|
||||
(define collection "remember")
|
||||
(define deps '("base"
|
||||
"rackunit-lib"
|
||||
"compatibility-lib"
|
||||
"scribble-lib"
|
||||
"typed-racket-lib"
|
||||
"phc-toolkit"
|
||||
"hyper-literate"))
|
||||
(define build-deps '("scribble-lib"
|
||||
"racket-doc"
|
||||
"typed-racket-doc"
|
||||
"scribble-enhanced"))
|
||||
(define scribblings '(("scribblings/remember.scrbl" ())
|
||||
("remember-implementation.hl.rkt" () (omit-start))))
|
||||
(define compile-omit-paths '("test/test-error.rkt"))
|
||||
(define test-omit-paths '("test/test-error.rkt"))
|
||||
(define pkg-desc (string-append "Compile-time memoize across compilations."
|
||||
" Writes values to a file, so that they will"
|
||||
" be remembered during the next compilation."))
|
||||
(define version "0.9")
|
||||
(define pkg-authors '(|Georges Dupéron|))
|
19
licenses/bsd.txt
Normal file
19
licenses/bsd.txt
Normal file
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) 2000-2015 Dipanwita Sarkar, Andrew W. Keep, R. Kent Dybvig, Oscar Waddell
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
165
licenses/lgpl-3.0--license.txt
Normal file
165
licenses/lgpl-3.0--license.txt
Normal file
|
@ -0,0 +1,165 @@
|
|||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
3
main.rkt
Normal file
3
main.rkt
Normal file
|
@ -0,0 +1,3 @@
|
|||
#lang racket
|
||||
(require "remember-implementation.hl.rkt")
|
||||
(provide (all-from-out "remember-implementation.hl.rkt"))
|
303
remember-implementation.hl.rkt
Normal file
303
remember-implementation.hl.rkt
Normal file
|
@ -0,0 +1,303 @@
|
|||
#lang hyper-literate racket/base
|
||||
@(require scribble-enhanced/doc)
|
||||
@doc-lib-setup
|
||||
|
||||
@title[#:style manual-doc-style
|
||||
#:tag "remember"
|
||||
#:tag-prefix "(lib remember/remember-implementation.hl.rkt)"
|
||||
]{Implementation of Remember}
|
||||
|
||||
@(chunks-toc-prefix
|
||||
'("(lib remember/remember-implementation.hl.rkt)"))
|
||||
|
||||
@(table-of-contents)
|
||||
|
||||
@section{@racket[remember]}
|
||||
|
||||
This module allows macros to remember some values across
|
||||
compilations. Values are stored within the
|
||||
@tc[remembered-values] hash table, which associates a
|
||||
@racket[_category] (a symbol) with a set of values.
|
||||
|
||||
@chunk[<remembered-values>
|
||||
(begin-for-syntax
|
||||
(define remembered-values (make-hash)))]
|
||||
|
||||
A second set tracks values which were recently written, but
|
||||
not initially added via @racket[remembered!] or
|
||||
@racket[remembered-add!].
|
||||
|
||||
@chunk[<remembered-values>
|
||||
(begin-for-syntax
|
||||
(define written-values (make-hash)))]
|
||||
|
||||
The user can specify input files from which remembered
|
||||
values are loaded, and optionally an output file to which
|
||||
new, not-yet-remembered values will be appended:
|
||||
|
||||
@CHUNK[<remember-file>
|
||||
(define-for-syntax remember-output-file-parameter
|
||||
(make-parameter #f (or? path-string? false?)))
|
||||
|
||||
(define-syntax (remember-output-file stx)
|
||||
(syntax-case stx ()
|
||||
[(_ new-value)
|
||||
(string? (syntax-e #'new-value))
|
||||
(begin (remember-output-file-parameter (syntax-e #'new-value))
|
||||
#'(void))]
|
||||
[(_)
|
||||
(quasisyntax/loc stx remember-output-file-parameter)]))
|
||||
|
||||
(define-syntax (remember-input-file stx)
|
||||
(syntax-case stx ()
|
||||
[(_ name)
|
||||
(string? (syntax-e #'name))
|
||||
#'(require (only-in name))]))
|
||||
|
||||
(define-syntax-rule (remember-io-file name)
|
||||
(begin (remember-input-file name)
|
||||
(remember-output-file name)))]
|
||||
|
||||
@CHUNK[<remember>
|
||||
(define-syntax-rule (remembered! category value)
|
||||
(begin-for-syntax
|
||||
(remembered-add! 'category 'value)))
|
||||
|
||||
(define-for-syntax writable?
|
||||
(disjoin number?
|
||||
string?
|
||||
symbol?
|
||||
char?
|
||||
null?
|
||||
(λ (v) (and (pair? v)
|
||||
(writable? (car v))
|
||||
(writable? (cdr v))))
|
||||
(λ (v) (and (vector? v)
|
||||
(andmap writable? (vector->list v))))))
|
||||
|
||||
(define-for-syntax (remembered-add! category value)
|
||||
(unless (writable? value)
|
||||
(error "Value to remember does not seem to be safely writable:"
|
||||
value))
|
||||
(unless (symbol? category)
|
||||
(error (format "The category was not a symbol, when remembering ~a:"
|
||||
value)
|
||||
category))
|
||||
(hash-update! remembered-values
|
||||
category
|
||||
(λ (s) (set-add s value))
|
||||
set))
|
||||
|
||||
(define-for-syntax (remembered-add-written! category value)
|
||||
(unless (writable? value)
|
||||
(error "Value to remember does not seem to be safely writable:"
|
||||
value))
|
||||
(unless (symbol? category)
|
||||
(error (format "The category was not a symbol, when remembering ~a:"
|
||||
value)
|
||||
category))
|
||||
(hash-update! written-values
|
||||
category
|
||||
(λ (s) (set-add s value))
|
||||
set))
|
||||
|
||||
(define-for-syntax (remembered? category value)
|
||||
(unless (writable? value)
|
||||
(error "Value to remember does not seem to be safely writable:"
|
||||
value))
|
||||
(set-member? (hash-ref remembered-values category set) value))
|
||||
|
||||
(define-for-syntax (written? category value)
|
||||
(unless (writable? value)
|
||||
(error "Value to remember does not seem to be safely writable:"
|
||||
value))
|
||||
(set-member? (hash-ref written-values category set) value))
|
||||
|
||||
(define-for-syntax (remembered-or-written? category value)
|
||||
(or (remembered? category value)
|
||||
(written? category value)))
|
||||
|
||||
(define-for-syntax (remember-write! category value)
|
||||
(unless (writable? value)
|
||||
(error "Value to remember does not seem to be safely writable:"
|
||||
value))
|
||||
(unless (or (remembered? category value)
|
||||
(written? category value))
|
||||
(when (remember-output-file-parameter)
|
||||
(with-output-file [port (remember-output-file-parameter)]
|
||||
#:exists 'append
|
||||
(writeln (list 'remembered! category value)
|
||||
port)))
|
||||
(remembered-add-written! category value)))]
|
||||
|
||||
@chunk[<delayed-errors>
|
||||
(begin-for-syntax
|
||||
(define remember-errors-list '())
|
||||
(define remember-lifted-error #f))]
|
||||
|
||||
@chunk[<error>
|
||||
(define-for-syntax (remembered-error! category
|
||||
stx-value
|
||||
[stx-errs (list stx-value)])
|
||||
(set! remember-errors-list
|
||||
(cons (list category stx-value stx-errs) remember-errors-list))
|
||||
|
||||
(unless (disable-remember-immediate-error)
|
||||
(if (not (syntax-local-lift-context))
|
||||
;; Trigger the error right now
|
||||
(remember-all-hard-error)
|
||||
;; Lift a delayed error, which will be triggered later on
|
||||
(lift-maybe-delayed-errors))))
|
||||
|
||||
(define-for-syntax (remembered-add-error! category stx-value)
|
||||
(remembered-add! category (syntax-e stx-value))
|
||||
(remembered-error! category stx-value))]
|
||||
|
||||
@CHUNK[<remember-all-hard-error>
|
||||
;; These two functions allow us to wait around 1000 levels of nested
|
||||
;; macro-expansion before triggering the error.
|
||||
;; If the error is triggered immediately when the lifted statements are
|
||||
;; added at the end of the module, then it can get executed before macros
|
||||
;; used in the righ-hand side of a (define …) are expanded, for example.
|
||||
;; Since these macros may need to remember more values, it's better to
|
||||
;; wait until they are all expanded.
|
||||
;; The number 1000 above in #`(delay-remember-all-hard-error1 1000) is
|
||||
;; arbitrary, but should be enough for most practical purposes, worst
|
||||
;; case the file would require a few more compilations to settle.
|
||||
(define-syntax (delay-remember-all-hard-error1 stx)
|
||||
(syntax-case stx ()
|
||||
[(_ n)
|
||||
(number? (syntax-e #'n))
|
||||
(if (> (syntax-e #'n) 0)
|
||||
#`(let ()
|
||||
(define blob
|
||||
(delay-remember-all-hard-error2 #,(- (syntax-e #'n) 1)))
|
||||
(void))
|
||||
(begin (syntax-local-lift-module-end-declaration
|
||||
#`(remember-all-hard-error-macro))
|
||||
#'(void)))]))
|
||||
|
||||
(define-syntax (delay-remember-all-hard-error2 stx)
|
||||
(syntax-case stx ()
|
||||
[(_ n)
|
||||
(number? (syntax-e #'n))
|
||||
(begin
|
||||
(syntax-local-lift-module-end-declaration
|
||||
#'(delay-remember-all-hard-error1 n))
|
||||
#'n)]))
|
||||
|
||||
(define-for-syntax (remember-all-hard-error)
|
||||
(define remember-errors-list-orig remember-errors-list)
|
||||
(set! remember-errors-list '())
|
||||
(unless (empty? remember-errors-list-orig)
|
||||
(raise-syntax-error
|
||||
'remember
|
||||
(format (~a "The values ~a were not remembered."
|
||||
" Some of them may have been added to the"
|
||||
" appropriate list automatically."
|
||||
" Please recompile this file now.")
|
||||
(string-join (remove-duplicates
|
||||
(reverse
|
||||
(stx-map (compose ~a syntax->datum)
|
||||
(map cadr
|
||||
remember-errors-list-orig))))
|
||||
", "))
|
||||
#f
|
||||
#f
|
||||
(remove-duplicates
|
||||
(append-map caddr remember-errors-list-orig)
|
||||
#:key (λ (e)
|
||||
(cons (syntax->datum e)
|
||||
(build-source-location-list e)))))))
|
||||
(define-syntax (remember-all-hard-error-macro stx)
|
||||
(remember-all-hard-error)
|
||||
#'(void))]
|
||||
|
||||
The @racket[disable-remember-immediate-error] parameter allows code to
|
||||
temporarily prevent @racket[remembered-error!] from lifting a delayed error.
|
||||
This can be useful for example when calling @racket[remembered-error!] from a
|
||||
context where @racket[(syntax-local-lift-context)] is @racket[#false], e.g.
|
||||
outside of the expansion of a macro, but within a @racket[begin-for-syntax]
|
||||
block.
|
||||
|
||||
@chunk[<disable-remember-errors>
|
||||
(define-for-syntax disable-remember-immediate-error (make-parameter #f))]
|
||||
|
||||
The error is still put aside, so that if a delayed error was triggered by
|
||||
another call to @racket[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
|
||||
that, the user can call @racket[lift-maybe-delayed-errors] within a context
|
||||
where lifts are possible.
|
||||
|
||||
@chunk[<lift-maybe-delayed-errors>
|
||||
(define-for-syntax (lift-maybe-delayed-errors)
|
||||
(if (syntax-transforming-module-expression?)
|
||||
;; Lift a delayed error, attempting to allow several (1000) levels
|
||||
;; of nested let blocks to expand before pulling the alarm signal.
|
||||
(unless remember-lifted-error
|
||||
(set! remember-lifted-error #t)
|
||||
(syntax-local-lift-module-end-declaration
|
||||
#`(delay-remember-all-hard-error1 1000)))
|
||||
;; Lift a delayed error, which will be triggered after the current
|
||||
;; expansion pass (i.e. before the contents of any let form is
|
||||
;; expanded).
|
||||
(syntax-local-lift-expression
|
||||
#`(remember-all-hard-error-macro))))]
|
||||
|
||||
|
||||
@CHUNK[<get-remembered>
|
||||
(define-for-syntax (get-remembered category)
|
||||
(hash-ref remembered-values category set))]
|
||||
|
||||
@chunk[<provide>
|
||||
(begin-for-syntax
|
||||
(provide get-remembered
|
||||
remembered-add!
|
||||
remembered?
|
||||
remembered-or-written?
|
||||
remember-write!
|
||||
remembered-error!
|
||||
remember-output-file-parameter
|
||||
disable-remember-immediate-error
|
||||
lift-maybe-delayed-errors))
|
||||
(provide remember-input-file
|
||||
remember-output-file
|
||||
remember-io-file
|
||||
remembered!)
|
||||
|
||||
(module+ private
|
||||
(begin-for-syntax
|
||||
(provide remembered-add-written!)))]
|
||||
|
||||
@; TODO: circumvents bug https://github.com/racket/scribble/issues/44
|
||||
@(require racket/require)
|
||||
@chunk[<*>
|
||||
(require mzlib/etc
|
||||
;; TODO: circumvent https://github.com/racket/scribble/issues/44
|
||||
racket/require
|
||||
(subtract-in phc-toolkit/untyped syntax/stx)
|
||||
syntax/stx
|
||||
(for-syntax racket/base
|
||||
racket/function
|
||||
racket/bool
|
||||
racket/set
|
||||
racket/list
|
||||
mzlib/etc
|
||||
;;TODO: https://github.com/racket/scribble/issues/44
|
||||
(subtract-in phc-toolkit/untyped
|
||||
syntax/stx)
|
||||
syntax/stx
|
||||
syntax/srcloc
|
||||
racket/string
|
||||
racket/format))
|
||||
<provide>
|
||||
<remembered-values>
|
||||
<remember-file>
|
||||
<remember>
|
||||
<get-remembered>
|
||||
<delayed-errors>
|
||||
<disable-remember-errors>
|
||||
<lift-maybe-delayed-errors>
|
||||
<remember-all-hard-error>
|
||||
<error>]
|
258
scribblings/remember.scrbl
Normal file
258
scribblings/remember.scrbl
Normal file
|
@ -0,0 +1,258 @@
|
|||
#lang scribble/manual
|
||||
@require[@for-label[remember
|
||||
racket/base]]
|
||||
|
||||
@title{Remember: storage for macros which is persistant across compilations}
|
||||
@author{Georges Dupéron}
|
||||
|
||||
@defmodule[remember]
|
||||
|
||||
This library is implemented using literate programming. The
|
||||
implementation details are presented in
|
||||
@other-doc['(lib "remember/remember-implementation.hl.rkt")].
|
||||
|
||||
This module allows macros to remember some values across
|
||||
compilations. Values are grouped by @racket[_category], so
|
||||
that multiple macros can use this facility without
|
||||
interfering with each other. The @racket[_category] is
|
||||
simply a symbol given when remembering the value.
|
||||
|
||||
The list of all remembered values for a given
|
||||
@racket[_category] is returned by @racket[get-remembered],
|
||||
and it is possible to check if a single value has been
|
||||
remembered using @racket[remembered?].
|
||||
|
||||
Values are loaded from files using
|
||||
@racket[remember-input-file] and @racket[remember-io-file].
|
||||
An output file can be set with
|
||||
@racket[remember-output-file] and
|
||||
@racket[remember-io-file].
|
||||
|
||||
When an output file has been declared, new values passed to
|
||||
@racket[remember-write!] are marked as
|
||||
@racket[remembered-or-written?] and appended to that file
|
||||
(more precisely, the expression
|
||||
@racket[(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
|
||||
@racket[(remembered! _category _value)] statements:
|
||||
|
||||
@codeblock[#:keep-lang-line? #t]|{
|
||||
#lang racket
|
||||
(require remember)}|
|
||||
|
||||
The @racket[remembered!] macro indicates an
|
||||
already-remembered value, and is typically used inside input
|
||||
files. The @racket[for-syntax] function
|
||||
@racket[remembered-add!] can also be used instead, to mark a
|
||||
value as @racket[remembered?] without adding it to any file
|
||||
(this can be useful for values which should implicitly be
|
||||
remembered).
|
||||
|
||||
@defproc[#:kind "for-syntax procedure"
|
||||
(get-remembered [category symbol?]) list?]{
|
||||
Returns a list of all values that have been remembered for
|
||||
the given @racket[category] (i.e. all values passed as the
|
||||
second argument to @racket[remembered-add!],
|
||||
@racket[remember-write!] or @racket[remembered!], with the given
|
||||
category as the first argument).}
|
||||
|
||||
@defproc[#:kind "for-syntax procedure"
|
||||
(remembered-add! [category symbol?] [value any/c]) void?]{
|
||||
Marks the given @racket[value] as remembered in the given
|
||||
@racket[category]. If the same value is remembered twice
|
||||
for the same category, the second occurrence is ignored
|
||||
(i.e. values are stored in a distinct @racket[set] for each
|
||||
category).
|
||||
|
||||
This @racket[for-syntax] procedure is called by the
|
||||
@racket[remembered!] macro, but can also be executed on its
|
||||
own.}
|
||||
|
||||
@defproc[#:kind "for-syntax procedure"
|
||||
(remembered? [category symbol?] [value any/c]) boolean?]{
|
||||
Checks whether the given @racket[value] has already been
|
||||
added to the set of remembered values for the given
|
||||
@racket[category].}
|
||||
|
||||
@defproc[#:kind "for-syntax procedure"
|
||||
(remembered-or-written? [category symbol?] [value any/c]) boolean?]{
|
||||
Checks whether the given @racket[value] has already been
|
||||
added to the set of remembered values for the given
|
||||
@racket[category], or if it was freshly written to a file
|
||||
during the current expansion.}
|
||||
|
||||
@defproc[#:kind "for-syntax procedure"
|
||||
(remember-write! [category symbol?] [value any/c]) void?]{
|
||||
Adds the given @racket[value] to the current
|
||||
@racket[remember-output-file] for the given category. More
|
||||
precisely, the expression
|
||||
@racket[(remembered! category value)] is appended to the
|
||||
file, followed by a newline.
|
||||
|
||||
If the value is already @racket[remembered-or-written?],
|
||||
then the file is left unchanged, i.e. two or more calls to
|
||||
@racket[remember-write!] with the same @racket[category]
|
||||
and @racket[value] will only append an expression to the
|
||||
file the first time.
|
||||
|
||||
The value is also added to the set of
|
||||
@racket[remembered-or-written?] values, so that subsequent
|
||||
calls to @racket[remembered-or-written?] return
|
||||
@racket[#t] for that category and value. Calls to
|
||||
@racket[remembered?] will be unaffected, and will still
|
||||
return @racket[#f]. If some declarations are created by a
|
||||
library based on the @racket[get-remembered] set, it is
|
||||
therefore possible to check whether a value was already
|
||||
present, or if it was added by a subsequent
|
||||
@racket[remember-write!].}
|
||||
|
||||
@defproc[#:kind "for-syntax procedure"
|
||||
(remembered-error! [category symbol] [stx-value syntax?]) void?]{
|
||||
Produces a delayed error indicating that this value has
|
||||
not been remembered, but was added to the output file.
|
||||
|
||||
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
|
||||
@racket[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 @racket[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.}
|
||||
|
||||
@defparam[disable-remember-immediate-error disable? boolean? #:value #f]{
|
||||
The @racket[disable-remember-immediate-error] parameter allows code to
|
||||
temporarily prevent @racket[remembered-error!] from lifting a delayed error.
|
||||
This can be useful for example when calling @racket[remembered-error!] from a
|
||||
context where @racket[(syntax-local-lift-context)] is @racket[#false], e.g.
|
||||
outside of the expansion of a macro, but within a @racket[begin-for-syntax]
|
||||
block.
|
||||
|
||||
The error is still put aside, so that if a delayed error was triggered by
|
||||
another call to @racket[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 @racket[lift-maybe-delayed-errors] within a context
|
||||
where lifts are possible.}
|
||||
|
||||
@defproc[(lift-maybe-delayed-errors) void?]{
|
||||
Uses @racket[syntax-local-lift-module-end-declaration] or
|
||||
@racket[syntax-local-lift-expression], depending on the context, to lift an
|
||||
expression which will trigger delayed errors, if any. If no delayed errors
|
||||
have been recorded by @racket[remembered-error!] when the lifted form is
|
||||
executed, then nothing will happen and expansion will proceed.
|
||||
|
||||
Note that when @racket[(syntax-transforming-module-expression?)] returns
|
||||
@racket[#false], @racket[syntax-local-lift-expression] is used. The lifted
|
||||
form is then run as part of the current expansion pass, before the contents of
|
||||
any @racket[let] forms are expanded. This means that calls to
|
||||
@racket[remembered-error!] must not happen within the expansion of nested
|
||||
@racket[let] forms (with respect to the @racket[let] form being expanded (if
|
||||
any) when @racket[lift-maybe-delayed-errors] is called), as they would add
|
||||
delayed errors too late, i.e. after the lifted form got executed.}
|
||||
|
||||
@defform[(remember-input-file name)
|
||||
#:grammar ([name string?])]{
|
||||
The file is loaded with @racket[require], but no
|
||||
identifier is imported from that module. Instead,
|
||||
@racket[remembered?] relies on its internal mutable
|
||||
@racket[for-syntax] hash table which stores remembered
|
||||
values associated to their category.
|
||||
|
||||
@racket[remembered-values]. Values are added to the hash
|
||||
via the @racket[remembered!] macro. The @racket[name] file
|
||||
should therefore @racket[require] the
|
||||
@racketmodname[remember] library, and contain a number of
|
||||
calls to @racket[remembered!], each adding a new value to
|
||||
the mutable hash.}
|
||||
|
||||
@deftogether[
|
||||
(@defform*[((remember-output-file)
|
||||
(remember-output-file name))
|
||||
#:grammar ([name (or/c string? false?)])]
|
||||
@defproc*[#:kind "for-syntax parameter"
|
||||
#:link-target? #f
|
||||
([(remember-output-file) (or/c string? false?)]
|
||||
[(remember-output-file [name (or/c string? false?)]) void?])]
|
||||
)]{
|
||||
Indicates that new values added via
|
||||
@racket[remember-write!] should be appended to the file
|
||||
@racket[name]. More precisely, the expression
|
||||
@racket[(remembered! _category _value)] is appended to the
|
||||
file, followed by a newline.
|
||||
|
||||
Note that if the @racket[_value] given to
|
||||
@racket[remember-write!] is already registered in an input
|
||||
file with @racket[remembered!] for the same category, it
|
||||
will not be appended to the output file.
|
||||
|
||||
For now there can only be one @racket[output] file at the
|
||||
same time, any call to @racket[remember-output-file]
|
||||
overrides the setting from previous calls. Future versions
|
||||
of this library may offer the possibility to specify an
|
||||
output file per @racket[_category].
|
||||
|
||||
The special value @racket[#f] indicates that there is no
|
||||
output file, in which case @racket[remember-write!] simply
|
||||
marks the @racket[value] as
|
||||
@racket[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.}
|
||||
|
||||
@defparam[remember-output-file-parameter output-file
|
||||
(or/c path-string? false?)
|
||||
#:value #f]{
|
||||
This for-syntax parameter that new values added via @racket[remember-write!]
|
||||
should be appended to the file whose name is stored within the parameter.
|
||||
|
||||
The @racket[remember-output-file] macro simply sets this parameter.}
|
||||
|
||||
@defform[(remember-io-file name)
|
||||
#:grammar ([name string?])]{
|
||||
Indicates that calls to @racket[remembered!] in this file
|
||||
should be taken into account, and that new values added
|
||||
with @racket[remember-write!] should be appended to this
|
||||
file.
|
||||
|
||||
It is equivalent to:
|
||||
@racketblock[(remember-input-file name)
|
||||
(remember-output-file name)]}
|
||||
|
||||
@defform[(remembered! category value)
|
||||
#:grammar ([category identifier?])]{
|
||||
Marks the given @racket[value] as remembered in the given
|
||||
@racket[category]. If the same value is remembered twice
|
||||
for the same category, the second occurrence is ignored
|
||||
(i.e. values are stored in a distinct @racket[set] for each
|
||||
category).
|
||||
|
||||
Calls to this macro are usually present in an input file
|
||||
loaded with @racket[remember-input-file] or
|
||||
@racket[remember-io-file], but can also be inserted in the
|
||||
main file or any other file loaded with @racket[require].}
|
7
test/input-error.rkt
Normal file
7
test/input-error.rkt
Normal file
|
@ -0,0 +1,7 @@
|
|||
#lang racket
|
||||
(require remember)
|
||||
(remembered! foo-error (1 2 3))
|
||||
(remembered! foo-error (1 2 3 4))
|
||||
(remembered! foo-error (1 2 3 5))
|
||||
(define + 'wrong)
|
||||
(provide +)
|
5
test/input1.rkt
Normal file
5
test/input1.rkt
Normal file
|
@ -0,0 +1,5 @@
|
|||
#lang racket
|
||||
(require remember)
|
||||
(remembered! foo (1 2 3))
|
||||
(remembered! foo (1 2 3 4))
|
||||
(remembered! foo (1 2 3 5))
|
7
test/input3.rkt
Normal file
7
test/input3.rkt
Normal file
|
@ -0,0 +1,7 @@
|
|||
#lang racket
|
||||
(require remember)
|
||||
(remembered! foo3 (1 2 3))
|
||||
(remembered! foo3 (1 2 3 4))
|
||||
(remembered! foo3 (1 2 3 5))
|
||||
(define + 'wrong)
|
||||
(provide +)
|
3
test/io2.rkt
Normal file
3
test/io2.rkt
Normal file
|
@ -0,0 +1,3 @@
|
|||
#lang racket
|
||||
(require remember)
|
||||
(remembered! bar (1 2 3 xyz))
|
18
test/test-error.rkt
Normal file
18
test/test-error.rkt
Normal file
|
@ -0,0 +1,18 @@
|
|||
#lang racket
|
||||
|
||||
(require remember
|
||||
rackunit)
|
||||
(remember-input-file "input-error.rkt")
|
||||
(define-syntax (test-rem stx)
|
||||
(syntax-case stx ()
|
||||
[(_ val)
|
||||
(let ([v (syntax-e #'val)])
|
||||
(unless (remembered? 'err-category v)
|
||||
(remembered-error! 'err-category #'val)))
|
||||
#'(void)]))
|
||||
|
||||
(test-rem one)
|
||||
(test-rem two)
|
||||
(check-equal? (+ 1 2) 3)
|
||||
(test-rem three)
|
||||
(test-rem four)
|
13
test/test1.rkt
Normal file
13
test/test1.rkt
Normal file
|
@ -0,0 +1,13 @@
|
|||
#lang racket
|
||||
(require remember
|
||||
rackunit
|
||||
(submod "../remember-implementation.hl.rkt" private))
|
||||
(remember-input-file "input1.rkt")
|
||||
(begin-for-syntax
|
||||
(require rackunit)
|
||||
(define secs (current-seconds))
|
||||
(remembered-add-written! 'foo `(1 2 3 secs))
|
||||
(check-false (remembered? 'foo `(1 2 3 secs)))
|
||||
(check-true (remembered-or-written? 'foo `(1 2 3 secs))))
|
||||
;; check that no identifiers were imported from "input1.rkt".
|
||||
(check-not-equal? + 'wrong)
|
9
test/test2.rkt
Normal file
9
test/test2.rkt
Normal file
|
@ -0,0 +1,9 @@
|
|||
#lang racket
|
||||
(require remember)
|
||||
(remember-io-file "io2.rkt")
|
||||
(begin-for-syntax
|
||||
(require rackunit)
|
||||
;; Manually check for an error the first time this
|
||||
;; file is compiled after emptying io2.rkt
|
||||
(check-true (remembered? 'bar '(1 2 3 xyz)))
|
||||
(remember-write! 'bar '(1 2 3 xyz)))
|
8
test/test3.rkt
Normal file
8
test/test3.rkt
Normal file
|
@ -0,0 +1,8 @@
|
|||
#lang racket
|
||||
(require remember)
|
||||
(remember-io-file "input3.rkt")
|
||||
(begin-for-syntax
|
||||
(require rackunit
|
||||
racket/set)
|
||||
(check set=? (get-remembered 'foo3)
|
||||
(set '(1 2 3) '(1 2 3 5) '(1 2 3 4))))
|
Loading…
Reference in New Issue
Block a user