/* jscpd:ignore-start */

/*
 * Generated by PEG.js 0.10.0.
 *
 * http://pegjs.org/
 */
'use strict'

function peg$subclass (child, parent) {
  function ctor () { this.constructor = child }
  ctor.prototype = parent.prototype
  child.prototype = new ctor()
}

function peg$SyntaxError (message, expected, found, location) {
  this.message = message
  this.expected = expected
  this.found = found
  this.location = location
  this.name = 'SyntaxError'

  if (typeof Error.captureStackTrace === 'function') {
    Error.captureStackTrace(this, peg$SyntaxError)
  }
}

peg$subclass(peg$SyntaxError, Error)

peg$SyntaxError.buildMessage = function (expected, found) {
  const DESCRIBE_EXPECTATION_FNS = {
    literal: function (expectation) {
      return '"' + literalEscape(expectation.text) + '"'
    },

    class: function (expectation) {
      let escapedParts = ''
      let i

      for (i = 0; i < expectation.parts.length; i++) {
        escapedParts += expectation.parts[i] instanceof Array
          ? classEscape(expectation.parts[i][0]) + '-' + classEscape(expectation.parts[i][1])
          : classEscape(expectation.parts[i])
      }

      return '[' + (expectation.inverted ? '^' : '') + escapedParts + ']'
    },

    any: function (expectation) {
      return 'any character'
    },

    end: function (expectation) {
      return 'end of input'
    },

    other: function (expectation) {
      return expectation.description
    }
  }

  function hex (ch) {
    return ch.charCodeAt(0).toString(16).toUpperCase()
  }

  function literalEscape (s) {
    return s
      .replace(/\\/g, '\\\\')
      .replace(/"/g, '\\"')
      .replace(/\0/g, '\\0')
      .replace(/\t/g, '\\t')
      .replace(/\n/g, '\\n')
      .replace(/\r/g, '\\r')
      .replace(/[\x00-\x0F]/g, function (ch) { return '\\x0' + hex(ch) })
      .replace(/[\x10-\x1F\x7F-\x9F]/g, function (ch) { return '\\x' + hex(ch) })
  }

  function classEscape (s) {
    return s
      .replace(/\\/g, '\\\\')
      .replace(/\]/g, '\\]')
      .replace(/\^/g, '\\^')
      .replace(/-/g, '\\-')
      .replace(/\0/g, '\\0')
      .replace(/\t/g, '\\t')
      .replace(/\n/g, '\\n')
      .replace(/\r/g, '\\r')
      .replace(/[\x00-\x0F]/g, function (ch) { return '\\x0' + hex(ch) })
      .replace(/[\x10-\x1F\x7F-\x9F]/g, function (ch) { return '\\x' + hex(ch) })
  }

  function describeExpectation (expectation) {
    return DESCRIBE_EXPECTATION_FNS[expectation.type](expectation)
  }

  function describeExpected (expected) {
    const descriptions = new Array(expected.length)
    let i; let j

    for (i = 0; i < expected.length; i++) {
      descriptions[i] = describeExpectation(expected[i])
    }

    descriptions.sort()

    if (descriptions.length > 0) {
      for (i = 1, j = 1; i < descriptions.length; i++) {
        if (descriptions[i - 1] !== descriptions[i]) {
          descriptions[j] = descriptions[i]
          j++
        }
      }
      descriptions.length = j
    }

    switch (descriptions.length) {
      case 1:
        return descriptions[0]

      case 2:
        return descriptions[0] + ' or ' + descriptions[1]

      default:
        return descriptions.slice(0, -1).join(', ') +
          ', or ' +
          descriptions[descriptions.length - 1]
    }
  }

  function describeFound (found) {
    return found ? '"' + literalEscape(found) + '"' : 'end of input'
  }

  return 'Expected ' + describeExpected(expected) + ' but ' + describeFound(found) + ' found.'
}

