summaryrefslogtreecommitdiff
path: root/sources/scalac/transformer/AddAccessors.java
blob: 14bf9c610ad39d9fa74c6a57833f1f28a9d74ad4 (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
/*     ____ ____  ____ ____  ______                                     *\
**    / __// __ \/ __// __ \/ ____/    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;

    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.AbsTypeDef[] tparams,
                      Tree.ValDef[][] vparams,
                      Tree tpe,
                      Tree.Template impl): {
            Symbol clsSym = tree.symbol();
            assert vparams.length == 1;
            Tree.ValDef[] params = vparams[0];

            // Recursively transform body
            Tree[] body = impl.body;
            LinkedList/*<Tree>*/ newBody = new LinkedList();
            for (int i = 0; i < body.length; ++i) {
                Tree mem = body[i];
                Symbol sym = mem.symbol();
                inClassContext =
                    mem.definesSymbol() && (sym.isClass() || sym.isMethod());
                newBody.add(transform(mem));
            }

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

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

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

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

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

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

            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 Select(Tree qualifier, _): {
            Symbol sym = tree.symbol();
	    assert sym.kind != Kinds.NONE : tree;
            if (sym.owner().isPrimaryConstructor())
                return gen.Apply(gen.Select(tree.pos, transform(qualifier), accessor(sym)));
            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(tree.pos, accessor(sym)));
            else
                return copy.Ident(tree, sym);
        }

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