summaryrefslogtreecommitdiff
path: root/sources/scalac/ast/TreeCopier.java
blob: 092f7960c23d4cbce037dc167bdfa90cf0d3919b (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
/*     ____ ____  ____ ____  ______                                     *\
**    / __// __ \/ __// __ \/ ____/    SOcos COmpiles Scala             **
**  __\_ \/ /_/ / /__/ /_/ /\_ \       (c) 2002, LAMP/EPFL              **
** /_____/\____/\___/\____/____/                                        **
\*                                                                      */

// $OldId: TreeCopier.java,v 1.17 2002/06/13 12:04:12 schinz Exp $
// $Id$

package scalac.ast;

import scalac.*;
import scalac.util.Name;
import scalac.symtab.*;
import java.util.*;

/**
 * Superclass for tree copiers. Takes care of duplicating symbols and
 * types when needed.
 *
 * @author Michel Schinz
 * @version 1.0
 */

public class TreeCopier extends SubstTransformer {
    public TreeCopier(Global global, TreeFactory make) {
        super(global, make);
    }

    private boolean inPattern = false;

    // Return true iff tree's symbol must be copied. By default,
    // symbols which are defined are copied.
    public boolean mustCopySymbol(Tree tree) {
        switch (tree) {
        case Ident(Name name):
            return (inPattern && name.isVariable()) || tree.definesSymbol();
        default:
            return tree.definesSymbol();
        }
    }

    public Tree copy(Tree tree) {
        // Copy all symbols that have to be copied.
        Traverser symCopier = new Traverser() {
                public void traverse(Tree tree) {
                    if (tree.hasSymbol()) {
                        Symbol sym = tree.symbol();

                        if (sym != Symbol.NONE
                            && mustCopySymbol(tree)
                            && !symbolMap.containsKey(sym)) {
                            Symbol newSym = sym.cloneSymbol();

                            if (symbolMap.containsKey(newSym.owner()))
                                newSym.setOwner((Symbol)symbolMap.get(newSym.owner()));

                            symbolMap.put(sym, newSym);
                        }
                    }
                    switch (tree) {
                    case CaseDef(Tree pat, Tree guard, Tree body):
                        inPattern = true; traverse(pat); inPattern = false;
                        traverse(guard);
                        traverse(body);
                        break;
                    default:
                        super.traverse(tree);
                    }
                }
            };
        symCopier.traverse(tree);

        // Copy tree
        Tree newTree = transform(tree);

        // Update symbols
        Iterator symbolsIt = symbolMap.entrySet().iterator();
        while (symbolsIt.hasNext()) {
            Map.Entry symPair = (Map.Entry)symbolsIt.next();
            Symbol oldSym = (Symbol)symPair.getKey();
            Symbol newSym = (Symbol)symPair.getValue();

            newSym.setInfo(smApplier.apply(typeMap.apply(oldSym.info())));
        }

        return newTree;
    }
}