func execute()

in Sources/_StringProcessing/Legacy/HareVM.swift [72:217]


  func execute(
    input: String, in range: Range<String.Index>, mode: MatchMode
  ) -> MatchResult? {
    let (start, end) = range.destructure

    assert(code.last!.isAccept)
    var bunny = Leveret(code.startIndex, start, input: input)
    var stack = BunnyStack()

    // TODO: Which bunny to return? Longest, left most, or what?

    func yieldBunny() -> MatchResult? {
      if mode == .wholeString, bunny.sp != end {
        return nil
      }
      return MatchResult(
        start ..< bunny.sp, bunny.core.singleCapture())
    }

    while true {
      let inst = code[bunny.pc]

      // Consuming operations require more input
      if bunny.sp == end && inst.isConsuming {
        // If there are no more alternatives to try, we failed
        guard !stack.isEmpty else { return nil }

        // Continue with the next alternative
        bunny = stack.restore()
        continue
      }

      switch code[bunny.pc] {
      case .nop: bunny.hop()
      case .accept:
        // If we've matched all of our input, we're done
        if bunny.sp == end {
          return yieldBunny()
        }
        // If there are no more alternatives to try, we're done
        guard !stack.isEmpty else {
          return yieldBunny()
        }

        // If (TODO?) we want partial matching and we want left-most, we're done
        if mode == .partialFromFront {
          return yieldBunny()
        }

        // Continue with the next alternative
        bunny = stack.restore()

      case .any:
        assert(bunny.sp < end)
        bunny.nibble(on: input)
        bunny.hop()

      case .character(let c):
        assert(bunny.sp < end)
        guard input[bunny.sp] == c else {
          // If there are no more alternatives to try, we failed
          guard !stack.isEmpty else {
            return nil
          }

          // Continue with the next alternative
          bunny = stack.restore()
          continue
        }
        bunny.nibble(on: input)
        bunny.hop()

      case .unicodeScalar(let u):
        assert(bunny.sp < end)
        guard input.unicodeScalars[bunny.sp] == u else {
          // If there are no more alternatives to try, we failed
          guard !stack.isEmpty else {
            return nil
          }

          // Continue with the next alternative
          bunny = stack.restore()
          continue
        }
        bunny.nibbleScalar(on: input)
        bunny.hop()

      case .characterClass(let cc):
        assert(bunny.sp < end)
        guard let nextSp = cc.matches(in: input, at: bunny.sp) else {
          // If there are no more alternatives to try, we failed
          guard !stack.isEmpty else {
            return nil
          }

          // Continue with the next alternative
          bunny = stack.restore()
          continue
        }
        bunny.nibble(to: nextSp)
        bunny.hop()

      case .split(let disfavoring):
        var disfavoredBunny = bunny
        disfavoredBunny.hop(to: code.lookup(disfavoring))
        stack.save(disfavoredBunny)
        bunny.hop()

      case .goto(let label):
        bunny.hop(to: code.lookup(label))

      case .label(_):
        bunny.hop()

      case .beginCapture:
        bunny.core.beginCapture(bunny.sp)
        bunny.hop()

      case let .endCapture(transform):
        guard bunny.core.endCapture(bunny.sp, transform: transform) else {
          return nil
        }
        bunny.hop()

      case .beginGroup:
        bunny.core.beginGroup()
        bunny.hop()

      case .endGroup:
        bunny.core.endGroup()
        bunny.hop()

      case .captureSome:
        bunny.core.captureSome()
        bunny.hop()

      case .captureNil(let childType):
        bunny.core.captureNil(childType: childType)
        bunny.hop()

      case .captureArray(let childType):
        bunny.core.captureArray(childType: childType)
        bunny.hop()
      }
    }
  }