write(tree, outputName = undefined, sourceRoot = undefined,
      sourceURL = undefined) {
    outputName = this.normalize(outputName);

    if (sourceRoot === undefined)
      sourceRoot = this.options_.sourceRoot;

    if (sourceRoot === true)
      sourceRoot = basePath(outputName);
    else if (!sourceRoot) // false or '' or undefined
      sourceRoot = undefined;
    else
      sourceRoot = this.normalize(sourceRoot);

    let writer;
    this.sourceMapCache_ = null;
    this.sourceMapConfiguration_ =
        this.createSourceMapConfiguration_(outputName, sourceRoot, sourceURL);
    if (this.sourceMapConfiguration_) {
      this.sourceMapConfiguration_.lowResolution =
          this.options_.lowResolutionSourceMap;
      writer =
          new ParseTreeMapWriter(this.sourceMapConfiguration_, this.options_);
    } else {
      writer = new ParseTreeWriter(this.options_);
    }

    writer.visitAny(tree);

    let compiledCode = writer.toString();

    let link = this.debuggerLink(sourceURL, outputName);
    if (link) {
      compiledCode += link;
    }

    return compiledCode;
  }
Produce output source from tree.
@param {ParseTree} tree
@param {string} outputName used for sourceMap URL and default sourceRoot.
@param {string} sourceRoot base for sourceMap sources
@param {string} sourceURL value for sourceURL
@return {string}