summaryrefslogtreecommitdiff
path: root/sources/scalac/transformer/TransMatch.java
blob: 37f7a7889c0a7d4d0cb9537a424e68a08ecc62dc (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
/*     ____ ____  ____ ____  ______                                     *\
**    / __// __ \/ __// __ \/ ____/    SOcos COmpiles Scala             **
**  __\_ \/ /_/ / /__/ /_/ /\_ \       (c) 2002, LAMP/EPFL              **
** /_____/\____/\___/\____/____/                                        **
\*                                                                      */

// $Id$

package scalac.transformer;

import java.io.*;
import java.util.*;
import scalac.*;
import scalac.ast.*;
import scalac.symtab.*;
import scalac.util.*;       // Names
import Tree.*;

import scalac.transformer.matching.PatternMatcher ;
import scalac.transformer.matching.TestRegTraverser ;
import scalac.transformer.matching.AlgebraicMatcher ;

/** A transformer for expanding match expressions into
 *  flat sequences of .is and .as method calls
 *
 *  @author     Matthias Zenger, Burak Emir
 *  @version    1.1
 */
public class TransMatch extends OwnerTransformer {

      /** container. classes AlgebraicMatcher and SequenceMatcher get input and store their results in here.
       *  resembles the 'Memento' design pattern, could also be named 'Liaison'
       */
    public static class Matcher {

        /** owner of the code we create (input)
         */
        public Symbol owner;

        /** the selector value (input)
         */
        public Tree   selector;

        /** type of the result of the whole match (input)
         */
        public Type   resultType;

        /** tree representing the matcher (output)
         */
        public Tree   tree;

        public int pos;

        public HashMap varMap;    // needed in LeftTracerInScala
        public Tree[]  stms;      // needed in LeftTracerInScala

        public Matcher(Symbol owner,
                       Tree root,
                       Type resultType) {

            assert( owner != null ) : "owner is null";
            assert owner != Symbol.NONE ;
            this.owner      = owner;

            assert root != null;
            assert root.type != null;
            this.selector   = root;

            assert this.resultType != Type.NoType;
            this.resultType = resultType;

            this.pos        = root.pos; // for convenience only

        }

    }

    Unit unit;

    public TransMatch(Global global) {
        super(global);
    }

    public void apply(Unit unit) {
        this.unit = unit;
        super.apply(unit);
    }

    protected Tree transform(Tree root, CaseDef[] cases, Type restpe) {
        boolean containsReg = false;
        int i = 0;
        while (i < cases.length) {
            containsReg = TestRegTraverser.apply(cases[i]) || containsReg;
            Set nilvars = TestRegTraverser.getNilVariables();
            if(!nilvars.isEmpty()) {
                //System.err.println("nilvars present");
                Tree[] newBody = new Tree[ nilvars.size() + 1 ];
                int j=0;
                for( Iterator it = nilvars.iterator(); it.hasNext(); ) {
                    Symbol v = (Symbol) it.next();
                    newBody[ j++ ] = unit.global.treeGen.ValDef(v,
                                                                unit.global.treeGen.Nil(cases[i].pos));
                }
                newBody[ newBody.length - 1 ] = cases[i].body;
                cases[i].body = unit.global.treeGen.mkBlock( newBody );
            }
            i++;
        }
        if (containsReg) {
            AlgebraicMatcher am = new AlgebraicMatcher( unit );
            Matcher matcher = new Matcher( currentOwner, root, restpe );
            am.construct( matcher, cases );
            return matcher.tree;
        } else {
            PatternMatcher pm = new PatternMatcher(unit, root,
                                                   currentOwner, restpe);
            pm.construct(cases);
            if (global.log()) {
                global.log("internal pattern matching structure");
                pm.print();
            }
            return pm.toTree();
        }
    }

    public Tree transform(Tree tree) {
        if (tree == null)
            return null;
        switch (tree) {
            case Apply(Select( Tree receiver, Names.match ), Tree[] args):
                if ((args != null) && (args.length == 1))
                    switch (args[0]) {
                        case Visitor(CaseDef[] cases):
                            return transform(transform(receiver), transform(cases), tree.type);
                    }
                return tree;
            case Apply(TypeApply(Select( Tree receiver, Names.match ), Tree[] targs), Tree[] args):
                if ((args != null) && (args.length == 1))
                    switch (args[0]) {
                        case Visitor(CaseDef[] cases):
                            return transform(transform(receiver), transform(cases), tree.type);
                    }
                return tree;
            default:
                return super.transform(tree);
        }
    }
}