/**********************************************************************/
/*              klint - Static Analyzer for KL1 Programs              */
/*                                                                    */
/*                            Version 2.0                             */
/*                             March 1998                             */
/*                                                                    */
/*                           Kazunori Ueda                            */
/*           Department of Information and Computer Science           */
/*                         Waseda University                          */
/*                    ueda@ueda.info.waseda.ac.jp                     */
/*                                                                    */
/*                 Copyright (C) 1998  Kazunori Ueda                  */
/*                                                                    */
/**********************************************************************/

1. OVERVIEW

Klint V2 is a constraint-based static analyzer of KL1 programs, which
performs 

  - mode analysis, 
  - linearity analysis, and
  - type analysis.

The key feature of klint V2 is mode analysis.  It analyzes the mode of
a KL1 program using the ideas described in [1].  Well-modedness
roughly means that the communication protocols used in a program are
cooperative.  It is highly recommended to write your KL1 programs in a
well-moded manner, because it enables the klint system to detect many
of program errors statically [3] and it enables more sophisticated
compiler optmization.

Klint V2 also analyzes the linearity and the type of the program.
Linearity analysis distinguishes data that are guaranteed to be
referenced from only one reader occurrence of a variable from data
possibly shared by two or more occurrences of variables.  Linearity
analysis provides basic information for compile-time garbage
collection.

Types in klint V2 express what categories of function symbols
(integers, floating-point numbers, [], other constants, strings,
vectors, cons, other function symbols) may occur at each path (=
position in a data structure that a goal may possibly have as its
argument).

Klint V2 does not require programmers to provide mode, linearity, or
type declarations; instead, klint V2 will infer the
mode/linearity/type of a given program.

Klint V2 consists of three parts: a constraint generator, a
mode/linearity constraint solver, and a type constraint solver.  The
constraint generator generates the mode/linearity/type constraints
syntactically imposed by a given KL1 program.  The mode/linearity
constraint solver first tries to solve the set S of mode constraints
by forming a mode graph [1] to see if S is consistent (satisfiable).
The mode graph thus formed is regarded as expressing the 'principal'
(i.e., most general) mode of the program.  If S is [in]consistent, the
program is said to be [non-]well-moded, respectively.  When the
program turns out to be well-moded, the solver goes on to perform
linearity analysis and forms the linearity graph of the program.

The type constraint solver forms the type graph of a program.  Unlike
mode analysis, type analysis will not report a type error because
klint V2 does not assume that function symbols belonging to different
categories cannot occur at the same path in a program.

An introductory article of mode analysis can be found in [2].


2. USAGE

Klint is quite easy to use.  Simply give your KL1 source file to klint
as:

  % klint < xxx.kl1

INPUT:

The input to klint V2 is a KL1 program that may consist of more than
one module, which are read from stdin (standard input).  If your program
is split into several files, say:

  % cat xxx.kl1 yyy.kl1 zzz.kl1 | klint


OUTPUT:

When the given program is well-moded, klint V2 outputs the mode,
linearity, and type graphs of the program from stdout (standard output).

When the program is non-well-moded, klint V2 reports what mode
constraint finally caused an mode error, and then outputs the current
mode graph.  It then outputs a type graph, skipping linearity
analysis.  Non-well-modedness means that the set of mode constraints
is inconsistent.  The next version of klint will find minimal
inconsistent subsets of mode constraints, which will help you to
locate bugs better, using the ideas describedin [4].

The mode/linearity/type constraints generated by klint V2 can be
viewed by running klint1 instead of klint.  The command

  % klint1 < xxx.kl1 | klint2

will produce the same output as

  % klint <xxx.kl1 .


3. EXAMPLES

Suppose the file merge.kl1 contains a program

  :- module m.

  merge([],   Y,    Z ) :- true| Z=Y.
  merge(X,    [],   Z ) :- true| Z=X.
  merge([A|X],Y,    Z0) :- true| Z0=[A|Z], merge(X,Y,Z).
  merge(X,    [A|Y],Z0) :- true| Z0=[A|Z], merge(X,Y,Z).

Then klint V2 will produce:

  > klint < merge.kl1
  *** Mode Graph ***
  node(0): (unconstrained)
   <(m:merge)/3,1> ---> node(13)
   <(m:merge)/3,2> ---> node(13)
   <(m:merge)/3,3> --*> node(13)
  node(13): in
   <cons,1> ---> node(15)
   <cons,2> ---> node(13)
  node(15): (unconstrained)

  *** Linearity Graph ***
  node(0): (unconstrained)
   <(m:merge)/3,1> ---> node(13)
   <(m:merge)/3,2> ---> node(13)
   <(m:merge)/3,3> ---> node(13)
  node(13): (unconstrained)
   <cons,1> ---> node(15)
   <cons,2> ---> node(13)
  node(15): (unconstrained)

  *** Type Graph ***
  node(0): []
   <(m:merge)/3,1> ---> node(13)
   <(m:merge)/3,2> ---> node(13)
   <(m:merge)/3,3> ---> node(13)
  node(13): [nil,cons]
   <cons,1> ---> node(15)
   <cons,2> ---> node(13)
  node(15): []

Here's how to read the above mode graph: The arcs from the root node
(0) say that the first and the second arguments have exactly the same
mode, which is represented by node 13, and that the third argument has
an exactly opposite mode (note the asterisk in the arrow, which means
mode inversion [1]).  Node 13 says that the cdr of a list occurring as
an argument of 'merge' will have the same mode with the whole list.
The graphical representation of this graph can be found in [3].

