Squashed commits

This commit is contained in:
Georges Dupéron 2017-04-27 23:38:55 +02:00
commit 109659c456
180 changed files with 7808 additions and 0 deletions

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
*~
\#*
.\#*
.DS_Store
compiled
/doc/

0
.gitmodules vendored Normal file
View File

63
.travis.yml Normal file
View File

@ -0,0 +1,63 @@
language: c
# Based from: https://github.com/greghendershott/travis-racket
# Optional: Remove to use Travis CI's older infrastructure.
sudo: false
env:
global:
# Supply a global RACKET_DIR environment variable. This is where
# Racket will be installed. A good idea is to use ~/racket because
# that doesn't require sudo to install and is therefore compatible
# with Travis CI's newer container infrastructure.
- RACKET_DIR=~/racket
matrix:
# Supply at least one RACKET_VERSION environment variable. This is
# used by the install-racket.sh script (run at before_install,
# below) to select the version of Racket to download and install.
#
# Supply more than one RACKET_VERSION (as in the example below) to
# create a Travis-CI build matrix to test against multiple Racket
# versions.
#- RACKET_VERSION=6.0
#- RACKET_VERSION=6.1
#- RACKET_VERSION=6.1.1
#- RACKET_VERSION=6.2
#- RACKET_VERSION=6.3
#- RACKET_VERSION=6.4 # scribble bug prevents compiling the docs for the "type-expander" dependency.
- RACKET_VERSION=6.5
- RACKET_VERSION=6.6
- RACKET_VERSION=6.7
- RACKET_VERSION=6.8
- RACKET_VERSION=HEAD
matrix:
allow_failures:
- env: RACKET_VERSION=6.0
- env: RACKET_VERSION=6.1
- env: RACKET_VERSION=6.1.1
- env: RACKET_VERSION=6.2
- env: RACKET_VERSION=6.3
fast_finish: true
before_install:
- git clone https://github.com/greghendershott/travis-racket.git
- cat travis-racket/install-racket.sh | bash # pipe to bash not sh!
- export PATH="${RACKET_DIR}/bin:${PATH}" #install-racket.sh can't set for us
install:
- raco pkg install -j 2 --deps search-auto
before_script:
# Here supply steps such as raco make, raco test, etc. You can run
# `raco pkg install --deps search-auto phc-toolkit` to install any required
# packages without it getting stuck on a confirmation prompt.
script:
- raco test -p phc-toolkit
- raco setup --check-pkg-deps --no-zo --no-launcher --no-install --no-post-install --no-docs --pkgs phc-toolkit
after_success:
- raco pkg install --deps search-auto cover cover-codecov
- raco cover -b -f codecov -d $TRAVIS_BUILD_DIR/coverage .

13
LICENSE Normal file
View File

