summaryrefslogblamecommitdiff
path: root/sources/scalac/transformer/matching/CodeFactory.java
blob: 425fd4c9acdeddd869fe684abd91bd46bd16781f (plain) (tree)





















                                                                          
                                         












                                                                             


                                                         
 







                                                              
                         
                                                          

     
                         
                                                                


                        
                                                                                           

     
                         








                                                                               





                                                                            


                                                                                
 



                                                                               








                                                                                 

                                                  




















                                                                           


















                                                         
                                     





                                                          
                                          





                                                          
                                          
                                        

                                                                          
                                                           


                                                      


                                                    
                                                                    

                                                                                 




                                                      



                           








                                                                           

                                                 
                                                                          

                                                       
                                                                              

                                                       
                                                                                  



                                                      
                                                                       

                                                       
                                                                        

                                                        
                                                                         

                                                         
                                                                    
                                                        
                                                            
                                                     





                                                                             


                                  




                                                                                          
 

                                         
                                                                     

     




                                                      
                                                                             







                                                
                                            


                                
                                                          

                                            




                                                                    


                                              
                                                                                  





















                                                                     
          
                                            
                                                                        

                                           
          
                                                                                              

     


                                                         
                                                                     


                                                   

                                                                                                                           



                                                
                                             
                                                                         



                                                   
                                        
       


                                                                      
 

                                                                                   
 










                                                              
                                      

                             
                                                                                   
         
 

     


                                    
                                                            
                                           
                                                                            

     
                      
       

                                       
                                                 
 
                                                                                        



                      

                                                                  

                                          
 














































                                                              


















                                                           




                                                                         



                                                

                                      








                                                                           
 

                                               

                                                                  

                        

                                                             


                                             





                                                                                 



                                              

                                                                  

                        

                                                              


                                            





                                                                                




                                             









                                                                                                            




                                             









                                                                                                            




                                                  
















                                                                                         





                                                                            






                                                            


                                                                    




















                                                                                                                                             


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

package scalac.transformer.matching;

import ch.epfl.lamp.util.Position;

import scalac.*;
import scalac.ast.*;
import scalac.util.*;
import scalac.symtab.*;
import scalac.typechecker.*;
import PatternNode.*;
import Tree.*;

class CodeFactory extends PatternTool {

    private int pos = Position.FIRSTPOS ;

      static final Name HEAD_N       = Name.fromString("head");

      static final Name TAIL_N       = Name.fromString("tail");

      static final Name SEQ_TRACE_N      = Name.fromString("scala.SeqTrace");

      static final Name HEADSTATE_N       = Name.fromString("headState");

      static final Name HEADELEM_N        = Name.fromString("headElem");

      static final Name ISEMPTY_N        = Name.fromString("isEmpty");

    Symbol refSym() { // delete Names.Ref
	return defs.getType( Names.scala_Ref ).symbol() ;
    }

    Symbol seqSym() {
	return defs.getType( Names.scala_Seq ).symbol() ;
    }

    Symbol iteratorSym() {
	return defs.getType( Names.scala_Iterator ).symbol() ;
    }

    Symbol seqListSym() {
	return defs.getType( Names.scala_List ).symbol() ;
    }

    Symbol seqConsSym() {
	return defs.getType( Names.scala_COLONCOLON ).symbol() ;
    }

    Symbol seqNilSym() {
	return defs.getType( Names.scala_Nil ).symbol(); // no need for TypeApply anymore!x
    }

    Symbol seqIterSym() {
	return defs.getType( Names.scala_Iterator ).symbol();
    }

    Symbol seqIterSym_next() {
	Scope scp = seqIterSym().members(); return scp.lookup( Names.next );
    }

    Symbol seqIterSym_hasNext() {
	Scope scp = seqIterSym().members(); return scp.lookup( Names.hasNext );
    }

    Symbol seqTraceSym() {
	return defs.getType( Name.fromString( "scala.SeqTrace" ) ).symbol();
    }

    Symbol seqTraceConsSym() {
	return defs.getType( Name.fromString( "scala.SeqTraceCons" ) ).symbol();
    }

    Symbol seqTraceNilSym() {
	return defs.getType( Name.fromString( "scala.SeqTraceNil" ) ).symbol();
    }

    Symbol iterableSym() {
	return defs.getType( Names.scala_Iterable ).symbol();
    }

    Symbol newIterSym() {
	Scope scp = iterableSym().members(); return scp.lookup( Names.elements );
    }


