define(
  ["../exception","exports"],
  function(__dependency1__, __exports__) {
    "use strict";
    var Exception = __dependency1__["default"];

    function SourceLocation(source, locInfo) {
      this.source = source;
      this.start = {
        line: locInfo.first_line,
        column: locInfo.first_column
      };
      this.end = {
        line: locInfo.last_line,
        column: locInfo.last_column
      };
    }

    __exports__.SourceLocation = SourceLocation;function stripFlags(open, close) {
      return {
        open: open.charAt(2) === '~',
        close: close.charAt(close.length-3) === '~'
      };
    }

    __exports__.stripFlags = stripFlags;function stripComment(comment) {
      return comment.replace(/^\{\{~?\!-?-?/, '')
                    .replace(/-?-?~?\}\}$/, '');
    }

    __exports__.stripComment = stripComment;function preparePath(data, parts, locInfo) {
      /*jshint -W040 */
      locInfo = this.locInfo(locInfo);

      var original = data ? '@' : '',
          dig = [],
          depth = 0,
          depthString = '';

      for(var i=0,l=parts.length; i<l; i++) {
        var part = parts[i].part;
        original += (parts[i].separator || '') + part;

        if (part === '..' || part === '.' || part === 'this') {
          if (dig.length > 0) {
            throw new Exception('Invalid path: ' + original, {loc: locInfo});
          } else if (part === '..') {
            depth++;
            depthString += '../';
          }
        } else {
          dig.push(part);
        }
      }

      return new this.PathExpression(data, depth, dig, original, locInfo);
    }

    __exports__.preparePath = preparePath;function prepareMustache(path, params, hash, open, strip, locInfo) {
      /*jshint -W040 */
      // Must use charAt to support IE pre-10
      var escapeFlag = open.charAt(3) || open.charAt(2),
          escaped = escapeFlag !== '{' && escapeFlag !== '&';

      return new this.MustacheStatement(path, params, hash, escaped, strip, this.locInfo(locInfo));
    }

    __exports__.prepareMustache = prepareMustache;function prepareRawBlock(openRawBlock, content, close, locInfo) {
      /*jshint -W040 */
      if (openRawBlock.path.original !== close) {
        var errorNode = {loc: openRawBlock.path.loc};

        throw new Exception(openRawBlock.path.original + " doesn't match " + close, errorNode);
      }

      locInfo = this.locInfo(locInfo);
      var program = new this.Program([content], null, {}, locInfo);

      return new this.BlockStatement(
          openRawBlock.path, openRawBlock.params, openRawBlock.hash,
          program, undefined,
          {}, {}, {},
          locInfo);
    }

    __exports__.prepareRawBlock = prepareRawBlock;function prepareBlock(openBlock, program, inverseAndProgram, close, inverted, locInfo) {
      /*jshint -W040 */
      // When we are chaining inverse calls, we will not have a close path
      if (close && close.path && openBlock.path.original !== close.path.original) {
        var errorNode = {loc: openBlock.path.loc};

        throw new Exception(openBlock.path.original + ' doesn\'t match ' + close.path.original, errorNode);
      }

      program.blockParams = openBlock.blockParams;

      var inverse,
          inverseStrip;

      if (inverseAndProgram) {
        if (inverseAndProgram.chain) {
          inverseAndProgram.program.body[0].closeStrip = close.strip;
        }

        inverseStrip = inverseAndProgram.strip;
        inverse = inverseAndProgram.program;
      }

      if (inverted) {
        inverted = inverse;
        inverse = program;
        program = inverted;
      }

      return new this.BlockStatement(
          openBlock.path, openBlock.params, openBlock.hash,
          program, inverse,
          openBlock.strip, inverseStrip, close && close.strip,
          this.locInfo(locInfo));
    }

    __exports__.prepareBlock = prepareBlock;
  });