content: // Copyright (c) 2013, 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.
  
  part of dart2js.js_emitter;
  
  // TODO(ahe): This code should be integrated in CodeEmitterTask.finishClasses.
  String getReflectionDataParser(String classesCollector, Namer namer) {
    String metadataField = '"${namer.metadataField}"';
    String reflectableField = namer.reflectableField;
    String defaultValuesField = namer.defaultValuesField;
    String methodsWithOptionalArgumentsField =
        namer.methodsWithOptionalArgumentsField;
    return '''
  (function (reflectionData) {
  '''
  // [map] returns an object literal that V8 shouldn't try to optimize with a
  // hidden class. This prevents a potential performance problem where V8 tries
  // to build a hidden class for an object used as a hashMap.
  '''
    function map(x){x={x:x};delete x.x;return x}
    if (!init.libraries) init.libraries = [];
    if (!init.mangledNames) init.mangledNames = map();
    if (!init.mangledGlobalNames) init.mangledGlobalNames = map();
    if (!init.statics) init.statics = map();
    if (!init.typeInformation) init.typeInformation = map();
    if (!init.globalFunctions) init.globalFunctions = map();
    var libraries = init.libraries;
    var mangledNames = init.mangledNames;
    var mangledGlobalNames = init.mangledGlobalNames;
    var hasOwnProperty = Object.prototype.hasOwnProperty;
    var length = reflectionData.length;
    for (var i = 0; i < length; i++) {
      var data = reflectionData[i];
  '''
  // [data] contains these elements:
  // 0. The library name (not unique).
  // 1. The library URI (unique).
  // 2. A function returning the metadata associated with this library.
  // 3. The global object to use for this library.
  // 4. An object literal listing the members of the library.
  // 5. This element is optional and if present it is true and signals that this
  // library is the root library (see dart:mirrors IsolateMirror.rootLibrary).
  //
  // The entries of [data] are built in [assembleProgram] above.
  '''
      var name = data[0];
      var uri = data[1];
      var metadata = data[2];
      var globalObject = data[3];
      var descriptor = data[4];
      var isRoot = !!data[5];
      var fields = descriptor && descriptor[""];
      var classes = [];
      var functions = [];
      function processStatics(descriptor) {
        for (var property in descriptor) {
          if (!hasOwnProperty.call(descriptor, property)) continue;
          if (property === "") continue;
          var element = descriptor[property];
          var firstChar = property.substring(0, 1);
          var previousProperty;
          if (firstChar === "+") {
            mangledGlobalNames[previousProperty] = property.substring(1);
            if (descriptor[property] == 1) ''' // Break long line.
  '''descriptor[previousProperty].$reflectableField = 1;
            if (element && element.length) ''' // Break long line.
  '''init.typeInformation[previousProperty] = element;
          } else if (firstChar === "@") {
            property = property.substring(1);
            ${namer.CURRENT_ISOLATE}[property][$metadataField] = element;
          } else if (firstChar === "*") {
            globalObject[previousProperty].$defaultValuesField = element;
            var optionalMethods = descriptor.$methodsWithOptionalArgumentsField;
            if (!optionalMethods) {
              descriptor.$methodsWithOptionalArgumentsField = optionalMethods = {}
            }
            optionalMethods[property] = previousProperty;
          } else if (typeof element === "function") {
            globalObject[previousProperty = property] = element;
            functions.push(property);
            init.globalFunctions[property] = element;
          } else {
            previousProperty = property;
            var newDesc = {};
            var previousProp;
            for (var prop in element) {
              if (!hasOwnProperty.call(element, prop)) continue;
              firstChar = prop.substring(0, 1);
              if (prop === "static") {
                processStatics(init.statics[property] = element[prop]);
              } else if (firstChar === "+") {
                mangledNames[previousProp] = prop.substring(1);
                if (element[prop] == 1) ''' // Break long line.
  '''element[previousProp].$reflectableField = 1;
              } else if (firstChar === "@" && prop !== "@") {
                newDesc[prop.substring(1)][$metadataField] = element[prop];
              } else if (firstChar === "*") {
                newDesc[previousProp].$defaultValuesField = element[prop];
                var optionalMethods = newDesc.$methodsWithOptionalArgumentsField;
                if (!optionalMethods) {
                  newDesc.$methodsWithOptionalArgumentsField = optionalMethods={}
                }
                optionalMethods[prop] = previousProp;
              } else {
                newDesc[previousProp = prop] = element[prop];
              }
            }
            $classesCollector[property] = [globalObject, newDesc];
            classes.push(property);
          }
        }
      }
      processStatics(descriptor);
      libraries.push([name, uri, classes, functions, metadata, fields, isRoot,
                      globalObject]);
    }
  })''';
  }
  