The linearity graph says that the 'merge' program itself will not
cause any sharing of data.  Thus, as long as the elements of the two
input streams are non-shared (node 15), the elements of output streams
are guaranteed to be non-shared.  The program will not cause the
sharing of the skeletons (node 13) of input or output streams, either.
As long as the skeletons of the input streams are not shared (which
can be guaranteed by analyzing the whole program), they can be
recycled locally to form the skeleton of the output stream.

Here is a case where sharing is detected:

  :- module main.

  main :- true | tty:ttystream([gett(X),putt(Y),nl]), quicksort(X,Y).

  quicksort(Xs,Ys) :- qsort(Xs,Ys,[]).
  qsort([],    Ys0,Ys ) :- true | Ys=Ys0.
  qsort([X|Xs],Ys0,Ys3) :- true |
      part(X,Xs,S,L), qsort(S,Ys0,[X|Ys2]), qsort(L,Ys2,Ys3).

  part(_,[],    S, L ) :- true | S=[], L=[].
  part(A,[X|Xs],S0,L ) :- A>=X | S0=[X|S], part(A,Xs,S,L).
  part(A,[X|Xs],S, L0) :- A< X | L0=[X|L], part(A,Xs,S,L).

This quicksort program produces:

  *** Linearity Graph ***
  node(0): (unconstrained)
   <(main:quicksort)/2,1> ---> node(28)
   <(main:quicksort)/2,2> ---> node(20)
   <(main:qsort)/3,1> ---> node(28)
   <(main:qsort)/3,2> ---> node(20)
   <(main:qsort)/3,3> ---> node(20)
   <(main:part)/4,1> ---> SHARED
   <(main:part)/4,2> ---> node(28)
   <(main:part)/4,3> ---> node(28)
   <(main:part)/4,4> ---> node(28)
   <(tty:ttystream)/1,1> ---> node(1)
  node(28): (unconstrained)
   <cons,2> ---> node(28)
  node(20): (unconstrained)
   <cons,1> ---> SHARED
   <cons,2> ---> node(20)
  node(1): (unconstrained)
   <cons,1> ---> node(2)
   <cons,2> ---> node(5)
  node(2): (unconstrained)
   <gett/1,1> ---> node(28)
  node(5): (unconstrained)
   <cons,1> ---> node(6)
  node(6): (unconstrained)
   <putt/1,1> ---> node(20)

This means that the elements of a result list (node 20) may be shared
as well as the pivot value (first argument of 'part').  The reason of
sharing is the second clause of 'qsort'.  Note, however, that the
skeleton of the result list are not shared.  Note also that the
skeleton and the elements of the input list does not become shared.



4. INSTALLATION

Klint V2 is totally written in KL1 and can be compiled using KLIC.
Just say

  % make

to make klint, klint1, and klint2.

For your information, the klint V2 distribution contains the following
files:

  (1) Makefile -- make file
  (2) Readme-E -- Thie file
      Readme-J -- Japanese version of this file
  (3) klint-main.kl1, klint1-main3.kl1, klint2-mainA.kl1
      read_program3.kl1, normalize5.kl1, unify.kl1
      builtin_DB5.kl1, numberbuiltin3.kl1, findpath4.kl1
      constraints9.kl1, type.kl1, stdinout.kl1
      graphB.kl1, tgraph2.kl1, decode2.kl1, tdecode.kl1
      reduce5.kl1, sort.kl1, outmessage4.kl1, klint2.kl1
	       -- source files of klint V2
  (4) examples/merge.kl1, examples/quicksort.kl1
               -- sample KL1 programs used in this manual

5. FEATURES NOT YET SUPPORTED

(1) Macro expansion.  We expect that a future release of klic will
feature a KL1 counterpart of cc's  -E option.

(2) 'inline' expansion feature.

(3) Generic object creation of the form `generic:new(...)' and generic
    method calls of the form "generic:METHOD"

All the other built-in predicates supported by the current
distribution of KLIC V3 are supported.


6. RESTRICTIONS

(1) Klint V2 may strengthen mode constraints using the assumption that
non-linear variables (i.e., variables with more than three
occurrences) always have simple, one-way dataflow rather than
bi-directional dataflow such as massages with reply boxes.  However,
our observation is that non-linear variables have been almost always
used for one-way communication.

(2) The satisfiability of non-binary constraints that could not be
reduced to unary/binary constraints is not checked.  Instead, the system
reports what non-binary constraints remained unreduced.



REFERENCES

[1] Ueda, K. and Morita, M., Moded Flat GHC and Its Message-Oriented
Implementation Technique.  New Generation Computing, Vol.13, No.1
(1994), pp.3-43.

[2] Ueda, K., I/O Mode Analysis in Concurrent Logic Programming.  In
Theory and Practice of Parallel Programming, LNCS 907, Springer, 1995,
pp.356-368.

[3] Ueda, K., Experiences with Strong Moding in Concurrent
Logic/Constraint Programming.  In Proc. Int. Workshop on Parallel
Symbolic Languages and Systems (PSLS'95), T. Ito, R.H. Halstead, Jr., and
C. Queinnec (eds.), LNCS 1068, Springer, 1996, pp.134-153.

[4] Cho, K. and Ueda, K., Diagnosing Non-Well-Moded Concurrent Logic
Programs.  To be presented at 1996 Joint International Conference and
Symposium on Logic Programming (JICSLP'96), Bonn, Germany, September
1996.
