summaryrefslogblamecommitdiff
path: root/sources/scalac/transformer/UnCurry.java
blob: bdc0072adcb09fe26b1d0570910ec9b6688d3b11 (plain) (tree)
1
2
3
4
5
6
7
8



                                                                          

                                                                          

       








                           
                                      
 











                                                                                    

                                                         




                                             
              

                                                       
                      


                           




                                  





















                                                                    

                                                                        


         





















                                                                                          









                                                                                        
                                                                          
                                                         

                                      
                                                                                                         


                                                                    
                                                                                               
                                 
                                             



                                                           
                                                                                        
                                                      
                               
                                             


                                                           
                                              
                                                 

                                                                                           
                                                                     
                    
                                             










                                                              
                                                                



















                                                                                    


                          




                                                                                       
                            
                                                                              


                                                       
             
 




                                         

                                                                 

                                                                  
                                                                       





                                                                                                                             

                                            
                                                                          
                                                     
             
                                
                                                   
                                   
                                                         




                                                           
             
                         
                                     
                                                   
                

                                                                                            

         




                                                                 

                                                                         





                                                                 

                                                                                





                                                            


                                                        
                                           




                                                                       
                                                                   


                                                 
                             
                                                                                        


                                  

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

// $Id$

package scalac.transformer;

import java.io.*;
import java.util.*;
import scalac.*;
import scalac.util.*;
import scalac.ast.*;
import scalac.symtab.*;
import Tree.*;
import scalac.typechecker.DeSugarize ;

/** - uncurry all symbol and tree types (@see UnCurryPhase)
 *  - for every curried parameter list:  (ps_1) ... (ps_n) ==> (ps_1, ..., ps_n)
 *  - for every curried application: f(args_1)...(args_n) ==> f(args_1, ..., args_n)
 *  - for every type application: f[Ts] ==> f[Ts]() unless followed by parameters
 *  - for every use of a parameterless function: f ==> f()  and  q.f ==> q.f()
 *  - for every def-parameter:  def x: T ==> x: () => T
 *  - for every use of a def-parameter: x ==> x.apply()
 *  - for every argument to a def parameter `def x: T':
 *      if argument is not a reference to a def parameter:
 *        convert argument `e' to (expansion of) `() => e'
 *  - for every argument list that corresponds to a repeated parameter
 *       (a_1, ..., a_n) => (Sequence(a_1, ..., a_n))
 *  - for every argument list that is an escaped sequence
 *       (a_1:_*) => (a_1)
 */
