func emit()

in Sources/_StringProcessing/Compiler.swift [38:161]


  func emit(_ node: AST.Node) throws {

    switch node {
    case .atom(let a) where a.kind == .any:
      try emitAny()
      
    // Single characters we just match
    case .atom(let a) where a.singleCharacter != nil :
      builder.buildMatch(a.singleCharacter!)

    // Alternation: p0 | p1 | ... | pn
    //     save next_p1
    //     <code for p0>
    //     branch done
    //   next_p1:
    //     save next_p2
    //     <code for p1>
    //     branch done
    //   next_p2:
    //     save next_p...
    //     <code for p2>
    //     branch done
    //   ...
    //   next_pn:
    //     <code for pn>
    //   done:
    case .alternation(let alt):
      let done = builder.makeAddress()
      for component in alt.children.dropLast() {
        let next = builder.makeAddress()
        builder.buildSave(next)
        try emit(component)
        builder.buildBranch(to: done)
        builder.label(next)
      }
      try emit(alt.children.last!)
      builder.label(done)

    case .conditional:
      throw unsupported(node.renderAsCanonical())

    // FIXME: Wait, how does this work?
    case .groupTransform(let g, _):
      try emit(g.child)


    case .concatenation(let concat):
      try concat.children.forEach(emit)

    case .trivia, .empty:
      break

    case .absentFunction:
      throw unsupported(node.renderAsCanonical())

    case .group(let g):
      options.beginScope()
      defer { options.endScope() }
      
      if let lookaround = g.lookaroundKind {
        try emitLookaround(lookaround, g.child)
        return
      }

      switch g.kind.value {
      case .lookahead, .negativeLookahead,
          .lookbehind, .negativeLookbehind:
        fatalError("unreachable")

      case .capture, .namedCapture:
        let cap = builder.makeCapture()
        builder.buildBeginCapture(cap)
        try emit(g.child)
        builder.buildEndCapture(cap)

      case .changeMatchingOptions(let optionSequence, _):
        options.apply(optionSequence)
        try emit(g.child)

      default:
        // FIXME: Other kinds...
        try emit(g.child)
      }

    case .quantification(let quant):
      try emitQuantification(quant)

    // For now, we model sets and atoms as consumers.
    // This lets us rapidly expand support, and we can better
    // design the actual instruction set with real examples
    case _ where try node.generateConsumer(options) != nil:
      try builder.buildConsume(by: node.generateConsumer(options)!)

    case .quote(let q):
      // We stick quoted content into read-only constant strings
      builder.buildMatchSequence(q.literal)

    case .atom(let a) where a.assertionKind != nil:
      try emitAssertion(a.assertionKind!)

    case .atom(let a):
      switch a.kind {
      case .backreference(let r):
        if r.recursesWholePattern {
          // TODO: A recursive call isn't a backreference, but
          // we could in theory match the whole match so far...
          throw unsupported(node.renderAsCanonical())
        }

        switch r.kind {
        case .absolute(let i):
          // Backreferences number starting at 1
          builder.buildBackreference(.init(i-1))
        case .relative, .named:
          throw unsupported(node.renderAsCanonical())
        }
      default:
        throw unsupported(node.renderAsCanonical())
      }

    case .customCharacterClass:
      throw unsupported(node.renderAsCanonical())
    }
  }