    public CodeFactory( Unit unit, Infer infer ) {
	super( unit, infer );
    }

    // --------- these are new

    /** If  ... pos, type is copied from thenBody
     */
    Tree If( Tree cond, Tree thenBody, Tree elseBody ) {
	//assert( thenBody.type().equals( elseBody.type() )
	//       || thenBody.type().isSubType( elseBody.type() )
	//        /*|| elseBody.type().isSubType( thenBody.type()  BUG  */)
	//    : "you try to construct a naughty if "
	//     + "thenBody: "+thenBody.type+" elseBody:"+elseBody.type;
	assert cond != null:"cond is null";
	assert thenBody != null:"thenBody is null";
	assert elseBody != null:"elseBody is null";
	return make.If( thenBody.pos,
			cond,
			thenBody,
			elseBody ).setType( elseBody.type() );
    }

    Tree Switch( Tree selector,
		 Tree condition[],
		 Tree body[],
		 Tree defaultBody ) {
	assert selector != null:"selector is null";
	assert condition != null:"cond is null";
	assert body != null:"body is null";
	assert defaultBody != null:"defaultBody is null";
	Tree result = defaultBody;

	for( int i = condition.length-1; i >= 0; i-- )
	    result = If( condition[ i ],
			 body[ i ],
			 result
			 ).setType( result.type );

	return result ;
    }

    /** returns `List[ elemType ]' */
      Type SeqListType( Type elemType ) {
            return Type.TypeRef( defs.SCALA_TYPE,
                                 seqListSym(),
                                 new Type[] { elemType });
      }

    /** returns  `SeqTrace[ elemType ]' */
      Type SeqTraceType( Type elemType ) {
            return Type.TypeRef( defs.SCALA_TYPE,
                                 seqTraceSym(),
                                 new Type[] { elemType });
      }

    /**  returns `Iterator[ elemType ]' */
    Type _seqIterType( Type elemType ) {
	Symbol seqIterSym = defs.getType( Names.scala_Iterator ).symbol();

	return Type.TypeRef( defs.SCALA_TYPE, seqIterSym(),
			     new Type[] { elemType });
    }

    /**  returns `<seqObj.elements>' */
    Tree newIterator( Tree seqObj, Type elemType ) {
	Symbol newIterSym = newIterSym();
	Tree t1 = gen.Select( Position.FIRSTPOS, seqObj, newIterSym)
	    .setType( Type.MethodType(new Symbol[] {},_seqIterType( elemType )));

	Tree theIterator = gen.Apply(seqObj.pos,
				     t1,
				     Tree.EMPTY_ARRAY)
	    .setType( _seqIterType( elemType ) );

	return theIterator;

    }

    /** returns code `<seqObj>.elements'
     *  the parameter needs to have type attribute `Sequence[<elemType>]'
     */
    Tree newIterator( Tree seqObj ) {
	return newIterator( seqObj, getElemType_Sequence( seqObj.type() ));
    }

    /** FIXME - short type
     */
      Tree ignoreValue( Type asType ) {
            if( asType.isSameAs(defs.BYTE_TYPE ))
                  return make.Literal(Position.FIRSTPOS, new Integer( 0 ))
                        .setType( defs.INT_TYPE );
            else if( asType.isSameAs( defs.CHAR_TYPE ))
                  return make.Literal(Position.FIRSTPOS, new Character( 'a' ))
                        .setType( defs.CHAR_TYPE );
            else if( asType.isSameAs(defs.SHORT_TYPE ))
		return make.Literal(Position.FIRSTPOS, new Integer/*Short?*/( 0 ))
                        .setType( defs.SHORT_TYPE );
            else if( asType.isSameAs(defs.INT_TYPE ))
                  return Int( 0 );
            else if( asType.isSameAs(defs.LONG_TYPE ))
                  return make.Literal(Position.FIRSTPOS, new Long( 0 ))
                        .setType( defs.LONG_TYPE );
            else if( asType.isSameAs(defs.FLOAT_TYPE ))
                  return make.Literal(Position.FIRSTPOS, new Float( 0 ))
                        .setType( defs.FLOAT_TYPE );
            else if( asType.isSameAs(defs.DOUBLE_TYPE ))
                  return make.Literal(Position.FIRSTPOS, new Double( 0 ))
                        .setType( defs.DOUBLE_TYPE );
            else if( asType.isSameAs(defs.BOOLEAN_TYPE ))
                  return gen.mkBooleanLit(Position.FIRSTPOS, false);
            else if( asType.isSameAs(defs.STRING_TYPE ))
                  return make.Literal(Position.FIRSTPOS, "")
                        .setType( defs.STRING_TYPE );
            /** FIX ME FOR THE NEW VERSION*/
	    else
		return /*gen.Apply( */Null( asType )/*,
						      Tree.EMPTY_ARRAY)*/;

	    //throw new ApplicationError("don't know how to handle "+asType);
      }