public class UnCurry extends OwnerTransformer
                     implements Modifiers {

    UnCurryPhase descr;
    Unit unit;

    public UnCurry(Global global, UnCurryPhase descr) {
        super(global);
	this.descr = descr;
    }

    public void apply(Unit unit) {
	super.apply(unit);
	this.unit = unit;
    }

    /** (ps_1) ... (ps_n) => (ps_1, ..., ps_n)
     */
    ValDef[][] uncurry(ValDef[][] params) {
	int n = 0;
	for (int i = 0; i < params.length; i++)
	    n = n + params[i].length;
	ValDef[] ps = new ValDef[n];
	int j = 0;
	for (int i = 0; i < params.length; i++) {
	    System.arraycopy(params[i], 0, ps, j, params[i].length);
	    j = j + params[i].length;
	}
	return new ValDef[][]{ps};
    }

    /** tree of non-method type T ==> same tree with method type ()T
     */
    Tree asMethod(Tree tree) {
	switch (tree.type) {
	case MethodType(_, _):
	    return tree;
	default:
	    return tree.setType(
		Type.MethodType(Symbol.EMPTY_ARRAY, tree.type.widen()));
	}
    }

    /** apply parameterless functions and def parameters
     */
    Tree applyDef(Tree tree1) {
	assert tree1.symbol() != null : tree1;
	switch (tree1.symbol().type()) {
	case PolyType(Symbol[] tparams, Type restp):
	    if (tparams.length == 0 && !(restp instanceof Type.MethodType)) {
		return gen.Apply(asMethod(tree1), new Tree[0]);
	    } else {
		return tree1;
	    }
	default:
	    if (tree1.symbol().isDefParameter()) {
		tree1.type = global.definitions.functionType(
		    Type.EMPTY_ARRAY, tree1.type.widen());
		return gen.Apply(gen.Select(tree1, global.definitions.FUNCTION_APPLY(0)));
	    } else {
		return tree1;
	    }
	}
    }

    /** - uncurry all symbol and tree types (@see UnCurryPhase)
     *  - for every curried parameter list:  (ps_1) ... (ps_n) ==> (ps_1, ..., ps_n)
     *  - for every curried application: f(args_1)...(args_n) ==> f(args_1, ..., args_n)
     *  - for every type application: f[Ts] ==> f[Ts]() unless followed by parameters
     *  - for every use of a parameterless function: f ==> f()  and  q.f ==> q.f()
     *  - for every def-parameter:  def x: T ==> x: () => T
     *  - for every use of a def-parameter: x ==> x.apply()
     *  - for every argument to a def parameter `def x: T':
     *      if argument is not a reference to a def parameter:
     *        convert argument `e' to (expansion of) `() => e'
     *  - for every argument list that corresponds to a repeated parameter
     *       (a_1, ..., a_n) => (Sequence(a_1, ..., a_n))
     */
    public Tree transform(Tree tree) {
	//new scalac.ast.printer.TextTreePrinter().print("uncurry: ").print(tree).println().end();//DEBUG
	//uncurry type and symbol
	if (tree.type != null) tree.type = descr.uncurry(tree.type);
        switch (tree) {
	case ClassDef(_, _, AbsTypeDef[] tparams, ValDef[][] vparams, Tree tpe, Template impl):
	    return copy.ClassDef(
		tree, tree.symbol(), tparams,
		uncurry(transform(vparams, tree.symbol())),
		tpe,
		transform(impl, tree.symbol()));

	case DefDef(_, _, AbsTypeDef[] tparams, ValDef[][] vparams, Tree tpe, Tree rhs):
	    Tree rhs1 = transform(rhs, tree.symbol());
	    return copy.DefDef(
		tree, tree.symbol(), tparams,
		uncurry(transform(vparams, tree.symbol())),
		tpe, rhs1);

	case ValDef(_, _, Tree tpe, Tree rhs):
	    if (tree.symbol().isDefParameter()) {
		Type newtype = global.definitions.functionType(Type.EMPTY_ARRAY, tpe.type);
		Tree tpe1 = gen.mkType(tpe.pos, newtype);
                return copy.ValDef(tree, tpe1, rhs).setType(newtype);
	    } else {
		return super.transform(tree);
	    }

	case TypeApply(Tree fn, Tree[] args):
	    Tree tree1 = asMethod(super.transform(tree));
	    return gen.Apply(tree1, new Tree[0]);

	case Apply(Tree fn, Tree[] args):
	    // f(x)(y) ==> f(x, y)
	    // argument to parameterless function e => ( => e)
	    Type ftype = fn.type;
	    Tree fn1 = transform(fn);
	    Tree[] args1 = transformArgs(tree.pos, args, ftype);
	    if (TreeInfo.methSymbol(fn1) == global.definitions.MATCH &&
		!(args1[0] instanceof Tree.Visitor)) {
		switch (TreeInfo.methPart(fn1)) {
		case Select(Tree qual, Name name):
		    assert name == Names.match;
		    return gen.postfixApply(qual, args1[0], currentOwner);
		default:
		    throw new ApplicationError("illegal prefix for match: " + tree);
		}

	    } else {
		switch (fn1) {
		case Apply(Tree fn2, Tree[] args2):
		    Tree[] newargs = new Tree[args1.length + args2.length];
		    System.arraycopy(args2, 0, newargs, 0, args2.length);
		    System.arraycopy(args1, 0, newargs, args2.length, args1.length);
		    return copy.Apply(tree, fn2, newargs);
		default:
		    return copy.Apply(tree, fn1, args1);
		}
	    }

	case Select(_, _):
	    return applyDef(super.transform(tree));

	case Ident(Name name):
	    if (name == TypeNames.WILDCARD_STAR) {
		unit.error(tree.pos, " argument does not correspond to `*'-parameter");
		return tree;
	    } else if (tree.symbol() == global.definitions.PATTERN_WILDCARD) {
		return tree;
	    } else {
		return applyDef(super.transform(tree));
	    }

	default:
	    return super.transform(tree);
	}
    }

//    java.util.HashSet visited = new java.util.HashSet();//DEBUG

    /** Transform arguments `args' to method with type `methtype'.
     */
    private Tree[] transformArgs(int pos, Tree[] args, Type methtype) {
//	if (args.length != 0 && visited.contains(args)) {
//	    new scalac.ast.printer.TextTreePrinter().print("dup args: ").print(make.Block(pos, args)).println().end();//DEBUG
//	    assert false;
//	}
//	visited.add(args);//DEBUG

	switch (methtype) {
	case MethodType(Symbol[] params, _):
	    if (params.length == 1 && (params[0].flags & REPEATED) != 0) {
		args = toSequence(pos, params, args);
	    }
	    Tree[] args1 = args;
	    for (int i = 0; i < args.length; i++) {
		Tree arg = args[i];
		Tree arg1 = transformArg(arg, params[i]);
		if (arg1 != arg && args1 == args) {
		    args1 = new Tree[args.length];
		    System.arraycopy(args, 0, args1, 0, i);
		}
		args1[i] = arg1;
	    }
	    return args1;
	case PolyType(_, Type restp):
	    return transformArgs(pos, args, restp);
	default:
	    if (args.length == 0) return args; // could be arguments of nullary case pattern
	    else throw new ApplicationError(methtype);
	}
    }

    /** converts `a_1,...,a_n' to Seq(a_1,...,a_n)
     *  if a_1 is an escaped sequence  as in  x:_*, takes care of
     *  escaping
     */
    private Tree[] toSequence(int pos, Symbol[] params, Tree[] args) {
	assert (args.length != 1 || !(args[0] instanceof Tree.Sequence));
 	if (args.length == 1) {
            switch (args[0]) {
            case Typed(Tree arg, Ident(TypeNames.WILDCARD_STAR)):
                return new Tree[]{arg};
            }
        }
	return new Tree[]{make.Sequence( pos, args ).setType(params[0].type())};
    }

    /** for every argument to a def parameter `def x: T':
     *    if argument is not a reference to a def parameter:
     *      convert argument `e' to (expansion of) `() => e'
     */
    private Tree transformArg(Tree arg, Symbol formal) {
	if ((formal.flags & DEF) != 0) {
	    Symbol sym = arg.symbol();
	    if (sym != null && (sym.flags & DEF) != 0) {
		Tree arg1 = transform(arg);
		switch (arg1) {
		case Apply(Select(Tree qual, Name name), Tree[] args1):
		    assert name == Names.apply && args1.length == 0;
		    return qual;
		default:
		    global.debugPrinter.print(arg1).flush();//debug
		    throw new ApplicationError();
		}
	    }
	    return transform(
		gen.mkUnitFunction(arg, descr.uncurry(arg.type.widen()), currentOwner));
	} else {
	    return transform(arg);
	}
    }
}