API
Conditions
inference-error
cycle-detected
node
An already seen nodeOption Value Allocation: instance Type: nil
Initarg: :node
Readers: (cycle-detected-node)
typesystem-error
type-system
A top node of the type systemOption Value Allocation: instance Type: nil
Initarg: :type-system
Readers: (typesystem-error-system)
incorrect-definition
arity-error
actual-arity
Arity of a function seen in the codeOption Value Allocation: instance Type: alexandria:non-negative-fixnum
Initarg: :actual
Readers: (actual-arity)
expected-arity
Arity of a function in FNDBOption Value Allocation: instance Type: alexandria:non-negative-fixnum
Initarg: :expected
Readers: (expected-arity)
unknown-function
unknown-literal
code
An expression which contains unknown literalOption Value Allocation: instance Type: nil
Initarg: :code
Readers: (unknown-literal-code)
fndb-entry-exists
parser-error
code
Parser errorOption Value Allocation: instance Type: nil
Initarg: :code
Readers: (parser-error-code)
typecheck-error
varname
Name of the variable which holds a value of invalid typeOption Value Allocation: instance Type: nil
Initarg: :varname
Readers: (typecheck-error-varname)
actual
Actual type of a value stored in the variableOption Value Allocation: instance Type: nil
Initarg: :actual
Readers: (typecheck-error-actual)
expected
Expected type of a value stored in the variableOption Value Allocation: instance Type: nil
Initarg: :expected
Initform: nil
Readers: (typecheck-error-expected)
cannot-redefine
Type system
During to serapeum limitations, the typetype-node
and the
corresponding constructor cannot be documented. Look at examples in
this section.
type-node-order
nil
:EQ
, :LT
, :GT
or
NIL
. The latter is to indicate that there is no order between two
types.le
(order)
t
if order
is either :eq
or :lt
, nil
otherwise.ge
(order)
t
if order
is either :eq
or :gt
, nil
otherwise.type-node-order
(top t1 t2)
:eq
when t1 = t2
, :lt
when t1 < t2
, :gt
when t1 > t2
or nil
otherwise. Top
is the top type of the
type system.find-type-node
(name type-node)
A
which has the name name
and A ⊂
type-node
.flatten-type-graph
(type-node)
type-node
.check-type-system
(type-node)
type-node
if a type system for which this node is a top
node is defined correctly, otherwise signal typesystem-error
or
just do not return control.join
(top t1 t2)
t1
and t2
. Join t
is the
minimal type for which t1 ⊂ t
and t2 ⊂ t
. Top
is the top
type for the type system.meet
(top t1 t2)
t1
and t2
. Meet t
is the
maximal type for which t ⊂ t1
and t ⊂ t2
. Top
is the top
type for the type system.types-intersect-p
(top t1 t2)
t
if t1 ∧ t2
is not the bottom type, nil
otherwise. Top
is the top type of the type system.print-graphviz-representation
(top &optional (stream *standard-output*))
top
in
Graphviz format to the output stream stream
.Known functions
defknown
(db top names arguments-clause type-bindings-clause (&key (bottom-guard nil bottom-guard-p)) t0-cond-clauses &optional t1+-cond-clauses)
Add new known functions to the database db
. Top
is the top
type of a type system. Names
is a list of function names to be
added. The new functions all have the same arity and the same
functions \(T_0\), \(T_1\), etc.Arguments-clause
is a form (arglist (result-variable
top-variable narg-variable))
and contains some important variables
which can be used in the body of functions \(T_i\). Arglist
is a
list of variables which are bound to types of arguments of the defined
functions. Top-variable
is bound to the top type of a type-system,
result-variable
is bound to type of the result of the defined
function and narg-variable
is bound to \(i-1\) in the body of
\(T_i\) when \(i > 0\).Type-bindings-clause
is an associative list with entries in the
form (variable-name . type-name)
which contains additional
bindings of variables to types inside \(T_i\) functions.Bottom-guard
argument must always be present and be either nil
or name of a variable bound to the bottom type. If bottom-guard
is
not null then bottom guards will be present in \(T_i\) functions.T0-cond-clauses
define a body of function T₀ in which bindings to
top-variable
and variables in arglist
are in effect. This body
is an explicit cond, so t0-cond-clauses
may be like this
((condition-1 form-1)
(condition-2 form-2)
etc)
T0-cond-clauses
must evaluate to a type. If bottom-guard
is
not nil
an implicit conditional is inserted before all other
conditionals in cond. This conditional checks if any of variables in
arglist
are bound to the bottom type, and if so the bottom type is
returned. Also another conditional is inserted after all other
conditionals which just returns the bottom type in any case.T1+-cond-clauses
define a body of functions T₁, T₂, etc in which
bindings to top-variable
, res-variable
, narg-variable
and
variables in arglist
are in effect. This body is an explicit cond
and must evaluate to a type, just like T0-cond-clauses
.
For example the following code
(defknown *fndb* *type-system* (length)((x)(res top n))
((integer . integer)
(sequence . sequence)
(bottom . nil))
(:bottom-guard bottom)
;; T₀
(((types-intersect-p top x sequence) integer))
;; T₁
(((ge (type-node-order top res integer))
(meet top x sequence))))
creates a function T₀
(lambda (top x)
(let ((integer (find-type-node 'integer top))
(sequence (find-type-node 'sequence top))
(bottom (find-type-node nil top)))
(cond
((eq x bottom) bottom)
((types-intersect-p top x sequence) integer)
(t bottom))))
and T₁
(lambda (top n res x)
(assert (< n 1))
(let ((integer (find-type-node 'integer top))
(sequence (find-type-node 'sequence top))
(bottom (find-type-node nil top)))
(cond
((or (eq x bottom)
(eq res bottom))
bottom)
((ge (type-node-order top res integer))
(meet top x sequence))
(t bottom))))
and adds a corresponding entry about the function length
in
*fndb*
.
defknown*
(db top names arg-types res-type)
names
to the
function database fndb
. This is a simplified SBCL-like version of
DEFKNOWN
. Everything what is known about added functions is that
they take arguments of types arg-types
and return a value of type
res-type
.definitializer
(db top name type)
name
which takes zero arguments
and returns a value of type type
to FNDB db
(definitializer db top name type)
is equivalent to
(defknown db top (name)(() res top n)
((type-var . type))
(:bottom-guard nil)
((t type-var))
())
make-fndb
(top-node)
top-node
.Code parsing
NB: This API is subject to change.parse-expr
(code &optional literal-initializers)
Parse an expression code
and construct a control flow
graph. Literal-initializers
is an associative list which contains
predicates as keys and initializer functions as values. When
parse-code
sees a term of the expression, it runs predicates in
literal-initializers
(in the order of appearance) on that term. If
a predicate returns T
then that term is considered as a literal
and the corresponding initializer function is used to initialize a
constant variable with a value of type of the literal. For example:
CL-USER> (parse-code '(+ x 3)) ; => Signals UNKNOWN-LITERAL
CL-USER> (type-inference-engine:parse-expr
'(+ x 3)
(list
(cons #'integerp 'init/integer)))
((TYPE-INFERENCE-ENGINE:FLAT-CONTROL-NODE (2)(1)(#<TYPE-INFERENCE-ENGINE:STATEMENT X ← (INITIALIZE )>
#<TYPE-INFERENCE-ENGINE:STATEMENT RES567 ← (INITIALIZE )>
#<TYPE-INFERENCE-ENGINE:STATEMENT VAR568 ← (INITIALIZE )>))
(TYPE-INFERENCE-ENGINE:FLAT-CONTROL-NODE (0)(2)(#<TYPE-INFERENCE-ENGINE:STATEMENT VAR568 ← (INIT/INTEGER )>))
(TYPE-INFERENCE-ENGINE:FLAT-CONTROL-NODE (1)(0)(#<TYPE-INFERENCE-ENGINE:STATEMENT RES567 ← (+ X
#:VAR568)>)))
This function returns a control flow graph which can be passed to infer-types
.
compile-function
(form fndb top-type &optional literal-initializers)
Infer types for a function defined by the defun form (just like in Common Lisp) and add this function to the database if it typechecks.
Example (tie/ex
is a local nickname for the package
type-inference-engine/example
):
TIE-EXAMPLE> (tie:compile-function
'(defun foo (x y)
(let ((z (elt x (1+ y))))
(* z (+ y z))))
tie/ex:*fndb* tie/ex:*type-system*)
#S(TIE::SIMPLE-KNOWN-FUNCTION
:NAME FOO
:ARG-TYPES (#<TIE:TYPE-NODE SEQUENCE {102E78D253}>
#<TIE:TYPE-NODE INTEGER {102E78D2B3}>)
:RES-TYPE #<TIE:TYPE-NODE NUMBER {102E78D313}>)
See also: parse-expr
.
result-variable
(flat-nodes)
Type inference
infer-types
(db top graph)
parse-expr
. Graph
is an
internal representation of an expression in the form of parallel
assignment statements. Db
is a database of known functions and
top
is the top type of your type system. This function returns an
array of variable->type mappings for each parallel assignment
statement in the flattened control flow graph. The first element in
that array is the most important as it corresponds to a fully
evaluated expression.