    /** FIX ME FOR THE NEW VERSION
     */
    Tree Null( Type asType ) {
	return gen.Ident(pos, defs.NULL );/*gen.TypeApply(pos, gen.Ident(pos, defs.NULL ),
					    new Tree[] { gen.mkType(pos, asType) } );*/
    }

    // the caller needs to set the type !
    Tree  _applyNone( Tree arg ) {
	return make.Apply(Position.FIRSTPOS, arg, Tree.EMPTY_ARRAY );
    }

    /** code `new SeqTraceNil[ elemType ]()'
     */

    Tree _seqTraceNil( Type elemType ) {
	assert elemType != null : "elemType = null??";
	return gen.New( Position.FIRSTPOS, defs.SCALA_TYPE, seqTraceNilSym(),
			new Type[] { elemType },
			new Tree[] {});
    }


      /** creates an scala.Int constant
       */
      Tree Int( int val ) {
            return Int( new Integer( val ));
      }

      Tree Int( Integer valI ) {
            return make.Literal( Position.FIRSTPOS, valI )
                  .setType( defs.INT_TYPE );

      }

      /** code `new SeqTraceCons[ elemType ]( state, head, tail )'
       */
      Tree newSeqTraceCons(  Integer state, Tree head, Tree tail ) {
	  assert head != null : "head null";
	  assert tail != null : "tail null";
	  assert state != null : "state null";
            return gen.New( Position.FIRSTPOS, defs.SCALA_TYPE, seqTraceConsSym(),
                            new Type[] { head.type() },
                            new Tree[] { Int( state ), head, tail });
      }


      /*
      Type _seqTraceConsType( Type elemType ) {
            return Type.TypeRef( defs.SCALA_TYPE,
                                 seqTraceConsSym,
                                 new Type[] { elemType });
      }
      */

      //                       `SeqCons[ elemType ]'

      Type _seqConsType( Type elemType ) {
            return Type.TypeRef( defs.SCALA_TYPE,
                                 seqConsSym(),
                                 new Type[] { elemType });
      }

    Tree newSeqNil( Type tpe ) {
	/*
	assert tpe != null :"tpe = null !?";
	return gen.New( Position.FIRSTPOS, defs.SCALA_TYPE, seqNilSym(),
			new Type[] { tpe },
			new Tree[] {});
	*/
	return gen.Select(gen.Ident(Position.FIRSTPOS, defs.SCALA), Names.Nil/*seqNilSym()*/);
    }

    // EXPERIMENTAL
    Tree newRef( Tree init ) {
	//System.out.println( "hello:"+refSym().type() );
	return gen.New( Position.FIRSTPOS, defs.SCALA_TYPE, refSym(),
			new Type[] { init.type() },
			new Tree[] { init } );
	/*
	return gen.Apply( gen.TypeApply(Position.FIRSTPOS, gen.Select(gen.Ident(Position.FIRSTPOS, defs.SCALA), Names.Ref),
					new Tree[] { gen.mkType(Position.FIRSTPOS, init.type() ) } ),
			  new Tree[] { init } );
	*/
    }

    Tree newSeqCons( Tree head, Tree tail ) {
	return gen.New( Position.FIRSTPOS, defs.SCALA_TYPE, seqConsSym(),
			new Type[] { head.type() },
			new Tree[] { head, tail });
    }

    /** returns A for T <: Sequence[ A ]
     */
    Type getElemType_Sequence( Type tpe ) {
	//System.err.println("getElemType_Sequence("+tpe.widen()+")");
	Type tpe1 = tpe.widen().baseType( seqSym() );

	if( tpe1 == Type.NoType )
	    throw new ApplicationError("arg "+tpe+" not subtype of Sequence[ A ]");

	return tpe1.typeArgs()[ 0 ];
    }

    /** returns A for T <: Iterator[ A ]
     */
    Type getElemType_Iterator( Type tpe ) {
	//System.err.println("getElemType_Iterator("+tpe+")");

	Type tpe1 = tpe.widen().baseType( iteratorSym() );

	switch( tpe1 ) {
	case TypeRef(_,_,Type[] args):
	    return args[ 0 ];
	default:
	    throw new ApplicationError("arg "+tpe+" not subtype of Iterator[ A ]");
	}

    }

