summaryrefslogtreecommitdiff
path: root/sources/scalac/transformer/matching/SequenceMatcher.java
blob: 68d698986c9adcdcaf00c913991c03729e2a328a (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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
package scalac.transformer.matching ;

import scalac.*;
import scalac.ast.Tree;
import Tree.*;

//import scala.compiler.printer.TextTreePrinter ; // DEBUGGING\
    //import scala.compiler.printer.XMLAutomPrinter ; // DEBUGGING\

    import scalac.transformer.TransMatch.Matcher ;
import scalac.ast.* ;
import scalac.symtab.* ;

import java.util.* ;

import ch.epfl.lamp.util.Position;

/** constructs a matcher for a sequence pattern. plays two roles in
 *  described in design pattern Builder.
 *  is the "Director" for "Builder" class BerrySethi.
 *  is the "Builder" for "Director" class TransMatch.
 */

public class SequenceMatcher extends PatternTool {

    final static Integer IGNORED = new Integer(42);
    CodeFactory cf;

    Matcher _m;

    //Tree pat[];
    //Tree body[];

    BindingBerrySethi bbuild = null;

    /** translates the det/switching automaton to scala code
     *  precondition: pat.type() corresponds to element type
     */
    Tree addBinderToBody( Tree pat, Tree body ) {
        if( bbuild == null )
            bbuild = new BindingBerrySethi();

        Type elementType = cf.getElemType_Sequence( pat.getType() );

        // (a) build *binding* nfa (sequential machine)
        NondetWordAutom left =  bbuild.automatonFrom( pat, IGNORED );
        NondetWordAutom right = bbuild.revnfa;

        //  (b) determinize + translate L

        DetWordAutom dLeft  = new DetWordAutom( left );

        LeftTracerInScala ltis =
            new LeftTracerInScala( dLeft, elementType, _m.owner, _m.selector, cf);

        Tree trace = ltis.getTrace();

        Tree theTrace = gen.Ident( cf.pos, ltis.resultSym );

        //  (c) determinize + translate R

        DetWordAutom dRight = new DetWordAutom( right, left, dLeft );

        Set seqVars = NondetWordAutom.collectVariables( left );
        //System.out.println("seqVars here are:"+seqVars);
        final RightTracerInScala rtis =
            new RightTracerInScala( dRight, seqVars, _m.owner,
                                    cf, pat, elementType );

        Tree stms2[] = rtis.getStms( theTrace, unit, body );

        // paste statements together

        Tree items[] = new Tree[ 1 + stms2.length ];

        items[ 0 ] = trace;
        System.arraycopy( stms2, 0, items, 1, stms2.length );

        return gen.mkBlock( body.pos, items );
    }

    private NondetWordAutom[] buildNfas( Tree[] pat ) {
        BerrySethi build = new BerrySethi();
        NondetWordAutom manyNfa[] = new NondetWordAutom[ pat.length ];

        for( int i = 0; i < pat.length; i++ ) {
            manyNfa[ i ] = build.automatonFrom( pat[ i ],
                                                new Integer( i ));
            //manyNfa[ i ].print();
        }
        return manyNfa;
    }

    /** constructs a word recognizer from an array of patterns which
     *  should all be SequencePatterns ( no wildcard * )
     *  precondition: pat.type corresponds to element type
     *  @param _m          Matcher object, holds the result
     *  @param pat         the (Sequence) patterns
     *  @param body        the bodies
     *  @param defaultCase code that is run when nothing matches. may be null, it
     *                     becomes a ThrowMatchError then
     *  @param doBinding   flasg that indicates whether variables should be bound
    */
    public void construct( Matcher _m,
                           Tree[] pat,
                           Tree[] body,
                           Tree defaultCase,
                           boolean doBinding ) {
        this._m = _m;
        //this.pat  = pat;
        //this.body = body;
        assert body.length == pat.length;
        if( defaultCase == null )
            defaultCase = cf.ThrowMatchError( cf.pos, _m.resultType );

        this.cf = new CodeFactory( unit, _m.pos );

        Type seqType = pat[ 0 ].getType();
        Type elementType = cf.getElemType_Sequence( seqType );

        // STEP 1 - build nfas for each pattern

        NondetWordAutom manyNfa[] = buildNfas( pat );

        // STEP 2 - recognizing

        // (a) merge nfas into one if necessary
        NondetWordAutom nfa =
            (pat.length > 1) ? new NondetWordAutom( manyNfa )
            : manyNfa[ 0 ];
        //nfa.print();

        // (b) determinize
        DetWordAutom dfa = new DetWordAutom( nfa );

        // (c) translate to scala code
        WordAutomInScala scalaAut = new WordAutomInScala( dfa,
                                                          elementType,
                                                          _m.owner,
                                                          cf,
                                                          unit.global.target == Global.TARGET_JVM );
        scalaAut.translate();

        // STEP 3 - binding

        Tree newbody[];
        if( !doBinding )
            newbody = body;
        else {  // this is done in the body of the matching case
            newbody = new Tree[body.length];
            for( int i = 0; i < body.length; i++ )
                if( !CollectVariableTraverser.containsBinding( pat[ i ] ) )
                    newbody[ i ] = body[ i ]; // no need for binding
                else
                    newbody[ i ] = addBinderToBody( pat[ i ], body[ i ] );
        }

        _m.tree = scalaAut.getMatcherSwitch( _m.selector,
                                             defaultCase,
                                             newbody,
                                             _m.resultType );
    } // construct (Matcher, Tree[], Tree[], Tree, boolean )

      /** constructor, invoked  by AlgebraicMatcher
       */
    SequenceMatcher( Unit unit ) {
        super( unit );
    }
} // class SequenceMatcher