blob: 9b0820f10ea82b141eba018c74a2c9781f94097b [file] [log] [blame]
// 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);
}
}