phc-toolkit/scribblings/meta-struct.scrbl
2021-03-04 20:37:46 +00:00

169 lines
7.3 KiB
Racket

#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["Suzanne Soy" "racket@suzanne.soy"]}
@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))