summaryrefslogtreecommitdiff
path: root/sources/scalac/transformer/AddAccessors.java
blob: 3d3c5a9ba85599ab1325488b1eaacf779406df4b (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
138
139
140
141
142
143
144
145
146
147
/*     ____ ____  ____ ____  ______                                     *\
**    / __// __ \/ __// __ \/ ____/    SOcos COmpiles Scala             **
**  __\_ \/ /_/ / /__/ /_/ /\_ \       (c) 2002, LAMP/EPFL              **
** /_____/\____/\___/\____/____/                                        **
\*                                                                      */

// $OldId: AddAccessors.java,v 1.2 2002/11/21 14:14:31 schinz Exp $
// $Id$

package scalac.transformer;

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

import java.util.*;

/**
 * Add private accessor functions for all class constructor arguments
 * which are accessed from within the class' methods, or nested
 * classes.
 *
 * @author Michel Schinz
 * @version 1.0
 */

public class AddAccessors extends Transformer {
    public AddAccessors(Global global) {
        super(global);
    }

    protected Name valName(Symbol sym) {
        return Name.fromString(sym.name.toString() + "$");
    }

    protected final HashMap/*<Symbol,Symbol>*/ accessorMap = new HashMap();
    protected boolean inClassContext = true;

    protected Symbol accessor(Symbol sym) {
        Symbol accessor = (Symbol)accessorMap.get(sym);
        if (accessor == null) {
            accessor = new TermSymbol(sym.pos,
                                      sym.name,
                                      sym.classOwner(),
                                      Modifiers.STABLE
                                      | Modifiers.ACCESSOR
                                      | Modifiers.PRIVATE);
            accessor.setType(Type.MethodType(Symbol.EMPTY_ARRAY, sym.type()));
            accessorMap.put(sym, accessor);
        }
        return accessor;
    }

    public Tree transform(Tree tree) {
        switch (tree) {
        case ClassDef(_, // :
                      _,
                      Tree.TypeDef[] tparams,
                      Tree.ValDef[][] vparams,
                      Tree tpe,
                      Tree.Template impl): {
            Symbol clsSym = tree.symbol();

            LinkedList/*<Tree>*/ newBody =
                new LinkedList(Arrays.asList(transform(impl.body)));

            // Add value definitions and accessors for all constructor
            // arguments which were found in the body of the class.
            assert vparams.length == 1;
            Tree.ValDef[] params = vparams[0];
            Scope newMembers = new Scope(clsSym.members());
            for (int i = 0; i < params.length; ++i) {
                Symbol paramSym = params[i].symbol();
                if (accessorMap.containsKey(paramSym)) {
                    Symbol accessorSym = (Symbol)accessorMap.get(paramSym);

                    Symbol valSym = new TermSymbol(paramSym.pos,
                                                   valName(paramSym),
                                                   clsSym,
                                                   Modifiers.PRIVATE);
                    valSym.setType(paramSym.type());

                    newBody.addFirst(gen.DefDef(accessorSym, gen.Ident(valSym)));
                    newMembers.enter(accessorSym);

                    newBody.addFirst(gen.ValDef(valSym, gen.Ident(paramSym)));
                    newMembers.enter(valSym);
                }
            }

            // Update class type with new values/accessors.
            clsSym.updateInfo(Type.compoundType(clsSym.parents(),
                                                newMembers,
                                                clsSym));

            assert inClassContext;
            inClassContext = false;
            Tree[] newParents = transform(impl.parents);
            inClassContext = true;

            Tree[] newBodyA = (Tree[])newBody.toArray(new Tree[newBody.size()]);

            return copy.ClassDef(tree,
                                 clsSym,
                                 transform(tparams),
                                 transform(vparams),
                                 transform(tpe),
                                 copy.Template(impl, newParents, newBodyA));
        }

        case ValDef(_, _, _, _): {
            // Do not go into RHS of value definitions which reference
            // case class constructor arguments, to avoid creating
            // another accessor.
            if (Modifiers.Helper.isCaseAccessor(tree.symbol().flags)) {
                return tree;
            } else
                return super.transform(tree);
        }

        case Select(Tree qualifier, _): {
            Symbol sym = tree.symbol();
	    assert sym.kind != Kinds.NONE : tree;
            if (sym.owner().isPrimaryConstructor())
                return gen.Apply(gen.Select(transform(qualifier), accessor(sym)),
                                 Tree.EMPTY_ARRAY);
            else
                return copy.Select(tree, sym, transform(qualifier));
        }

        case Ident(_): {
            Symbol sym = tree.symbol();
            if (inClassContext
                && sym.name.isTermName()
                && sym.owner().isPrimaryConstructor())
                return gen.Apply(gen.Ident(accessor(sym)), Tree.EMPTY_ARRAY);
            else
                return copy.Ident(tree, sym);
        }

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