func generateConsumer()

in Sources/_StringProcessing/ConsumerInterface.swift [124:211]


  func generateConsumer(
    _ opts: MatchingOptions
  ) throws -> Program<String>.ConsumeFunction {
    switch self {
    case .custom(let ccc):
      return try ccc.generateConsumer(opts)

    case .range(let r):
      guard let lhs = r.lhs.literalCharacterValue else {
        throw unsupported("\(r.lhs) in range")
      }
      guard let rhs = r.rhs.literalCharacterValue else {
        throw unsupported("\(r.rhs) in range")
      }

      return { input, bounds in
        // TODO: check for out of bounds?
        let curIdx = bounds.lowerBound
        if (lhs...rhs).contains(input[curIdx]) {
          // TODO: semantic level
          return input.index(after: curIdx)
        }
        return nil
      }

    case .atom(let atom):
      guard let gen = try atom.generateConsumer(opts) else {
        throw unsupported("TODO")
      }
      return gen

    case .quote(let q):
      // TODO: Not optimal.
      let consumers = try q.literal.map {
        try AST.Atom(.char($0), .fake).generateConsumer(opts)!
      }
      return { input, bounds in
        for consumer in consumers {
          if let idx = consumer(input, bounds) {
            return idx
          }
        }
        return nil
      }

    case .setOperation(let lhs, let op, let rhs):
      // TODO: We should probably have a component type
      // instead of a members array... for now we reconstruct
      // an AST node...
      let start = AST.Located(
        faking: AST.CustomCharacterClass.Start.normal)

      let lhs = try AST.CustomCharacterClass(
        start, lhs, .fake
      ).generateConsumer(opts)
      let rhs = try AST.CustomCharacterClass(
        start, rhs, .fake
      ).generateConsumer(opts)

      return { input, bounds in
        // NOTE: Easy way to implement, not performant
        let lhsIdxOpt = lhs(input, bounds)
        let rhsIdxOpt = rhs(input, bounds)

        // TODO: What if lengths don't line up?
        assert(lhsIdxOpt == rhsIdxOpt || lhsIdxOpt == nil
               || rhsIdxOpt == nil)

        switch op.value {
        case .subtraction:
          guard rhsIdxOpt == nil else { return nil }
          return lhsIdxOpt

        case .intersection:
          if let idx = lhsIdxOpt {
            return rhsIdxOpt == nil ? nil : idx
          }
          return nil

        case .symmetricDifference:
          if let idx = lhsIdxOpt {
            return rhsIdxOpt == nil ? idx : nil
          }
          return rhsIdxOpt
        }
      }
    }
  }