summaryrefslogblamecommitdiff
path: root/sources/scalac/transformer/UnCurry.java
blob: ff8167294065429e3ec7c0e46fc673c9ff238a75 (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 ;
/** Make all functions into one-argument functions
 */
public class UnCurry extends OwnerTransformer
                     implements Modifiers {

    UnCurryPhase descr;

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

    /** (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));
	}
    }

    /** - 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(_, _, TypeDef[] 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(_, _, TypeDef[] 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);
	    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(_, _):
	case Ident(_):
	    if( TreeInfo.isWildcardPattern( tree ) )
		return tree;
	    Tree tree1 = super.transform(tree);
	    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);
		    return gen.Apply(gen.Select(tree1, Names.apply), new Tree[0]);
		} else {
		    return tree1;
		}
	    }
	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) {
		assert (args.length != 1 || !(args[0] instanceof Tree.Sequence));
		args = new Tree[]{make.Sequence( pos, args ).setType(params[0].type())};

	    }

	    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);
	}
    }

    /** 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), currentOwner));
	} else {
	    return transform(arg);
	}
    }
}