/* Generated by re2swift */
#sourceLocation(file: "swift/submatch/02_mtags.re", line: 1)
// re2swift $INPUT -o $OUTPUT
import Foundation

// Unbounded number of version components.
struct Ver: Equatable { let components: [Int] }

func parse(_ yyinput: UnsafePointer<UInt8>) -> Ver? {
  let tagNone = -1

  var yycursor = 0, yymarker = 0
  var mTagPool = [MTag]()

  // Final tag variables available in semantic action.
  
#sourceLocation(file: "swift/submatch/02_mtags.swift", line: 18)
  let t1: Int
  let t2: Int
#sourceLocation(file: "swift/submatch/02_mtags.re", line: 14)

  
#sourceLocation(file: "swift/submatch/02_mtags.swift", line: 24)
  let t3: MTag?
  let t4: MTag?
#sourceLocation(file: "swift/submatch/02_mtags.re", line: 15)


  // Intermediate tag variables used by the lexer (must be autogenerated).
  
#sourceLocation(file: "swift/submatch/02_mtags.swift", line: 32)
  var yyt1 = tagNone
  var yyt2 = tagNone
#sourceLocation(file: "swift/submatch/02_mtags.re", line: 18)

  
#sourceLocation(file: "swift/submatch/02_mtags.swift", line: 38)
  var yytm3: MTag? = nil
  var yytm4: MTag? = nil
#sourceLocation(file: "swift/submatch/02_mtags.re", line: 19)


  
#sourceLocation(file: "swift/submatch/02_mtags.swift", line: 45)
  var yych: UInt8 = 0
  var yystate: UInt = 0
  yyl: while true {
    switch yystate {
      case 0:
        yych = yyinput[yycursor]
        switch yych {
          case 0x30...0x39:
            yyt1 = yycursor
            yycursor += 1
            yystate = 3
            continue yyl
          default:
            yycursor += 1
            yystate = 1
            continue yyl
        }
      case 1:
        yystate = 2
        continue yyl
      case 2:
#sourceLocation(file: "swift/submatch/02_mtags.re", line: 36)
        return nil
#sourceLocation(file: "swift/submatch/02_mtags.swift", line: 69)
      case 3:
        yymarker = yycursor
        yych = yyinput[yycursor]
        switch yych {
          case 0x00:
            yytm4 = add(tag: yytm4, value: tagNone)
            yytm3 = add(tag: yytm3, value: tagNone)
            yyt2 = yycursor
            yycursor += 1
            yystate = 4
            continue yyl
          case 0x2E:
            yyt2 = yycursor
            yycursor += 1
            yystate = 5
            continue yyl
          case 0x30...0x39:
            yycursor += 1
            yystate = 7
            continue yyl
          default:
            yystate = 2
            continue yyl
        }
      case 4:
        t1 = yyt1
        t2 = yyt2
        t3 = yytm3
        t4 = yytm4
#sourceLocation(file: "swift/submatch/02_mtags.re", line: 31)
        
      var components = [s2n(t1..<t2)]
      unfold(&components, t3, t4)
      return Ver(components: components)

#sourceLocation(file: "swift/submatch/02_mtags.swift", line: 105)
      case 5:
        yych = yyinput[yycursor]
        switch yych {
          case 0x30...0x39:
            yytm3 = add(tag: yytm3, value: yycursor)
            yycursor += 1
            yystate = 8
            continue yyl
          default:
            yystate = 6
            continue yyl
        }
      case 6:
        yycursor = yymarker
        yystate = 2
        continue yyl
      case 7:
        yych = yyinput[yycursor]
        switch yych {
          case 0x00:
            yytm4 = add(tag: yytm4, value: tagNone)
            yytm3 = add(tag: yytm3, value: tagNone)
            yyt2 = yycursor
            yycursor += 1
            yystate = 4
            continue yyl
          case 0x2E:
            yyt2 = yycursor
            yycursor += 1
            yystate = 5
            continue yyl
          case 0x30...0x39:
            yycursor += 1
            yystate = 7
            continue yyl
          default:
            yystate = 6
            continue yyl
        }
      case 8:
        yych = yyinput[yycursor]
        switch yych {
          case 0x00:
            yytm4 = add(tag: yytm4, value: yycursor)
            yycursor += 1
            yystate = 4
            continue yyl
          case 0x2E:
            yytm4 = add(tag: yytm4, value: yycursor)
            yycursor += 1
            yystate = 5
            continue yyl
          case 0x30...0x39:
            yycursor += 1
            yystate = 8
            continue yyl
          default:
            yystate = 6
            continue yyl
        }
      default: fatalError("internal lexer error")
    }
  }
#sourceLocation(file: "swift/submatch/02_mtags.re", line: 37)


  // Recursively unwind tag histories and collect version components.
  func unfold(_ ver: inout [Int], _ x: MTag?, _ y: MTag?) {
    if x == nil && y == nil {
      // Reached the root of the m-tag tree, stop recursion.
      return
    }

    // Unwind history further.
    unfold(&ver, x?.prev, y?.prev)

    // Get tag values, tag histories must have equal length.
    guard let ex = x?.elem, let ey = y?.elem else {
      fatalError("mismatched history length")
    }

    guard ex != tagNone && ey != tagNone else {
      // Both tags are empty, this corresponds to zero repetitions.
      assert(ex == ey)
      return
    }

    // Both tags are valid indices, extract component.
    ver.append(s2n(ex..<ey))
  }

  // Pre-parsed string to number.
  func s2n(_ range: Range<Int>) -> Int {
    range.reduce(0) { accum, idx in
      accum * 10 + Int(yyinput[idx] - UInt8(ascii: "0"))
    }
  }

  // Append a single value to an m-tag history.
  func add(tag prevTag: MTag?, value: Int) -> MTag {
    let tag = MTag(prev: prevTag, element: value)
    mTagPool.append(tag)
    return tag
  }
}

// An m-tag tree is a way to store histories with an O(1) copy operation.
// Histories naturally form a tree, as they have common start and fork at some
// point. The tree is stored as an array of pairs (tag value, link to parent).
// An m-tag is represented with a single link in the tree (array index).
class MTag {
  weak var prev: MTag?  // Link of predecessor node or root (nil)
  var elem: Int  // Tag value

  init(prev: MTag?, element: Int) {
    self.prev = prev
    self.elem = element
  }
}

assert(parse("1") == Ver(components: [1]))
assert(parse("1.2.3.4.5.6.7") == Ver(components: [1, 2, 3, 4, 5, 6, 7]))
assert(parse("1.2.") == nil)