@ -0,0 +1,13 @@
This software was initially written as part of a project at Cortus, S.A.S. which
can be reached at 97 Rue de Freyr, 34000 Montpellier, France.
This software is licensed under the GNU Lesser General Public License (LGPL) or
under the BSD license, at your option. Both licenses can be found in the
`licenses/` folder.
This double-licensing has been chosen in order to make it possible to integrate
the type-expander library with Typed/Racket
(https://github.com/racket/typed-racket) and/or Racket
(https://github.com/racket/racket), which are both under the LGPL license, as
well as integrate the graph library with the Nanopass Compiler Framework
(https://github.com/akeep/nanopass-framework), which is under the BSD license.

23
README.md Normal file
View File

@ -0,0 +1,23 @@
[![Build Status,](https://img.shields.io/travis/jsmaniac/phc-toolkit/master.svg)](https://travis-ci.org/jsmaniac/phc-toolkit)
[![Coverage Status,](https://img.shields.io/codecov/c/github/jsmaniac/phc-toolkit/master.svg)](https://codecov.io/gh/jsmaniac/phc-toolkit)
[![Build Stats,](https://img.shields.io/badge/build-stats-blue.svg)](http://jsmaniac.github.io/travis-stats/#jsmaniac/phc-toolkit)
[![Maintained as of 2017,](https://img.shields.io/maintenance/yes/2017.svg)](https://github.com/jsmaniac/phc-toolkit/issues)
[![Online Documentation.](https://img.shields.io/badge/docs-online-blue.svg)](http://docs.racket-lang.org/phc-toolkit/)
phc-toolkit
===========
This is a collection of minor addendums to Racket and Typed/Racket's
standard libraries. It is used by the jsmaniac/phc project.
Although most functions are unlikely to change, this library should
not be considered stable. Some functions need an overhaul, and the
typed/untyped mechanism used to provide both a typed and an untyped
version of each file might change in the future.
Installation
------------
```
raco pkg install --deps search-auto phc-toolkit
```

33
README.md.old Normal file
View File

@ -0,0 +1,33 @@
Library functions and utilities
-------------------------------
* `eval-get-values.rkt`
Wrapper for the racket `eval` function that allows the evaluation of code
with multiple return values in typed/racket.
* `main.rkt`
Utilities that complement racket and typed/racket's standard libraries.
* `untyped-only/for-star-list-star.rkt`
A utility macro similar to `for*/list` to iterate over collections and return
a list of results, but which can return nested lists instead of just a flat
one.
* `test-framework.rkt`
Some wrappers and utilities that allow easier use of the rackunit test
framework from typed/racket files.
* `list-lang.rkt`
Tiny programming language extension that allows constructing a list with the
contents of all trailing lines in the file. This makes appending data to the
list easy, as there is no need to remove the last closing parentheses and add
them back afterwards — simply appending an s-expression to the file works.
Alternatively, one could avoid using this language by appending an
instruction of the form:
(set! list (cons item list))

41
aliases.rkt Normal file
View File

@ -0,0 +1,41 @@
#lang typed/racket/base (require phc-toolkit/is-typed)
(provide (all-from-out racket/match)
…+
attr
when-attr
@
match-λ
match-λ*
match-λ**
generate-temporary
true?
false?)
(require racket/match)
(require (only-in racket/base
[compose ]
[... ])
(only-in racket/bool
false?)
(only-in syntax/parse
[...+ …+])
(only-in phc-toolkit/untyped-only/syntax-parse
[attribute* attr]
[attribute* @]))
(define-syntax-rule (when-attr a e)
(if (attr a) e #'()))
(require (only-in racket/match
[match-lambda match-λ]
[match-lambda* match-λ*]
[match-lambda** match-λ**]))
(require/typed racket/syntax [generate-temporary ( Any Identifier)])
(if-typed
(require (only-in alexis/bool true?))
(require (only-in typed/alexis/bool true?)))

14
backtrace.rkt Normal file
View File

@ -0,0 +1,14 @@
#lang typed/racket
(require "typed-untyped.rkt")
(define-typed/untyped-modules #:no-test
(provide show-backtrace
with-backtrace)
(define backtrace (make-parameter '()))
(define-syntax-rule (with-backtrace push . body)
(parameterize ([backtrace (cons push (backtrace))])
. body))
(define (show-backtrace)
(pretty-write (backtrace))))

21
compat.rkt Normal file
View File

@ -0,0 +1,21 @@
#lang typed/racket
;; Compatibility functions for Racket version 6.5.
(require "typed-untyped.rkt")
(define-typed/untyped-modules #:no-test
(require (only-in racket/syntax with-disappeared-uses))
(require/typed racket/syntax
[record-disappeared-uses
;; This is the type in v. 6.5. Later versions allow
;; (U Identifier (Listof Identifier)). The wrapper below
;; generalizes that type.
( (Listof Identifier) Any)])
(provide with-disappeared-uses*
record-disappeared-uses*)
(define-syntax-rule (with-disappeared-uses* . body)
(with-disappeared-uses (let () . body)))
(: record-disappeared-uses* ( (U Identifier (Listof Identifier)) Any))
(define (record-disappeared-uses* ids)
(record-disappeared-uses (if (list? ids) ids (list ids)))))

19
cond-let.rkt Normal file
View File

@ -0,0 +1,19 @@
#lang typed/racket
(require "typed-untyped.rkt")
(define-typed/untyped-modules #:no-test
(provide cond-let)
(require (for-syntax syntax/parse
phc-toolkit/untyped/aliases))
(define-syntax (cond-let stx)
(syntax-parse stx
[(_)
#'(typecheck-fail #,stx)]
[(_ #:let bindings:expr clause )
#'(let bindings (cond-let clause ))]
[(_ [condition:expr (~seq #:else-let binding ) . body] clause )
#'(if condition
(begin . body)
(let (binding )
(cond-let clause )))])))

51
contract.rkt Normal file
View File

@ -0,0 +1,51 @@
#lang typed/racket
(require "typed-untyped.rkt")
(define-typed/untyped-modules #:no-test
(require racket/contract
(for-syntax syntax/parse
racket/contract))
(provide define-for-syntax/contract?
define/contract?
regexp-match/c
id/c)
(begin-for-syntax
(define-splicing-syntax-class freevar
(pattern {~and {~or {~seq #:freevar id contract-expr}
{~seq #:freevars ([ids contract-exprs] ...)}
{~seq}}
{~seq fv ...}})))
(begin-for-syntax
(define enable-contracts (make-parameter #t)))
(define-syntax define-for-syntax/contract?
(syntax-parser
[(_ id/head contract-expr fv:freevar . body)
(if (enable-contracts)
#'(begin-for-syntax
(define/contract id/head contract-expr fv.fv ... . body))
#'(define-for-syntax id/head . body))]))
(define-syntax define/contract?
(syntax-parser
[(_ id/head contract-expr fv:freevar . body)
(if (enable-contracts)
#'(define/contract id/head contract-expr fv.fv ... . body)
#'(define id/head . body))]))
(module m-contracts racket/base
(require racket/contract)
(provide regexp-match/c
id/c)
(define (regexp-match/c rx)
(and/c (or/c string? bytes? path? input-port?)
(λ (s) (regexp-match? rx s))))
(define (id/c id)
(and/c identifier? (λ (i) (free-identifier=? i id)))))
(require 'm-contracts))

17
eval-get-values.rkt Normal file
View File

@ -0,0 +1,17 @@
#lang typed/racket
(require "typed-untyped.rkt")
(define-typed/untyped-modules #:no-test
(module m racket/base
(provide eval-get-values)
(define (eval-get-values expr [namespace (current-namespace)])
(call-with-values (λ () (eval expr namespace)) list)))
(require "typed-untyped.rkt")
(if-typed
(begin
(require typed/racket/unsafe)
(unsafe-require/typed 'm [eval-get-values (->* (Any) (Namespace) (Listof Any))]))
(require 'm))
(provide eval-get-values))

13
fixnum.rkt Normal file
View File

@ -0,0 +1,13 @@
#lang typed/racket
(require "typed-untyped.rkt")
(define-typed/untyped-modules #:no-test
(provide fxxor fxxor2)
;; For fxxor, used to compute hashes.
;; The type obtained just by writing (require racket/fixnum) is wrong, so we
;; get a more precise one.
(require/typed racket/fixnum [(fxxor fxxor2) ( Fixnum Fixnum Fixnum)])
(: fxxor ( Fixnum * Fixnum))
(define (fxxor . args)
(foldl fxxor2 0 args)))

23
generate-indices.rkt Normal file
View File

@ -0,0 +1,23 @@
#lang typed/racket
(require "typed-untyped.rkt")
(define-typed/untyped-modules #:no-test
(provide generate-indices)
(require "typed-untyped.rkt")
(require-typed/untyped "sequence.rkt")
(: generate-indices ( (T) (case→ ( Integer (Syntax-Listof T)
(Listof Integer))
( (Syntax-Listof T)
(Listof Nonnegative-Integer)))))
(define generate-indices
(case-lambda
[(start stx)
(for/list ([v (my-in-syntax stx)]
[i (in-naturals start)])
i)]
[(stx)
(for/list ([v (my-in-syntax stx)]
[i : Nonnegative-Integer
(ann (in-naturals) (Sequenceof Nonnegative-Integer))])
i)])))

321
ids.rkt Normal file
View File

@ -0,0 +1,321 @@
#lang typed/racket
(require "typed-untyped.rkt")
(define-typed/untyped-modules #:no-test #:untyped-first
(provide !temp
(rename-out [!temp &])
format-ids
hyphen-ids
format-temp-ids
#|!temp|#
define-temp-ids)
(require "typed-untyped.rkt"
"untyped-only/syntax-parse.rkt")
(require-typed/untyped "sequence.rkt")
(if-typed (require phc-toolkit/aliases)
(require phc-toolkit/untyped/aliases))
(begin-for-syntax (require "typed-untyped.rkt"
"untyped-only/format-id-record.rkt")
(if-typed (require phc-toolkit/aliases)
(require phc-toolkit/untyped/aliases)))
(module m-!temp racket
(provide !temp)
(require syntax/parse
syntax/parse/experimental/template)
(define-template-metafunction (!temp stx)
(syntax-parse stx
[(_ id:id)
#:with (temp) (generate-temporaries #'(id))
#'temp]
#|[(_ . id:id)
#:with (temp) (generate-temporaries #'(id))
#'temp]
[(_ id:id ...)
(generate-temporaries #'(id ...))]|#)))
(require 'm-!temp)
(require/typed racket/syntax
[format-id ( Syntax String (U String Identifier) *
Identifier)])
(require (only-in racket/syntax define/with-syntax)
(only-in syntax/stx stx-map)
(for-syntax racket/base
racket/format
racket/syntax
syntax/parse
syntax/parse/experimental/template))
;(require racket/sequence) ;; in-syntax
(define-type S-Id-List
(U String
Identifier
(Listof String)
(Listof Identifier)
(Syntaxof (Listof Identifier))))
; TODO: format-ids doesn't accept arbitrary values. Should we change it?
;
(: format-ids ( (U Syntax ( (U String Identifier) * Syntax))
String
S-Id-List *
(Listof Identifier)))
(define (format-ids lex-ctx format . vs)
(let* ([seqs
(map (λ ([v : S-Id-List])
(cond
[(string? v) (in-cycle (in-value v))]
[(identifier? v) (in-cycle (in-value v))]
[(list? v) (in-list v)]
[else (in-list (syntax->list v))]))
vs)]
[justconstants (andmap (λ (x) (or (string? x) (identifier? x))) vs)]
[seqlst (apply sequence-list seqs)])
(for/list : (Listof Identifier)
([items seqlst]
[bound-length (if justconstants
(in-value 'yes)
(in-cycle (in-value 'no)))])
(apply format-id
(if (procedure? lex-ctx) (apply lex-ctx items) lex-ctx)
format
items))))
(: hyphen-ids ( (U Syntax ( (U String Identifier) * Syntax))
S-Id-List *
(Listof Identifier)))
(define (hyphen-ids lex-ctx . vs)
(apply format-ids
lex-ctx
(string-join (map (λ _ "~a") vs) "-")
vs))
(: format-temp-ids ( String
S-Id-List *
(Listof Identifier)))
(define (format-temp-ids format . vs)
;; Introduce the binding in a fresh scope.
(apply format-ids
(λ _ ((make-syntax-introducer) (if (syntax? format)
format
(datum->syntax #f '()))))
format
vs))
(: to-identifier ( Any Identifier))
(define (to-identifier v)
(cond
[(identifier? v) v]
[(syntax? v) (datum->syntax v (to-symbol (syntax-e v)))]
[else (datum->syntax #f (to-symbol v))]))
(: to-symbol ( Any Symbol))
(define (to-symbol v)
(cond
[(symbol? v) v]
[(string? v) (string->symbol v)]
[(number? v) (string->symbol (format "~a" v))]
[else (syntax-e (generate-temporary v))]))
(: generate-string ( String))
(define (generate-string)
(symbol->string
(syntax-e
(generate-temporary ""))))
(require (for-syntax (submod "stx.rkt" untyped)))
(: curried-map-on-attribute-step
( (A B) ( ( A B)
(case→ ( #f #f)
( (Listof A) (Listof B))
( (U #f (Listof A))
(U #f (Listof B)))))))
(define ((curried-map-on-attribute-step f) l)
(if (eq? l #f)
l
(map f l)))
(: curried-map-on-attribute-last
( (A B) ( ( (Syntaxof A) B)
(case→ ( #f #f)
( (Syntaxof A) B)
( (U #f (Syntaxof A)) (U #f B))))))
(define ((curried-map-on-attribute-last f) v)
(if (eq? v #f)
v
(f v)))
;; (map-on-attribute f depth)
(define-syntax (map-on-attribute stx)
(syntax-case stx ()
[(_ f 0)
#'(curried-map-on-attribute-last f)]
[(_ f depth)
#`(curried-map-on-attribute-step
(map-on-attribute f
#,(sub1 (syntax-e #'depth))))]))
(begin-for-syntax
(define-syntax-class dotted
(pattern id:id
#:attr make-dotted
(λ (x) x)
#:attr wrap
(λ (x f) (f x #t))
#:attr depth 0
#:with stx-depth #'0)
(pattern (nested:dotted (~literal ...));(~and dots (~literal ...)) ...+)
#:with id #'nested.id
#:attr make-dotted
(λ (x) #`(#,((attribute nested.make-dotted) x) (... ...)))
#:attr wrap
(λ (x f) (f ((attribute nested.wrap) x f) #f))
#:attr depth (add1 (attribute nested.depth))
#:with stx-depth #`#,(add1 (attribute nested.depth))))
(define-syntax-class simple-format
(pattern format
#:when (string? (syntax-e #'format))
#:when (regexp-match #rx"^([^~]|~~)*~a([^~]|~~)*$"
(syntax-e #'format)))))
;; This macro should really be heavily refactored.
;; TODO: merge all cases thanks to format-id/record and syntax classes.
(define-syntax (define-temp-ids stx)
(with-arrows
(syntax-parse stx
#|
;; TODO : factor this with the next case.
[(_ format ((base:id (~literal ...)) (~literal ...)))
#:when (string? (syntax-e #'format))
(with-syntax ([pat (format-id #'format (syntax-e #'format) #'base)])
#'(define/with-syntax ((pat (... ...)) (... ...))
(stx-map (curry format-temp-ids format)
#'((base (... ...)) (... ...)))))]
|#
;; Multiple formats
[(_ {~and {~optional #:concise} {~seq maybe-concise }}
(format:simple-format )
(~and (~seq options )
(~seq base:dotted
(~or (~seq #:first-base first-base)
(~optional (~seq #:first first)))
(~optional (~seq #:prefix prefix)))))
#'(begin (define-temp-ids maybe-concise format options ) )]
;; New features (arrows and #:first) special-cased for now
;; TODO: make these features more general.
;; With #:first-base, translated to #:first
[(_ {~and {~optional #:concise} {~seq maybe-concise }}
format:simple-format base:dotted
#:first-base first-base
(~optional (~seq #:prefix prefix)))
#:with first (format-id/record #'format #'format #'first-base)
(template
(define-temp-ids maybe-concise format base
#:first first
(?? (?@ #:prefix prefix))))]
;; Base case with a simple format "...~a...".
[(_ {~optional {~and #:concise concise?}}
format:simple-format
base:dotted
(~optional (~seq #:first first))
(~optional (~seq #:first… first…))
(~optional (~seq #:prefix prefix)))
(let* ([base-len (string-length (symbol->string (syntax-e #'base.id)))])
(define/with-syntax pat
(format-id/record #'format #'format #'base.id))
(define/with-syntax pat-dotted ((attribute base.make-dotted) #'pat))
(define/with-syntax maybe-generate-temporary
(if (attribute concise?)
#'to-identifier
#'generate-temporary))
(define/with-syntax format-temp-ids-last
(template
(λ (x)
(car (format-temp-ids (?? (?@ (string-append "~a:" format) prefix)
format)
(maybe-generate-temporary x))))))
(define/with-syntax format-temp-ids*
#'(map-on-attribute format-temp-ids-last base.stx-depth))
(define/with-syntax (tmp-valvar) (generate-temporaries #`(base.id)))
(define/with-syntax do-define-pat
(syntax-parse (attribute-info #'base.id '(pvar attr))
[({~datum attr} valvar depth name syntax?)
#'(define-raw-attribute pat
tmp-valvar
(format-temp-ids* valvar)
depth
syntax?)]
[({~datum pvar} valvar depth)
#'(define-raw-syntax-mapping pat
tmp-valvar
(format-temp-ids* valvar)
depth)]))
(define/with-syntax do-define-first…
(if (attribute first…)
(let ()
(define/with-syntax (tmp-first-valvar)
(generate-temporaries #`(base.id)))
(syntax-parse (attribute-info #'base.id '(pvar attr))
[({~datum attr} valvar depth name syntax?)
;; TODO: always define an attribute, but don't use
;; define-raw-attribute, instead use the copy-attribute
;; code from subtemplate.
#`(define-raw-attribute first…
tmp-first-valvar
(car tmp-valvar)
#,(sub1 (syntax-e #'depth))
syntax?)]
[({~datum pvar} valvar depth)
#`(define-raw-syntax-mapping first…
tmp-first-valvar
(car tmp-valvar)
#,(sub1 (syntax-e #'depth)))]))
#'(begin)))
(define/with-syntax do-define-first
(if (attribute first)
#'(define/with-syntax (first . _)
#'pat-dotted)
#'(begin)))
#'(begin do-define-pat
do-define-first
do-define-first…))]
;; Simplistic handling when the format contains no ~ at all.
;; (TODO: should allow ~~)
[(_ {~optional {~and #:concise concise?}} format base:dotted)
#:when (string? (syntax-e #'format))
#:when (regexp-match #rx"^([^~]|~~)*$" (syntax-e #'format))
(define/with-syntax pat (format-id/record #'format #'format))
(define/with-syntax pat-dotted ((attribute base.make-dotted) #'pat))
(define/with-syntax format-temp-ids*
((attribute base.wrap) #`(λ (x)
#,(if (attribute concise?)
#'(car (format-temp-ids
(string-append format)))
#'(car (format-temp-ids
(string-append format "-~a")
(generate-string)))))
(λ (x deepest?)
(if deepest?
x
#`(curry stx-map #,x)))))
#'(define/with-syntax pat-dotted
(format-temp-ids* #'base))]
;; Very simplistic handling when the name is explicitly given.
[(_ {~optional {~and #:concise concise?}}
name:id format:expr . vs)
#`(define/with-syntax name (format-temp-ids format . vs))]))))

13
in.rkt Normal file
View File

@ -0,0 +1,13 @@
#lang racket/base
(provide in)
(require racket/stxparam
(for-syntax racket/base))
(define-syntax-parameter in
(λ (stx)
(raise-syntax-error
'in
"used out of context. It can only be used in some forms."
stx)))

21
info.rkt Normal file
View File

@ -0,0 +1,21 @@
#lang info
(define collection "phc-toolkit")
(define deps '("base"
"rackunit-lib"
"alexis-util"
"typed-racket-lib"
"typed-racket-more"
"reprovide-lang"
"type-expander"
"hyper-literate"))
(define build-deps '("scribble-lib"
"racket-doc"
"typed-racket-doc"
"predicates"
"rackunit-doc"
"scribble-math"
"drracket"))
(define scribblings '(("scribblings/phc-toolkit.scrbl" (multi-page))))
(define pkg-desc "My toolkit")
(define version "1.1")
(define pkg-authors '(|Georges Dupéron|))

4
is-typed.rkt Normal file
View File

@ -0,0 +1,4 @@
#lang racket/base
(provide if-typed)
;; if-typed
(define-syntax-rule (if-typed t u) t)

4
is-untyped.rkt Normal file
View File

@ -0,0 +1,4 @@
#lang racket/base
(provide if-typed)
;; if-typed
(define-syntax-rule (if-typed t u) u)

19
licenses/bsd.txt Normal file
View 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.

View 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.

46
light-no-check.rkt Normal file
View File

@ -0,0 +1,46 @@
#lang racket/base
(provide (except-out (all-from-out racket/base)
define)
(rename-out [new-: :]
[new-define-type define-type]
[new-define define]
[new-require/typed require/typed]))
(require (for-syntax racket/base))
(begin-for-syntax
(define (process-arg stx)
(syntax-case stx (new-:)
[id/kw (or (identifier? #'id/kw) (keyword? (syntax-e #'id/kw))) #'id/kw]
[[_ _] stx] ;; [arg default]
[[arg new-: _] #'arg]
[[arg new-: _ default] #'[arg default]]))
(define (process-curried stx)
(syntax-case stx ()
[id (identifier? #'id) #'id]
[(recur arg ...)
(with-syntax ([recur.no-types (process-curried #'recur)]
[(arg.no-types ...)
(map process-arg (syntax->list #'(arg ...)))])
#'(recur.no-types arg.no-types ...))])))
(define-syntax (new-: stx) #'(begin))
(define-syntax (new-define-type stx) #'(begin))
(define-syntax (new-define stx)
(syntax-case stx (new-:)
[(_ #:∀ _ curried new-: _ e ...)
(with-syntax ([curried.no-types (process-curried #'curried)])
#'(define curried.no-types e ...))]
[(_ #:∀ _ curried e ...)
(with-syntax ([curried.no-types (process-curried #'curried)])
#'(define curried.no-types e ...))]
[(_ curried new-: _ e ...)
(with-syntax ([curried.no-types (process-curried #'curried)])
#'(define curried.no-types e ...))]
[(_ curried e ...)
(with-syntax ([curried.no-types (process-curried #'curried)])
#'(define curried.no-types e ...))]))
(define-syntax-rule (new-require/typed mod [id τ] ...)
(require (only-in mod id ...)))

16
list-lang.rkt Normal file
View File

@ -0,0 +1,16 @@
#lang racket
(require typed/racket);(only-meta-in 0 typed/racket))
(provide (except-out (all-from-out typed/racket)
#%module-begin)
(rename-out [module-begin #%module-begin]))
(require (for-syntax syntax/parse))
(define-syntax (module-begin stx)
(syntax-parse stx
[(_ forms ... ((~literal define-list-values) name rest ...) values ...)
#'(#%module-begin (define-for-syntax name '(values ...))
(define name rest ... '(values ...))
forms ...)]))

103
list.rkt Normal file
View File

@ -0,0 +1,103 @@
#lang typed/racket
(require "typed-untyped.rkt")
(define-typed/untyped-modules #:no-test
(define-syntax (skip<=6.6 stx)
(syntax-case stx ()
[(_ . rest)
(if (or (regexp-match #px"^6(\\.[012345](\\..*|)|)$" (version))
(regexp-match #px"^6.6$" (version))
(regexp-match #px"^[123245]\\..*$" (version)))
#'(begin)
#'(begin . rest))]))
(skip<=6.6
(provide replace-first))
(provide indexof
map+fold
AListof
List3-Maybe
List3
Listof*)
(define-type (AListof K V) (Listof (Pairof K V)))
(define-match-expander alistof
(λ (stx)
(syntax-case stx ()
[(keys-pat vals-pat)
#'(list (cons keys-pat vals-pat) )])))
(: indexof ( (A B) (->* [A (Listof B)] [( A B Any)] (U #f Integer))))
(define (indexof elt lst [compare equal?])
(let rec ([lst lst] [index 0])
(if (null? lst)
#f
(if (compare elt (car lst))
index
(rec (cdr lst) (+ index 1))))))
(define-type (List3-Maybe Start Mid End)
(Listof* Start
(U Null
(Pairof Mid (Listof End)))))
(define-type (List3 Start Mid End)
(Listof* Start
(Pairof Mid (Listof End))))
(define-type (Listof* Start End)
(Rec R (U (Pairof Start R)
End)))
(skip<=6.6
(: replace-first ( (A B1 B2 C D)
(case→
( C
(Listof (U A B1))
( (U A B1) Any : #:+ B1 #:- (! B1))
(List3-Maybe A C (U A B1)))
( C
(Listof* A (U Null (Pairof B2 D)))
( (U A B2) Any : #:+ (! A) ;; ∴ (and (! A) B2)
#:- (! B2))
(Listof* A (U Null (Pairof C D))))
( C
(Listof* A (Pairof B2 D))
( (U A B2) Any : #:+ (! A) ;; ∴ (and (! A) B2)
#:- (! B2))
(Listof* A (Pairof C D)))
( C
(Listof A)
( (U A B1) Any)
(List3-Maybe A C (U A B1)))
( A
C
(Listof A)
(List3-Maybe A C (U A B1)))
( A
C
(Listof A)
( A (U A B1) Any)
(List3-Maybe A C (U A B1))))))
(define (replace-first a1 a2 a3 [a4 eq?])
(if (list? a3)
(replace-first a2 a3 (λ ([x : (U A B1)]) (a4 a1 x)))
(let ([to a1]
[pred? a3])
(let rec ([l a2])
(if (null? l)
'()
(if (pred? (car l))
(cons to (cdr l))
(cons (car l)
(rec (cdr l))))))))))
(: map+fold ( (E R A) ( ( E A (values R A)) A (Listof E)
(Values (Listof R) A))))
(define (map+fold f init-acc lst)
(if (null? lst)
(values '() init-acc)
(let*-values ([(item new-acc) (f (car lst) init-acc)]
[(new-lst last-acc) (map+fold f new-acc (cdr lst))])
(values (cons item new-lst)
last-acc)))))

82
logn-id.rkt Normal file
View File

@ -0,0 +1,82 @@
#lang typed/racket
(require "typed-untyped.rkt")
(define-typed/untyped-modules #:no-test
(provide define-logn-ids)
(require (for-syntax syntax/parse
racket/syntax
racket/function
racket/match
syntax/stx)
"typed-untyped.rkt")
(begin-for-syntax
(define (insert make-node v ts)
(match ts
[`() `((,v))]
[`(() . ,b) `((,v) . ,b)]
[`((,a) . ,b) `(() . ,(insert make-node (make-node v a) b))]))
(define (merge-trees make-node ts)
(match ts
[`{[,a]} a]
[`{[,a] [] . ,rest} (merge-trees make-node `{[,a] . ,rest})]
[`{[] . ,rest} (merge-trees make-node rest)]
[`{[,a] [,b] . ,rest} (merge-trees make-node
`{[,(make-node a b)] . ,rest})]))
(define (make-binary-tree l make-node make-leaf)
(merge-trees make-node
(foldl (curry insert make-node)
'()
(map make-leaf l)))))
(define-syntax (define-logn-ids stx)
(syntax-parse stx
[(_ matcher:id [id:id ty:id] ...)
(define/with-syntax (tmp ...) (generate-temporaries #'(id ...)))
(define bt
(make-binary-tree (syntax->list #'([ty id . tmp] ...))
(λ (x y) `(node ,(generate-temporary) ,x ,y))
(λ (x) `(leaf ,(stx-car x)
,(generate-temporary (stx-car x))
,(stx-car (stx-cdr x))
,(stx-cdr (stx-cdr x))))))
(define (make-structs bt parent)
(match bt
[`(node ,s ,a ,b) #`(begin (struct #,s #,@parent ())
#,(make-structs a (list s))
#,(make-structs b (list s)))]
[`(leaf ,t ,s ,a ,_) #`(begin (struct #,s #,@parent
()
#:type-name #,t)
(define #,a (#,s)))]))
(define (make-btd bt)
(match bt
[`(node ,s ,(and a `(,_ ,sa . ,_)) ,b)
#`(if (if-typed ((make-predicate #,sa) v-cache)
#,(format-id sa "~a?" sa))
#,(make-btd a)
#,(make-btd b))]
[`(leaf ,s ,a ,t ,tmp)
tmp]))
#`(begin #,(make-structs bt #'())
(define-syntax (matcher stx)
(syntax-parse stx
[(_ v:expr [(~literal id) tmp] ...)
#'(let ([v-cache v])
#,(make-btd bt))])))]))
(module* test typed/racket
(require (submod "..")
typed/rackunit)
(define-logn-ids match-x [a A] [b B] [c C] [d D] [e E])
(check-equal? (match-x (ann b (U A B C D E))
[a 1]
[b 2]
[c 3]
[d 4]
[e 5])
2)))

45
main.rkt Normal file
View File

@ -0,0 +1,45 @@
#lang typed/racket
(require "typed-untyped.rkt")
(define-typed/untyped-modules #:no-test
(require "typed-untyped.rkt")
(provide (all-from-out "typed-untyped.rkt"))
(if-typed
(begin (require "aliases.rkt")
(provide (all-from-out "aliases.rkt")))
(begin (require "untyped/aliases.rkt")
(provide (all-from-out "untyped/aliases.rkt"))))
;(require/provide (typed/untyped "fixnum.rkt" …))
(require/provide-typed/untyped
"misc.rkt"
"require-provide.rkt"
"fixnum.rkt"
"typed-rackunit.rkt"
"typed-rackunit-extensions.rkt"
"syntax-parse.rkt"
"tmpl.rkt"
"threading.rkt"
"sequence.rkt"
"repeat-stx.rkt"
"stx.rkt"
"list.rkt"
"values.rkt"
"ids.rkt"
"generate-indices.rkt"
"set.rkt"
"type-inference-helpers.rkt"
"percent.rkt"
"not-implemented-yet.rkt"
"cond-let.rkt"
"multiassoc-syntax.rkt"
"tmpl-multiassoc-syntax.rkt"
"logn-id.rkt"
"compat.rkt"
"eval-get-values.rkt"
"meta-struct.rkt"
"contract.rkt")
(when-untyped
(require/provide "untyped/for-star-list-star.rkt"
"untyped/format-id-record.rkt")))

131
meta-struct.rkt Normal file
View File

@ -0,0 +1,131 @@
#lang typed/racket
(require "typed-untyped.rkt")
(define-typed/untyped-modules #:no-test
(require (for-syntax syntax/parse/experimental/template
syntax/parse
racket/syntax))
(begin-for-syntax
(provide meta-struct?
(struct-out meta-struct-info)
get-meta-struct-info
;; More provided by `shorthand` in the code below
meta-struct-subtype?
struct-type-id-is-immutable?))
(provide struct-predicate
struct-constructor
struct-accessor
struct-type-is-immutable?
struct-instance-is-immutable?)
(module info racket/base
(require racket/struct-info)
(provide meta-struct?
(struct-out meta-struct-info)
get-meta-struct-info)
(define (meta-struct? s)
(and (identifier? s)
(let ([v (syntax-local-value s (λ _ #f))])
(and v (struct-info? v)))))
(struct meta-struct-info
(type-descriptor
constructor
predicate
accessors
mutators
super-type)
#:transparent)
(define (get-meta-struct-info s
#:srcloc [srcloc #f]
#:fallback [fallback #f])
(if (meta-struct? s)
(apply meta-struct-info
(extract-struct-info (syntax-local-value s)))
(if fallback
(fallback)
(raise-syntax-error 'get-struct-info
"not a structure definition"
(or srcloc s)
s)))))
(require 'info
(for-syntax 'info))
(define-syntax (shorthand stx)
(syntax-case stx ()
[(_ base)
(with-syntax ([name (format-id #'base "meta-struct-~a" #'base)]
[accessor (format-id #'base "meta-struct-info-~a" #'base)]
[tmpl (format-id #'base "!struct-~a" #'base)])
#'(begin-for-syntax
(provide name tmpl)
(define-template-metafunction (tmpl stx)
(syntax-parse stx
[(_ s
(~optional (~seq #:srcloc srcloc))
(~optional (~seq #:fallback fallback)))
(accessor
(get-meta-struct-info #'s #:srcloc (attribute srcloc)))]))
(define (name s #:srcloc [srcloc #f] #:fallback [fallback #f])
(define err (gensym))
(define val
(get-meta-struct-info s
#:srcloc srcloc
#:fallback (and fallback (λ () err))))
(if (and (eq? val err) fallback)
(fallback)
(accessor val)))))]))
(shorthand type-descriptor)
(shorthand constructor)
(shorthand predicate)
(shorthand accessors)
(shorthand mutators)
(shorthand super-type)
(define-syntax (struct-predicate stx)
(syntax-case stx ()
[(_ s) (meta-struct-info-predicate (get-meta-struct-info #'s))]))
(define-syntax (struct-constructor stx)
(syntax-case stx ()
[(_ s) (meta-struct-info-constructor (get-meta-struct-info #'s))]))
(define-syntax (struct-accessor stx)
(syntax-case stx ()
[(_ s field)
(identifier? #'field)
(begin
(record-disappeared-uses (list #'s #'field))
(format-id #'s "~a-~a" #'s #'field))]
[(_ s i)
(exact-positive-integer? (syntax-e #'i))
(list-ref (meta-struct-info-accessors (get-meta-struct-info #'s))
(syntax-e #'i))]))
(define-for-syntax (meta-struct-subtype? sub super)
(or (equal? (meta-struct-type-descriptor sub)
(meta-struct-type-descriptor super))
(let ((up (meta-struct-super-type sub)))
(and (meta-struct? up)
(meta-struct-subtype? up super)))))
(define-for-syntax (struct-type-id-is-immutable? id)
(andmap not (meta-struct-mutators id)))
(define (struct-type-is-immutable? [st : Struct-TypeTop]) : Boolean
(let-values ([(_1 nfields _3 _4 _5 immutable-idx super not-most-specific?)
(struct-type-info st)])
(and (not not-most-specific?)
(equal? (sort immutable-idx <)
(range nfields))
(if super (struct-type-is-immutable? super) #t))))
(define (struct-instance-is-immutable? v)
(let-values ([(st not-most-specific?) (struct-info v)])
(and (not not-most-specific?)
st
(struct-type-is-immutable? st)))))

75
misc.rkt Normal file
View File

@ -0,0 +1,75 @@
#lang typed/racket
(require "typed-untyped.rkt")
(define-typed/untyped-modules #:no-test
(provide hash-set**
;string-set!
;string-copy!
;string-fill!
with-output-file
or?)
(require (for-syntax syntax/parse syntax/parse/experimental/template))
;; hash-set**: hash-set a list of K V pairs.
(begin
(: hash-set** ( (K V)
( (HashTable K V) (Listof (Pairof K V)) (HashTable K V))))
(define (hash-set** h l)
(if (null? l)
h
(hash-set** (hash-set h (caar l) (cdar l)) (cdr l)))))
;; Disable string mutation
(begin
(define-syntax (string-set! stx)
(raise-syntax-error 'string-set! "Do not mutate strings." stx))
(define-syntax (string-copy! stx)
(raise-syntax-error 'string-copy! "Do not mutate strings." stx))
(define-syntax (string-fill! stx)
(raise-syntax-error 'string-fill! "Do not mutate strings." stx)))
;; with-output-file
(begin
#|
(define-syntax (with-output-file stx)
(syntax-parse stx
[(_ filename:expr (~optional (~seq #:mode mode:expr))
(~optional (~seq #:exists exists:expr))
body ...)
(template (with-output-to-file filename
(λ () body ...)
(?? (?@ #:mode mode))
(?? (?@ #:exists exists))))]))
|#
(define-syntax (with-output-file stx)
(syntax-parse stx
[(_ [var:id filename:expr]
(~optional (~seq #:mode mode:expr))
(~optional (~seq #:exists exists:expr))
body ...)
(template (call-with-output-file filename
(λ (var) body ...)
(?? (?@ #:mode mode))
(?? (?@ #:exists exists))))])))
#;(: or? ( (A B) (case→ ( ( A A))
( ( A B) ( A B) * ( A B)))))
#;(define or?
(case-lambda
[() (λ (a)
a)]
[(f . f*) (λ (a)
(let ([b (f a)])
(if (or b (null? f*))
b
((apply or? f*) a))))]))
(: or? ( (A) ( ( A Boolean) * ( A (U A #f)))))
(define (or? . f*)
(if (null? f*)
(λ (a) a)
(λ (a)
(if ((car f*) a)
a
((apply (inst or? A) (cdr f*)) a))))))

36
multiassoc-syntax.rkt Normal file
View File

@ -0,0 +1,36 @@
#lang typed/racket
(require "typed-untyped.rkt")
(define-typed/untyped-modules #:no-test
(provide multiassoc-syntax
cdr-assoc-syntax
assoc-syntax)
(require "typed-untyped.rkt")
(if-typed (require phc-toolkit/aliases)
(require phc-toolkit/untyped/aliases))
(require-typed/untyped "stx.rkt")
;; TODO: cdr-stx-assoc is already defined in lib/low.rkt
(define-type (Stx-AList A)
(Syntaxof (Listof (Syntaxof (Pairof Identifier A)))))
(: multiassoc-syntax ( (A) ( Identifier (Stx-AList A) (Listof A))))
(define (multiassoc-syntax query alist)
((inst map A (Syntaxof (Pairof Identifier A)))
stx-cdr
(filter (λ ([xy : (Syntaxof (Pairof Identifier A))])
(free-identifier=? query (stx-car xy)))
(syntax->list alist))))
(: cdr-assoc-syntax ( (A) ( Identifier (Stx-AList A) A)))
(define (cdr-assoc-syntax query alist)
(stx-cdr (assert (assoc-syntax query alist))))
(: assoc-syntax ( (A) ( Identifier
(Stx-AList A)
(U False (Syntaxof (Pairof Identifier A))))))
(define (assoc-syntax query alist)
(findf (λ ([xy : (Syntaxof (Pairof Identifier A))])
(free-identifier=? query (stx-car xy)))
(syntax->list alist))))

19
not-implemented-yet.rkt Normal file
View File

@ -0,0 +1,19 @@
#lang typed/racket
(require "typed-untyped.rkt")
(define-typed/untyped-modules #:no-test
(provide ? ?*)
(define-syntax (?* stx)
(syntax-case stx ()
[(q . rest)
(quasisyntax/loc stx
((λ () : (U) #,(syntax/loc #'q (error "Not implemented yet"))
. rest)))]))
(define-syntax (? stx)
(syntax-case stx ()
[(q t . rest)
(quasisyntax/loc stx
((ann (λ () #,(syntax/loc #'q (error "Not implemented yet"))
. rest)
( t))))])))

51
partial-include.rkt Normal file
View File

@ -0,0 +1,51 @@
#lang racket/base
(provide include-without-first-line)
(require (for-syntax racket/base))
(define-for-syntax (replace-context ctx stx)
(define (recur e)
(cond
[(syntax? e) (datum->syntax ctx (recur (syntax-e e)) e e)]
[(pair? e) (cons (recur (car e)) (recur (cdr e)))]
[(null? e) e]
[(vector? e) ((if (immutable? e)
vector->immutable-vector
(λ (v) v))
(list->vector
(recur (vector->list e))))]
[(hash? e) ((if (immutable? e)
(cond [(hash-eq? e) make-immutable-hasheq]
[(hash-eqv? e) make-immutable-hasheqv]
[else make-immutable-hash])
(cond [(hash-eq? e) make-hasheq]
[(hash-eqv? e) make-hasheqv]
[else make-hash]))
(recur (hash->list e)))]
[(prefab-struct-key e) => (λ (k)
(apply make-prefab-struct
k
(recur (cdr
(vector->list
(struct->vector e))))))]
[(box? e) ((if (immutable? e) box-immutable box)
(recur (unbox e)))]
[else e]))
(recur stx))
(define-syntax (include-without-first-line stx)
(syntax-case stx ()
[(_ filename1-stx . filename+-stx)
(let*-values ([(user-filename) (map syntax-e
(syntax->list
#'(filename1-stx . filename+-stx)))]
[(base _1 _2) (split-path (syntax-source #'filename1-stx))]
[(filename) (apply build-path base user-filename)])
(with-input-from-file filename
(λ ()
(read-line) ;; discard the first line.
(replace-context
#'filename1-stx
#`(begin
. #,(for/list ([rd (in-producer read-syntax eof filename)])
rd))))))]))

78
percent.rkt Normal file
View File

@ -0,0 +1,78 @@
#lang typed/racket
(require "typed-untyped.rkt")
(define-typed/untyped-modules #:no-test
(provide % define% in let1)
(require (for-syntax syntax/parse
"typed-untyped.rkt")
"in.rkt")
(begin-for-syntax
(if-typed (require phc-toolkit/aliases)
(require phc-toolkit/untyped/aliases)))
(define-syntax-rule (let1 var val . body)
(let-values ([(var) val]) . body))
#|(define-syntax (% stx)
(syntax-parse stx #:literals (= :)
[(_ (~seq (~or ((~and var (~not :)) ...)
(~seq (~and var (~not (~or = :))) ...)) = expr)
...
(~optional (~literal )) . body)
#'(let-values ([(var ...) expr] ...) . body)]))|#
(begin-for-syntax
(define-syntax-class %pat
(pattern v:id
#:with expanded #'v)
(pattern ()
#:with expanded #'(list))
(pattern (x:%pat . rest:%pat)
#:with expanded #'(cons x.expanded rest.expanded))
(pattern #(x:%pat )
#:with expanded #'(vector x.expanded )))
(define-splicing-syntax-class %assignment
#:attributes ([pat.expanded 1] [expr 0])
#:literals (= in)
(pattern (~seq (~and maybe-pat (~not (~or = in))) ...
(~datum =) expr:expr)
#:with [pat:%pat ...] #'(maybe-pat ...))))
(define-syntax (% stx)
(syntax-parse stx #:literals (= in)
[(_ :%assignment ... (~optional (~literal in)) . body)
#'(match-let*-values ([(pat.expanded ...) expr] ...) . body)]))
(begin-for-syntax
(define-syntax-class typed-pat
(pattern [x:%pat (~literal :) type:expr]
#:with (tmp) (generate-temporaries #'(x))
#:with var-type #`[tmp : type]
#:with (expanded ...) #'([x.expanded tmp]))
(pattern x:id
#:with var-type #'x
#:with (expanded ...) #'())
(pattern x:%pat
#:with (tmp) (generate-temporaries #'(x))
#:with var-type #'tmp
#:with (expanded ...) #'([x.expanded tmp]))))
(define-syntax (define% stx)
(syntax-parse stx
[(_ (name param:typed-pat ...)
(~and (~seq ret ...) (~optional (~seq (~literal :) ret-type)))
. body)
#'(define (name param.var-type ...)
(match-let (param.expanded ... ...) ret ... . body))]))
#|
(begin-for-syntax
(define-syntax-class λ%expr
(pattern e:id #:where (symbol->string e))
(pattern e)
(pattern (e . rest:λ%expr))))
(define-syntax (λ% stx)
(syntax-parse stx
[(_ expr )]))
|#)

BIN
perf.rkt.ods Normal file

Binary file not shown.

View File

@ -0,0 +1,98 @@
cd /tmp; for m in '' phc-toolkit/untyped phc-toolkit/untyped/misc phc-toolkit/untyped/require-provide phc-toolkit/untyped/fixnum phc-toolkit/untyped/typed-rackunit phc-toolkit/untyped/typed-rackunit-extensions phc-toolkit/untyped/syntax-parse phc-toolkit/untyped/tmpl phc-toolkit/untyped/threading phc-toolkit/untyped/aliases phc-toolkit/untyped/sequence phc-toolkit/untyped/repeat-stx phc-toolkit/untyped/stx phc-toolkit/untyped/list phc-toolkit/untyped/values phc-toolkit/untyped/ids phc-toolkit/untyped/generate-indices phc-toolkit/untyped/set phc-toolkit/untyped/type-inference-helpers phc-toolkit/untyped/percent phc-toolkit/untyped/not-implemented-yet phc-toolkit/untyped/cond-let phc-toolkit/untyped/multiassoc-syntax phc-toolkit/untyped/tmpl-multiassoc-syntax phc-toolkit/untyped/logn-id phc-toolkit/untyped/compat phc-toolkit/untyped/eval-get-values phc-toolkit/untyped/meta-struct phc-toolkit/untyped/contract; do echo "#lang racket/base (require $m)" > perf.rkt; echo $(((0$(for i in `seq 5`; do rm -fr compiled; t="$((time raco make perf.rkt) 2>&1)"; echo -n '+'; echo "$t" | sed -e 's/raco make perf.rkt *//' -e 's/s .*$//' -e 's/^\([0-9]*\)$/\100/' -e 's/,\([0-9]\)$/\10/' -e 's/,\([0-9][0-9]\)/\1/'; done)) / 5)) $m; done
36 none
140 phc-toolkit/untyped
83 phc-toolkit/untyped/misc
83 phc-toolkit/untyped/require-provide
81 phc-toolkit/untyped/fixnum
126 phc-toolkit/untyped/typed-rackunit
129 phc-toolkit/untyped/typed-rackunit-extensions
84 phc-toolkit/untyped/syntax-parse
81 phc-toolkit/untyped/tmpl
81 phc-toolkit/untyped/threading
82 phc-toolkit/untyped/aliases
83 phc-toolkit/untyped/sequence
81 phc-toolkit/untyped/repeat-stx
83 phc-toolkit/untyped/stx
81 phc-toolkit/untyped/list
82 phc-toolkit/untyped/values
103 phc-toolkit/untyped/ids
82 phc-toolkit/untyped/generate-indices
81 phc-toolkit/untyped/set
112 phc-toolkit/untyped/type-inference-helpers
84 phc-toolkit/untyped/percent
82 phc-toolkit/untyped/not-implemented-yet
82 phc-toolkit/untyped/cond-let
83 phc-toolkit/untyped/multiassoc-syntax
82 phc-toolkit/untyped/tmpl-multiassoc-syntax
81 phc-toolkit/untyped/logn-id
80 phc-toolkit/untyped/compat
83 phc-toolkit/untyped/eval-get-values
81 phc-toolkit/untyped/meta-struct
83 phc-toolkit/untyped/contract
cd /tmp; for m in '' phc-toolkit/untyped phc-toolkit/untyped/misc phc-toolkit/untyped/require-provide phc-toolkit/untyped/fixnum phc-toolkit/untyped/typed-rackunit phc-toolkit/untyped/typed-rackunit-extensions phc-toolkit/untyped/syntax-parse phc-toolkit/untyped/tmpl phc-toolkit/untyped/threading phc-toolkit/untyped/aliases phc-toolkit/untyped/sequence phc-toolkit/untyped/repeat-stx phc-toolkit/untyped/stx phc-toolkit/untyped/list phc-toolkit/untyped/values phc-toolkit/untyped/ids phc-toolkit/untyped/generate-indices phc-toolkit/untyped/set phc-toolkit/untyped/type-inference-helpers phc-toolkit/untyped/percent phc-toolkit/untyped/not-implemented-yet phc-toolkit/untyped/cond-let phc-toolkit/untyped/multiassoc-syntax phc-toolkit/untyped/tmpl-multiassoc-syntax phc-toolkit/untyped/logn-id phc-toolkit/untyped/compat phc-toolkit/untyped/eval-get-values phc-toolkit/untyped/meta-struct phc-toolkit/untyped/contract; do echo "#lang racket (require $m)" > perf.rkt; echo $(((0$(for i in `seq 5`; do rm -fr compiled; t="$((time raco make perf.rkt) 2>&1)"; echo -n '+'; echo "$t" | sed -e 's/raco make perf.rkt *//' -e 's/s .*$//' -e 's/^\([0-9]*\)$/\100/' -e 's/,\([0-9]\)$/\10/' -e 's/,\([0-9][0-9]\)/\1/'; done)) / 5)) $m; done
55 none
143 phc-toolkit/untyped
82 phc-toolkit/untyped/misc
83 phc-toolkit/untyped/require-provide
82 phc-toolkit/untyped/fixnum
126 phc-toolkit/untyped/typed-rackunit
129 phc-toolkit/untyped/typed-rackunit-extensions
83 phc-toolkit/untyped/syntax-parse
82 phc-toolkit/untyped/tmpl
83 phc-toolkit/untyped/threading
82 phc-toolkit/untyped/aliases
83 phc-toolkit/untyped/sequence
83 phc-toolkit/untyped/repeat-stx
84 phc-toolkit/untyped/stx
82 phc-toolkit/untyped/list
82 phc-toolkit/untyped/values
103 phc-toolkit/untyped/ids
82 phc-toolkit/untyped/generate-indices
83 phc-toolkit/untyped/set
110 phc-toolkit/untyped/type-inference-helpers
82 phc-toolkit/untyped/percent
83 phc-toolkit/untyped/not-implemented-yet
82 phc-toolkit/untyped/cond-let
84 phc-toolkit/untyped/multiassoc-syntax
83 phc-toolkit/untyped/tmpl-multiassoc-syntax
82 phc-toolkit/untyped/logn-id
83 phc-toolkit/untyped/compat
81 phc-toolkit/untyped/eval-get-values
82 phc-toolkit/untyped/meta-struct
82 phc-toolkit/untyped/contract
cd /tmp; for m in '' phc-toolkit phc-toolkit/misc phc-toolkit/require-provide phc-toolkit/fixnum phc-toolkit/typed-rackunit phc-toolkit/typed-rackunit-extensions phc-toolkit/syntax-parse phc-toolkit/tmpl phc-toolkit/threading phc-toolkit/aliases phc-toolkit/sequence phc-toolkit/repeat-stx phc-toolkit/stx phc-toolkit/list phc-toolkit/values phc-toolkit/ids phc-toolkit/generate-indices phc-toolkit/set phc-toolkit/type-inference-helpers phc-toolkit/percent phc-toolkit/not-implemented-yet phc-toolkit/cond-let phc-toolkit/multiassoc-syntax phc-toolkit/tmpl-multiassoc-syntax phc-toolkit/logn-id phc-toolkit/compat phc-toolkit/eval-get-values phc-toolkit/meta-struct phc-toolkit/contract; do echo "#lang typed/racket/base (require $m)" > perf.rkt; echo $(((0$(for i in `seq 5`; do rm -fr compiled; t="$((time raco make perf.rkt) 2>&1)"; echo -n '+'; echo "$t" | sed -e 's/raco make perf.rkt *//' -e 's/s .*$//' -e 's/^\([0-9]*\)$/\100/' -e 's/,\([0-9]\)$/\10/' -e 's/,\([0-9][0-9]\)/\1/'; done)) / 5)) $m; done
153 none
291 phc-toolkit
167 phc-toolkit/misc
170 phc-toolkit/require-provide
172 phc-toolkit/fixnum
233 phc-toolkit/typed-rackunit
238 phc-toolkit/typed-rackunit-extensions
175 phc-toolkit/syntax-parse
167 phc-toolkit/tmpl
169 phc-toolkit/threading
172 phc-toolkit/aliases
170 phc-toolkit/sequence
169 phc-toolkit/repeat-stx
178 phc-toolkit/stx
167 phc-toolkit/list
171 phc-toolkit/values
243 phc-toolkit/ids
170 phc-toolkit/generate-indices
168 phc-toolkit/set
198 phc-toolkit/type-inference-helpers
173 phc-toolkit/percent
167 phc-toolkit/not-implemented-yet
172 phc-toolkit/cond-let
180 phc-toolkit/multiassoc-syntax
172 phc-toolkit/tmpl-multiassoc-syntax
171 phc-toolkit/logn-id
168 phc-toolkit/compat
174 phc-toolkit/eval-get-values
170 phc-toolkit/meta-struct
167 phc-toolkit/contract

114
repeat-stx.rkt Normal file
View File

@ -0,0 +1,114 @@
#lang typed/racket
(require "typed-untyped.rkt")
(define-typed/untyped-modules #:no-test
(provide repeat-stx)
(require syntax/stx
(for-syntax racket/base
racket/syntax
syntax/parse))
(define-for-syntax (repeat-stx-2 stx)
(syntax-parse stx
[(a:id b:id)
#'(λ _ a)]
[(a:id (b:expr (~literal ...)))
#`(λ (bs) (stx-map #,(repeat-stx-2 #'(a b)) bs))]))
(define-for-syntax (repeat-stx-1 stx)
(syntax-parse stx
[(a:id b:expr)
#`(λ (a bs) (#,(repeat-stx-2 #'(a b)) bs))]
[((a:expr (~literal ...)) (b:expr (~literal ...)))
#`(λ (s1 s2) (stx-map #,(repeat-stx-1 #'(a b)) s1 s2))]))
(define-syntax (repeat-stx stx)
(syntax-parse stx
[(_ a:expr b:expr)
#`(#,(repeat-stx-1 #'(a b)) #'a #'b)])))
(module test racket
(require (submod ".." untyped))
(require syntax/parse
rackunit)
(check-equal?
(syntax-parse #'(1 2)
[(a b)
(syntax->datum
(datum->syntax
#'dummy
(repeat-stx a b)))])
1)
(check-equal?
(syntax-parse #'(1 2 3)
[(a b ...)
(syntax->datum
(datum->syntax
#'dummy
(repeat-stx a (b ...))))])
'(1 1))
(check-equal?
(syntax-parse #'(1 (2 3) (uu vv ww) (xx yy))
[(a (b ...) ...)
(syntax->datum
(datum->syntax
#'dummy
(repeat-stx a ((b ...) ...))))])
'((1 1) (1 1 1) (1 1)))
(check-equal?
(syntax-parse #'(1 ((2) (3 3)) ((uu) (vv vv) (ww ww ww)) ((xx) (yy)))
[(a ((b ...) ...) ...)
(syntax->datum
(datum->syntax
#'dummy
(repeat-stx a (((b ...) ...) ...))))])
'(((1) (1 1)) ((1) (1 1) (1 1 1)) ((1) (1))))
(check-equal?
(syntax-parse #'([1 x] [2 y] [3 z])
[([a b] ...)
(syntax->datum
(datum->syntax
#'dummy
(repeat-stx (a ...) (b ...))))])
'(1 2 3))
(check-equal?
(syntax-parse #'((1 2 3) (a b))
[([a b ...] ...)
(syntax->datum
(datum->syntax
#'dummy
(repeat-stx (a ...) ((b ...) ...))))])
'((1 1) (a)))
(check-equal?
(syntax-parse #'(((1 2 3) (a b)) ((x y z t) (-1 -2)))
[[[[a b ...] ...] ...]
(syntax->datum
(datum->syntax
#'dummy
(repeat-stx ((a ...) ...) (((b ...) ...) ...))))])
'(((1 1) (a)) ((x x x) (-1))))
(check-equal?
(syntax-parse #'((f (1 2 3) (a b)) (g (x y z t) (-1 -2)))
[[[a (b ...) ...] ...]
(syntax->datum
(datum->syntax
#'dummy
(repeat-stx (a ...) (((b ...) ...) ...))))])
'(((f f f) (f f)) ((g g g g) (g g))))
(check-equal?
(syntax-parse #'((h () ()) (i () (x y z) ()))
[([a (b ...) ...] ...)
(syntax->datum
(datum->syntax
#'dummy
(repeat-stx (a ...) (((b ...) ...) ...))))])
'((() ()) (() (i i i) ()))))

22
require-provide.rkt Normal file
View File

@ -0,0 +1,22 @@
#lang typed/racket
(require "typed-untyped.rkt")
(define-typed/untyped-modules
(provide require/provide)
(define-syntax (require/provide stx)
(syntax-case stx ()
[(_ require-spec ...)
#'(begin
(require require-spec ...)
(provide (all-from-out require-spec ...)))]))
(module+ test
(require typed/rackunit)
(module ma typed/racket
(define require-provide-foo 7)
(provide require-provide-foo))
(module mb typed/racket
(require (submod ".." ".."))
(require/provide (submod ".." ma)))
(require 'mb)
(check-equal? require-provide-foo 7)))

View File

@ -0,0 +1,29 @@
#lang scribble/manual
@require["utils.rkt"
@for-label[phc-toolkit/untyped/aliases
racket/base
(only-in racket ... compose)
racket/match
syntax/parse]]
@(def-orig orig [racket/syntax]
generate-temporary)
@title{Untyped versions of the aliases}
@defmodule[phc-toolkit/untyped/aliases
#:use-sources
[phc-toolkit/untyped/aliases]]
@defidform[∘]{An alias for @racket[compose]}
@defidform[…]{An alias for @racket[...]}
@defidform[…+]{An alias for @racket[...+]}
@defidform[match-λ]{An alias for @racket[match-lambda]}
@defidform[match-λ*]{An alias for @racket[match-lambda*]}
@defidform[match-λ**]{An alias for @racket[match-lambda**]}
@defidform[generate-temporary]{Equivalent to @orig:generate-temporary (but not
@racket[free-identifier=?] to the original for now)}
@defidform[attr]{An alias for @racket[attribute] which also works for plain
syntax pattern variables}
@defidform[|@|]{An alias for @racket[attribute] which also works for plain
syntax pattern variables}
@defform[(when-attr name expr)]{
Equivalent to @racket[(if (attribute name) expr #'())]}

31
scribblings/aliases.scrbl Normal file
View File

@ -0,0 +1,31 @@
#lang scribble/manual
@require["utils.rkt"
@for-label[phc-toolkit/aliases
racket/base
(only-in racket ... compose)
racket/match
syntax/parse]]
@(def-orig orig [racket/syntax]
generate-temporary)
@title{Aliases for other racket identifiers}
@author{@author+email["Georges Dupéron" "georges.duperon@gmail.com"]}
@defmodule[phc-toolkit/aliases
#:use-sources
[phc-toolkit/aliases]]
@defidform[∘]{An alias for @racket[compose]}
@defidform[…]{An alias for @racket[...]}
@defidform[…+]{An alias for @racket[...+]}
@defidform[match-λ]{An alias for @racket[match-lambda]}
@defidform[match-λ*]{An alias for @racket[match-lambda*]}
@defidform[match-λ**]{An alias for @racket[match-lambda**]}
@defidform[generate-temporary]{Typed version of @orig:generate-temporary}
@defidform[attr]{An alias for @racket[attribute] which also works for plain
syntax pattern variables}
@defidform[|@|]{An alias for @racket[attribute] which also works for plain
syntax pattern variables}
@defform[(when-attr name expr)]{
Equivalent to @racket[(if (attribute name) expr #'())]}
@include-section{aliases-untyped.scrbl}

View File

@ -0,0 +1,11 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/untyped/backtrace]]
@(def-orig typed [phc-toolkit/backtrace])
@title{Untyped versions of backtrace}
@author{@author+email["Georges Dupéron" "georges.duperon@gmail.com"]}
@defmodule[phc-toolkit/untyped/backtrace
#:use-sources
[(submod (lib "phc-toolkit/backtrace.rkt") untyped)]]

View File

@ -0,0 +1,11 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/backtrace]]
@title{backtrace}
@author{@author+email["Georges Dupéron" "georges.duperon@gmail.com"]}
@defmodule[phc-toolkit/backtrace
#:use-sources
[(submod (lib "phc-toolkit/backtrace.rkt") typed)]]
@include-section{backtrace-untyped.scrbl}

View File

@ -0,0 +1,16 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/untyped/compat]]
@(def-orig typed [phc-toolkit/compat]
with-disappeared-uses*
record-disappeared-uses*)
@title{Untyped versions of compat}
@defmodule[phc-toolkit/untyped/compat
#:use-sources
[(submod (lib "phc-toolkit/compat.rkt") untyped)]]
@defidform[record-disappeared-uses*]{
Untyped version of @|typed:record-disappeared-uses*|.}
@defidform[with-disappeared-uses*]{
Untyped version of @|typed:with-disappeared-uses*|.}

23
scribblings/compat.scrbl Normal file
View File

@ -0,0 +1,23 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/compat]]
@title{Compatibility wrappers}
@author{@author+email["Georges Dupéron" "georges.duperon@gmail.com"]}
@defmodule[phc-toolkit/compat
#:use-sources
[(submod (lib "phc-toolkit/compat.rkt") typed)]]
@defproc[(record-disappeared-uses* [ids : (U Identifier (Listof Identifier))])
Any]{
On Racket 6.5, @racket[record-disappeared-uses] only accepted a list
of identifiers, not a single identifier on its own. This wrapper allows
passing a single identifier on Racket 6.5 too.}
@defform[(with-disappeared-uses* . body)]{
On Racket 6.5, @racket[with-disappeared-uses] allowed a single body
expression. This wrapper wraps the @racket[body] expressions with a
@racket[let] form, so that multiple expressions and definitions can be used as
the body of @racket[with-disappeared-uses*] on Racket 6.5 too.}
@include-section{compat-untyped.scrbl}

View File

@ -0,0 +1,10 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/untyped/cond-let]]
@(def-orig typed [phc-toolkit/cond-let])
@title{Untyped versions of cond-let}
@defmodule[phc-toolkit/untyped/cond-let
#:use-sources
[(submod (lib "phc-toolkit/cond-let.rkt") untyped)]]

View File

@ -0,0 +1,11 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/cond-let]]
@title{cond-let}
@author{@author+email["Georges Dupéron" "georges.duperon@gmail.com"]}
@defmodule[phc-toolkit/cond-let
#:use-sources
[(submod (lib "phc-toolkit/cond-let.rkt") typed)]]
@include-section{cond-let-untyped.scrbl}

View File

@ -0,0 +1,10 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/untyped/contract]]
@(def-orig typed [phc-toolkit/contract])
@title{Untyped versions of contract}
@defmodule[phc-toolkit/untyped/contract
#:use-sources
[(submod (lib "phc-toolkit/contract.rkt") untyped)]]

View File

@ -0,0 +1,33 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/contract
racket/function
racket/contract]]
@title{contract}
@author{@author+email["Georges Dupéron" "georges.duperon@gmail.com"]}
@defmodule[phc-toolkit/contract
#:use-sources
[(submod (lib "phc-toolkit/contract.rkt") typed)]]
@defproc[(regexp-match/c [rx (or/c string? regexp?)]) contract?
#:value (and/c (or/c string? bytes? path? input-port?)
(curry regexp-match? rx))]{
Returns a contract which accepts only values matching the given regular
expression.}
@defproc[(id/c [id identifier?]) contract?
#:value (and/c identifier? (curry free-identifier=? id))]{
Returns a contract which accepts only identifiers which are
@racket[free-identifier=?] to @racket[id].}
@defidform[define/contract?]{
Like @racket[define/contract], but later versions of this library may allow
disabling the contracts via a parameter or syntax parameter. This form will be
useful for internal functions, to ease debugging during development, but with
the (future) possibility of disabling the contracts in the final version, to
avoid the performance cost of checking many contracts between internal
functions.}
@include-section{contract-untyped.scrbl}

View File

@ -0,0 +1,10 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/untyped/eval-get-values]]
@(def-orig typed [phc-toolkit/eval-get-values])
@title{Untyped versions of eval-get-values}
@defmodule[phc-toolkit/untyped/eval-get-values
#:use-sources
[(submod (lib "phc-toolkit/eval-get-values.rkt") untyped)]]

View File

@ -0,0 +1,11 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/eval-get-values]]
@title{eval-get-values}
@author{@author+email["Georges Dupéron" "georges.duperon@gmail.com"]}
@defmodule[phc-toolkit/eval-get-values
#:use-sources
[(submod (lib "phc-toolkit/eval-get-values.rkt") typed)]]
@include-section{eval-get-values-untyped.scrbl}

View File

@ -0,0 +1,10 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/untyped/fixnum]]
@(def-orig typed [phc-toolkit/fixnum])
@title{Untyped versions of fixnum}
@defmodule[phc-toolkit/untyped/fixnum
#:use-sources
[(submod (lib "phc-toolkit/fixnum.rkt") untyped)]]

20
scribblings/fixnum.scrbl Normal file
View File

@ -0,0 +1,20 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/fixnum]]
@(def-orig orig [racket/fixnum] fxxor)
@title{Fixnum operations (fxxor …)}
@author{@author+email["Georges Dupéron" "georges.duperon@gmail.com"]}
@defmodule[phc-toolkit/fixnum
#:use-sources
[(submod (lib "phc-toolkit/fixnum.rkt") typed)]]
@defproc[(fxxor2 [a Fixnum] [b Fixnum]) Fixnum]{
@orig:fxxor from @racketmodname[racket/fixnum], re-provided with the type
@racket[(Fixnum Fixnum → Fixnum)].}
@defproc[(fxxor [a Fixnum] ...) Fixnum]{
N-aray generalization or @racket[fxxor2]. Equivalent to
@racket[(foldl fxxor2 0 args)].}
@include-section{fixnum-untyped.scrbl}

View File

@ -0,0 +1,33 @@
#lang scribble/manual
@require[@for-label[phc-toolkit/stx
racket/base]]
@title{for*/list*}
@author{@author+email["Georges Dupéron" "georges.duperon@gmail.com"]}
@defmodule[phc-toolkit/untyped/for-star-list-star]
@defform[(for*/list* [sequences …] . body)
#:grammar ([sequences
(* [id seq-expr] …)
([id seq-expr] …)])]{
This form allows iteration over sequences, collecting
nested lists as the final result. Each @racket[sequences]
group of @racket[[id seq-expr]] starts a new level of
nesting. When the @racket[*] is present at the beginning of
a group, its bindings are evaluated in sequence (like
@racket[let*] and @racket[for*/list]), otherwise they are
evaluated in parallel (like @racket[let] and
@racket[for/list]).
This form is equivalent to:
@racketblock[
(for/list ([id seq-expr …])
(for/list ([id seq-expr …])
(for/list ([id seq-expr …])
(for/list ([id seq-expr …])
body))))]
except when a group of @racket[[id seq-expr]] starts with
a @racket[*], then @racket[for*/list] is used for that
group instead of @racket[for/list].}

View File

@ -0,0 +1,124 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
scribble/struct
scribble/decode
@for-label[phc-toolkit/untyped-only/format-id-record
phc-toolkit/stx
racket/syntax
syntax/parse
racket/contract
racket/base]]
@title[#:tag "phc-toolkit-format-id-record"]{Formatting identifiers so that
DrRacket still shows arrows}
@author{@author+email["Georges Dupéron" "georges.duperon@gmail.com"]}
@defmodule[phc-toolkit/untyped-only/format-id-record
#:use-sources
[(lib "phc-toolkit/untyped-only/format-id-record.rkt")]]
@defproc[(format-id/record [lctx (or/c syntax? #f)]
[fmt (stx-e/c
(and/c string?
(regexp-match/c "^([^~]|~~|~a|~A)*$")))]
[#:source src (or/c syntax? #f) #f]
[#:props props (or/c syntax? #f) #f]
[vs (or/c string? symbol? keyword? char? number?
(syntax/c string?)
identifier?
(syntax/c keyword?)
(syntax/c char?)
(syntax/c number?))]
...)
identifier?]{
Like @racket[format-id], but cooperates with @racket[with-sub-range-binders]
to record sub-range binders, which allow DrRacket to draw arrows from the
identifiers present in @racket[vs ...] to occurrences of the resulting
identifier. It also means that when one or more identifiers present in
@racket[vs ...] are concatenated with other strings, it is possible to rename
parts of the resulting identifier in DrRacket.
If @racket[fmt] is a syntax object containing a string, then arrows are drawn
from the format itself to the generated identifier, for each part of the
format which appears in the identifier (e.g. if the format is
@racket["x~~y~az"], then two arrows will be drawn from the format, one for
@racket["x~~y"], and one for @racket["z"].
This function must be called within the dynamic extent of
@racket[with-sub-range-binders] or @racket[with-arrows].}
@defform[(with-sub-range-binders body-expr ... stx-expr)]{
The value produced by @racket[stx-expr] must be a syntax object. All
@seclink["Syntax_Properties_that_Check_Syntax_Looks_For"
#:doc '(lib "scribblings/tools/tools.scrbl")]{sub-range binders}
recorded via @racket[record-sub-range-binders!] or
@racket[maybe-record-sub-range-binders!] are added to the syntax object in a
@seclink["Syntax_Properties_that_Check_Syntax_Looks_For"
#:doc '(lib "scribblings/tools/tools.scrbl")
]{@racket['sub-range-binders]} property.
}
@defform[(with-arrows body-expr ... stx-expr)]{
Equivalent to:
@racketblock[(with-disappeared-uses
(with-sub-range-binders
body-expr ... stx-expr))]}
@defform[(syntax-parser-with-arrows . syntax-parser-options+clauses)]{
Equivalent to:
@racketblock[(λ (stx)
(with-arrows
((syntax-parser . syntax-parser-options+clauses) stx)))]
Within the @racket[syntax-parser-options+clauses], it is possible to use the
@racket[stx] identifier to refer to the whole syntax, in addition to using
@racket[syntax/parse]'s @racket[this-syntax].}
@defproc[(record-sub-range-binders! [sub-range-binders
(or/c sub-range-binder/c
(listof sub-range-binder/c))])
void?]{
Cooperates with the enclosing @racket[with-sub-range-binders] or
@racket[with-arrows] to record the given sub-range-binders so that they are
added to the syntax object returned by @racket[with-sub-range-binders] or
@racket[with-arrows].
This function must be called within the dynamic extent of
@racket[with-sub-range-binders] or @racket[with-arrows].}
@defproc[(maybe-record-sub-range-binders! [sub-range-binders
(or/c sub-range-binder/c
(listof sub-range-binder/c))])
void?]{
Cooperates with the enclosing @racket[with-sub-range-binders] or
@racket[with-arrows] to record the given sub-range-binders so that they are
added to the syntax object returned by @racket[with-sub-range-binders] or
@racket[with-arrows].
If this function is not called within the dynamic extent of
@racket[with-sub-range-binders] or @racket[with-arrows], it has no effect and
the sub-range-binders are not recorded.}
@defparam[current-recorded-sub-range-binders sub-range-binders
(or/c (listof sub-range-binder/c) false/c)]{
This parameter contains the list of sub-range-binders recorded so far by the
nearest @racket[with-sub-range-binders] or @racket[with-arrows].}
@defthing[sub-range-binder/c chaperone-contract?
#:value
(or/c (vector/c syntax?
exact-nonnegative-integer? exact-nonnegative-integer?
(real-in 0 1) (real-in 0 1)
syntax?
exact-nonnegative-integer? exact-nonnegative-integer?
(real-in 0 1) (real-in 0 1))
(vector/c syntax?
exact-nonnegative-integer? exact-nonnegative-integer?
syntax?
exact-nonnegative-integer? exact-nonnegative-integer?)
)]{
A contract accepting valid representations of
@seclink["Syntax_Properties_that_Check_Syntax_Looks_For"
#:doc '(lib "scribblings/tools/tools.scrbl")]{sub-range binders}.
}

View File

@ -0,0 +1,10 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/untyped/generate-indices]]
@(def-orig typed [phc-toolkit/generate-indices])
@title{Untyped versions of generate-indices}
@defmodule[phc-toolkit/untyped/generate-indices
#:use-sources
[(submod (lib "phc-toolkit/generate-indices.rkt") untyped)]]

View File

@ -0,0 +1,11 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/generate-indices]]
@title{generate-indices}
@author{@author+email["Georges Dupéron" "georges.duperon@gmail.com"]}
@defmodule[phc-toolkit/generate-indices
#:use-sources
[(submod (lib "phc-toolkit/generate-indices.rkt") typed)]]
@include-section{generate-indices-untyped.scrbl}

View File

@ -0,0 +1,10 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/untyped/ids]]
@(def-orig typed [phc-toolkit/ids])
@title{Untyped versions of ids}
@defmodule[phc-toolkit/untyped/ids
#:use-sources
[(submod (lib "phc-toolkit/ids.rkt") untyped)]]

76
scribblings/ids.scrbl Normal file
View File

@ -0,0 +1,76 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[racket/base
racket/contract
phc-toolkit/ids
phc-toolkit/contract]]
@title{Generating identifiers}
@author{@author+email["Georges Dupéron" "georges.duperon@gmail.com"]}
@defmodule[phc-toolkit/ids
#:use-sources
[(submod (lib "phc-toolkit/ids.rkt") typed)]]
@defform[(define-temp-ids maybe-concise simple-format base+ellipses
maybe-first-base maybe-prefix)
#:grammar
[(base+ellipses base
(base+ellipses ooo))
(maybe-concise (code:line)
(code:line #:concise))
(maybe-first-base (code:line)
(code:line #:first-base first-base))
(maybe-prefix (code:line)
(code:line #:prefix prefix))]
#:contracts
[(simple-format (syntax/c
(and/c string?
(or/c (regexp-match/c #rx"^[^~]*~a[^~]*$")
(regexp-match/c #rx"^[^~]*$")))))
(base identifier?)
(first-base identifier?)
(prefix (or/c string? identifier?))
(ooo (id/c ...))]]{
Defines @racket[_new-name] as a syntax attribute, with the same nested
structure as @racket[base]. The @racket[_new-name] is obtained by applying the
@racket[base] to the given @racket[simple-format] string. The generated syntax
contains identifiers derived using the @racket[base] and
@racket[simple-format] in the same way. Each of the generated identifiers is
unique, in the sense that there are not two generated identifiers which are
@racket[free-identifier=?] to each other.
If the @racket[#:first-base] option is specified, then @racket[_new-first] is
also defined to be the first generated identifier in the whole tree. In other
words, @racket[_new-first] will be bound to the same identifier as
@racket[_new-name] if there are no ellipses, to the value of
@racket[(stx-car _new-name)] if there is one level of ellipses, to the value
of @racket[(stx-car (stx-car _new-name))] if there are two levels, and so on.
The identifier @racket[_new-first] is generated by applying
@racket[first-base] to the @racket[simple-format].
If the @racket[#:prefix] option is specified, then the generated identifiers
are prefixed with @racket[prefix], followed by a colon @racket[":"]. This does
not impact the @racket[_new-name] and @racket[_new-first] identifiers, so it
can be useful when succinct identifiers are desired for the syntax attributes
within the macro which uses @racket[define-temp-ids], but the generated
identifiers should contain more context, to improve the readability of error
messages which involve the generated temporary identifiers.
If the @racket[#:concise] option is specified, then the generated identifiers
are more concise, which makes them easier to read when debugging macros, but
also means that two distinct identifiers can look the same (but have distinct
scopes). If the @racket[#:concise] option is omitted, the generated identifiers
may contain extra characters do help visually disambiguate similar identifiers
(those extra characters are obtained using @racket[generate-temporary]).
@history[#:changed "1.1"
@list{The lexical context for the defined identifier
@racket[_new-name] is now taken from the format, instead of being
taken from the base @racket[name]. Previously, the lexical context
was taken from the base @racket[name], except when the simple format
did not contain any @racket["~a"], in which case it was taken from
the whole @racket[base+ellipses] (this was a bug, which is fixed now
that both cases use the lexical context of @racket[format]). The
same applies to the lexical context for @racket[_new-first]}]}
@include-section{ids-untyped.scrbl}

View File

@ -0,0 +1,10 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/untyped/in]]
@(def-orig typed [phc-toolkit/in])
@title{Untyped versions of in}
@defmodule[phc-toolkit/untyped/in
#:use-sources
[(lib "phc-toolkit/in.rkt")]]

11
scribblings/in.scrbl Normal file
View File

@ -0,0 +1,11 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/in]]
@title{in}
@author{@author+email["Georges Dupéron" "georges.duperon@gmail.com"]}
@defmodule[phc-toolkit/in
#:use-sources
[(lib "phc-toolkit/in.rkt")]]
@include-section{in-untyped.scrbl}

View File

@ -0,0 +1,6 @@
#lang scribble/manual
@require[racket/require
(for-label (only-meta-in 0 phc-toolkit/list-lang))]
@title{list-lang}
@author{@author+email["Georges Dupéron" "georges.duperon@gmail.com"]}
@defmodule[phc-toolkit/list-lang]

View File

@ -0,0 +1,10 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/untyped/list]]
@(def-orig typed [phc-toolkit/list])
@title{Untyped versions of list}
@defmodule[phc-toolkit/untyped/list
#:use-sources
[(submod (lib "phc-toolkit/list.rkt") untyped)]]

11
scribblings/list.scrbl Normal file
View File

@ -0,0 +1,11 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/list]]
@title{list}
@author{@author+email["Georges Dupéron" "georges.duperon@gmail.com"]}
@defmodule[phc-toolkit/list
#:use-sources
[(submod (lib "phc-toolkit/list.rkt") typed)]]
@include-section{list-untyped.scrbl}

View File

@ -0,0 +1,10 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/untyped/logn-id]]
@(def-orig typed [phc-toolkit/logn-id])
@title{Untyped versions of logn-id}
@defmodule[phc-toolkit/untyped/logn-id
#:use-sources
[(submod (lib "phc-toolkit/logn-id.rkt") untyped)]]

11
scribblings/logn-id.scrbl Normal file
View File

@ -0,0 +1,11 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/logn-id]]
@title{logn-id}
@author{@author+email["Georges Dupéron" "georges.duperon@gmail.com"]}
@defmodule[phc-toolkit/logn-id
#:use-sources
[(submod (lib "phc-toolkit/logn-id.rkt") typed)]]
@include-section{logn-id-untyped.scrbl}

View File

@ -0,0 +1,23 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/untyped/meta-struct]]
@(def-orig typed [phc-toolkit/meta-struct]
struct-predicate
struct-constructor
struct-accessor
struct-type-is-immutable?
struct-instance-is-immutable?)
@title{Untyped versions of the meta-struct typed macros}
@defmodule[phc-toolkit/untyped/meta-struct
#:link-target? #f
#:use-sources
[(submod (lib "phc-toolkit/meta-struct.rkt") untyped)]]
@defidform[struct-predicate]{Untyped version of @|typed:struct-predicate|.}
@defidform[struct-constructor]{Untyped version of @|typed:struct-constructor|.}
@defidform[struct-accessor]{Untyped version of @|typed:struct-accessor|.}
@defidform[struct-type-is-immutable?]{
Untyped version of @|typed:struct-type-is-immutable?|.}
@defidform[struct-instance-is-immutable?]{
Untyped version of @|typed:struct-instance-is-immutable?|.}

View File

@ -0,0 +1,168 @@
#lang scribble/manual
@require[@for-label[phc-toolkit/stx
(only-meta-in 0 phc-toolkit/meta-struct)
(only-meta-in 1 phc-toolkit/untyped/meta-struct)
racket/base
racket/struct-info]]
@title{meta operations on structs}
@author{@author+email["Georges Dupéron" "georges.duperon@gmail.com"]}
@section{Typed macros and procedures}
@defmodule[phc-toolkit/meta-struct
#:use-sources
[(submod (lib "phc-toolkit/meta-struct.rkt") typed)]]
@defform[(struct-predicate s)
#:grammar [[s meta-struct?]]]{
Expands to a predicate for the given @racket[struct], with the
type @racket[(-> any/c boolean? : s)].}
@defform[(struct-constructor s)
#:grammar [[s meta-struct?]]]{
This macro expands to the constructor function for the given @racket[struct],
with the type @racket[(-> _arg … s)] where each @racket[_arg] corresponds to an
argument expected by the @racket[struct]'s constructor.}
@defform*[{(struct-accessor s i)
(struct-accessor s field)}
#:grammar [[s meta-struct?]
[i (expr/c exact-nonnegative-integer?)]
[field identifier?]]]{
This macro expands to the @racket[i]-th accessor function for the given
@racket[struct], with the type @racket[(-> s _t)] where @racket[_t] is the
@racket[struct]'s @racket[_i]-th field's type.
If the second argument is an identifier, then this macro concatenates the
identifiers @racket[s] and @racket[field] with a @racket[-] in between, and
expands to the resulting @racket[_s-field]. The lexical context of
@racket[_s-field] is the same as the lexical context of @racket[s]. In some
rare cases this might not resolve to the accessor for @racket[field] on
@racket[s]. Passing an @racket[exact-nonnegative-integer?] as the second
argument should be more reliable.}
@defproc[#:kind "phase 1 procedure"
(struct-type-is-immutable? [st Struct-TypeTop])
boolean?]{
Returns @racket[#t] if the given struct type can be determined
to have only immutable fields. Returns @racket[#f] otherwise.}
@defproc[(struct-instance-is-immutable? [v struct?])
boolean?]{
Returns @racket[#t] if @racket[v] can be determined to be an instance of an
immutable struct. Returns @racket[#f] otherwise. Note that when given an
instance of an opaque struct @racket[struct-instance-is-immutable?] cannot
access the struct info, and therefore returns @racket[#f].}
@include-section{meta-struct-untyped.scrbl}
@section{Untyped for-syntax utilities}
@defmodule[phc-toolkit/untyped/meta-struct
#:use-sources
[(submod (lib "phc-toolkit/meta-struct.rkt") untyped)]]
@defproc[(meta-struct? [v any/c]) boolean?]{
Returns @racket[#t] if @racket[v] can be used by the
functions provided by this module, and @racket[#f]
otherwise. More precisely, @racket[v] must be an
@racket[identifier] whose @racket[syntax-local-value] is a
@racket[struct-info?].
@history[#:changed "1.0" "This function is provided at phase 1."]}
@defstruct[meta-struct-info ([type-descriptor (or/c identifier? #f)]
[constructor (or/c identifier? #f)]
[predicate (or/c identifier? #f)]
[accessors (list*of identifier?
(or/c (list/c #f) null?))]
[mutators (list*of (or/c identifier? #f)
(or/c (list/c #f) null?))]
[super-type (or/c identifier? #f)])]{
Encapsulates the result of @racket[extract-struct-info] in
a structure with named fields, instead of an obscure
six-element list. The precise contents of each field is
described in
@secref["structinfo" #:doc '(lib "scribblings/reference/reference.scrbl")].
@history[#:changed "1.0" "The identifiers are provided at phase 1."]}
@defproc[(get-meta-struct-info [s meta-struct?]
[#:srcloc srcloc (or/c #f syntax?) #f])
meta-struct-info?]{
Returns the @racket[meta-struct-info] for the given
identifier. The optional @racket[#:srcloc] keyword argument
gives the source location for error messages in case the
given identifier is not a @racket[meta-struct?].
@history[#:changed "1.0" "This function is provided at phase 1."]}
@defproc[(meta-struct-subtype? [sub meta-struct?] [super meta-struct?])
boolean?]{
Returns @racket[#t] if the @racket[struct] associated to
the identifier @racket[sub] is a subtype of the
@racket[struct] associated to the identifier
@racket[super], and @racket[#f] otherwise or if the current
inspector is not strong enough to know.
@history[#:changed "1.0" "This function is provided at phase 1."]}
@defproc[#:kind "phase 1 procedure"
(struct-type-id-is-immutable? [id identifier?])
boolean?]{
Returns @racket[#t] if the struct with the given @racket[id] can be determined
to have only immutable fields. Returns @racket[#f] otherwise.}
@(require (for-syntax racket/base
racket/syntax
racket/struct
racket/vector))
@(define-for-syntax (strip-loc e)
(cond [(syntax? e) (datum->syntax e (strip-loc (syntax-e e)) #f)]
[(pair? e) (cons (strip-loc (car e)) (strip-loc (cdr e)))]
[(vector? e) (vector-map strip-loc e)]
[(box? e) (box (strip-loc (unbox e)))]
[(prefab-struct-key e)
=> (λ (k) (apply make-prefab-struct
k
(strip-loc (struct->list e))))]
[else e]))
@(define-syntax (shorthand stx)
(syntax-case stx ()
[(_ base expresion-type)
(with-syntax ([loc (datum->syntax #'base #'base #f)]
[name (format-id #'base "meta-struct-~a" #'base)]
[accessor (format-id #'base "meta-struct-info-~a" #'base)]
[tmpl (format-id #'base "!struct-~a" #'base)])
#`(deftogether
[(defproc (name [s meta-struct?]
[#:srcloc srcloc (or/c #f syntax?) #f])
(expressionof
(→ s #,(strip-loc #'expresion-type))))
(defform #:kind "template metafunction"
(tmpl #,(strip-loc #'s) #,(strip-loc #'maybe-srcloc))
#:grammar ([s meta-struct?]
[maybe-srcloc (code:line)
#||# (code:line #:srcloc srcloc)]))]
@list{
@;{} Shorthand for @racket[(accessor (get-meta-struct-info s))]
@;{} (with the optional @racket[#:srcloc] passed to
@;{} @racket[get-meta-struct-info]). The precise contents of the
@;{} returned value field is described in
@;{} @secref["structinfo"
#:doc '(lib "scribblings/reference/reference.scrbl")].
@;{}
@;{} @history[#:changed "1.0"
"This function is provided at phase 1."]}))]))
@(shorthand type-descriptor (or/c identifier? #f))
@(shorthand constructor (or/c identifier? #f))
@(shorthand predicate (or/c identifier? #f))
@(shorthand accessors (list*of identifier?
(or/c (list/c #f) null?)))
@(shorthand mutators (list*of (or/c identifier? #f)
(or/c (list/c #f) null?)))
@(shorthand super-type (or/c identifier? #f))

View File

@ -0,0 +1,10 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/untyped/misc]]
@(def-orig typed [phc-toolkit/misc])
@title{Untyped versions of misc}
@defmodule[phc-toolkit/untyped/misc
#:use-sources
[(submod (lib "phc-toolkit/misc.rkt") untyped)]]

62
scribblings/misc.scrbl Normal file
View File

@ -0,0 +1,62 @@
#lang scribble/manual
@(require (for-label typed/racket/base
phc-toolkit/misc))
@(module racket-ids racket/base
(require scribble/manual
(for-label predicates))
(define or?-id (racket or?))
(provide (all-defined-out)))
@(require 'racket-ids)
@title{Miscellaneous utilities}
@section{Typed miscellaneous utilities}
@defmodule[phc-toolkit/misc]
@defproc[(hash-set** [h (HashTable K V)] [l* (Listof (Pairof K V))])
(HashTable K V)]{
Calls @racket[hash-set] on the hash @racket[h] for each
key-value pair contained in each list of @racket[l*].}
@defform[(with-output-file [var filename] maybe-mode maybe-exists body …)
#:grammar ([var Identifier]
[filename (ExpressionOf String)]
[maybe-mode (code:line) (code:line #:mode mode)]
[maybe-exists (code:line) (code:line #:exists exists)])]{
Executes body with @racket[var] bound to the
@racket[output-port?] obtained when opening the file. The
port is automatically closed at the end of the
@racket[body]. This is a macro version of
@racket[call-with-output-file].}
@defproc[(or? [f (→ A Boolean)] ...) (→ A (U A #f))]{
Typed version of @or?-id from the
@racketmodname[predicates] package, which returns the value
itself when all predicates are satisfied instead of just
returning @racket[#t].}
@subsection{Untyped versions of miscellaneous utilities}
@defmodule[phc-toolkit/untyped #:link-target? #f]
@defproc[(hash-set** [h (HashTable K V)] [l* (Listof (Pairof K V))])
(HashTable K V)]{
Untyped version.}
@defform[(with-output-file [var filename] maybe-mode maybe-exists body …)
#:grammar ([var Identifier]
[filename (ExpressionOf String)]
[maybe-mode (code:line) (code:line #:mode mode)]
[maybe-exists (code:line) (code:line #:exists exists)])]{
Untyped version.}
@defproc[(or? [f (→ A Boolean)] ...) (→ A (U A #f))]{
Untyped version.}
@include-section{misc-untyped.scrbl}

View File

@ -0,0 +1,11 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/untyped/multiassoc-syntax]]
@(def-orig typed [phc-toolkit/multiassoc-syntax])
@title{Untyped versions of multiassoc-syntax}
@defmodule[phc-toolkit/untyped/multiassoc-syntax
#:use-sources
[(submod (lib "phc-toolkit/multiassoc-syntax.rkt") untyped)]]
@include-section{tmpl-multiassoc-syntax-untyped.scrbl}

View File

@ -0,0 +1,12 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/multiassoc-syntax]]
@title{multiassoc-syntax}
@author{@author+email["Georges Dupéron" "georges.duperon@gmail.com"]}
@defmodule[phc-toolkit/multiassoc-syntax
#:use-sources
[(submod (lib "phc-toolkit/multiassoc-syntax.rkt") typed)]]
@include-section{tmpl-multiassoc-syntax.scrbl}
@include-section{multiassoc-syntax-untyped.scrbl}

View File

@ -0,0 +1,10 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/untyped/not-implemented-yet]]
@(def-orig typed [phc-toolkit/not-implemented-yet])
@title{Untyped versions of not-implemented-yet}
@defmodule[phc-toolkit/untyped/not-implemented-yet
#:use-sources
[(submod (lib "phc-toolkit/not-implemented-yet.rkt") untyped)]]

View File

@ -0,0 +1,49 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/not-implemented-yet]]
@title{not-implemented-yet}
@author{@author+email["Georges Dupéron" "georges.duperon@gmail.com"]}
@defmodule[phc-toolkit/not-implemented-yet
#:use-sources
[(submod (lib "phc-toolkit/not-implemented-yet.rkt") typed)]]
@defform[(? type expr ...)]{
Can be used as a placeholder for an expression returning @racket[type]. This
form throws an error at run-time, but will allow the program to typecheck so
that the developer can focus on other parts without a myriad of type errors,
and can come back to implement the @racket[?] placeholders later.
The @racket[expr ...] expressions are included within a @racket[lambda]
function, after the @racket[(error "Not implemented yet")], so Typed/Racket's
dead code detection will ignore most type errors within those expressions.
This makes @racket[?] useful as a joker to temporarily ignore type errors
within the expressions, while annotating them with the type they should
normally have once they are fixed.}
@defform[(?* expr ...)]{
Can be used as a placeholder for an expression returning @racket[Nothing].
This form throws an error at run-time, but will allow the program to typecheck
so that the developer can focus on other parts without a myriad of type
errors, and can come back to implement the expressions marked with @racket[?*]
later.
The @racket[expr ...] expressions are included within a @racket[lambda]
function, after the @racket[(error "Not implemented yet")], so Typed/Racket's
dead code detection will ignore most type errors within those expressions.
This makes @racket[?*] useful as a joker to temporarily ignore type errors
within the expressions. @racket[?*] is also useful as a joker to allow the
whole @racket[(?* expr ...)] expression to be used as an argument to nearly
any function, as it has the type @racket[Nothing], i.e. "bottom", which is a
subtype of (nearly) all other types (no value has the type @racket[Nothing],
i.e. it is the return type of functions which never return, which is the case
here, since @racket[?*] always throws an error at run-time.
Caveat: the @racket[Nothing] type can propagate (when Typed/Racket encounters
a function called with @racket[Nothing] as the type of one of its arguments,
it may mark the return value of that function as @racket[Nothing] too, since
the call may never happen). This means that other parts of the code may be
considered dead code, and type errors in these other parts may be ignored.}
@include-section{not-implemented-yet-untyped.scrbl}

View File

@ -0,0 +1,10 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/untyped/percent]]
@(def-orig typed [phc-toolkit/percent])
@title{Untyped versions of percent}
@defmodule[phc-toolkit/untyped/percent
#:use-sources
[(submod (lib "phc-toolkit/percent.rkt") untyped)]]

70
scribblings/percent.scrbl Normal file
View File

@ -0,0 +1,70 @@
#lang scribble/manual
@(require (for-label typed/racket/base
phc-toolkit/percent))
@title{@racket[let-in] binding and destructuring form}
@defmodule[phc-toolkit/percent]
The forms in this module may possibly be moved to a separate
package, as part of the template library described in
@secref{template-lib} (for now the template library is not
implemented yet).
@defform[#:literals (in = and)
(% parallel-binding …
maybe-in
body …)
#:grammar
[(parallel-binding (code:line binding and parallel-binding)
binding)
(binding (code:line pattern … = expr))
(maybe-in (code:line)
in)
(expr expression)]]{
Locally binds the variables in the @racket[pattern]s to the
@racket[expr]. Each binding clause should contain as many
@racket[pattern]s as @racket[expr] produces values. The
@racket[body …] forms are evaluated with the given
variables bound.
The bindings are executed in sequence, as if bound with
@racket[let*], unless grouped using @racket[and], in which
case they are executed in parallel, as if bound with
@racket[let].
NOTE: TODO: for now bindings are run in sequence, and
parallel bindings have not been implemented yet.}
@defidform[in]{
This identifier is only valid in certain forms, like
@racket[(% x = 10 in (+ x x))]. It is an error to use it as
an expression otherwise.}
@defform[#:literals (: :: …)
(define% (name pattern …)
body …)
#:grammar
[(pattern variable
[variable : type]
cons-pattern
list-pattern
vector-pattern)
(cons-pattern (pattern . pattern)
(pattern :: pattern))
(list-pattern (pattern …)
(pattern … :: tail-pattern))
(tail-pattern pattern)
(vector-pattern #(pattern …))
(variable identifier)]]{
Locally binds the variables in the @racket[pattern]s to the
@racket[expr]. Each binding clause should contain as many
@racket[pattern]s as @racket[expr] produces values. The
@racket[body …] forms are evaluated with the given
variables bound.
The bindings are executed in parallel, as if bound with
@racket[let].}
@include-section{percent-untyped.scrbl}

View File

@ -0,0 +1,76 @@
#lang scribble/manual
@require[@for-label[phc-toolkit
racket/base]]
@title{phc-toolkit}
@author{@author+email["Georges Dupéron" "georges.duperon@gmail.com"]}
@defmodule[phc-toolkit]
This library contains a small toolkit of utilities used by
the @url{https://github.com/jsmaniac/phc} project and other
helper libraries for that project.
This library exports the following typed modules:
@itemlist[
@item{@racketmodname[phc-toolkit/stx]}
@item{@racketmodname[phc-toolkit/misc]}
@item{@racketmodname[phc-toolkit/percent]}
@item{@racketmodname[phc-toolkit/meta-struct]}
@item{…}]
Untyped versions of the above modules are available under
@racketmodname[phc-toolkit/untyped], which also contains the
following additional untyped-only modules:
@itemlist[
@item{@racketmodname[phc-toolkit/untyped/for-star-list-star]}]
The @secref{template-lib} document discusses the
hypothetical features of a still-unwritten parser and
template library. The template part aims to be the pendant
of @racket[match] and @racket[syntax/parse], and the parser
part should unify @racket[match] and @racket[syntax/parse],
to enable parsing of syntax and regular data alike. This
library is not implemented yet, and will probably be moved
to a separate package when it is.
@(local-table-of-contents)
@include-section{aliases.scrbl}
@include-section{backtrace.scrbl}
@include-section{compat.scrbl}
@include-section{cond-let.scrbl}
@include-section{contract.scrbl}
@include-section{eval-get-values.scrbl}
@include-section{fixnum.scrbl}
@include-section{generate-indices.scrbl}
@include-section{ids.scrbl}
@include-section{in.scrbl}
@include-section{list-lang.scrbl}
@include-section{list.scrbl}
@include-section{logn-id.scrbl}
@include-section{misc.scrbl}
@include-section{multiassoc-syntax.scrbl}
@include-section{not-implemented-yet.scrbl}
@include-section{percent.scrbl}
@include-section{repeat-stx.scrbl}
@include-section{require-provide.scrbl}
@include-section{sequence.scrbl}
@include-section{set.scrbl}
@include-section{stx.scrbl}
@include-section{syntax-parse.scrbl}
@include-section{test-framework.scrbl}
@include-section{threading.scrbl}
@include-section{tmpl.scrbl}
@include-section{typed-rackunit.scrbl}
@include-section{typed-rackunit-extensions.scrbl}
@include-section{typed-untyped.scrbl}
@include-section{type-inference-helpers.scrbl}
@include-section{values.scrbl}
@include-section{untyped.scrbl}
@include-section{for-star-list-star.scrbl}
@include-section{meta-struct.scrbl}
@include-section{format-id-record-untyped.scrbl}
@include-section{template.scrbl}

View File

@ -0,0 +1,10 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/untyped/repeat-stx]]
@(def-orig typed [phc-toolkit/repeat-stx])
@title{Untyped versions of repeat-stx}
@defmodule[phc-toolkit/untyped/repeat-stx
#:use-sources
[(submod (lib "phc-toolkit/repeat-stx.rkt") untyped)]]

View File

@ -0,0 +1,11 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/repeat-stx]]
@title{repeat-stx}
@author{@author+email["Georges Dupéron" "georges.duperon@gmail.com"]}
@defmodule[phc-toolkit/repeat-stx
#:use-sources
[(submod (lib "phc-toolkit/repeat-stx.rkt") typed)]]
@include-section{repeat-stx-untyped.scrbl}

View File

@ -0,0 +1,10 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/untyped/require-provide]]
@(def-orig typed [phc-toolkit/require-provide])
@title{Untyped versions of require-provide}
@defmodule[phc-toolkit/untyped/require-provide
#:use-sources
[(submod (lib "phc-toolkit/require-provide.rkt") untyped)]]

View File

@ -0,0 +1,11 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/require-provide]]
@title{require-provide}
@author{@author+email["Georges Dupéron" "georges.duperon@gmail.com"]}
@defmodule[phc-toolkit/require-provide
#:use-sources
[(submod (lib "phc-toolkit/require-provide.rkt") typed)]]
@include-section{require-provide-untyped.scrbl}

View File

@ -0,0 +1,10 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/untyped/sequence]]
@(def-orig typed [phc-toolkit/sequence])
@title{Untyped versions of sequence}
@defmodule[phc-toolkit/untyped/sequence
#:use-sources
[(submod (lib "phc-toolkit/sequence.rkt") untyped)]]

View File

@ -0,0 +1,11 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/sequence]]
@title{sequence}
@author{@author+email["Georges Dupéron" "georges.duperon@gmail.com"]}
@defmodule[phc-toolkit/sequence
#:use-sources
[(submod (lib "phc-toolkit/sequence.rkt") typed)]]
@include-section{sequence-untyped.scrbl}

View File

@ -0,0 +1,10 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/untyped/set]]
@(def-orig typed [phc-toolkit/set])
@title{Untyped versions of set}
@defmodule[phc-toolkit/untyped/set
#:use-sources
[(submod (lib "phc-toolkit/set.rkt") untyped)]]

11
scribblings/set.scrbl Normal file
View File

@ -0,0 +1,11 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/set]]
@title{set}
@author{@author+email["Georges Dupéron" "georges.duperon@gmail.com"]}
@defmodule[phc-toolkit/set
#:use-sources
[(submod (lib "phc-toolkit/set.rkt") typed)]]
@include-section{set-untyped.scrbl}

View File

@ -0,0 +1,84 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/stx]]
@(def-orig typed [phc-toolkit/stx]
stx-assoc
identifier->string
identifier→string
quasisyntax/top-loc
syntax/top-loc
quasisyntax/whole-loc
syntax/whole-loc)
@title{Patching source locations}
@(declare-exporting phc-toolkit/stx
#:use-sources
[(lib "phc-toolkit/stx/fold.rkt")])
@defform[(quasisyntax/top-loc stx-expr quasitemplate)]{
Like @racket[(quasisyntax/loc stx-expr quasitemplate)], but the source
location for all "top" parts of the resulting syntax object are updated, so
long as their source location is the same as the source location for the
topmost part of the @racket[quasitemplate].
In other words, this does a traversal of the syntax object and updates the
source location of the traversed parts, but the traversal does not go within a
part whose source file differs from that of the @racket[quasitemplate].
For example, in the following code, the source location of parts within
@racket[user-code] will not be updated (unless @racket[user-code] originates
from the same file as @racket[quasitemplate]), but the source location of all
other parts will be updated, including the @racket[begin] identifier and its
surrounding form (its surrounding "pair of parentheses"). In contrast,
@racket[quasisyntax/loc] would have updated only the topmost syntax object,
i.e. the outermost "pair of parentheses" of the @racket[let] form.
@racketblock[(λ (stx)
(syntax-case stx ()
[(_ . user-code)
(with-syntax ([bg #'(begin . user-code)])
(quasisyntax/top-loc stx (let () bg)))]))]}
@defform[(syntax/top-loc stx-expr quasitemplate)]{
Like @racket[(syntax/loc stx-expr quasitemplate)], but the source location
for all "top" parts of the resulting syntax object are updated, like is done
by @racket[quasisyntax/top-loc].}
@defform[(quasisyntax/whole-loc stx-expr quasitemplate)]{
Like @racket[(quasisyntax/top-loc stx-expr quasitemplate)], but the source
location for all parts of the resulting syntax object are updated if they
belong to the same source file as the @racket[quasitemplate], not only the
"top" ones.
In the following example, all parts of the syntax object which source file is
the same as the macro will be updated, including those within
@racket[user-code] (e.g. if the @racket[user-code] contains code generated by
other macros from the same file.
@racketblock[(λ (stx)
(syntax-case stx ()
[(_ . user-code)
(with-syntax ([bg #'(begin . user-code)])
(quasisyntax/whole-loc stx (let () bg)))]))]
This is usually not needed, as @racket[quasisyntax/top-loc] would have
updated the source location of @racket[1], @racket[2] and @racket[3] and their
surrounding syntax list (the "pair of parentheses" around them), since their
surrounding syntax list comes from the same file as the macro:
@racketblock[(λ (stx)
(syntax-case stx ()
[(_ . user-function)
(quasisyntax/top-loc stx
(user-function 1 2 3))]))]}
@defform[(syntax/whole-loc stx-expr quasitemplate)]{
Like @racket[(syntax/top-loc stx-expr quasitemplate)], but the source
location for all parts of the resulting syntax object are updated if they
belong to the same source file as the @racket[quasitemplate], not only the
"top" ones, like is done by @racket[quasisyntax/whole-loc].}

View File

@ -0,0 +1,44 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/stx]]
@title{Transformers utilities}
@(declare-exporting phc-toolkit/stx
#:use-sources
[(lib "phc-toolkit/untyped-only/stx.rkt")])
@defproc[(make-rest-transformer [tranformer-function (-> syntax? syntax?)])
(-> syntax? syntax?)]{
Returns a transformer function which applies @racket[tranformer-function] on
the @racket[stx-cdr] of its argument. It is a shorthand for:
@racketblock[(λ (stx)
(syntax-case stx ()
[(_ . rest) (f #'rest)]))]
}
@defproc[(make-id+call-transformer [result syntax?])
(-> syntax? syntax?)]{
Returns a transformer function which returns:
@itemlist[
@item{the given @racket[result], when it is called as an identifier macro}
@item{@racket[(result arg ...)] where the @racket[arg ...] are the macro's
arguments (except the macro identifier itself), when it is called as a
regular macro.}]
It is a shorthand for:
@RACKETBLOCK[(λ (stx)
(syntax-case stx ()
[(_ . args) (quasisyntax/top-loc stx (#,result . args))]
[id (identifier? #'id) result]))]
}
@defproc[(make-id+call-transformer-delayed [result (-> syntax?)])
(-> syntax? syntax?)]{
Like @racket[make-id+call-transformer], but the result is wrapped in a
function which is evaluated only when the returned transformer function is
run. This is useful when the expression depends on some mutable context.}

View File

@ -0,0 +1,47 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/untyped/stx]]
@(def-orig typed [phc-toolkit/stx]
stx-assoc
identifier->string
identifier→string
make-rest-transformer
make-id+call-transformer
quasisyntax/top-loc
syntax/top-loc
quasisyntax/whole-loc
syntax/whole-loc)
@title{Untyped versions of syntax object manipulation utilities}
@defmodule[phc-toolkit/untyped/stx
#:use-sources
[(submod (lib "phc-toolkit/stx.rkt") untyped)
(lib "phc-toolkit/stx/fold.rkt")]]
@defidform[stx-assoc]{Untyped version of @|typed:stx-assoc|.}
@defproc*[([(identifier->string [identifier Identifier]) String]
[(identifier→string [identifier Identifier]) String])]{
Untyped version of @|typed:identifier->string| and @|typed:identifier→string|.
}
@defidform[make-rest-transformer]{
Untyped version of @|typed:make-rest-transformer|.}
@defidform[make-id+call-transformer]{
Untyped version of @|typed:make-id+call-transformer|.}
@defidform[quasisyntax/top-loc]{
Untyped version of @|typed:quasisyntax/top-loc|.}
@defidform[syntax/top-loc]{
Untyped version of @|typed:syntax/top-loc|.}
@defidform[quasisyntax/whole-loc]{
Untyped version of @|typed:quasisyntax/whole-loc|.}
@defidform[syntax/whole-loc]{
Untyped version of @|typed:syntax/whole-loc|.}

118
scribblings/stx.scrbl Normal file
View File

@ -0,0 +1,118 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/stx
phc-toolkit/syntax-parse
(subtract-in phc-toolkit/untyped
phc-toolkit/stx
phc-toolkit/syntax-parse)
racket/base
racket/contract]]
@(def-orig orig [syntax/stx racket/base]
stx-car
stx-cdr
syntax-e)
@title{Syntax object manipulation utilities}
@author{@author+email["Georges Dupéron" "georges.duperon@gmail.com"]}
@defmodule[phc-toolkit/stx
#:use-sources
[(submod (lib "phc-toolkit/stx.rkt") typed)]]
@; TODO: fix the types
@defproc[(stx-car [v (or/c (syntax/c pair?) pair?)]) any/c]{
Typed version of @orig:stx-car from @racketmodname[syntax/stx].}
@defproc[(stx-cdr [v (or/c (syntax/c pair?) pair?)]) any/c]{
Typed version of @orig:stx-cdr from @racketmodname[syntax/stx].}
@defproc[(stx-e [v (or/c (syntax/c any/c) any/c)]) any/c]{
Typed version of @orig:syntax-e which also accepts objects which are not
syntax (in which case the original object is returned).}
@defproc[(stx-pair? [v Any]) Boolean]{
A predicate which returns true for pairs and for syntax pairs alike.
}
@defproc[(stx-car/c [car-c (→ Any Result)]) (→ Any (U #f Result))]{
Returns a contract similar to the one returned by
@racket[(cons/c car-c any/c)], but which accepts both syntax pairs
(@racket[stx-pair?]) and pairs (@racket[pair?]), as long as their
@racket[stx-car] (@racket[car] respectively) is accepted by @racket[car-c].}
@defproc[(stx-cdr/c [cdr-c (→ Any Result)]) (→ Any (U #f Result))]{
Returns a contract similar to the one returned by
@racket[(cons/c any/c cdr-c)], but which accepts both syntax pairs
(@racket[stx-pair?]) and pairs (@racket[pair?]), as long as their
@racket[stx-cdr] (@racket[cdr] respectively) is accepted by @racket[cdr-c].}
@defproc[(stx-e/c [e-c (→ Any Result)]) (→ Any (U #f Result))]{
Equivalent to @racket[(or/c e-c (syntax/c e-c))].
Also equivalent to @racket[(λ (v) (e-c (stx-e v)))].
Returns a contract which accepts any value accepted by @racket[e-c]. The
contract also accepts any value @racket[_v] for which @racket[syntax?] returns
true and @racket[(syntax-e v)] is accepted by @racket[e-c].}
@defform[#:kind "type"
(Stx-List? A)]{
A polymorphic type which is defined as:
@racketblock[(U Null
(Pairof A (Stx-List? A))
(Syntaxof Null)
(Syntaxof (Pairof A (Stx-List? A))))]}
@defproc[(stx-list? [v Any]) Boolean]{
A predicate for @racket[Stx-List?].
}
@defproc[(stx->list [l (Stx-List? A)]) (Listof A)]{
Turns into a list any syntax list, which can be any proper sequence of syntax
pairs terminated by a syntax list or by @racket[#'()]. If the value @racket[l]
is already a regular non-syntax list, a copy of the list is returned (note
that this means that the returned list will most likely not be @racket[eq?] to
the original).}
@defproc[(stx-list/c [l-c (→ Any Result)]) (→ Any (U #f Result))]{
Equivalent to:
@racketblock[
(λ (v)
(and (stx-list? v)
(l-c (stx->list v))))]
Returns a contract which accepts any list accepted by @racket[l-c]. The
contract also accepts any value @racket[_v] for which @racket[stx-list?]
returns true and @racket[(stx->list v)] is accepted by @racket[e-c].}
@defproc[(stx-null? [v Any]) Boolean]{
Returns @racket[#true] for the empty list (@racket[null]) and for any empty
syntax list (@racket[#'()]). Returns @racket[#false] for any other value.}
@defproc*[([(stx-assoc
[id Identifier]
[alist (Syntaxof (Listof (Syntaxof (Pairof Identifier T))))])
(U (Syntaxof (Pairof Identifier T)) #f)]
[(stx-assoc
[id Identifier]
[alist (Listof (Syntaxof (Pairof Identifier T)))])
(U (Syntaxof (Pairof Identifier T)) #f)]
[(stx-assoc [id Identifier]
[alist (Listof (Pairof Identifier T))])
(U (Pairof Identifier T) #f)])]{
Like @racket[assoc], but operates on syntax association lists.
}
@defproc*[([(identifier->string [identifier Identifier]) String]
[(identifier→string [identifier Identifier]) String])]{
Equivalent to @racket[(symbol->string (syntax-e identifier))].
}
@include-section{stx-untyped-only.scrbl}
@include-section{stx-patching-srcloc.scrbl}
@include-section{stx-untyped.scrbl}

View File

@ -0,0 +1,87 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/syntax-parse
racket/base
syntax/parse]]
@(def-orig orig [syntax/parse]
~or
~literal
~parse
~bind)
@title{Pattern expanders}
@author{@author+email["Georges Dupéron" "georges.duperon@gmail.com"]}
@declare-exporting[phc-toolkit/syntax-parse
#:use-sources
[(submod (lib "phc-toolkit/syntax-parse.rkt") typed)]]
@defform[#:kind "pattern expander"
(~either alt ...)]{
Like @orig:~or, but with no special behaviour when present under ellipses.
The use case for this is that @racket[({~or {~and 1 x} {~and 2 x}} ...)] would
match any list of @racket[1]s and @racket[2]s in any order, but it complains
that the attribute is bound twice, since both alternatives within the
@racket[~or] are understood as separate patterns, not mutually-exclusive
choices. On the other hand @racket[({~or {~and 1 x} {~and 2 x}} ...)] still
matches @racket[(2 1 1 1 2 2 1)], and successfully binds all the elements to
@racket[x ...].}
@defform[#:kind "pattern expander"
(~lit alt ...)]{
Alias for @|orig:~literal|.}
@defform[#:kind "pattern expander"
(~with pat val)]{
Alias for @|orig:~parse|, can be used semantically when @racket[#:with] would
have been used in a syntax class definition.}
@defform[#:kind "pattern expander"
(~attr attr-name val)]{
Alias for @racket[(#,orig:~bind [attr-name val])], can be used semantically
when @racket[#:attr] would have been used in a syntax class definition.}
@(define ttern
@seclink["stxparse-patterns"
#:doc '(lib "syntax/scribblings/syntax.scrbl")]{pattern})
@defform[#:kind "pattern expander"
(~optkw kw #,ttern ...)
#:contracts
[(kw keyword?)]]{
A shorthand for:
@racketblock[{~optional {~seq {~and _name kw} #,ttern ...}}]
where @racket[_name] is derived from the keyword, so that
@racket[~optkw #:foo] binds the pattern variable @racket[foo].}
@defform[#:kind "pattern expander"
(~optkw… kw #,ttern ...)
#:contracts
[(kw keyword?)]]{
A shorthand for:
@racketblock[(~optional {~seq {~and _name kw} #,ttern ...}
#:name "the kw keyword")]
where the occurrence of @racket["kw"] within the string is replaced by the
actual @racket[kw] keywords, and where the @racket[_name] is derived from the
keyword, so that @racket[~optkw #:foo] binds the pattern variable
@racket[foo], and uses the name @racket["the #:foo keyword"].
This form can only be used where an
@tech[#:doc '(lib "syntax/scribblings/syntax.scrbl")]{ellipsis-head pattern}
is allowed.}
@defform[#:kind "pattern expander"
(~maybe #,ttern ...)]{
A shorthand for:
@racketblock[(~optional {~seq #,ttern ...})]}

View File

@ -0,0 +1,22 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/untyped/syntax-parse]]
@(def-orig orig [phc-toolkit/syntax-parse]
stx
define-syntax/case
define-syntax/parse)
@title{Untyped versions of @racket[syntax-parse] helpers}
@defmodule[phc-toolkit/untyped/syntax-parse
#:use-sources
[(submod (lib "phc-toolkit/syntax-parse.rkt") untyped)]]
@defidform[stx]{
Untyped version of @|orig:stx|.
}
@defidform[define-syntax/case]{Untyped version of @|orig:define-syntax/case|.}
@defidform[define-syntax/parse]{Untyped version of @|orig:define-syntax/parse|.}

View File

@ -0,0 +1,101 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/syntax-parse
racket/base
syntax/parse]]
@title{@racket[syntax-parse] helpers}
@author{@author+email["Georges Dupéron" "georges.duperon@gmail.com"]}
@defmodule[phc-toolkit/syntax-parse
#:use-sources
[(submod (lib "phc-toolkit/syntax-parse.rkt") typed)]]
@defidform[stx]{
This identifier can only be used in the body of some forms,
like @racket[define-syntax]. It is an error to use it as an
expression elsewhere.}
@defform[(define-syntax/case (name . args) (literal-id ...) . body)]{
This form is roughly equivalent to:
@racketblock[(define-syntax (name stx)
(syntax-case stx (literal-id ...)
[(_ . args) (let () . body)]))]
Within @racket[body], the syntax parameter @racket[stx] can be used to refer to
the whole syntax given as an argument to @racket[name].}
@(define ntax-patterns (tech #:doc '(lib "syntax/scribblings/syntax.scrbl")
#:key "syntax pattern"
"syntax-patterns"))
@(define ttern-directive (tech #:doc '(lib "syntax/scribblings/syntax.scrbl")
#:key "pattern-directive"
"pattern-directive"))
@(define tterns
@seclink["stx-patterns"
#:doc '(lib "scribblings/reference/reference.scrbl")]{patterns})
@(define ttern
@seclink["stx-patterns"
#:doc '(lib "scribblings/reference/reference.scrbl")]{pattern})
@defform[(define-syntax/parse (name . #,ntax-patterns)
#,ttern-directive ... . body)]{
This form is roughly equivalent to:
@racketblock[(define-syntax (name stx)
(syntax-parse stx
[(_ . #,ntax-patterns) #,ttern-directive ... . body]))]
Within the @racket[#,ntax-patterns], the @racket[#,ttern-directive] and the
@racket[body], the syntax parameter @racket[stx] can be used to refer to the
whole syntax given as an argument to @racket[name].}
@defform[(λ/syntax-parse (name . #,ntax-patterns)
#,ttern-directive ... . body)]{
This form is roughly equivalent to:
@racketblock[(λ (stx)
(syntax-parse stx
[(_ . #,ntax-patterns) #,ttern-directive ... . body]))]
Within the @racket[#,ntax-patterns], the @racket[#,ttern-directive] and the
@racket[body], the syntax parameter @racket[stx] can be used to refer to the
whole syntax given as an argument to the function.}
@defform[(define-for-syntax/case-args (name (pattern ...)) . body)]{
This form is roughly equivalent to:
@racketblock[(define-for-syntax (name _arg ...)
(with-syntax ([pattern _arg] ...)
. body))]
where each @racket[_arg] is a fresh identifier.}
@defform[(λ/syntax-case #,tterns (literal ...) . body)]{
This form is roughly equivalent to:
@racketblock[(λ (stx)
(syntax-case stx (literal ...)
[(_ . #,tterns) ... . body]))]
Within the @racket[#,tterns], and the @racket[body], the syntax parameter
@racket[stx] can be used to refer to the whole syntax given as an argument to
the function.}
@defform[(define/case-args (name (#,ttern ...)) . body)]{
This form is roughly equivalent to:
@racketblock[(define (name _arg ...)
(with-syntax ([#,ttern _arg] ...)
. body))]
where each @racket[_arg] is a fresh identifier.}
@include-section{syntax-parse-pattern-expanders.scrbl}
@include-section{syntax-parse-untyped.scrbl}

492
scribblings/template.scrbl Normal file
View File

@ -0,0 +1,492 @@
#lang scribble/manual
@(require (for-label typed/racket/base
syntax/parse
;"template.rkt"
))
@(define ellipses (racket ...))
@title[#:tag "template-lib"]{Versatile parser and template library}
Keywords: grammar, parser, template.
@defform[(parse expr [pattern body …] …)]{
Analogous to @racket[syntax-parse], except it isn't
specialized for syntax, but rather works for arbitrary
s-expressions, including syntax ones (denoted by
@racket[#'(…)] in the pattern).}
@defform[#:literals (: :: ... else struct)
(tmpl template)
#:grammar
[(template variable
[variable : type] ;; (ann variable type)
;; cons-template
(template . template)
(template :: template)
;; list
(template**)
;; list*
template**-dotted
;; vector
#(template**)
(vector . template**-dotted)
;; hash-template: template** must expand to a list of pairs.
(hash . template**-dotted) ;; TODO: how to distinguish
(hasheq . template**-dotted) ;; mutable and immutable?
(hasheqv . template**-dotted)
#hash([template . template])
#hasheq([template . template])
#hasheqv([template . template])
;; struct-template
(struct-id template …)
(struct struct-id template …)
#s(prefab-id template …)
#s(template template …) ;; Only allowed in untyped racket
;; box
#&template
;; call-template
(~identifier args …) ;; calls (identifier args …)
(~ expr args …) ;; calls (expr args …)
;; unquote-template
,expr
,@(list expr)
,@(list* expr) ;; must appear in last position.
;; template-expander
template-expander-id
(template-expander-id args …)
;; maybe-template (should all be template expanders
;; which means the system is extensible enough to express
;; these special cases).
(?? alt-template …)
(?@ . template**-dotted)
(??@ . template**-dotted)
(?if condition template template)
(|@if| condition template template)
(if@ condition template template)
(|@cond| [condition template] …)
(|@cond| [condition template] … [else template])
(cond@ condition template template)
;; like #,@(with-syntax ([meta-var #'template])
;; #'(template**))
(~let ([meta-var+args template])
. template**-dotted)
(~sort key template ooo)
(~loc stxloc . template)
;; Like (template . template), but discards the first and
;; keeps just the second. If the first contains pattern
;; variables which are repeated, this has the effect of
;; repeating the second as many times as the first. Example:
;; #'(vector (~each some-pattern-var '()))
;; => (vector '() '() '() '() '())
(~each template template)
;; escaped
(ddd escaped)
;;
;; literal
#t
#f
string
bytes
number
char
keyword
regexp
pregexp)
(meta-var+args meta-var
(meta-var meta-arg …))
(tail-template template)
;; specialize mid-sequence in repetition (diagonal-matrix-style)
(variable identifier)
(template**-dotted (template* … . template)
template**)
(template** (code:line template* …)
(code:line template* … :: template)
(code:line template* … (~rest . template)))
(template* template
(code:line template ooo)
special-cased-template)
(special-cased-template (code:line template vardd)
(code:line template ddvar))
;; Where var is an iterated variable.
(vardd var.. ;; exclude the current iteration
var...) ;; include the current iteration
(ddvar ..var ;; exclude the current iteration
...var) ;; include the current iteration
(ooo #,ellipses ;; TODO: make it a hyperlink
___
..k ;; k positive integer
__k ;; k positive integer
(code:line .. expr) ;; expr must return a positive integer
(code:line __ expr)) ;; expr must return a positive integer
(ddd #,ellipses)
]]{
TODO: implement the versatile template library.
@racket[...]
TODO: support for typed/racket.
TODO: optimization feature: would it be useful if the
expanded code could be optimized? For example, when looking
at the output of syntax-parse, the code is far from being
concise.
The patterns for @racket[parse] should all have a way to
create a symmetric counterpart for @racket[tmpl], which
produces the original value. This symmetry is important
because it allows lens-like macros, which operate on only a
part of the data structure, leaving everything else
intact.
@racket[??] works like @racket[??] from
@racket[syntax/parse/experimental/template], except it
allows any number of alternatives (including 0, to avoid
special-casing in macros). It is more or less equivalent to
@racket[(?? a (?? b (?? c …)))], following syntax/parse's
semantics.
@racket[?@] has the same meaning as in syntax/parse.
@racket[(??@ t* …)] is a shortcut for
@racket[(?? (?@ t* …))]
For better compatibility with at-exp, @racket[|@if|] can be
written @racket[if@], and the same goes for
@racket[|@cond|] etc.
TODO: what's the difference between @racket[~],
@racket[template-expander] and @racket[unquote]?
@racket[template-expander] runs at compile-time and should
treat its arguments as syntax.
Concerning unquoting, unlike @racket[racket]'s default
behaviour in @RACKET[#'([x #,(y …)] …)], unquoting should
not break the nesting of ellipses. How should we express
voluntary variation of the level of nesting? @racket[~let]
already allows expanding part of the template at some level
and inserting it verbatim somewhere below, but it's not a
silver bullet. One case which comes to mind is when some of
the nested data should be mixed with less-nested data, for
example going from
@racket[([10 1 2 3] [100 4 5] [1000 6])] to
@racket[([10 20 30] [400 500] [6000])] should be relatively
easy to express. Maybe @racket[~let] with parameters can be
a suitable generalized solution:
@RACKET[({~let ([(addx v) #,(+ x v)]) [(addx y) …]} …)]
The special-cased template syntax should allow special
treatment of the @racket[i]-th iteration in a doubly-nested
loop: matching @racket[x] on @racket[(1 2 3 4 5)], and
using the template @racket[(0 x.. ,(* x x) ..x 1) …] will
produce @racket[(1 1 1 1 1)
(0 4 1 1 1)
(0 0 9 1 1)
(0 0 0 16 1)
(0 0 0 0 24)]. The pattern before
@racket[x..] and the pattern after @racket[..x] can expand
to multiple items which will be spliced in by wrapping it
with @racket[?@].}
@section{Ideas for implementation}
@subsection{Extensibility (expanders)}
Allow normal, inline-prefix, inline-postfix and inline-infix
expanders, which can bind using regular expressions. This
allows implementing exotic syntax like @racket[var..]
(postfix, operates on the pattern preceeding it),
@racket[..var] (postfix, operates on the pattern after it),
@racket[(… escaped-pattern)] (normal, operates on the
containing s-exp)
@subsection{Customization}
For things that are likely to be customized by the user in
the whole file scope, define a grammar/custom module, used
as follows:
@racketblock[(require grammar/custom)
(grammar/custom option …)]
The @racket[grammar/custom] macro expands to
@racket[(require grammar/core)] followed by a bunch of
@racket[define-syntax] which wrap the core macros, providing
them the custom options:
@racketblock[(require grammar/core)
(define-syntax-rule (parse . rest)
(parse/core #:global-options (option …) . rest))
(define-syntax-rule (tmpl . rest)
(parse/core #:global-options (option …) . rest))]
This can also be used to rename the @racket[parse] and
@racket[tmpl] macros, if desired (for example,
@racket[tmpl] could be renamed to @racket[quasisyntax], or
something similar).
Otherwise, @racket[grammar/custom] could just @racket[set!]
some for-syntax variable which stores the options. A second
boolean for-syntax variable could be used to check if
@racket[grammar/custom] was called twice, and throw an error
in that case.
Or maybe we should just use units? Can they be customized in
a similar way?
The idea is to avoid having to wrap the whole file in a
@racket[(parameterize …)], and be able to easily
@racket[provide] a customized variation of this library:
@racketblock[(provide (customized-out grammar/custom))]
@subsection{Unsorted ideas}
@subsubsection{Global pattern constraints}
For patterns, have global constraints: @racket[(~global-or id)] binds
@racket[id] to true if the enclosing pattern was matched at least once, and
false otherwise. Multiple occurrences of the same @racket[(~global-or id)] make
the @racket[id] true if any of the containing clauses was matched at least
once.
Inside a @racket[{~no-order}], it should be possible to impose some partial
order constraints, so that we can say:
@racketblock[
{~no-order
{~optional pat-a}
{~optional pat-b}
pat-c
{~optional {~constrain pat-d {~after pat-a}}}}]
The above code means that @racket[pat-a], @racket[pat-b] and @racket[pat-d] are
optional (but not @racket[pat-c]), the four patterns can appear in any order,
but if @racket[pat-a] and @racket[pat-d] are both present, then @racket[pat-d]
must appear after @racket[pat-a].
Scopes: the global constraints apply within a scope. By default, there is an
implicit top-level scope, and some forms might implicitly introduce a catch-all
scope unless otherwise specified, like the implicit @racket[~demimit-cut] for
@racket[define-syntax-class] from @racket[syntax/parse]. There could be two
kinds of scopes: unhygienic catch-all scopes which scope all "global"
constraints within, and naming scopes, which explicitly say which identifiers
they scope.
@racketblock[
{~scope {a}
{~vector
{~scope {b} {~no-order {~once a} {~optional b}}}
{~scope {b} {~no-order {~once a} {~optional b}}}}}]
The code above matches against a vector of two @racket[~no-order] lists. The
@racket[a] pattern must appear exactly once, either in the first list or in the
second, but not in both. On the other hand, the @racket[b] pattern may appear
zero or one time in the first list, zero or one time in the second list, and may
appear in both since its constraint is scoped for each list. Although it is less
clear, the following code is semantically identical:
@racketblock[
{~scope {a b}
{~vector
{~no-order {~once a} {~optional b}}
{~scope {b} {~no-order {~once a} {~optional b}}}}}]
Since the @racket[b] in the @racket{~no-order} is bound to the enclosing
@racket[{~scope {b} …}], it does not interact in any way with the outer scope.
The @racket[~optional] constraint on the @racket[b] in the first
@racket[~no-order] therefore does not interact withe the @racket[~optional]
constraint in the second @racket[~no-order].
@subsubsection{Generalization of pattern/template kinds}
Nearly all patterns and templates should work equally well for regular lists and
syntax objects. It should be possible and easy enough to create new "kinds" of
data, which modify how patterns and templates work all the way through the
pattern or template tree, until it switches to a new kind. As an example, the
following pattern starts as a normal s-expr pattern, and switches to syntax in
two nodes:
@racketblock[
{~s-expr 1 2 (buckle {~optional my} shoe)
3 4 {~syntax (knock {~optional at the} door)}
5 6 (pick {~optional-wrap (up _) (sticks)})
7 8 {~syntax (lay {~optional-wrap (them _) (straight)})}}]
That pattern should match the following value:
@racketblock[
`(1 2 (buckle shoe)
3 4 ,#'(knock door)
5 6 (pick (up (sticks)))
7 8 ,#'(lay (them (straight))))]
The @racket[~syntax] indicates that the whole subtree should start matching (or
producing) syntax objects, instead of regular s-expressions. It is worht noting
that syntax objects have extra information (source location, syntax properties)
that regular s-expressions lack. One way of implementing this would be to make
the pattern directives operate on "enhanced" s-expressions. Enhanced
s-expressions are s-expressions with arbitrary kind-specific data attached to
them. The @racket[~s-expr] simply translates s-expressions into enhanced
s-expressions with an empty data attached, while @racket[~syntax] is a sort of
pre-processor which turns syntax objects into enhanced s-expressions with source
location and syntax properties attached. These "kind" pre-processors run before
the normal pattern directives are applied. Some kind-specific pattern directives
can access those properties (if they are used in within the scope of the
appropriate @racket[~kind]), so that a @racket[(~loc srcloc . pattern)] matches
@racket[pattern] and saves its source location into the variable
@racket[srcloc].
Kinds should also be able to alter how the pattern variables are bound:
@racket[~s-expr] simply binds (in patterns) and uses (in templates) normal
Racket variables. On the other hand, @racket[~syntax] binds and uses syntax
pattern variables, so that the bound variables are used as @racket[#'var]
instead of @racket[var].
Different pattern and template forms can specify a default kind (possibly by
simply wrapping their pattern or tempalte with the appropriate @racket[~kind]).
For example, a @racket[define/match] form would use @racket[~s-expr] by default,
whereas a @racket[define-syntax/match] would use @racket[~syntax]. The same
would apply for re-implementations of Racket's @racket[match] and
@racket[syntax-parse].
Do the "kinds" form some sort of monad? TODO: Think about this, and try to see
if there are some monads which can be translated to pattern/template kinds
usefully.
@subsubsection{Lenses}
It should be possible to describe lenses using the patterns: you can work on
the focused part of the match, possibly access (read-only) other parts, and
return a new value. What should happen when the focused part is under an
ellipsis and has more than one match ? Implicitly execute the code n times, like
a sort of @racket[for/list]?
@subsubsection{Backtracking}
Since the parser may need to backtrack, we need to expose the backtracking
mechanism to the user in some way, so that the user can:
@itemlist[
@item{Cut the current branch}
@item{Perform some side-effects and undo them when backtracking (dangerous)}
@item{Record a side-effectful lambda which is executed when the match succeeds
or when the current branch is @racket[~commit]ted.}
@item{Querry information about the previously failed branches}
@item{Maybe affect the order in which non-deterministic branches are taken.
This feature would mainly be used by optimizers.
As a toy "just because we can" example, the backtracking mechanism should be
configurable enough that some CSP algorithm like AC2003 can be expressed by
the user, turning the pattern library into a CSP solver (where the CSP problem
is expressed as a pattern over an empty object). Another toy "just because we
can" example would be a datalog implementation built upon this library, where
the deduction rules are expressed as patterns.
The goal is that the parser's backtracking mechanism should be modular enough
to allow us to implement a dead-simple unoptimized backtracker, and allow
optimizers to be written as plug-ins. For example, an optimiazer could
statically detect branches that can be cut due to a prior failure (e.g. if the
two-element-list pattern @racket[(foo:id bar:number)] failed because the first
element was not an @racket[identifier?], there's no point in trying
@racket[(baz:id quux:string fuzz:number)] on the same term.
Extensive configurability of the backtracking mechanism and optimization
features may interact badly with partial application and partial compilation,
see below. Think it through before giving too much or too little expressivity
to the user.}]
@subsubsection{Partial application}
It should be possible to give a partial input with holes to a pattern or
template form, and, for optimization purposes, request that the pattern or
template processes the input as much as it can (for the parser, it would
potentially open a bounded number of backtracking branches, ready to switch to
the next one if one fails), leaving an efficient "continuation".
@subsubsection{Partial compilation}
One of the drawbacks of @racketmodname[syntax/parse] is that compiling a
@racket[syntax-parse] form takes some non-negligible time. This means that if a
macro generates another macro, and the generated macro code uses syntax-parse,
each call to the "generator" macro will be expensive. A complex macro generating
syntax which contains hundreds of uses of syntax-case will be reasonnably fast.
The same code using syntax-parse will be much slower. Since the generated uses
of @racket[syntax-parse] will all have the same "shape" with a few identifiers
etc. changing, it would be nice to be able to partially pre-expand a use of
@racket[syntax-parse], leaving only the "holes" to be expanded. With a bottom-up
expansion mechanism there's not much to do, so we have to try hard to make the
pattern / template expander top-down as much as possible, and/or use a lazy
language (for which most things can be evaluated, leaving a continuation for the
few things that actually depend on the holes).
Although partial compilation sounds like a very interesting academic project,
it might be too difficult to get something useful out of it in practice. An
alternative, which would procude the sought performance benefits for macros
generating code which uses the pattern/template library, would be to make as
many of the concepts first-class, so that they can easily be supplied as a
parameter. Note that firs-class in this case does not necessarily mean "run-time
first-class", but possibly "compile-time first-class": we only need to be able
to pre-declare parametric templates, then use them in the code generated by a
macro. As long as the parametric templates support a form of "separate
compilation" and optimization, filling in the parameters can be handled by a
fast macro.
Some of the optimization plug-ins may however rely on a closed-world assumption
(i.e. they want to have the whole, final pattern or template, in order to
optimize it). If such an optimization plug-in is used, we may have to fall back
to the idea of using partial compilation, or simply accept that macros which
generate such code will take a while to expand.
@subsubsection{QuickCheck test generation}
It should be possible to generate random data that matches (and does not match,
too, that's a distinct problem) a pattern (unless there's a user-provided
predicate that is opaque to the library, in which case we can just ignore it and
generate instances at random, hoping that some will match and some won't).
Combined with the fact that pattern directives should be reversible into
template directives, and vica versa, it means that each directive should also
express its set of accepted values in terms of its contents. Of course, we don't
expect to be able to uniformly sample random instances, nor do we expect to be
able to support in a useful way complex patterns with lots of opaque predicates.
@subsubsection{Error messages}
@racketmodname[syntax/parse] generates good error messages, but it does not
work as well when the patterns become complex. Think this through, so that the
annotation burden is minimal, and so that users don't have to think too hard
about where to put a @racket[~describe] (I frequently had the problem with
@racket[syntax/parse] where I wrote a @racket[~describe], but it wasn't taken
into account.
@subsection{Things to look at}
@itemlist[
@item{@racket[math/arry], for @racket[::] and array
broadcasting.}
@item{Quasipatterns in @racket[match].}
@item{The @racket[lens] library}
@item{@url{https://github.com/racket/racket/issues/1304}
non-linear matching (with repeated binding variables, for
example, that should be eq? or equal?)}]

View File

@ -0,0 +1,10 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/untyped/test-framework]]
@(def-orig typed [phc-toolkit/test-framework])
@title{Untyped versions of test-framework}
@defmodule[phc-toolkit/untyped/test-framework
#:use-sources
[(submod (lib "phc-toolkit/test-framework.rkt") untyped)]]

View File

@ -0,0 +1,11 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/test-framework]]
@title{test-framework}
@author{@author+email["Georges Dupéron" "georges.duperon@gmail.com"]}
@defmodule[phc-toolkit/test-framework
#:use-sources
[(submod (lib "phc-toolkit/test-framework.rkt") typed)]]
@include-section{test-framework-untyped.scrbl}

View File

@ -0,0 +1,10 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/untyped/threading]]
@(def-orig typed [phc-toolkit/threading])
@title{Untyped versions of threading}
@defmodule[phc-toolkit/untyped/threading
#:use-sources
[(submod (lib "phc-toolkit/threading.rkt") untyped)]]

View File

@ -0,0 +1,11 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/threading]]
@title{threading}
@author{@author+email["Georges Dupéron" "georges.duperon@gmail.com"]}
@defmodule[phc-toolkit/threading
#:use-sources
[(submod (lib "phc-toolkit/threading.rkt") typed)]]
@include-section{threading-untyped.scrbl}

View File

@ -0,0 +1,10 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/untyped/tmpl-multiassoc-syntax]]
@(def-orig typed [phc-toolkit/tmpl-multiassoc-syntax])
@title{Untyped versions of tmpl-multiassoc-syntax}
@defmodule[phc-toolkit/untyped/tmpl-multiassoc-syntax
#:use-sources
[(submod (lib "phc-toolkit/tmpl-multiassoc-syntax.rkt") untyped)]]

View File

@ -0,0 +1,28 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/tmpl-multiassoc-syntax]]
@title{Template metafunction for @racket[multiassoc-syntax]}
@defmodule[phc-toolkit/tmpl-multiassoc-syntax
#:use-sources
[(submod (lib "phc-toolkit/tmpl-multiassoc-syntax.rkt")
typed
m-tmpl-cdr-assoc-syntax)]]
@deftogether[
[@defform[#:kind "template metafunction"
(tmpl-cdr-assoc-syntax maybe-default query [k . v] …)
#:grammar
[(maybe-default (code:line)
(code:line #:default default))]]
@defform[#:kind "template metafunction"
(!cdr-assoc maybe-default query [k . v] …)
#:grammar
[(maybe-default (code:line)
(code:line #:default default))]]]]{
This template metafunction returns the first @racket[v] whose @racket[k] is
@racket[free-identifier=?] to the given @racket[query]. If no such @racket[k]
exists, then @racket[default] is returned if specified, and otherwise an error
is raised while expanding the template.}

View File

@ -0,0 +1,10 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/untyped/tmpl]]
@(def-orig typed [phc-toolkit/tmpl])
@title{Untyped versions of tmpl}
@defmodule[phc-toolkit/untyped/tmpl
#:use-sources
[(submod (lib "phc-toolkit/tmpl.rkt") untyped)]]

11
scribblings/tmpl.scrbl Normal file
View File

@ -0,0 +1,11 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/tmpl]]
@title{tmpl}
@author{@author+email["Georges Dupéron" "georges.duperon@gmail.com"]}
@defmodule[phc-toolkit/tmpl
#:use-sources
[(submod (lib "phc-toolkit/tmpl.rkt") typed)]]
@include-section{tmpl-untyped.scrbl}

View File

@ -0,0 +1,10 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/untyped/type-inference-helpers]]
@(def-orig typed [phc-toolkit/type-inference-helpers])
@title{Untyped versions of type-inference-helpers}
@defmodule[phc-toolkit/untyped/type-inference-helpers
#:use-sources
[(submod (lib "phc-toolkit/type-inference-helpers.rkt") untyped)]]

View File

@ -0,0 +1,16 @@
#lang scribble/manual
@require[racket/require
"utils.rkt"
@for-label[phc-toolkit/type-inference-helpers]]
@title{type-inference-helpers}
@author{@author+email["Georges Dupéron" "georges.duperon@gmail.com"]}
@defmodule[phc-toolkit/type-inference-helpers
#:use-sources
[(submod (lib "phc-toolkit/type-inference-helpers.rkt") typed)]]
@defform[#:kind "type expander"
(maybe-apply-type τ arg ...)]{
Expands to @racket[τ] if there are no arguments, and to @racket[(τ arg ...)]
if there is at least one argument. }
@include-section{type-inference-helpers-untyped.scrbl}

Some files were not shown because too many files have changed in this diff Show More