| // 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. |
| |
| library runtime_types; |
| |
| import 'dart2jslib.dart'; |
| import 'elements/elements.dart'; |
| import 'tree/tree.dart'; |
| import 'universe/universe.dart'; |
| import 'util/util.dart'; |
| |
| class RuntimeTypeInformation { |
| /** |
| * Names used for elements in runtime type information. This map is kept to |
| * detect elements with the same name and use a different name instead. |
| */ |
| final Map<String, Element> usedNames = new Map<String, Element>(); |
| |
| /** Get a unique name for the element. */ |
| String getName(Element element) { |
| String guess = element.name.slowToString(); |
| String name = guess; |
| int id = 0; |
| while (usedNames.containsKey(name) && usedNames[name] != element) { |
| name = '$guess@$id'; |
| id++; |
| } |
| usedNames[name] = element; |
| return name; |
| } |
| |
| bool hasTypeArguments(DartType type) { |
| if (type is InterfaceType) { |
| InterfaceType interfaceType = type; |
| return !interfaceType.arguments.isEmpty; |
| } |
| return false; |
| } |
| |
| /** |
| * Map type variables to strings calling [:stringify:] and joins the results |
| * to a single string separated by commas. |
| * The argument [:hasValue:] is used to treat variables that will not receive |
| * a value at the use site of the code that is generated with this function. |
| */ |
| static String stringifyTypeVariables(Link collection, |
| int numberOfInputs, |
| stringify(TypeVariableType variable, |
| bool hasValue)) { |
| int currentVariable = 0; |
| bool isFirst = true; |
| StringBuffer buffer = new StringBuffer(); |
| collection.forEach((TypeVariableType variable) { |
| if (!isFirst) buffer.add(", "); |
| bool hasValue = currentVariable < numberOfInputs; |
| buffer.add(stringify(variable, hasValue)); |
| isFirst = false; |
| currentVariable++; |
| }); |
| return buffer.toString(); |
| } |
| |
| /** |
| * Generate a string representation template for this element, using '#' to |
| * denote the place for the type argument input. If there are more type |
| * variables than [numberOfInputs], 'Dynamic' is used as the value for these |
| * arguments. |
| */ |
| String generateRuntimeTypeString(ClassElement element, int numberOfInputs) { |
| String elementName = getName(element); |
| if (element.typeVariables.isEmpty) return "'$elementName'"; |
| String stringify(_, bool hasValue) => hasValue ? "' + # + '" : "Dynamic"; |
| String arguments = stringifyTypeVariables(element.typeVariables, |
| numberOfInputs, |
| stringify); |
| return "'$elementName<$arguments>'"; |
| } |
| |
| /** |
| * Generate a string template for the runtime type fields that contain the |
| * type descriptions of the reified type arguments, using '#' to denote the |
| * place for the type argument value, or [:null:] if there are more than |
| * [numberOfInputs] type variables. |
| */ |
| static String generateTypeVariableString(ClassElement element, |
| int numberOfInputs) { |
| String stringify(TypeVariableType variable, bool hasValue) { |
| return "'${variable.name.slowToString()}': #"; |
| } |
| return stringifyTypeVariables(element.typeVariables, numberOfInputs, |
| stringify); |
| } |
| } |