summaryrefslogtreecommitdiff
path: root/sources/scalac/ast/TreeCloner.java
blob: 8d96c1b23e83c3ec50eb5e6939b6c30bdd2a64b5 (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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/*     ____ ____  ____ ____  ______                                     *\
**    / __// __ \/ __// __ \/ ____/    SOcos COmpiles Scala             **
**  __\_ \/ /_/ / /__/ /_/ /\_ \       (c) 2002-2005, LAMP/EPFL         **
** /_____/\____/\___/\____/____/                                        **
\*                                                                      */

// $Id$

package scalac.ast;

import java.util.Map;

import scalac.Global;
import scalac.symtab.Symbol;
import scalac.symtab.SymbolCloner;
import scalac.symtab.SymbolSubstTypeMap;
import scalac.symtab.Type;
import scalac.util.Debug;

/**
 * This class implements a deep tree cloner. It provides support to
 * change tree symbols and tree types on the fly. This cloner never
 * clones symbols, but its default implementation of getSymbolFor
 * requires that all symbols that are defined by the tree to be cloned
 * are present in the symbol substitution. This implies that if the
 * tree to clone contains definitions, it must first be traversed to
 * map all defined symbols. To do this, one can use TreeSymbolCloner.
 */
public class TreeCloner extends Transformer {

    //########################################################################
    // Private Fields

    /** The symbol substitution to apply to tree symbols */
    private final Map/*<Symbol,Symbol>*/ symbols;

    /** The type map to apply to tree types */
    private final Type.Map types;

    //########################################################################
    // Public Constructors

    /** Initializes a new instance. */
    public TreeCloner(Global global, SymbolSubstTypeMap types) {
        this(global, types.getSymbols(), types);
    }

    /** Initializes a new instance. */
    public TreeCloner(Global global, Map symbols, Type.Map types) {
        super(global, global.make, new StrictTreeCopier(global.make));
        this.symbols = symbols;
        this.types = types;
    }

    //########################################################################
    // Public Methods

    /**
     * Returns the symbol for the given cloned tree. The default
     * implementation returns the result of the application of the
     * symbol substitution to the given tree's symbol. If there is no
     * mapping for that symbol returns that same symbol.
     */
    public Symbol getSymbolFor(Tree tree) {
        Symbol oldsym = tree.symbol();
        Symbol newsym = (Symbol)symbols.get(oldsym);
        // cloned definitions must have a cloned symbol
        assert newsym != null || !tree.definesSymbol() : Debug.show(oldsym);
        return newsym != null ? newsym : oldsym;
    }

    /**
     * Returns the type for the given cloned tree. The default
     * implementation returns the result of the application of the
     * type map to the given tree's type.
     */
    public Type getTypeFor(Tree tree) {
        return types.apply(tree.getType());
    }

    /** Traverses the given tree and returns a deeply cloned one. */
    public Tree transform(Tree tree) {
        tree = super.transform(tree);
        if (tree.hasSymbol()) tree.setSymbol(getSymbolFor(tree));
        tree.setType(getTypeFor(tree));
        return tree;
    }

    //########################################################################
}


/** !!! */
public class GenTreeCloner extends GenTransformer {

    //########################################################################
    // Public Fields

    /** The symbol cloner */
    public final SymbolCloner cloner;

    //########################################################################
    // Public Constructors

    /** Initializes a new instance. */
    public GenTreeCloner(Global global, Type.Map map, SymbolCloner cloner) {
        super(global, map);
        this.cloner = cloner;
    }

    public GenTreeCloner(Global global, SymbolCloner cloner) {
        super(global, cloner.getTypeMap());
        this.cloner = cloner;
    }

    //########################################################################
    // Public Methods

    public Symbol getSymbolFor(Tree tree) {
        switch (tree) {
        case ValDef(_, _, _, _):
            if (tree.symbol().owner().isClass()) break;
            Symbol symbol = cloner.cloneSymbol(tree.symbol());
            symbol.setType(transform(symbol.type()));
            return symbol;
        case LabelDef(_, _, _):
            Symbol symbol = cloner.cloneSymbol(tree.symbol());
            symbol.setType(transform(symbol.type()));
            return symbol;
        }
        Symbol symbol = (Symbol)cloner.clones.get(tree.symbol());
        assert !tree.definesSymbol() || symbol != null: tree;
        return symbol != null ? symbol : tree.symbol();
    }

    //########################################################################
}