F #, FParsec и рекурсивный вызов потокового парсера

Я разрабатываю многочастный парсер MIME, используя F # и FParsec. Я разрабатываю итеративно, и поэтому это крайне неопределяемый, хрупкий код - он решает только мою первую непосредственную проблему. Красный, Зеленый, Рефакторинг.

Я должен анализировать поток, а не строку, которая действительно бросает меня за цикл. Учитывая это ограничение, насколько я понимаю, мне нужно рекурсивно вызывать синтаксический анализатор. Как это сделать, мне не по карману, по крайней мере, так, как я проделал это до сих пор.

namespace MultipartMIMEParser

open FParsec
open System.IO

type private Post = { contentType : string
                    ; boundary    : string
                    ; subtype     : string
                    ; content     : string }

type MParser (s:Stream) =
  let ($) f x = f x
  let ascii = System.Text.Encoding.ASCII
  let str cs = System.String.Concat (cs:char list)
  let q = "\""
  let qP = pstring q
  let pSemicolon = pstring ";"
  let manyNoDoubleQuote = many $ noneOf q
  let enquoted = between qP qP manyNoDoubleQuote |>> str
  let skip = skipStringCI
  let pContentType = skip "content-type: "
                     >>. manyTill anyChar (attempt $ preturn () .>> pSemicolon)
                     |>> str
  let pBoundary = skip " boundary=" >>. enquoted
  let pSubtype = opt $ pSemicolon >>. skip " type=" >>. enquoted
  let pContent = many anyChar |>> str // TODO: The content parser needs to recurse on the stream.
  let pStream = pipe4 pContentType pBoundary pSubtype pContent
                      $ fun c b t s -> { contentType=c; boundary=b; subtype=t; content=s }
  let result s = match runParserOnStream pStream () "" s ascii with
                 | Success (r,_,_) -> r
                 | Failure (e,_,_) -> failwith (sprintf "%A" e)
  let r = result s
  member p.ContentType = r.contentType
  member p.Boundary = r.boundary
  member p.ContentSubtype = r.subtype
  member p.Content = r.content

Первая строка примера POST выглядит следующим образом:

content-type: Multipart/related; boundary="RN-Http-Body-Boundary"; type="multipart/related"

Он занимает одну строку в файле. Другие части в содержании включаютcontent-type значения, которые охватывают несколько строк, поэтому я знаю, что мне придется уточнить свои парсеры, если я хочу их использовать повторно.

Как-то я должен позвонитьpContent с (строка?) результатамиpBoundary так что я могу разделить остальную часть потока на соответствующие границы, а затем каким-то образом вернуть несколько частей для содержимого сообщения, каждая из которых будет отдельной публикацией, с заголовками и содержимым (которое, очевидно, должно быть чем-то другим чем строка). Моя голова кружится. Этот код уже кажется слишком сложным, чтобы разобрать одну строку.

Большое спасибо за понимание и мудрость!

Ответы на вопрос(1)

Ваш ответ на вопрос