function peg$parse (input, options) {
  options = options !== void 0 ? options : {}

  const peg$FAILED = {}

  const peg$startRuleFunctions = { transformation_rule: peg$parsetransformation_rule }
  let peg$startRuleFunction = peg$parsetransformation_rule

  const peg$c0 = function (c1, c2, pred, pars) {
    let result = null

    // Construct rule
    if (pars.length === 1) {
      result = new TransformationRule(c1, c2, pred, pars[0])
    } else {
      if (pars.length === 2) {
        result = new TransformationRule(c1, c2, pred, pars[0], pars[1])
      } else {
        result = new TransformationRule(c1, c2, pred)
      }
    }
    return (result)
  }
  const peg$c1 = /^[!-~\xA1-\xFF]/
  const peg$c2 = peg$classExpectation([['!', '~'], ['\xA1', '\xFF']], false, false)
  const peg$c3 = function (characters) {
    let s = ''
    for (let i = 0; i < characters.length; i++) {
      s += characters[i]
    }
    return (s)
  }
  const peg$c4 = '*'
  const peg$c5 = peg$literalExpectation('*', false)
  const peg$c6 = function (wc) {
    return (wc)
  }
  const peg$c7 = '\r\n'
  const peg$c8 = peg$literalExpectation('\r\n', false)
  const peg$c9 = '\n'
  const peg$c10 = peg$literalExpectation('\n', false)
  const peg$c11 = '\r'
  const peg$c12 = peg$literalExpectation('\r', false)
  const peg$c13 = '//'
  const peg$c14 = peg$literalExpectation('//', false)
  const peg$c15 = peg$anyExpectation()
  const peg$c16 = ' '
  const peg$c17 = peg$literalExpectation(' ', false)
  const peg$c18 = '\t'
  const peg$c19 = peg$literalExpectation('\t', false)

  let peg$currPos = 0
  let peg$savedPos = 0
  const peg$posDetailsCache = [{ line: 1, column: 1 }]
  let peg$maxFailPos = 0
  let peg$maxFailExpected = []
  let peg$silentFails = 0

  let peg$result

  if ('startRule' in options) {
    if (!(options.startRule in peg$startRuleFunctions)) {
      throw new Error("Can't start parsing from rule \"" + options.startRule + '".')
    }

    peg$startRuleFunction = peg$startRuleFunctions[options.startRule]
  }

  function text () {
    return input.substring(peg$savedPos, peg$currPos)
  }

  function location () {
    return peg$computeLocation(peg$savedPos, peg$currPos)
  }

  function expected (description, location) {
    location = location !== void 0 ? location : peg$computeLocation(peg$savedPos, peg$currPos)

    throw peg$buildStructuredError(
      [peg$otherExpectation(description)],
      input.substring(peg$savedPos, peg$currPos),
      location
    )
  }

  function error (message, location) {
    location = location !== void 0 ? location : peg$computeLocation(peg$savedPos, peg$currPos)

    throw peg$buildSimpleError(message, location)
  }

  function peg$literalExpectation (text, ignoreCase) {
    return { type: 'literal', text: text, ignoreCase: ignoreCase }
  }

  function peg$classExpectation (parts, inverted, ignoreCase) {
    return { type: 'class', parts: parts, inverted: inverted, ignoreCase: ignoreCase }
  }

  function peg$anyExpectation () {
    return { type: 'any' }
  }

  function peg$endExpectation () {
    return { type: 'end' }
  }

  function peg$otherExpectation (description) {
    return { type: 'other', description: description }
  }

  function peg$computePosDetails (pos) {
    let details = peg$posDetailsCache[pos]; let p

    if (details) {
      return details
    } else {
      p = pos - 1
      while (!peg$posDetailsCache[p]) {
        p--
      }

      details = peg$posDetailsCache[p]
      details = {
        line: details.line,
        column: details.column
      }

      while (p < pos) {
        if (input.charCodeAt(p) === 10) {
          details.line++
          details.column = 1
        } else {
          details.column++
        }

        p++
      }

      peg$posDetailsCache[pos] = details
      return details
    }
  }

  function peg$computeLocation (startPos, endPos) {
    const startPosDetails = peg$computePosDetails(startPos)
    const endPosDetails = peg$computePosDetails(endPos)

    return {
      start: {
        offset: startPos,
        line: startPosDetails.line,
        column: startPosDetails.column
      },
      end: {
        offset: endPos,
        line: endPosDetails.line,
        column: endPosDetails.column
      }
    }
  }

  function peg$fail (expected) {
    if (peg$currPos < peg$maxFailPos) { return }

    if (peg$currPos > peg$maxFailPos) {
      peg$maxFailPos = peg$currPos
      peg$maxFailExpected = []
    }

    peg$maxFailExpected.push(expected)
  }

  function peg$buildSimpleError (message, location) {
    return new peg$SyntaxError(message, null, null, location)
  }

  function peg$buildStructuredError (expected, found, location) {
    return new peg$SyntaxError(
      peg$SyntaxError.buildMessage(expected, found),
      expected,
      found,
      location
    )
  }

  function peg$parsetransformation_rule () {
    let s0, s1, s2, s3, s4, s5

    s0 = peg$currPos
    s1 = peg$parsecategory1()
    if (s1 !== peg$FAILED) {
      s2 = peg$parseidentifier()
      if (s2 !== peg$FAILED) {
        s3 = peg$parseidentifier()
        if (s3 !== peg$FAILED) {
          s4 = []
          s5 = peg$parseidentifier()
          while (s5 !== peg$FAILED) {
            s4.push(s5)
            s5 = peg$parseidentifier()
          }
          if (s4 !== peg$FAILED) {
            peg$savedPos = s0
            s1 = peg$c0(s1, s2, s3, s4)
            s0 = s1
          } else {
            peg$currPos = s0
            s0 = peg$FAILED
          }
        } else {
          peg$currPos = s0
          s0 = peg$FAILED
        }
      } else {
        peg$currPos = s0
        s0 = peg$FAILED
      }
    } else {
      peg$currPos = s0
      s0 = peg$FAILED
    }

    return s0
  }

  function peg$parsecategory1 () {
    let s0

    s0 = peg$parsewild_card()
    if (s0 === peg$FAILED) {
      s0 = peg$parseidentifier()
    }

    return s0
  }

  function peg$parseidentifier () {
    let s0, s1, s2

    s0 = peg$currPos
    s1 = []
    if (peg$c1.test(input.charAt(peg$currPos))) {
      s2 = input.charAt(peg$currPos)
      peg$currPos++
    } else {
      s2 = peg$FAILED
      if (peg$silentFails === 0) { peg$fail(peg$c2) }
    }
    if (s2 !== peg$FAILED) {
      while (s2 !== peg$FAILED) {
        s1.push(s2)
        if (peg$c1.test(input.charAt(peg$currPos))) {
          s2 = input.charAt(peg$currPos)
          peg$currPos++
        } else {
          s2 = peg$FAILED
          if (peg$silentFails === 0) { peg$fail(peg$c2) }
        }
      }
    } else {
      s1 = peg$FAILED
    }
    if (s1 !== peg$FAILED) {
      s2 = peg$parseS_no_eol()
      if (s2 !== peg$FAILED) {
        peg$savedPos = s0
        s1 = peg$c3(s1)
        s0 = s1
      } else {
        peg$currPos = s0
        s0 = peg$FAILED
      }
    } else {
      peg$currPos = s0
      s0 = peg$FAILED
    }

    return s0
  }

  function peg$parsewild_card () {
    let s0, s1, s2

    s0 = peg$currPos
    if (input.charCodeAt(peg$currPos) === 42) {
      s1 = peg$c4
      peg$currPos++
    } else {
      s1 = peg$FAILED
      if (peg$silentFails === 0) { peg$fail(peg$c5) }
    }
    if (s1 !== peg$FAILED) {
      s2 = peg$parseS_no_eol()
      if (s2 !== peg$FAILED) {
        peg$savedPos = s0
        s1 = peg$c6(s1)
        s0 = s1
      } else {
        peg$currPos = s0
        s0 = peg$FAILED
      }
    } else {
      peg$currPos = s0
      s0 = peg$FAILED
    }

    return s0
  }

  function peg$parseEOL () {
    let s0

    if (input.substr(peg$currPos, 2) === peg$c7) {
      s0 = peg$c7
      peg$currPos += 2
    } else {
      s0 = peg$FAILED
      if (peg$silentFails === 0) { peg$fail(peg$c8) }
    }
    if (s0 === peg$FAILED) {
      if (input.charCodeAt(peg$currPos) === 10) {
        s0 = peg$c9
        peg$currPos++
      } else {
        s0 = peg$FAILED
        if (peg$silentFails === 0) { peg$fail(peg$c10) }
      }
      if (s0 === peg$FAILED) {
        if (input.charCodeAt(peg$currPos) === 13) {
          s0 = peg$c11
          peg$currPos++
        } else {
          s0 = peg$FAILED
          if (peg$silentFails === 0) { peg$fail(peg$c12) }
        }
      }
    }

    return s0
  }

  function peg$parseComment () {
    let s0, s1, s2, s3, s4, s5

    s0 = peg$currPos
    if (input.substr(peg$currPos, 2) === peg$c13) {
      s1 = peg$c13
      peg$currPos += 2
    } else {
      s1 = peg$FAILED
      if (peg$silentFails === 0) { peg$fail(peg$c14) }
    }
    if (s1 !== peg$FAILED) {
      s2 = []
      s3 = peg$currPos
      s4 = peg$currPos
      peg$silentFails++
      s5 = peg$parseEOL()
      peg$silentFails--
      if (s5 === peg$FAILED) {
        s4 = void 0
      } else {
        peg$currPos = s4
        s4 = peg$FAILED
      }
      if (s4 !== peg$FAILED) {
        if (input.length > peg$currPos) {
          s5 = input.charAt(peg$currPos)
          peg$currPos++
        } else {
          s5 = peg$FAILED
          if (peg$silentFails === 0) { peg$fail(peg$c15) }
        }
        if (s5 !== peg$FAILED) {
          s4 = [s4, s5]
          s3 = s4
        } else {
          peg$currPos = s3
          s3 = peg$FAILED
        }
      } else {
        peg$currPos = s3
        s3 = peg$FAILED
      }
      while (s3 !== peg$FAILED) {
        s2.push(s3)
        s3 = peg$currPos
        s4 = peg$currPos
        peg$silentFails++
        s5 = peg$parseEOL()
        peg$silentFails--
        if (s5 === peg$FAILED) {
          s4 = void 0
        } else {
          peg$currPos = s4
          s4 = peg$FAILED
        }
        if (s4 !== peg$FAILED) {
          if (input.length > peg$currPos) {
            s5 = input.charAt(peg$currPos)
            peg$currPos++
          } else {
            s5 = peg$FAILED
            if (peg$silentFails === 0) { peg$fail(peg$c15) }
          }
          if (s5 !== peg$FAILED) {
            s4 = [s4, s5]
            s3 = s4
          } else {
            peg$currPos = s3
            s3 = peg$FAILED
          }
        } else {
          peg$currPos = s3
          s3 = peg$FAILED
        }
      }
      if (s2 !== peg$FAILED) {
        s3 = peg$parseEOL()
        if (s3 === peg$FAILED) {
          s3 = peg$parseEOI()
        }
        if (s3 !== peg$FAILED) {
          s1 = [s1, s2, s3]
          s0 = s1
        } else {
          peg$currPos = s0
          s0 = peg$FAILED
        }
      } else {
        peg$currPos = s0
        s0 = peg$FAILED
      }
    } else {
      peg$currPos = s0
      s0 = peg$FAILED
    }

    return s0
  }

  function peg$parseS () {
    let s0, s1

    s0 = []
    if (input.charCodeAt(peg$currPos) === 32) {
      s1 = peg$c16
      peg$currPos++
    } else {
      s1 = peg$FAILED
      if (peg$silentFails === 0) { peg$fail(peg$c17) }
    }
    if (s1 === peg$FAILED) {
      if (input.charCodeAt(peg$currPos) === 9) {
        s1 = peg$c18
        peg$currPos++
      } else {
        s1 = peg$FAILED
        if (peg$silentFails === 0) { peg$fail(peg$c19) }
      }
      if (s1 === peg$FAILED) {
        s1 = peg$parseEOL()
        if (s1 === peg$FAILED) {
          s1 = peg$parseComment()
        }
      }
    }
    while (s1 !== peg$FAILED) {
      s0.push(s1)
      if (input.charCodeAt(peg$currPos) === 32) {
        s1 = peg$c16
        peg$currPos++
      } else {
        s1 = peg$FAILED
        if (peg$silentFails === 0) { peg$fail(peg$c17) }
      }
      if (s1 === peg$FAILED) {
        if (input.charCodeAt(peg$currPos) === 9) {
          s1 = peg$c18
          peg$currPos++
        } else {
          s1 = peg$FAILED
          if (peg$silentFails === 0) { peg$fail(peg$c19) }
        }
        if (s1 === peg$FAILED) {
          s1 = peg$parseEOL()
          if (s1 === peg$FAILED) {
            s1 = peg$parseComment()
          }
        }
      }
    }

    return s0
  }

  function peg$parseS_no_eol () {
    let s0, s1

    s0 = []
    if (input.charCodeAt(peg$currPos) === 32) {
      s1 = peg$c16
      peg$currPos++
    } else {
      s1 = peg$FAILED
      if (peg$silentFails === 0) { peg$fail(peg$c17) }
    }
    if (s1 === peg$FAILED) {
      if (input.charCodeAt(peg$currPos) === 9) {
        s1 = peg$c18
        peg$currPos++
      } else {
        s1 = peg$FAILED
        if (peg$silentFails === 0) { peg$fail(peg$c19) }
      }
      if (s1 === peg$FAILED) {
        s1 = peg$parseComment()
      }
    }
    while (s1 !== peg$FAILED) {
      s0.push(s1)
      if (input.charCodeAt(peg$currPos) === 32) {
        s1 = peg$c16
        peg$currPos++
      } else {
        s1 = peg$FAILED
        if (peg$silentFails === 0) { peg$fail(peg$c17) }
      }
      if (s1 === peg$FAILED) {
        if (input.charCodeAt(peg$currPos) === 9) {
          s1 = peg$c18
          peg$currPos++
        } else {
          s1 = peg$FAILED
          if (peg$silentFails === 0) { peg$fail(peg$c19) }
        }
        if (s1 === peg$FAILED) {
          s1 = peg$parseComment()
        }
      }
    }

    return s0
  }

  function peg$parseEOI () {
    let s0, s1

    s0 = peg$currPos
    peg$silentFails++
    if (input.length > peg$currPos) {
      s1 = input.charAt(peg$currPos)
      peg$currPos++
    } else {
      s1 = peg$FAILED
      if (peg$silentFails === 0) { peg$fail(peg$c15) }
    }
    peg$silentFails--
    if (s1 === peg$FAILED) {
      s0 = void 0
    } else {
      peg$currPos = s0
      s0 = peg$FAILED
    }

    return s0
  }

  var TransformationRule = require('./TransformationRule')

  peg$result = peg$startRuleFunction()

  if (peg$result !== peg$FAILED && peg$currPos === input.length) {
    return peg$result
  } else {
    if (peg$result !== peg$FAILED && peg$currPos < input.length) {
      peg$fail(peg$endExpectation())
    }

    throw peg$buildStructuredError(
      peg$maxFailExpected,
      peg$maxFailPos < input.length ? input.charAt(peg$maxFailPos) : null,
      peg$maxFailPos < input.length
        ? peg$computeLocation(peg$maxFailPos, peg$maxFailPos + 1)
        : peg$computeLocation(peg$maxFailPos, peg$maxFailPos)
    )
  }
}

module.exports = {
  SyntaxError: peg$SyntaxError,
  parse: peg$parse
}
/* jscpd:ignore-end */
