class
compiler::InitClosures
sys::Obj
compiler::CompilerSupport
compiler::CompilerStep
compiler::InitClosures
1 //
2 // Copyright (c) 2006, Brian Frank and Andy Frank
3 // Licensed under the Academic Free License version 3.0
4 //
5 // History:
6 // 16 Jan 06 Brian Frank Creation
7 // 2 Oct 06 Brian Frank Ported from Java to Fan
8 //
9
10 **
11 ** During the Parse step we created a list of all the closures.
12 ** In InitClosures we map each ClosureExpr into a TypeDef as
13 ** an anonymous class, then we map ClosureExpr.substitute to
14 ** call the constructor anonymous class.
15 **
16 class InitClosures : CompilerStep
17 {
18
19 //////////////////////////////////////////////////////////////////////////
20 // Constructor
21 //////////////////////////////////////////////////////////////////////////
22
23 new make(Compiler compiler)
24 : super(compiler)
25 {
26 }
27
28 //////////////////////////////////////////////////////////////////////////
29 // Run
30 //////////////////////////////////////////////////////////////////////////
31
32 override Void run()
33 {
34 log.verbose("Closures")
35 compiler.closures.each |ClosureExpr c| { process(c) }
36 }
37
38 //////////////////////////////////////////////////////////////////////////
39 // Process
40 //////////////////////////////////////////////////////////////////////////
41
42 private Void process(ClosureExpr c)
43 {
44 // class Class$Method$Num : |A,B..->R|
45 // {
46 // new $make() {}
47 // Bool isImmutable() { return true }
48 // Obj call(Obj a, Obj b, ...) { doCall((A)a, ...) }
49 // R doCall(A a, B b, ...) { closure.code }
50 // }
51
52 setup(c) // setup our fields to process this closure
53 genClass // generate anonymous implementation class
54 genCtor // generate $make()
55 genIsImmutable // generate isImmutable()
56 genDoCall // generate doCall(...)
57 genCall // generate call(...) { doCall(...) }
58 substitute // substitute closure code with anonymous class ctor
59 }
60
61 //////////////////////////////////////////////////////////////////////////
62 // Setup
63 //////////////////////////////////////////////////////////////////////////
64
65 private Void setup(ClosureExpr c)
66 {
67 this.closure = c
68 this.loc = c.location
69 this.signature = c.signature
70 this.enclosingType = c.enclosingType
71 this.enclosingMethod = c.enclosingMethod
72 }
73
74 //////////////////////////////////////////////////////////////////////////
75 // Generate Class
76 //////////////////////////////////////////////////////////////////////////
77
78 private Void genClass()
79 {
80 cls = TypeDef.make(ns, loc, closure.enclosingType.unit, closure.name)
81 cls.flags = FConst.Internal | FConst.Final | FConst.Synthetic
82 cls.base = closure.signature
83 cls.closure = closure
84 closure.cls = cls
85 addTypeDef(cls)
86 }
87
88 //////////////////////////////////////////////////////////////////////////
89 // Generate Constructor
90 //////////////////////////////////////////////////////////////////////////
91
92 private Void genCtor()
93 {
94 code := Block.make(loc)
95 code.stmts.add(ReturnStmt.make(loc))
96
97 ctor = MethodDef.make(loc, cls)
98 ctor.flags = FConst.Internal | FConst.Ctor | FConst.Synthetic
99 ctor.name = "make"
100 ctor.ret = ns.voidType
101 ctor.code = code
102 cls.addSlot(ctor)
103 }
104
105 //////////////////////////////////////////////////////////////////////////
106 // Generate IsConst Override
107 //////////////////////////////////////////////////////////////////////////
108
109 private Void genIsImmutable()
110 {
111 // we assume immutable until proved otherwise in ClosureVars step
112 genIsImmutableMethod(compiler, loc, cls, true)
113 }
114
115 static internal Void genIsImmutableMethod(Compiler compiler, Location loc, TypeDef parent, Bool literalVal)
116 {
117 Expr literal
118 if (literalVal)
119 literal = LiteralExpr.make(loc, ExprId.trueLiteral, compiler.ns.boolType, true)
120 else
121 literal = LiteralExpr.make(loc, ExprId.falseLiteral, compiler.ns.boolType, false)
122
123 code := Block.make(loc)
124 code.stmts.add(ReturnStmt.make(loc, literal))
125
126 m := MethodDef.make(loc, parent)
127 m.flags = FConst.Public | FConst.Synthetic | FConst.Override
128 m.name = "isImmutable"
129 m.ret = compiler.ns.boolType
130 m.code = code
131 parent.addSlot(m)
132 }
133
134 //////////////////////////////////////////////////////////////////////////
135 // Generate doCall()
136 //////////////////////////////////////////////////////////////////////////
137
138 private Void genDoCall()
139 {
140 doCall = MethodDef.make(loc, cls)
141 doCall.name = "doCall"
142 doCall.flags = FConst.Private | FConst.Synthetic
143 doCall.code = closure.code
144 doCall.ret = signature.ret
145 doCall.paramDefs = signature.toParamDefs(loc)
146 closure.doCall = doCall
147 cls.addSlot(doCall)
148 }
149
150 //////////////////////////////////////////////////////////////////////////
151 // Generate call()
152 //////////////////////////////////////////////////////////////////////////
153
154 private Void genCall()
155 {
156 c := CallExpr.makeWithMethod(loc, ThisExpr.make(loc), doCall)
157 genMethodCall(compiler, loc, cls, signature, c, false)
158 }
159
160 **
161 ** This method overrides either call(List) or callx(A...) to push the
162 ** args onto the stack, then redirect to the specified CallExpr c.
163 ** We share this code for both closures and curries.
164 **
165 static MethodDef genMethodCall(Compiler compiler, Location loc, TypeDef parent,
166 FuncType signature, CallExpr c, Bool firstAsTarget)
167 {
168 ns := compiler.ns
169
170 // method def
171 m := MethodDef.make(loc, parent)
172 m.name = "call"
173 m.flags = FConst.Override | FConst.Synthetic
174 m.ret = ns.objType
175 m.code = Block.make(loc)
176
177 // signature:
178 // call(List) // if > MaxIndirectParams
179 // call(Obj p0, Obj p1, ...) // if <= MaxIndirectParams
180 paramCount := signature.params.size
181 useListArgs := paramCount > 8
182 if (useListArgs)
183 {
184 p := ParamDef.make(loc, ns.objType.toListOf, "list")
185 m.params.add(p)
186 }
187 else
188 {
189 m.name += paramCount.toStr
190 paramCount.times |Int i|
191 {
192 p := ParamDef.make(loc, ns.objType, "p$i")
193 m.paramDefs.add(p)
194 }
195 }
196
197 // init the doCall() expr with arguments
198 paramCount.times |Int i|
199 {
200 Expr arg
201
202 // list.get(<i>)
203 if (useListArgs)
204 {
205 listGet := CallExpr.makeWithMethod(loc, UnknownVarExpr.make(loc, null, "list"), ns.objType.toListOf.method("get"))
206 listGet.args.add(LiteralExpr.make(loc, ExprId.intLiteral, ns.intType, i))
207 arg = listGet
208 }
209
210 // p<i>
211 else
212 {
213 arg = UnknownVarExpr.make(loc, null, "p$i")
214 }
215
216 // cast to closure param type
217 arg = TypeCheckExpr.make(loc, ExprId.cast, arg, signature.params[i])
218
219 // add to doCall() argument list
220 if (firstAsTarget && i === 0)
221 c.target = arg
222 else
223 c.args.add(arg)
224 }
225
226 // return:
227 // doCall; return null; // if doCall() is void
228 // return doCall // if doCall() non-void
229 if (signature.ret.isVoid)
230 {
231 m.code.add(c.toStmt)
232 m.code.add(ReturnStmt.make(loc, LiteralExpr.make(loc, ExprId.nullLiteral, ns.objType, null)))
233 }
234 else
235 {
236 m.code.add(ReturnStmt.make(loc, c))
237 }
238
239 // add to our synthetic parent class
240 parent.addSlot(m)
241 return m
242 }
243
244 //////////////////////////////////////////////////////////////////////////
245 // Substitute
246 //////////////////////////////////////////////////////////////////////////
247
248 private Void substitute()
249 {
250 closure.code = null
251 closure.substitute = CallExpr.makeWithMethod(loc, null, ctor)
252 }
253
254 //////////////////////////////////////////////////////////////////////////
255 // Fields
256 //////////////////////////////////////////////////////////////////////////
257
258 ClosureExpr closure // current closure
259 Location loc // closure.location
260 FuncType signature // closure.sig
261 TypeDef enclosingType // closure.enclosingType
262 MethodDef enclosingMethod // closure.enclosingMethod
263 TypeDef cls // current anonymous class implementing closure
264 MethodDef ctor // anonymous class make ctor
265 MethodDef doCall // R doCall(A a, ...) { closure.code }
266
267 }
2 // Copyright (c) 2006, Brian Frank and Andy Frank
3 // Licensed under the Academic Free License version 3.0
4 //
5 // History:
6 // 16 Jan 06 Brian Frank Creation
7 // 2 Oct 06 Brian Frank Ported from Java to Fan
8 //
9
10 **
11 ** During the Parse step we created a list of all the closures.
12 ** In InitClosures we map each ClosureExpr into a TypeDef as
13 ** an anonymous class, then we map ClosureExpr.substitute to
14 ** call the constructor anonymous class.
15 **
16 class InitClosures : CompilerStep
17 {
18
19 //////////////////////////////////////////////////////////////////////////
20 // Constructor
21 //////////////////////////////////////////////////////////////////////////
22
23 new make(Compiler compiler)
24 : super(compiler)
25 {
26 }
27
28 //////////////////////////////////////////////////////////////////////////
29 // Run
30 //////////////////////////////////////////////////////////////////////////
31
32 override Void run()
33 {
34 log.verbose("Closures")
35 compiler.closures.each |ClosureExpr c| { process(c) }
36 }
37
38 //////////////////////////////////////////////////////////////////////////
39 // Process
40 //////////////////////////////////////////////////////////////////////////
41
42 private Void process(ClosureExpr c)
43 {
44 // class Class$Method$Num : |A,B..->R|
45 // {
46 // new $make() {}
47 // Bool isImmutable() { return true }
48 // Obj call(Obj a, Obj b, ...) { doCall((A)a, ...) }
49 // R doCall(A a, B b, ...) { closure.code }
50 // }
51
52 setup(c) // setup our fields to process this closure
53 genClass // generate anonymous implementation class
54 genCtor // generate $make()
55 genIsImmutable // generate isImmutable()
56 genDoCall // generate doCall(...)
57 genCall // generate call(...) { doCall(...) }
58 substitute // substitute closure code with anonymous class ctor
59 }
60
61 //////////////////////////////////////////////////////////////////////////
62 // Setup
63 //////////////////////////////////////////////////////////////////////////
64
65 private Void setup(ClosureExpr c)
66 {
67 this.closure = c
68 this.loc = c.location
69 this.signature = c.signature
70 this.enclosingType = c.enclosingType
71 this.enclosingMethod = c.enclosingMethod
72 }
73
74 //////////////////////////////////////////////////////////////////////////
75 // Generate Class
76 //////////////////////////////////////////////////////////////////////////
77
78 private Void genClass()
79 {
80 cls = TypeDef.make(ns, loc, closure.enclosingType.unit, closure.name)
81 cls.flags = FConst.Internal | FConst.Final | FConst.Synthetic
82 cls.base = closure.signature
83 cls.closure = closure
84 closure.cls = cls
85 addTypeDef(cls)
86 }
87
88 //////////////////////////////////////////////////////////////////////////
89 // Generate Constructor
90 //////////////////////////////////////////////////////////////////////////
91
92 private Void genCtor()
93 {
94 code := Block.make(loc)
95 code.stmts.add(ReturnStmt.make(loc))
96
97 ctor = MethodDef.make(loc, cls)
98 ctor.flags = FConst.Internal | FConst.Ctor | FConst.Synthetic
99 ctor.name = "make"
100 ctor.ret = ns.voidType
101 ctor.code = code
102 cls.addSlot(ctor)
103 }
104
105 //////////////////////////////////////////////////////////////////////////
106 // Generate IsConst Override
107 //////////////////////////////////////////////////////////////////////////
108
109 private Void genIsImmutable()
110 {
111 // we assume immutable until proved otherwise in ClosureVars step
112 genIsImmutableMethod(compiler, loc, cls, true)
113 }
114
115 static internal Void genIsImmutableMethod(Compiler compiler, Location loc, TypeDef parent, Bool literalVal)
116 {
117 Expr literal
118 if (literalVal)
119 literal = LiteralExpr.make(loc, ExprId.trueLiteral, compiler.ns.boolType, true)
120 else
121 literal = LiteralExpr.make(loc, ExprId.falseLiteral, compiler.ns.boolType, false)
122
123 code := Block.make(loc)
124 code.stmts.add(ReturnStmt.make(loc, literal))
125
126 m := MethodDef.make(loc, parent)
127 m.flags = FConst.Public | FConst.Synthetic | FConst.Override
128 m.name = "isImmutable"
129 m.ret = compiler.ns.boolType
130 m.code = code
131 parent.addSlot(m)
132 }
133
134 //////////////////////////////////////////////////////////////////////////
135 // Generate doCall()
136 //////////////////////////////////////////////////////////////////////////
137
138 private Void genDoCall()
139 {
140 doCall = MethodDef.make(loc, cls)
141 doCall.name = "doCall"
142 doCall.flags = FConst.Private | FConst.Synthetic
143 doCall.code = closure.code
144 doCall.ret = signature.ret
145 doCall.paramDefs = signature.toParamDefs(loc)
146 closure.doCall = doCall
147 cls.addSlot(doCall)
148 }
149
150 //////////////////////////////////////////////////////////////////////////
151 // Generate call()
152 //////////////////////////////////////////////////////////////////////////
153
154 private Void genCall()
155 {
156 c := CallExpr.makeWithMethod(loc, ThisExpr.make(loc), doCall)
157 genMethodCall(compiler, loc, cls, signature, c, false)
158 }
159
160 **
161 ** This method overrides either call(List) or callx(A...) to push the
162 ** args onto the stack, then redirect to the specified CallExpr c.
163 ** We share this code for both closures and curries.
164 **
165 static MethodDef genMethodCall(Compiler compiler, Location loc, TypeDef parent,
166 FuncType signature, CallExpr c, Bool firstAsTarget)
167 {
168 ns := compiler.ns
169
170 // method def
171 m := MethodDef.make(loc, parent)
172 m.name = "call"
173 m.flags = FConst.Override | FConst.Synthetic
174 m.ret = ns.objType
175 m.code = Block.make(loc)
176
177 // signature:
178 // call(List) // if > MaxIndirectParams
179 // call(Obj p0, Obj p1, ...) // if <= MaxIndirectParams
180 paramCount := signature.params.size
181 useListArgs := paramCount > 8
182 if (useListArgs)
183 {
184 p := ParamDef.make(loc, ns.objType.toListOf, "list")
185 m.params.add(p)
186 }
187 else
188 {
189 m.name += paramCount.toStr
190 paramCount.times |Int i|
191 {
192 p := ParamDef.make(loc, ns.objType, "p$i")
193 m.paramDefs.add(p)
194 }
195 }
196
197 // init the doCall() expr with arguments
198 paramCount.times |Int i|
199 {
200 Expr arg
201
202 // list.get(<i>)
203 if (useListArgs)
204 {
205 listGet := CallExpr.makeWithMethod(loc, UnknownVarExpr.make(loc, null, "list"), ns.objType.toListOf.method("get"))
206 listGet.args.add(LiteralExpr.make(loc, ExprId.intLiteral, ns.intType, i))
207 arg = listGet
208 }
209
210 // p<i>
211 else
212 {
213 arg = UnknownVarExpr.make(loc, null, "p$i")
214 }
215
216 // cast to closure param type
217 arg = TypeCheckExpr.make(loc, ExprId.cast, arg, signature.params[i])
218
219 // add to doCall() argument list
220 if (firstAsTarget && i === 0)
221 c.target = arg
222 else
223 c.args.add(arg)
224 }
225
226 // return:
227 // doCall; return null; // if doCall() is void
228 // return doCall // if doCall() non-void
229 if (signature.ret.isVoid)
230 {
231 m.code.add(c.toStmt)
232 m.code.add(ReturnStmt.make(loc, LiteralExpr.make(loc, ExprId.nullLiteral, ns.objType, null)))
233 }
234 else
235 {
236 m.code.add(ReturnStmt.make(loc, c))
237 }
238
239 // add to our synthetic parent class
240 parent.addSlot(m)
241 return m
242 }
243
244 //////////////////////////////////////////////////////////////////////////
245 // Substitute
246 //////////////////////////////////////////////////////////////////////////
247
248 private Void substitute()
249 {
250 closure.code = null
251 closure.substitute = CallExpr.makeWithMethod(loc, null, ctor)
252 }
253
254 //////////////////////////////////////////////////////////////////////////
255 // Fields
256 //////////////////////////////////////////////////////////////////////////
257
258 ClosureExpr closure // current closure
259 Location loc // closure.location
260 FuncType signature // closure.sig
261 TypeDef enclosingType // closure.enclosingType
262 MethodDef enclosingMethod // closure.enclosingMethod
263 TypeDef cls // current anonymous class implementing closure
264 MethodDef ctor // anonymous class make ctor
265 MethodDef doCall // R doCall(A a, ...) { closure.code }
266
267 }