summaryrefslogblamecommitdiff
path: root/sources/scalac/transformer/matching/AlgebraicMatcher.java
blob: 7c564882b3c40acba16b76806997f319e6658563 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13












                                                                          





                                              
                          








                                                                      
                                                      


                 

                     

                                            

                                                 










                                                                          
                        
                                                                                
                                                     
                                                             
             



                                                                       




                                                                   
                         
       
         
 






































                                                                                  
                                                



                                                                    

                                                                         

     



                                     

                                                            
                                                                              


                                                                         
          
                   


                                               
                                                     
          
                                                 
     
 
                                                            
                                                      


                                                   
                                     

                                                    
                
                                                  















                                                                
                                                 















                                                                                
                                        



                                                                         
                                                                    
 

                                            
 


                                                                
 
                                                             
 
                                                              
 

                                            
                                                         
 

                                                       
 


                                                    
                                   




                                                                          
 
                                                                     
 
                                      
 
                        

       
 
/*     ____ ____  ____ ____  ______                                     *\
**    / __// __ \/ __// __ \/ ____/    SOcos COmpiles Scala             **
**  __\_ \/ /_/ / /__/ /_/ /\_ \       (c) 2002, LAMP/EPFL              **
** /_____/\____/\___/\____/____/                                        **
**                                                                      **
** $Id$
\*                                                                      */

package scalac.transformer.matching;

import scalac.*;
import scalac.ast.*;
import scalac.symtab.*;

import PatternNode.*;
import Tree.*;

import scalac.transformer.TransMatch.Matcher ;
import scalac.util.Name ;
import scalac.util.Names ;
//import scalac.ast.printer.TextTreePrinter ;

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

/** Matthias' algebraic pattern matcher, with some things factored out
 *  @author Matthias Zenger, Burak Emir
 */

public class AlgebraicMatcher extends PatternMatcher {

      Matcher _m;

      /** constructor
       */
      public AlgebraicMatcher( Unit unit ) {
            super( unit );
	    this.delegateSequenceMatching = true;
	    this.optimize = false;
      }

      /** constructs an algebraic pattern matcher from cases
       */
      public void construct( Matcher m, Tree[] cases) {
            construct(m, cases, true);
      }

      /** constructs an algebraic pattern matcher from cases
       */
      public void construct( Matcher m, Tree[] cases, boolean doBinding) {
            this._m = m;
	    super.initialize( _m.selector, _m.owner, _m.resultType, doBinding );
            for( int i = 0; i < cases.length; i++ ) {
                enter( cases[ i ] );//(CaseDef) cases[i], i);
            }
            if (unit.global.log()) {
                unit.global.log("internal pattern matching structure");
                print();
            }
            _m.tree = toTree();
      }


      /** initializes this AlgebraicMatcher, see Matcher.initialize
      void initialize() {
      }
       */


      /** returns true if p and q are pattern nodes of the same kind and p matches
       *  whenever q matches, possibly even more often
       */
    protected boolean superPat(PatternNode p, PatternNode q) {
        switch (p) {
            case DefaultPat():
                switch (q) {
                    case DefaultPat():
                        return true;
                    //case ConstantPat(_, _):
                    //    return q.type.isSubType(p.type);
                }
                return false;
           case ConstrPat(_):
                switch (q) {
                    case ConstrPat(_):
                        return q.type.isSubType(p.type);
                }
                return false;
           case ConstantPat( Object pval ):
                switch (q) {
                    case ConstantPat( Object qval ):
                        return pval.equals(qval);
                }
                return false;
        }
        return false;
    }

    protected boolean isDefaultPat(PatternNode p) {
        switch (p) {
            case DefaultPat():
                return true;
            default:
                return false;
        }
    }

        boolean isStarApply( Tree.Apply tree ) {
	Symbol params[] = tree.fun.type.valueParams();
	//System.err.println( tree.fun.type.resultType().symbol() );
	return  (tree.args.length == 1)
	    && (tree.type.symbol().flags & Modifiers.CASE) != 0
	    && params.length > 0
	    && (params[params.length-1].flags & Modifiers.REPEATED) != 0;
    }

//////////// generator methods

    public Tree toTree() {
        TreeList ts = new TreeList();
        ts.append( gen.ValDef(root.symbol(), _m.selector ));
        ts.append( gen.ValDef(resultVar,
                              gen.mkDefaultValue(_m.pos, resultVar.info()) ));
        ts.append( gen.If( toTree(root.and),
                           gen.Ident( _m.pos, resultVar ),
                           cf.ThrowMatchError( _m.pos, _m.resultType )));
        /*
            gen.If(
                _m.pos,
                toTree(root.and),
                gen.Ident( _m.pos, resultVar ),
                cf.ThrowMatchError( _m.resultType ));
        */
        return gen.mkBlock(_m.pos, ts.toArray());
    }

    protected Tree toTree(PatternNode node, Tree selector) {
	//System.err.println("AM.toTree called"+node);
        if (node == null)
            return gen.mkBooleanLit(_m.pos, false);
        switch (node) {
        case SeqContainerPat( _, _ ):
	    return  callSequenceMatcher( node,
					 selector );
        default:
	    return super.toTree( node, selector );
        }
    }

      /** collects all sequence patterns and returns the default
       */
      PatternNode collectSeqPats( PatternNode node,
                                  Vector seqPatNodes,
                                  Vector bodies ) {

              PatternNode defaultNode = null;

              do {
                    if( node == null )
                          break;// defaultNode = node;
                    else
                          switch( node ) {
                    case SeqContainerPat( _, _ ):
                          seqPatNodes.add( node );
                          bodies.add( toTree( node.and ) );
                          node = node.or;
                          break;
                    default:
                          defaultNode = node;
                    }
              } while (defaultNode == null) ;

              return defaultNode;
      }

      Tree callSequenceMatcher( PatternNode node,
                                Tree selector) {

              /*    ???????????????????????? necessary to test whether is a Seq?
		    gen.If(selector.pos,
                             maybe cf.And( cf.Is(selector, seqpat.type())
                             ...
              */

              // translate the _.and subtree of this SeqContainerPat

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

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

	  Tree defaultCase = toTree( defaultNode, selector );

	  SequenceMatcher wordRec = new SequenceMatcher(unit);

	  Matcher m = new Matcher( _m.owner,
				   selector,
				   defs.BOOLEAN_TYPE() );

	  Tree pats[] = new Tree[ seqPatNodes.size() ];
	  Tree body[] = new Tree[ seqPatNodes.size() ];

	  Object tmp[] = bodies.toArray();
	  int j = 0;
	  for( Iterator it = seqPatNodes.iterator();
                   it.hasNext();) {
	      pats[ j ]  = ((SeqContainerPat) it.next()).seqpat;
	      body[ j ] = (Tree) tmp[j];
	      j++;
	  }
	  //Tree defaultTree = toTree( node.or, selector ); // cdef.body ;

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

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

	  return m.tree;
      }

}