summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/matching/AlgebraicMatchers.scala
blob: 4137b128eb9afc390664cd10566b12ac4cab5567 (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
/* NSC -- new scala compiler
 * Copyright 2005 LAMP/EPFL
 * @author buraq
 */
// $Id$

package scala.tools.nsc.matching;

/** the pattern matcher, tweaked to work with regular patterns
 *  @author Burak Emir
 */
trait AlgebraicMatchers : TransMatcher {

  import global._;

 class AlgebraicMatcher extends PatternMatcher {

  import java.util.Vector ;
  import java.util.Iterator ;

  var _m: PartialMatcher = _;

  override protected var delegateSequenceMatching = true;
  override protected var optimize = false;

  /** constructs an algebraic pattern matcher from cases */
  def construct(m: PartialMatcher, cases: List[CaseDef]): Unit =
    construct(m, cases, true);

  /** constructs an algebraic pattern matcher from cases */
  def construct(m: PartialMatcher, cases: List[CaseDef], doBinding: Boolean): Unit = {
    this._m = m;
    super.initialize( _m.selector, _m.owner, doBinding );

    val it = cases.elements;
    while (it.hasNext) {
	  val cdef = it.next;
	  /*
	  if(cdef != null)
	  Console.println("algebraic matcher: "+cdef.toString()); // DEBUG
	  else
	  scala.Predef.error("got CaseDef null in alg matcher!");
	  */
      enter(cdef);
	}

    //if (unit.global.log()) {
    //  unit.global.log("internal pattern matching structure");
    //  print();
    // }
    _m.tree = toTree();
  }


  /** initializes this AlgebraicMatcher, see Matcher.initialize
   void initialize() {}
   */
  /*
   def isStarApply(tree: Tree.Apply): Boolean = {
   val params:Array[Symbol] = tree.fun.getType().valueParams();
   //System.err.println( tree.fun.type.resultType().symbol() );
   (tree.args.length == 1)
   && (tree.getType().symbol().flags & Modifiers.CASE) != 0
   && params.length > 0
   && (params(params.length-1).flags & Modifiers.REPEATED) != 0;
   }
   */
  //////////// generator methods

  override def toTree(): Tree = {

    this.exit = currentOwner.newLabel(root.pos, "exitA")
      .setInfo(new MethodType(List(resultType), resultType));

    val result = exit.newValueParameter(root.pos, "resultA").setInfo( resultType );

    Block(
      List (
        ValDef(root.symbol, _m.selector)
      ),
      If( super.toTree(root.and),
         LabelDef(exit, List(result), Ident(result)),
         ThrowMatchError( _m.pos, resultType ))
    );
  }

  protected override def toTree(node: PatternNode, selector: Tree): Tree = {
    //System.err.println("AM.toTree called"+node);
    if (node == null)
      Literal(false);
    else node match {
      case SeqContainerPat( _, _ ) =>
	callSequenceMatcher( node,
			    selector );
      case _ =>
	super.toTree( node, selector );
    }
  }

  /** collects all sequence patterns and returns the default
   */
  def collectSeqPats(node1: PatternNode, seqPatNodes: Vector, bodies: Vector): PatternNode = {
    var node = node1;
    var defaultNode: PatternNode = null;
    var exit = false;
      do {
        if( node == null )
          exit=true; //defaultNode = node; // break
        else
          node match {
            case SeqContainerPat( _, _ ) =>
              seqPatNodes.add( node );
              bodies.add( super.toTree( node.and ) );
              node = node.or;
              exit//defaultNode = node; //               break;

            case _ =>
              defaultNode = node;
          }
      } while (!exit && (null == defaultNode)) ;

    defaultNode;
  }

  def callSequenceMatcher(node: PatternNode, selector1: Tree):  Tree = {

    //Console.println("calling sequent matcher for"+node);
    /*    ???????????????????????? necessary to test whether is a Seq?
     gen.If(selector.pos, maybe And( Is(selector, seqpat.type()) )???)
     */

    // translate the _.and subtree of this SeqContainerPat

    val seqPatNodes = new Vector();
    val bodies      = new Vector();

    var defaultNode = collectSeqPats(node, seqPatNodes, bodies);

    val defaultCase = toTree(defaultNode, selector1);

    val wordRec = new SequenceMatcher();

    val m = new PartialMatcher {
      val owner = _m.owner;
      val selector = selector1;
    }

    var pats: scala.List[Tree] = Nil;
    var body: scala.List[Tree] = Nil;

    val tmp = bodies.toArray();
    var j = 0;
    val it = seqPatNodes.iterator();
    while (it.hasNext()) {
      //pats(j) = it.next().asInstanceOf[SeqContainerPat].seqpat;
      pats = it.next().asInstanceOf[SeqContainerPat].seqpat :: pats;
      //body(j) = tmp(j).asInstanceOf[Tree];
      body = tmp(j).asInstanceOf[Tree] :: body;
      j = j + 1;
    }
    //Tree defaultTree = toTree(node.or, selector); // cdef.body ;

    wordRec.construct(m, pats.reverse, body.reverse, defaultCase, doBinding);

    //_m.defs.addAll(m.defs);

    m.tree;
  }

} // class AlgebraicMatcher

}