docs: function compileBody(str, options){
    var debug_sources = {};
    debug_sources[options.filename] = str;
    var dependencies = [];
    var plugins = options.plugins || [];
    var ast = load.string(str, {
      filename: options.filename,
      basedir: options.basedir,
      lex: function (str, options) {
        var lexOptions = {};
        Object.keys(options).forEach(function (key) {
          lexOptions[key] = options[key];
        });
        lexOptions.plugins = plugins.filter(function (plugin) {
          return !!plugin.lex;
        }).map(function (plugin) {
          return plugin.lex;
        });
        var contents = applyPlugins(str, {filename: options.filename}, plugins, 'preLex');
        return applyPlugins(lex(contents, lexOptions), options, plugins, 'postLex');
      },
      parse: function (tokens, options) {
        tokens = tokens.map(function (token) {
          if (token.type === 'path' && path.extname(token.val) === '') {
            return {
              type: 'path',
              loc: token.loc,
              val: token.val + '.pug'
            };
          }
          return token;
        });
        tokens = stripComments(tokens, options);
        tokens = applyPlugins(tokens, options, plugins, 'preParse');
        var parseOptions = {};
        Object.keys(options).forEach(function (key) {
          parseOptions[key] = options[key];
        });
        parseOptions.plugins = plugins.filter(function (plugin) {
          return !!plugin.parse;
        }).map(function (plugin) {
          return plugin.parse;
        });
  
        return applyPlugins(
          applyPlugins(parse(tokens, parseOptions), options, plugins, 'postParse'),
          options, plugins, 'preLoad'
        );
      },
      resolve: function (filename, source, loadOptions) {
        var replacementFunc = findReplacementFunc(plugins, 'resolve');
        if (replacementFunc) {
          return replacementFunc(filename, source, options);
        }
  
        return load.resolve(filename, source, loadOptions);
      },
      read: function (filename, loadOptions) {
        dependencies.push(filename);
  
        var contents;
  
        var replacementFunc = findReplacementFunc(plugins, 'read');
        if (replacementFunc) {
          contents = replacementFunc(filename, options);
        } else {
          contents = load.read(filename, loadOptions);
        }
  
        var str = applyPlugins(contents, {filename: filename}, plugins, 'preLex');
        debug_sources[filename] = str;
        return str;
      }
    });
    ast = applyPlugins(ast, options, plugins, 'postLoad');
    ast = applyPlugins(ast, options, plugins, 'preFilters');
  
    var filtersSet = {};
    Object.keys(exports.filters).forEach(function (key) {
      filtersSet[key] = exports.filters[key];
    });
    if (options.filters) {
      Object.keys(options.filters).forEach(function (key) {
        filtersSet[key] = options.filters[key];
      });
    }
    ast = filters.handleFilters(ast, filtersSet, options.filterOptions, options.filterAliases);
  
    ast = applyPlugins(ast, options, plugins, 'postFilters');
    ast = applyPlugins(ast, options, plugins, 'preLink');
    ast = link(ast);
    ast = applyPlugins(ast, options, plugins, 'postLink');
  
    // Compile
    ast = applyPlugins(ast, options, plugins, 'preCodeGen');
    var js = generateCode(ast, {
      pretty: options.pretty,
      compileDebug: options.compileDebug,
      doctype: options.doctype,
      inlineRuntimeFunctions: options.inlineRuntimeFunctions,
      globals: options.globals,
      self: options.self,
      includeSources: options.includeSources ? debug_sources : false,
      templateName: options.templateName
    });
    js = applyPlugins(js, options, plugins, 'postCodeGen');
    // Debug compiler
    if (options.debug) {
      console.error('\nCompiled Function:\n\n\u001b[90m%s\u001b[0m', js.replace(/^/gm, '  '));
    }
  
    return {body: js, dependencies: dependencies};
  }