aboutsummaryrefslogtreecommitdiff
path: root/sucl/complete.icl
blob: 136db40b86b317e9260d0c698bfd17af2027e992 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
implementation module complete

// $Id$

import graph
import basic
import StdEnv

/*

To check completeness of patterns, we need to know whether, given a list
of (constructor) symbols, this list completely covers a type.

    complete :: [sym] -> Bool

It is assumed that a type can never  be  empty,  so  an  empty  list  of
constructors   can   never  cover  a  type.   Otherwise,  separate  type
information would be needed to determine the completeness  of  an  empty
list of constructors.


The algorithm uses /multipatterns/, which are lists of simple patterns.  A
multipattern is used to match at multiple node-ids in a graph in parallel.
This is necessary in the case of matching of product types.

*/

:: Pattern sym var
   :== (Graph sym var,[var])

/*

Coveredby checks  whether  a  multipattern  is  covered  by  a  list  of
multipatterns.  There are five cases to consider.

    First, if the multipattern is not the empty list, then to  cover  it
    some  multipattern  must  exist,  so if the list of multipatterns is
    empty, then the multipattern is not covered.

    Second, if the multipattern is  the  empty  list,  it  is  trivially
    covered by any list of multipatterns, including the empty.

    Third, if the first pattern of the multipattern is closed, we select
    only the multipatterns that it can match,  then  continue  with  the
    arguments, and then the rest of the multipattern.

    Fourth,  if  the  first pattern of the multipattern is open, and all
    its type constructors are present  in  the  first  patterns  of  the
    multipatterns  in  the list of multipatterns, then the first pattern
    of the multipattern is split according to all constructors, and  all
    possibilities must be covered.

    Fifth,  if  not all constructors are present, then the multipatterns
    of which the first pattern is open must cover the multipattern.   So
    those   are   selected  and  we  continue  with  the  tails  of  the
    multipatterns in this list.

To understand the order of the first two cases, check how a single  open
integer  pattern  is  covered  by  a  list  of  integer  patterns either
containing or not containing an open pattern.

*/

coveredby
 :: ([sym]->Bool)
    (Graph sym var)
    ![Pattern sym pvar]
    [var]
 -> Bool
 |  == sym
 &  == var
 &  == pvar

coveredby complete subject [] svars = False
coveredby complete subject pvarss [] = True
coveredby complete subject pvarss [svar:svars]
| sdef
= coveredby complete subject tmpvalue (sargs++svars)
| complete (map fst3 closeds)
= and (map covered closeds)
= coveredby complete subject opens svars
  where (opens,closeds) = psplit pvarss
        covered (sym,repvar`,pvarss`) = coveredby complete subject pvarss` (repvar (repvar` dummyvar) svar++svars)
        (sdef,(ssym,sargs)) = varcontents subject svar
        tmpvalue = (fst (foldr (spl (repvar sargs) ssym) ([],[]) pvarss))
        dummyvar = abort "complete: error: accessing dummy variable"

repvar pvars svar = map (const svar) pvars

/*

Split splits a list of multipatterns into parts; on one hand,  those  of
which  the  first  pattern  is  open,  and  on the other hand, for every
constructor, the list of applicable multipatterns,  in  which  case  the
multipatterns with an open pattern are expanded and added as well.

*/

psplit
 :: [Pattern sym var]
 -> (   [Pattern sym var]
    ,   [   (   sym
            ,   var->[var]
            ,   [Pattern sym var]
            )
        ]
    )
 |  == sym
 &  == var

psplit [] = ([],[])
psplit [(subject,[svar:svars]):svarss]
| not sdef
= ([(subject,svars):opens`],map add closeds`)
= (opens,[(ssym,repvar,[(subject,sargs++svars):ins]):closeds])
  where (opens`,closeds`) = psplit svarss
        add (sym,repvar,svarss`) = (sym,repvar,[(subject,repvar svar++svars):svarss`])
        (opens,closeds) = psplit outs
        (ins,outs) = foldr (spl repvar ssym) ([],[]) svarss
        repvar svar = map (const svar) sargs
        (sdef,(ssym,sargs)) = varcontents subject svar

/*

Spl, given a symbol, derives two lists of multipatterns  from  one.  The
first  are  the  multipatterns  of which the first pattern can match the
symbol, i.e. open ones and closed ones with  the  correct  symbol.   The
second  are  the  multipatterns  that can match other symbols, i.e. also
open ones, and closed ones with the wrong symbol.

*/

spl
 :: (var -> [var])
    sym
    (Pattern sym var)
    ([Pattern sym var],[Pattern sym var])
 -> ([Pattern sym var],[Pattern sym var])
 |  == sym
 &  == var

spl repvar sym (subject,[svar:svars]) (ins,outs)
| not sdef
= ([(subject,repvar svar++svars):ins],[(subject,[svar:svars]):outs])
| ssym==sym
= ([(subject,sargs++svars):ins],outs)
= (ins,[(subject,[svar:svars]):outs])
  where (sdef,(ssym,sargs)) = varcontents subject svar