text: (function (exports) {
  
    // Extend as needed.
    var lang = exports.lang = {
      Node: {
      },
  
      Program: {
        extends: "Node",
        fields:  ["@body"]
      },
  
      Statement: {
        extends: "Node"
      },
  
      EmptyStatement: {
        extends: "Statement"
      },
  
      BlockStatement: {
        extends: "Statement",
        fields:  ["@body"]
      },
  
      ExpressionStatement: {
        extends: "Statement",
        fields:  ["@expression"]
      },
  
      IfStatement: {
        extends: "Statement",
        fields:  ["@test", "@consequent", "@alternate"]
      },
  
      LabeledStatement: {
        extends: "Statement",
        fields:  ["@label", "@body"]
      },
  
      BreakStatement: {
        extends: "Statement",
        fields:  ["@label"]
      },
  
      ContinueStatement: {
        extends: "Statement",
        fields:  ["@label"]
      },
  
      WithStatement: {
        extends: "Statement",
        fields:  ["@object", "@body"]
      },
  
      SwitchStatement: {
        extends: "Statement",
        fields:  ["@discriminant", "@cases", "lexical"],
      },
  
      ReturnStatement: {
        extends: "Statement",
        fields:  ["@argument"]
      },
  
      ThrowStatement: {
        extends: "Statement",
        fields:  ["@argument"]
      },
  
      TryStatement: {
        extends: "Statement",
        fields:  ["@block", "@handlers", "@finalizer"]
      },
  
      WhileStatement: {
        extends: "Statement",
        fields:  ["@test", "@body"]
      },
  
      DoWhileStatement: {
        extends: "Statement",
        fields:  ["@body", "@test"]
      },
  
      ForStatement: {
        extends: "Statement",
        fields:  ["@init", "@test", "@update", "@body"]
      },
  
      ForInStatement: {
        extends: "Statement",
        fields:  ["@left", "@right", "@body", "each"]
      },
  
      LetStatement: {
        extends: "Statement",
        fields:  ["@head", "@body"]
      },
  
      DebuggerStatement: {
        extends: "Statement"
      },
  
      Declaration: {
        extends: "Statement"
      },
  
      FunctionDeclaration: {
        extends: "Declaration",
        fields:  ["@id", "@params", "@body", "@decltype", "generator", "expression", "@modifiers"]
      },
  
      VariableDeclaration: {
        extends: "Declaration",
        fields:  ["kind", "@declarations"]
      },
  
      VariableDeclarator: {
        extends: "Node",
        fields:  ["@id", "@init", "@decltype", "@arguments"]
      },
  
      Expression: {
        extends: "Pattern"
      },
  
      ThisExpression: {
        extends: "Expression"
      },
  
      ArrayExpression: {
        extends: "Expression",
        fields:  ["@elements"]
      },
  
      ObjectExpression: {
        extends: "Expression",
        fields:  ["@properties"]
      },
  
      Property: {
        extends: "Node",
        fields:  ["@key", "@value", "kind"],
      },
  
      FunctionExpression: {
        extends: "Expression",
        fields:  ["@id", "@params", "@body", "@decltype", "generator", "expression"]
      },
  
      SequenceExpression: {
        extends: "Expression",
        fields:  ["@expressions"]
      },
  
      UnaryExpression: {
        extends: "Expression",
        fields:  ["operator", "@argument", "prefix"]
      },
  
      BinaryExpression: {
        extends: "Expression",
        fields:  ["operator", "@left", "@right"]
      },
  
      AssignmentExpression: {
        extends: "Expression",
        fields:  ["@left", "operator", "@right"]
      },
  
      UpdateExpression: {
        extends: "Expression",
        fields:  ["operator", "@argument", "prefix"]
      },
  
      LogicalExpression: {
        extends: "Expression",
        fields:  ["operator", "@left", "@right"]
      },
  
      ConditionalExpression: {
        extends: "Expression",
        fields:  ["@test", "@consequent", "@alternate"]
      },
  
      NewExpression: {
        extends: "Expression",
        fields:  ["@callee", "@arguments"]
      },
  
      CallExpression: {
        extends: "Expression",
        fields:  ["@callee", "@arguments"]
      },
  
      MemberExpression: {
        extends: "Expression",
        fields:  ["@object", "@property", "computed", "kind"]
      },
  
      YieldExpression: {
        extends: "Expression",
        fields:  ["@argument"]
      },
  
      ComprehensionExpression: {
        extends: "Expression",
        fields:  ["@blocks", "@filter"]
      },
  
      GeneratorExpression: {
        extends: "Expression",
        fields:  ["@blocks", "@filter"]
      },
  
      LetExpression: {
        extends: "Expression",
        fields:  ["@head", "@body"]
      },
  
      Pattern: {
        extends: "Node"
      },
  
      ObjectPattern: {
        extends: "Pattern",
        fields:  ["@properties"]
      },
  
      ArrayPattern: {
        extends: "Pattern",
        fields:  ["@elements"]
      },
  
      SwitchCase: {
        extends: "Node",
        fields:  ["@test", "@consequent"]
      },
  
      CatchClause: {
        extends: "Node",
        fields:  ["@param", "@guard", "@body"]
      },
  
      Identifier: {
        extends: "Expression",
        fields:  ["name", "kind"]
      },
  
      Literal: {
        extends: "Expression",
        fields:  ["value"]
      },
  
      Type: {
        extends: "Node"
      },
  
      PointerType: {
        extends: "Type",
        fields: ["@base"]
      },
  
      ArrayType: {
        extends: "PointerType",
        fields: ["length"]
      },
  
      StructType: {
        extends: "Type",
        fields: ["@id", "@members", "isUnion"]
      },
  
      MemberDeclarator: {
        extends: "Node",
        fields: ["modifiers", "@declarator"]
      },
  
      ArrowType: {
        extends: "Type",
        fields: ["@params", "@return"]
      },
  
      TypeIdentifier: {
        extends: "Type",
        fields: ["name"]
      },
  
      TypeAliasDirective: {
        extends: "Node",
        fields: ["@original", "@alias"]
      },
  
      CastExpression: {
        extends: "Expression",
        fields: ["@as", "@argument"]
      }
    };
  
    function allFields(spec) {
      // Make the location a special last field.
      var fields = ["leadingComments", "loc"];
      while (spec) {
        if (spec.fields) {
          fields = spec.fields.concat(fields);
        }
        spec = spec.extends ? lang[spec.extends] : null;
      }
      return fields;
    };
    exports.allFields = allFields;
  
    function prefixUnderscore(s) {
      return "_" + s;
    }
  
    function ensureConstructor(name, spec) {
      if (!exports[name]) {
        // Make a new constructor if it doesn't exist yet.
        var fields = allFields(spec);
        var children = [];
        var body = ["this.type = \"" + name + "\";"];
        for (var i = 0, j = fields.length; i < j; i++) {
          var fname = fields[i];
          if (fname.charAt(0) === "@") {
            fields[i] = fname = fname.substr(1);
            children.push(fname);
          }
          body.push("this." + fname + " = _" + fname + ";");
        }
        // Prefix parameter names with underscores so keywords work.
        var node = new Function(fields.map(prefixUnderscore), body.join("\n"));
  
        // Hook up the prototypes.
        if (spec.extends) {
          var pnode = ensureConstructor(spec.extends, lang[spec.extends]);
          node.prototype = Object.create(pnode.prototype);
        }
  
        Object.defineProperty(node.prototype, "_children",
                              { value: children,
                                writable: true,
                                configurable: true,
                                enumerable: false });
  
        exports[name] = node;
      }
      return exports[name];
    }
  
    // Build constructors out of the language spec.
    for (var name in lang) {
      ensureConstructor(name, lang[name]);
    }
  
    // Make a walk function (map and replace) named |name|. By default it
    // walks the ASexports bottom-up. If different behavior is needed for different
    // nodes, override the walk function explicitly on those nodes.
    //
    // Returning null means "delete this null". Any other falsey values means
    // identity.
    exports.makePass = function makePass(name, prop) {
      return function (o) {
        var trans, arr;
        var child, children = this._children;
        for (var i = 0, j = children.length; i < j; i++) {
          if (!(child = this[children[i]])) {
            continue;
          }
  
          if (child instanceof Array) {
            arr = this[children[i]] = [];
            for (var k = 0, l = child.length; k < l; k++) {
              if (!child[k]) {
                arr.push(child[k]);
              } else if (typeof child[k][name] === "function") {
                trans = child[k][name](o);
                if (trans !== null) {
                  arr.push(trans);
                }
              }
            }
          } else if (typeof child[name] === "function") {
            trans = child[name](o);
            if (trans === null) {
              this[children[i]] = undefined;
            } else {
              this[children[i]] = trans;
            }
          }
        }
  
        if (typeof this[prop] === "function") {
          if (o.logger && typeof this.loc !== "undefined") {
            o.logger.push(this);
            trans = this[prop](o);
            o.logger.pop();
          } else {
            trans = this[prop](o);
          }
          if (trans === null) {
            return null;
          }
          return trans ? trans : this;
        }
  
        return this;
      };
    };
  
    exports.makePass = function makePass(name, prop, backward) {
      return function (o) {
        var trans, arr;
        var child, children = this._children;
        var i, k;
        for (var x = 0, j = children.length; x < j; x++) {
          i = backward ? children.length - 1 - x : x;
          if (!(child = this[children[i]])) {
            continue;
          }
  
          if (child instanceof Array) {
            arr = this[children[i]] = [];
            var y;
            for (var y = 0, l = child.length; y < l; y++) {
              k = backward ? child.length - 1 - y : y;
              if (!child[k]) {
                if (backward) {
                  arr.unshift(child[k]);
                } else {
                  arr.push(child[k]);
                }
              } else if (typeof child[k][name] === "function") {
                trans = child[k][name](o);
                if (trans !== null) {
                  if (backward) {
                    arr.unshift(trans);
                  } else {
                    arr.push(trans);
                  }
                }
              }
            }
          } else if (typeof child[name] === "function") {
            trans = child[name](o);
            if (trans === null) {
              this[children[i]] = undefined;
            } else {
              this[children[i]] = trans;
            }
          }
        }
  
        if (typeof this[prop] === "function") {
          if (o.logger && typeof this.loc !== "undefined") {
            o.logger.push(this);
            trans = this[prop](o);
            o.logger.pop();
          } else {
            trans = this[prop](o);
          }
          if (trans === null) {
            return null;
          }
          return trans ? trans : this;
        }
  
        return this;
      };
    };
  
    exports.lift = function lift(raw) {
      if (!raw) {
        return raw;
      }
      
      if (raw instanceof Array) {
        return raw.map(function (r) {
          return r ? lift(r) : r;
        });
      }
  
      var type = raw.type;
      var Node = exports[type];
      if (!Node) {
        throw new Error("unknown node type `" + type + "'");
      }
  
      var node = new Node();
      node.loc = raw.loc;
      var fields = allFields(lang[type]);
      for (var i = 0, j = fields.length; i < j; i++) {
        var field;
        if (fields[i].charAt(0) === "@") {
          field = fields[i].substr(1);
          if (raw[field]) {
            node[field] = lift(raw[field]);
          }
        } else {
          field = fields[i];
          node[field] = raw[field];
        }
      }
  
      return node;
    };
  
    exports.flatten = function flatten(node) {
      if (!node) {
        return node;
      }
      if (node instanceof Array) {
        return node.map(function (n) {
          return flatten(n);
        });
      }
  
      var type = node.type;
      var raw = { type: type };
      var fields = allFields(lang[type]);
      for (var i = 0, j = fields.length; i < j; i++) {
        var field;
        if (fields[i].charAt(0) === "@") {
          field = fields[i].substr(1);
          if (node[field]) {
            raw[field] = flatten(node[field]);
          } else {
            raw[field] = null;
          }
        } else {
          field = fields[i];
          raw[field] = node[field];
        }
      }
  
      return raw;
    };
  
  })(typeof exports === "undefined" ? (estransform = {}) : exports);
  