Index: frog/method_data.dart |
diff --git a/frog/method_data.dart b/frog/method_data.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..cd4ccf569cf577c6e94fc4fa4119c4d63c4e77eb |
--- /dev/null |
+++ b/frog/method_data.dart |
@@ -0,0 +1,151 @@ |
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
+// for details. All rights reserved. Use of this source code is governed by a |
+// BSD-style license that can be found in the LICENSE file. |
+ |
+ |
+class MethodCallData { |
+ MethodData data; |
+ |
+ MethodMember method; |
+ |
+ MethodGenerator _methodGenerator; |
+ |
+ MethodCallData(this.data, this.method); |
+ |
+ bool matches(MethodCallData other) { |
+ return method == other.method; |
+ } |
+ |
+ void run() { |
+ if (_methodGenerator !== null) return; |
+ |
+ _methodGenerator = new MethodGenerator(method, data.context); |
+ _methodGenerator.run(); |
+ } |
+} |
+ |
+ |
+/** |
+ * Stores a reference to a single actual method body as well as |
+ * potential specializations for either concrete generic types or |
+ * optimizations for concrete argument types. |
+ */ |
+class MethodData { |
+ MethodMember baseMethod; |
+ Statement body; |
+ bool needsTypeParams = false; |
+ |
+ CallingContext context; |
+ |
+ List<MethodCallData> _calls; |
+ |
+ MethodData(this.baseMethod, [this.context]): _calls = [] { |
+ body = baseMethod.definition.body; |
+ if (baseMethod.isConstructor) { |
+ needsTypeParams = true; |
+ } |
+ } |
+ |
+ void analyze() { |
+ // TODO(jimhug): Is there really no analysis to do for a missing body? |
+ if (body === null) return; |
+ var ma = new MethodAnalyzer(baseMethod, body); |
+ ma.analyze(context); |
+ // TODO(jimhug): Add support for specializing on type parameters. |
+ /* |
+ if (ma.hasTypeParams) { |
+ needsTypeParams = true; |
+ } |
+ */ |
+ } |
+ |
+ Value eval(MethodMember method, Value newObject, Arguments args) { |
+ if (method !== baseMethod) { |
+ if (!needsTypeParams) method = baseMethod; |
+ } |
+ |
+ // TODO(jimhug): Reconcile with run method below. |
+ var gen = new MethodGenerator(method, context); |
+ return gen.evalBody(newObject, args); |
+ } |
+ |
+ |
+ invokeCall(MethodCallData callData) { |
+ for (var cd in _calls) { |
+ if (cd.matches(callData)) { |
+ return cd.run(); |
+ } |
+ } |
+ _calls.add(callData); |
+ callData.run(); |
+ } |
+ |
+ void run(MethodMember method) { |
+ if (body === null && !method.isConstructor && !method.isNative) return; |
+ |
+ if (method !== baseMethod) { |
+ if (!needsTypeParams) method = baseMethod; |
+ } |
+ |
+ var callData = new MethodCallData(this, method); |
+ method.declaringType.genericType.markUsed(); |
+ |
+ invokeCall(callData); |
+ } |
+ |
+ bool writeDefinition(MethodMember method, CodeWriter writer) { |
+ var gen = null; |
+ // TODO(jimhug): Handle multiple matches. |
+ for (var cd in _calls) { |
+ if (cd.method == method) { |
+ gen = cd._methodGenerator; |
+ } |
+ } |
+ |
+ if (gen != null) { |
+ if (method.definition.nativeBody != null && method == baseMethod) { |
+ if (method.definition.nativeBody == '') return true; |
+ gen.writer = new CodeWriter(); |
+ gen.writer.write(method.definition.nativeBody); |
+ gen._paramCode = map(method.parameters, (p) => p.name); |
+ |
+ } |
+ gen.writeDefinition(writer, null); |
+ return true; |
+ } else { |
+ return false; |
+ } |
+ } |
+ |
+ void createFunction(CodeWriter writer) { |
+ this.run(baseMethod); |
+ writeDefinition(baseMethod, writer); |
+ } |
+ |
+ //TODO(jimhug): context belongs in constructor, not here. |
+ Value createLambda(LambdaExpression node, CallingContext context) { |
+ //TODO(jimhug): Only create the lambda if it is needed. |
+ final lambdaGen = new MethodGenerator(baseMethod, context); |
+ if (baseMethod.name != '') { |
+ // Note: we don't want to put this in our enclosing scope because the |
+ // name shouldn't be visible except inside the lambda. We also don't want |
+ // to put the name directly in the lambda's scope because parameters are |
+ // allowed to shadow it. So we create an extra scope for it to go into. |
+ lambdaGen._scope.create(baseMethod.name, baseMethod.functionType, |
+ baseMethod.definition.span, isFinal:true); |
+ lambdaGen._pushBlock(baseMethod.definition); |
+ } |
+ |
+ _calls.add(new MethodCallData(this, baseMethod)); |
+ |
+ lambdaGen.run(); |
+ if (baseMethod.name != '') { |
+ lambdaGen._popBlock(baseMethod.definition); |
+ } |
+ |
+ final writer = new CodeWriter(); |
+ lambdaGen.writeDefinition(writer, node); |
+ return new Value(baseMethod.functionType, writer.text, |
+ baseMethod.definition.span); |
+ } |
+} |