    /** `it.next()'
     */
    public Tree _next( Tree iter ) {
	Type elemType = getElemType_Iterator( iter.type() );
	Symbol nextSym = seqIterSym_next();
	return _applyNone( gen.Select( iter, nextSym )).setType( elemType );
    }

    /** `it.hasNext()'
     */
    public Tree _hasNext( Tree iter ) {

	Symbol hasNextSym = seqIterSym_hasNext();

	return _applyNone( gen.Select( iter, hasNextSym )).setType( defs.BOOLEAN_TYPE );
    }

    /** `!it.hasCur()'
     */
    public Tree _not_hasNext( Tree iter ) {
	return _applyNone( gen.Select( _hasNext( iter ), notSym ))
	    .setType( defs.BOOLEAN_TYPE );
    }

      /** `trace.isEmpty'
       */
      public Tree isEmpty( Tree iter ) {
            Scope scp = seqTraceSym().members();
            Symbol isEmptySym = scp.lookup ( ISEMPTY_N );
            return _applyNone( gen.Select( iter, isEmptySym ))
                  .setType( defs.BOOLEAN_TYPE );
      }

      Tree SeqTrace_headElem( Tree arg ) {
            Scope scp = seqTraceSym().members();
            Symbol headSym = scp.lookup ( HEADELEM_N );
            assert headSym != Symbol.NONE;
            return gen.Apply( gen.Select( pos, arg, headSym ),
                              Tree.EMPTY_ARRAY );
      }

      Tree SeqTrace_headState( Tree arg ) {
            Scope scp = seqTraceSym().members();
            Symbol headSym = scp.lookup ( HEADSTATE_N );
            assert headSym != Symbol.NONE;
            return gen.Apply( gen.Select( pos, arg, headSym ),
                              Tree.EMPTY_ARRAY );
      }

      Tree SeqTrace_tail( Tree arg ) {
            Scope scp = seqTraceSym().members();
            Symbol tailSym = scp.lookup ( TAIL_N );
            assert tailSym != Symbol.NONE;
            return gen.Apply( gen.Select( pos, arg, tailSym ),
                              Tree.EMPTY_ARRAY );
      }

      /** `<seqlist>.head()'
       */
      Tree SeqList_head( Tree arg ) {
            Scope scp = seqListSym().members();
            Symbol headSym = scp.lookup ( HEAD_N );
            assert headSym != Symbol.NONE;
            return gen.Apply( make.Select( pos,
                                           arg,
                                           HEAD_N )
                              .setType( headSym.type() )
                              .setSymbol( headSym ),
                              Tree.EMPTY_ARRAY);
      }

    /** return the analyzed type
     */
    public Type typeOf(Symbol sym) {
        return sym.type();
        //return sym.typeAt(unit.global.ANALYZER_PHASE.id);
    }

    /** return the analyzed type
     */
    public Type typeOf0(Symbol sym) {
        return sym.typeAt(unit.global.PHASE.ANALYZER.id);
    }


    protected Tree Block(int pos, Tree[] ts, Type tpe) {
        if (ts.length == 1)
            return ts[0];
        else if (ts.length > 1)
            switch (ts[ts.length - 1]) {
	    case Block(Tree[] ts0):
		Tree[] ts1 = new Tree[ts0.length + ts.length - 1];
		System.arraycopy(ts, 0, ts1, 0, ts.length - 1);
		System.arraycopy(ts0, 0, ts1, ts.length - 1, ts0.length);
		return Block(pos, ts1, tpe);
            }
        return make.Block(pos, ts).setType(tpe);
    }

     // unused
       public Tree Negate(Tree tree) {
       switch (tree) {
       case Literal(Object value):
       return gen.mkBooleanLit(tree.pos, !((Boolean)value).booleanValue());
       }
       return make.Apply(
       tree.pos,
       gen.Select(tree, NOT_N),
       Tree.EMPTY_ARRAY).setType(defs.BOOLEAN_TYPE);
       }

    protected Tree And(Tree left, Tree right) {
        switch (left) {
	case Literal(Object value):
	    return ((Boolean)value).booleanValue() ? right : left;
        }
        switch (right) {
	case Literal(Object value):
	    if (((Boolean)value).booleanValue()) return left;
        }
        Symbol fun = left.type.lookup(AND_N);
        return make.Apply(
			  left.pos,
			  make.Select(
				      left.pos,
				      left,
				      AND_N).setType(typeOf(fun)).setSymbol(fun),
			  new Tree[]{right}).setType(defs.BOOLEAN_TYPE);
    }

