OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 | |
6 class MethodCallData { | |
7 MethodData data; | |
8 | |
9 MethodMember method; | |
10 | |
11 MethodGenerator _methodGenerator; | |
12 | |
13 MethodCallData(this.data, this.method); | |
14 | |
15 bool matches(MethodCallData other) { | |
16 return method == other.method; | |
17 } | |
18 | |
19 void run() { | |
20 if (_methodGenerator !== null) return; | |
21 | |
22 _methodGenerator = new MethodGenerator(method, data.context); | |
23 _methodGenerator.run(); | |
24 } | |
25 } | |
26 | |
27 | |
28 /** | |
29 * Stores a reference to a single actual method body as well as | |
30 * potential specializations for either concrete generic types or | |
31 * optimizations for concrete argument types. | |
32 */ | |
33 class MethodData { | |
34 MethodMember baseMethod; | |
35 Statement body; | |
36 bool needsTypeParams = false; | |
37 | |
38 CallingContext context; | |
39 | |
40 List<MethodCallData> _calls; | |
41 | |
42 MethodData(this.baseMethod, [this.context]): _calls = [] { | |
43 body = baseMethod.definition.body; | |
44 if (baseMethod.isConstructor) { | |
45 needsTypeParams = true; | |
46 } | |
47 } | |
48 | |
49 void analyze() { | |
50 var ma = new MethodAnalyzer(baseMethod, body); | |
51 ma.analyze(context); | |
52 // TODO(jimhug): Add support for specializing on type parameters. | |
53 /* | |
54 if (ma.hasTypeParams) { | |
55 needsTypeParams = true; | |
56 } | |
57 */ | |
58 } | |
59 | |
60 Value eval(MethodMember method, Value newObject, Arguments args) { | |
61 if (method !== baseMethod) { | |
62 if (!needsTypeParams) method = baseMethod; | |
63 } | |
64 | |
65 // TODO(jimhug): Reconcile with run method below. | |
66 var gen = new MethodGenerator(method, context); | |
67 return gen.evalBody(newObject, args); | |
68 } | |
69 | |
70 | |
71 invokeCall(MethodCallData callData) { | |
72 for (var cd in _calls) { | |
73 if (cd.matches(callData)) { | |
74 return cd.run(); | |
75 } | |
76 } | |
77 _calls.add(callData); | |
78 callData.run(); | |
79 } | |
80 | |
81 void run(MethodMember method) { | |
82 if (body === null && !method.isConstructor && !method.isNative) return; | |
83 | |
84 if (method !== baseMethod) { | |
85 if (!needsTypeParams) method = baseMethod; | |
86 } | |
87 | |
88 var callData = new MethodCallData(this, method); | |
89 method.declaringType.genericType.markUsed(); | |
90 | |
91 invokeCall(callData); | |
92 } | |
93 | |
94 bool writeDefinition(MethodMember method, CodeWriter writer) { | |
95 var gen = null; | |
96 // TODO(jimhug): Handle multiple matches. | |
97 for (var cd in _calls) { | |
98 if (cd.method == method) { | |
99 gen = cd._methodGenerator; | |
100 } | |
101 } | |
102 | |
103 if (gen != null) { | |
104 if (method.isNative && method == baseMethod) { | |
105 if (!method.hasNativeBody) return true; | |
106 gen.writer = new CodeWriter(); | |
107 gen.writer.write(method.definition.nativeBody); | |
108 gen._paramCode = map(method.parameters, (p) => p.name); | |
109 } | |
110 gen.writeDefinition(writer, null); | |
111 return true; | |
112 } else { | |
113 return false; | |
114 } | |
115 } | |
116 | |
117 void createFunction(CodeWriter writer) { | |
118 this.run(baseMethod); | |
119 writeDefinition(baseMethod, writer); | |
120 } | |
121 | |
122 //TODO(jimhug): context belongs in constructor, not here. | |
123 Value createLambda(LambdaExpression node, CallingContext context) { | |
124 //TODO(jimhug): Only create the lambda if it is needed. | |
125 final lambdaGen = new MethodGenerator(baseMethod, context); | |
126 if (baseMethod.name != '') { | |
127 // Note: we don't want to put this in our enclosing scope because the | |
128 // name shouldn't be visible except inside the lambda. We also don't want | |
129 // to put the name directly in the lambda's scope because parameters are | |
130 // allowed to shadow it. So we create an extra scope for it to go into. | |
131 lambdaGen._scope.create(baseMethod.name, baseMethod.functionType, | |
132 baseMethod.definition.span, isFinal:true); | |
133 lambdaGen._pushBlock(baseMethod.definition); | |
134 } | |
135 | |
136 _calls.add(new MethodCallData(this, baseMethod)); | |
137 | |
138 lambdaGen.run(); | |
139 if (baseMethod.name != '') { | |
140 lambdaGen._popBlock(baseMethod.definition); | |
141 } | |
142 | |
143 final writer = new CodeWriter(); | |
144 lambdaGen.writeDefinition(writer, node); | |
145 return new Value(baseMethod.functionType, writer.text, | |
146 baseMethod.definition.span); | |
147 } | |
148 } | |
OLD | NEW |