racket/collects/mrflow/labels.ss
2005-05-27 18:56:37 +00:00

92 lines
5.3 KiB
Scheme

(module labels mzscheme
; XXX labels contain types and types contain labels, so we will need another layer for
; the contracts once the types are extracted from cgp.ss
(provide
(struct label (parents children type-var trace prim? term set edges))
(struct label-cst (value))
(struct label-cons (car cdr))
(struct label-vector (element))
(struct label-promise (value))
(struct label-case-lambda (struct rest-arg?s req-args argss exps effects))
(struct label-values (label))
(struct label-struct-value (type fields))
(struct label-struct-type (name parent parent-fields-nbr total-fields-nbr error?))
)
; parents = children = (listof label)
; type-var = (union type-var #f), trace = boolean, prim? = boolean
; term = syntax-object, set = (hash-table-of label (make-arrows (listof label) (listof label) (listof label)),
; edges = (hashtableof symbol edge))
; a flow graph label/node type-var is a type variable name used when reconstructing recursive
; types.
; trace is used to detect cycles in the graph during type reconstruction.
; prim? tells whether the label was created during graph reconstruction from a primitive
; type. We need this to detect the entrance of a tunnel.
; Note that the only reason we need to have this tunneling stuff is to keep the GUI arrows right.
; term: the source program term (or a fake version of it, in the case of "null" when we have
; a rest argument)
; set: contains label structures (see below) for all the values that flow into this term.
; Each label in the set has two lists of in and out edges pointing back and forth to the nodes
; from which this label has flowed in (or '() if the label is the source of the label) and
; flowed out to. The in edges (which need to be checked each time a propagation is done, to
; revent cycles) are in a list, and not in an hash-table, because we assume that the same
; label is not going to flow very often into this term through several paths. The out-edge
; list is only used to draw arrows, so it doesn't have to be implemented very efficiently.
; Note that, since constants are represented by label structs, the same constant can appear
; several times in the set, even symbols.
; edges: functions that take two labels as argument and either propagate the second one to
; another label, using the first label as the source, or transform the graph accordingly (if
; the inflowing label is a function pseudo-label and the label into which it flows corresponds
; to the operator in an application, for example).
; parent and children are used to memoize the parent and children arrows for all the values
; in the label's value set. Computing these when the code contains huge amounts of macro-
; generated recurisve code is quite expensive.
(define-struct label (parents children type-var trace prim? term set edges))
; a constant...
(define-struct (label-cst label) (value))
; car = label, cdr = label
(define-struct (label-cons label) (car cdr))
(define-struct (label-vector label) (element))
(define-struct (label-promise label) (value))
; struct = label-struct
; rest-arg?s = (listof boolean), req-args = (listof number), argss = (listof (listof label)),
; exps = (listof label), app-thunks = (listof (-> void))
; Each "level" of the six lists represents the args and body labels of a given clause in the
; case-lambda. At a given level, rest-arg? tells whether this clause has a rest argument,
; and req-args gives the number of required arguments, so it only has to be computed once.
; top-free-varss are the labels of the top level free variables in the corresponding clause.
; This field is updated as a side effect when analyzing top level variable references inside
; the body of a lambda. Edges flowing into these free variables must be created when the
; clause is applied. app-thunk is a thunk that is used to delay the transformation of the
; graph when a function flows into an application, until the clause around the application
; is itself applied. The two are merged, because one of the delayed app could set! a top level
; variable, and the top level variable can be referenced both before and after the application,
; so lookups and applications have to be done in exactly the right order.
; struct is just a placeholder to tell the type of structure a given structure-processing
; function is supposed to deal with.
(define-struct (label-case-lambda label)
(struct rest-arg?s req-args argss exps effects))
; label = label (a label-cons based list of labels)
; used to simulate multiple values. So this label is going to flow around and work pretty
; much like a cons label. the problem is that multiple values are not first-class in Scheme,
; so we have to be careful to only propagate them through edges that correspond to the result
; of applications, never through edges that correspond to arguments of applications. Hence
; the reason for the complication in create-simple-edge. Note that define-struct expands
; into a define-values, so we need all that stuff.
(define-struct (label-values label) (label))
; symbol symbol label number (listof label)
(define-struct (label-struct-value label) (type fields))
(define-struct (label-struct-type label)
(name parent parent-fields-nbr total-fields-nbr error?))
)