1 //
2 // Copyright (c) 2006, Brian Frank and Andy Frank
3 // Licensed under the Academic Free License version 3.0
4 //
5 // History:
6 // 2 Dec 05 Brian Frank Creation
7 // 30 Sep 06 Brian Frank Ported from Java to Fan
8 //
9
10 **
11 ** Normalize the abstract syntax tree:
12 ** - Collapse multiple static new blocks
13 ** - Init static fields in static new block
14 ** - Init instance fields in instance new block
15 ** - Add implicit return in methods
16 ** - Add implicit super constructor call
17 ** - Rewrite synthetic getter/setter for override of concrete field
18 **
19 class Normalize : CompilerStep
20 {
21
22 //////////////////////////////////////////////////////////////////////////
23 // Constructor
24 //////////////////////////////////////////////////////////////////////////
25
26 new make(Compiler compiler)
27 : super(compiler)
28 {
29 }
30
31 //////////////////////////////////////////////////////////////////////////
32 // Run
33 //////////////////////////////////////////////////////////////////////////
34
35 override Void run()
36 {
37 log.debug("Normalize")
38 walk(types, VisitDepth.typeDef)
39 bombIfErr
40 }
41
42 //////////////////////////////////////////////////////////////////////////
43 // Type Normalization
44 //////////////////////////////////////////////////////////////////////////
45
46 override Void visitTypeDef(TypeDef t)
47 {
48 location := t.location
49 iInit := Block.make(location) // instance init
50 sInit := Block.make(location) // static init
51
52 // walk thru all the slots
53 t.slotDefs.each |SlotDef s|
54 {
55 if (s is FieldDef)
56 {
57 f := (FieldDef)s
58 normalizeField(f)
59 if (f.init != null && !f.isAbstract)
60 {
61 if (f.isStatic)
62 sInit.add(fieldInitStmt(f))
63 else
64 iInit.add(fieldInitStmt(f))
65 f.init = null // don't walk the init expr anymore
66 }
67 }
68 else
69 {
70 // if a static initializer, append it
71 m := (MethodDef)s
72 if (m.isStaticInit)
73 appendStaticInit(sInit, m)
74 else
75 normalizeMethod(m)
76 }
77 }
78
79 // add instance$init if needed
80 if (!iInit.isEmpty)
81 {
82 iInit.add(ReturnStmt.make(location))
83 t.addSlot(MethodDef.makeInstanceInit(iInit.location, t, iInit))
84 }
85
86 // add static$init if needed
87 if (!sInit.isEmpty)
88 {
89 sInit.add(ReturnStmt.make(location))
90 t.normalizeStaticInits(MethodDef.makeStaticInit(sInit.location, t, sInit))
91 }
92 }
93
94 private Void appendStaticInit(Block sInit, MethodDef m)
95 {
96 // append inside an "if (true) {}" block so that each static
97 // initializer is given its own scope in the unified static initializer;
98 // the "if (true)" gets optimized away in CoodeAsm
99 loc := m.location
100 ifStmt := IfStmt.make(loc)
101 ifStmt.condition = LiteralExpr.make(loc, ExprId.trueLiteral, ns.boolType, true)
102 ifStmt.trueBlock = m.code
103 sInit.add(ifStmt)
104 m.code = null
105 }
106
107 //////////////////////////////////////////////////////////////////////////
108 // Method Normalization
109 //////////////////////////////////////////////////////////////////////////
110
111 private Void normalizeMethod(MethodDef m)
112 {
113 code := m.code
114 if (code == null) return
115
116 // add implicit return
117 if (!code.isExit) code.add(ReturnStmt.make(code.location))
118
119 // insert super constructor call
120 if (m.isCtor) insertSuperCtor(m)
121 }
122
123 private Void insertSuperCtor(MethodDef m)
124 {
125 // never insert super call for synthetic types, mixins, or Obj.make
126 parent := m.parent
127 base := parent.base
128 if (parent.isSynthetic) return
129 if (parent.isMixin) return
130 if (base.isObj) return
131
132 // check if the base class has exactly one available
133 // constructor with no parameters
134 superCtors := base.ctors
135 if (superCtors.size != 1) return
136 superCtor := superCtors.first
137 if (superCtor.isPrivate) return
138 if (superCtor.isInternal && base.pod != parent.pod) return
139 if (!superCtor.params.isEmpty) return
140
141 // if we find a ctor to use, then create an implicit super call
142 m.ctorChain = CallExpr.makeWithMethod(m.location, SuperExpr.make(m.location), superCtor)
143 m.ctorChain.isCtorChain = true
144 }
145
146 //////////////////////////////////////////////////////////////////////////
147 // Field Normalization
148 //////////////////////////////////////////////////////////////////////////
149
150 private Void normalizeField(FieldDef f)
151 {
152 // if this field overrides a concrete field, that means we already have
153 // a concrete getter/setter for this field - if either of this field's
154 // accessors is synthetic, then rewrite the one generated by Parser with
155 // one that calls the "super" version of the accessor
156 if (f.concreteBase != null)
157 {
158 if (!f.hasGet) genSyntheticOverrideGet(f)
159 if (!f.hasSet) genSyntheticOverrideSet(f)
160 }
161
162 // ensure that getter is using inherited return
163 // in case we have a covariant override
164 if (f.get != null)
165 f.get.inheritedRet = f.inheritedRet
166 }
167
168 private Void genSyntheticOverrideGet(FieldDef f)
169 {
170 loc := f.location
171 f.get.code.stmts.clear
172 f.get.code.add(ReturnStmt.make(loc, FieldExpr.make(loc, SuperExpr.make(loc), f.concreteBase)))
173 }
174
175 private Void genSyntheticOverrideSet(FieldDef f)
176 {
177 loc := f.location
178 lhs := FieldExpr.make(loc, SuperExpr.make(loc), f.concreteBase)
179 rhs := UnknownVarExpr.make(loc, null, "val")
180 code := f.get.code
181 f.set.code.stmts.clear
182 f.set.code.add(BinaryExpr.makeAssign(lhs, rhs).toStmt)
183 f.set.code.add(ReturnStmt.make(loc))
184 }
185
186 private static ExprStmt fieldInitStmt(FieldDef f)
187 {
188 useAccessor := f.concreteBase != null
189 lhs := f.makeAccessorExpr(f.location, useAccessor)
190 rhs := f.init
191 return BinaryExpr.makeAssign(lhs, rhs).toStmt
192 }
193
194 }