F #, FParsec und rekursives Aufrufen eines Stream-Parsers

Ich entwickle einen mehrteiligen MIME-Parser mit F # und FParsec. Ich entwickle iterativ und daher handelt es sich hier um sehr unverbesserlichen, spröden Code, der nur mein erstes unmittelbares Problem löst. Rot, Grün, Refactor.

Ich muss eher einen Stream als eine Zeichenfolge analysieren, was mich wirklich zu einer Schleife veranlasst. Angesichts dieser Einschränkung muss ich nach meinem besten Verständnis einen Parser rekursiv aufrufen. Wie das geht, ist jenseits meines Wissens, zumindest so, wie ich bisher vorgegangen bin.

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

Die erste Zeile des POST-Beispiels lautet:

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

It erstreckt sich über eine einzelne Zeile in der Datei. Weitere Unterteile im Inhalt sindcontent-type -Werte, die sich über mehrere Zeilen erstrecken, sodass ich weiß, dass ich meine Parser verfeinern muss, wenn ich sie wiederverwenden möchte.

Irgendwie muss ich @ anrufpContent mit den (string?) Ergebnissen vonpBoundary, so dass ich den Rest des Streams an den entsprechenden Grenzen aufteilen und dann irgendwie mehrere Teile für den Inhalt des Posts zurückgeben kann, von denen jeder ein separater Post ist, mit Überschriften und Inhalten (die natürlich etwas sein müssen) andere als eine Zeichenfolge). Mein Kopf dreht sich. Dieser Code scheint bereits viel zu komplex, um eine einzelne Zeile zu analysieren.

Viel Wertschätzung für Einsicht und Weisheit!

Antworten auf die Frage(1)

Ihre Antwort auf die Frage