    protected Tree Or(Tree left, Tree right) {
        switch (left) {
	case Literal(Object value):
	    return ((Boolean)value).booleanValue() ? left : right;
        }
        switch (right) {
	case Literal(Object value):
	    if (!((Boolean)value).booleanValue()) return left;
        }
        Symbol fun = left.type.lookup(OR_N);
        return make.Apply(
			  left.pos,
			  make.Select(
				      left.pos,
				      left,
				      OR_N).setType(typeOf(fun)).setSymbol(fun),
			  new Tree[]{right}).setType(defs.BOOLEAN_TYPE);
    }

    protected Tree Is(Tree tree, Type type) {
        return
            make.Apply(
		       tree.pos,
		       make.TypeApply(
				      tree.pos,
				      make.Select(
						  tree.pos,
						  tree,
						  defs.IS.name).setType(typeOf(defs.IS)).setSymbol(defs.IS),
				      new Tree[]{gen.mkType(tree.pos, type)})
		       .setType(Type.MethodType(Symbol.EMPTY_ARRAY, defs.BOOLEAN_TYPE)),
		       Tree.EMPTY_ARRAY).setType(defs.BOOLEAN_TYPE);
    }

    protected Tree As(Tree tree, Type type) {
        return
            make.Apply(
		       tree.pos,
		       make.TypeApply(
				      tree.pos,
				      make.Select(
						  tree.pos,
						  tree,
						  defs.AS.name).setType(typeOf(defs.AS)).setSymbol(defs.AS),
				      new Tree[]{gen.mkType(tree.pos, type)})
		       .setType(Type.MethodType(Symbol.EMPTY_ARRAY, type)),
		       Tree.EMPTY_ARRAY).setType(type);
    }

    protected Tree Equals(Tree left, Tree right) {
        Symbol fun = left.type.lookup(EQUALS_N);
        switch (typeOf(fun)) {
	case OverloadedType(Symbol[] alts, Type[] alttypes):
	    //System.out.println("**** " + left.type);
	    Tree t = make.Select(left.pos, left, EQUALS_N);
	    //for (int i = 0; i < alttypes.length; i++)
	    //    System.out.println(alts[i] + ": " + alttypes[i]);
	    infer.methodAlternative(t, alts, alttypes,
				    new Type[]{right.type}, defs.BOOLEAN_TYPE);
	    return make.Apply(left.pos, t, new Tree[]{right}).setType(defs.BOOLEAN_TYPE);
	default:
	    //System.out.println("#### " + left.type + ": " + fun);
	    return make.Apply(
			      left.pos,
			      make.Select(
					  left.pos,
					  left,
					  EQUALS_N).setType(typeOf(fun)).setSymbol(fun),
			      new Tree[]{right}).setType(defs.BOOLEAN_TYPE);
        }
    }

    protected Tree ThrowMatchError(int pos, Type type) {
        Symbol matchErrorModule = defs.SCALA.members().lookup(MATCHERROR_N);
        outer: switch (typeOf(matchErrorModule)) {
	case OverloadedType(Symbol[] alts, Type[] alttypes):
	    for (int i = 0; i < alts.length; i++)
		switch (alttypes[i]) {
		case TypeRef(_, _, _):
		    matchErrorModule = alts[i];
		    break outer;
		}
        }
        Symbol failMethod = typeOf(matchErrorModule).lookup(FAIL_N);
        return
	    make.Apply(
		       pos,
		       make.TypeApply(
				      pos,
				      make.Select(
						  pos,
						  make.Select(
							      pos,
							      make.Ident(pos, Names.scala).setType(typeOf(defs.SCALA)).setSymbol(defs.SCALA),
							      MATCHERROR_N)
						  .setSymbol(matchErrorModule)
						  .setType(typeOf(matchErrorModule)),
						  FAIL_N).setType(typeOf(failMethod)).setSymbol(failMethod),
				      new Tree[]{gen.mkType(pos, type)})
		       .setType(((Type.PolyType) typeOf(failMethod)).result.subst(
										  typeOf(failMethod).typeParams(),
										  new Type[]{type})),
		       new Tree[]{
			   make.Literal(pos, unit.toString()).setType(defs.STRING_TYPE),
			   make.Literal(pos, new Integer(Position.line(pos))).setType(defs.INT_TYPE)
		       }).setType(type);
    }

}