summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/matching/Autom2.scala
blob: b99db700b4613464ed69567042cd7fda7ba6f3fe (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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
package scala.tools.nsc.matching ;

//import java.util._ ;

import scala.tools.nsc.util.Position;

trait Autom2: TransMatcher {

  import global._;

  /**  @param owner owner of the pattern matching expression
   */
  abstract class Autom2Scala {

    val dfa: DetWordAutom;
    val owner: Symbol;

    protected var optimize = true;

    final val FAIL = -1;

    /** symbol of the matcher DefDef or Label */
    var funSym:Symbol = _;

    /** symbol of the iterator ( scala.SequenceIterator ) */
    var iterSym: Symbol = _;

    /** symbol of the switching result ( scala.Int ) */
    var resultSym: Symbol = _;

    /** symbol of the state variable ( scala.Int ) */
    var stateSym: Symbol = _;

    /** symbol of variable holding current label */
    var curSym: Symbol = _;

    /** symbol of boolean variable that indicates we have not reached end of sequence */
    var hasnSym: Symbol = _;

    val am = new AlgebraicMatcher();

    var pos: Int = Position.FIRSTPOS;

    val elementType: Type;

    def funRetType(): Type = {
      funSym.tpe match {
        case MethodType( _, retType )=> retType;
        case _ => scala.Predef.error("quoi?");
      }
    }

    def callFun(args: List[Tree]): Tree = Apply(Ident(funSym),args);

    // overridden in RightTracerInScala
    def loadCurrentElem(body: Tree): Tree = {
      Block(
        List(
          ValDef(this.hasnSym, _hasNext( _iter() ) ),
          ValDef(this.curSym, If(Ident( hasnSym ),
                                 _next( _iter() ),
                                 EmptyTree))
        ),
        body
      );
    }

    /** bug ?? */
    def currentElem() = { Ident( curSym ) }

    def currentMatches(label: Label): Tree = {
      label match {
        case TreeLabel( pat ) =>
          _cur_match( pat );
        case SimpleLabel(lit: Literal) =>
          Equals( currentElem(), lit );
        case _ => // cannot happen
          scala.Predef.error("expected either algebraic or simple label:"+label);
      }
    }

    //
    // translation of automata to scala code
    //


    /** `[switchResult]' */
    def _swres(): Tree = { Ident( resultSym );}

    /** `<state>' param */
    def _state(): Tree = { Ident( stateSym ); }

    /** `<iterator>' param */
    def  _iter(): Tree = { Ident( iterSym );  }

    /** simple optimization: if we are in a sink state, stop traversing sequence
     */
    def stateWrap(i: Int): Tree = {
      if( dfa.isSink( i ))
        run_finished( i ); // state won't change! optimization
      else
        If( Negate( Ident( hasnSym )),
           run_finished( i ),
           code_state_NEW( i ));
    }

    /** body of the matcherDefFun
     */
    def code_body_NEW(): Tree  = {
      var cases: List[CaseDef] = Nil;

      //val tags   = new Array[Int](dfa.nstates());
      //val bodies = new Array[Tree](dfa.nstates());
      var i = 0; while (i < dfa.nstates()) {
        cases = CaseDef( Literal(i), stateWrap(i)) :: cases;
        i = i + 1;
      }
      //if( optimize )
      loadCurrentElem( Match( _state(), cases ));

      /*
       Tree res = code_error();
       for( int i = dfa.nstates-2; i>= 0; i-- )
       res = gen.If( Equals( _state(), gen.mkIntLit( pos, i )),
       bodies[ i ] ,
       res );

       return loadCurrentElem( res );
       */
    }

    /* calling the (AlgebraicMatcher)PatternMatcher here */
    def _cur_match(pat: Tree): Tree  = {
      val m:  PartialMatcher = new PartialMatcher {
        val owner = Autom2Scala.this.funSym;   /* owner*/
        val selector = currentElem(); /* root */
                                 /* defs.boolean_TYPE() restype */
      };

      am.construct( m, List (
        CaseDef(                 pat, Literal(true)),
        CaseDef( Ident(nme.WILDCARD), Literal(false))
      ),
                   false);
      am.toTree();
    }

    // @todo should be abstract
    def code_delta( i:Int, label: Label): Tree = {
        scala.Predef.error("should not happen");
    }

    /** some error happened which is due to bug in translation/automaton
     */
    final def code_error(): Tree = {
        ThrowMatchError( pos , funRetType() );
    }

    def code_fail(): Tree = {
      Literal( FAIL ); //gen.mkIntLit(Position.FIRSTPOS, FAIL );
    }

    /** code for the return value of the automaton translation
     */
    def run_finished(state: Int): Tree = {
      if( dfa.isFinal( state ))
        Literal(
          dfa.finals.get( new Integer( state ) ).asInstanceOf[Integer]
          .intValue()
        )
      else
        Literal( FAIL );
    }

    def code_state_NEW(i: Int): Tree = {
      var stateBody = code_delta( i, DefaultLabel() );
      if( stateBody == null )
        stateBody = code_fail();
      val trans = dfa.deltaq( i );

      val  labs = dfa.labels().iterator();
      while(labs.hasNext()) {
        val label  = labs.next();
        val next   = trans.get( label ).asInstanceOf[Integer];
        val action = code_delta( i, label.asInstanceOf[Label] );
        if( action != null ) {
          /*assert*/ //stateBody != null : "stateBody is null";
          stateBody = If( currentMatches(label.asInstanceOf[Label] ),
                         action,
                         stateBody);
        }
      }
      stateBody;
    }
  }
}