(.module: [lux #* [control pipe [monad (#+ do)] ["p" parser ["l" text (#+ Parser)]]] [data ["." error (#+ Error)] [number ["." nat]] ["." text ["%" format (#+ format)]] [format ["." context (#+ Context)]] [collection ["." dictionary]]]]) (def: component (Parser Text) (p.rec (function (_ component) (do p.monad [head (l.some (l.none-of "+%&;"))] ($_ p.either (p.after (p.either l.end (l.this "&")) (wrap head)) (do @ [_ (l.this "+") tail component] (wrap (format head " " tail))) (do @ [_ (l.this "%") code (|> (l.exactly 2 l.hexadecimal) (p.codec nat.hex) (:: @ map text.from-code)) tail component] (wrap (format head code tail)))))))) (def: (form context) (-> Context (Parser Context)) ($_ p.either (do p.monad [_ l.end] (wrap context)) (do p.monad [key (l.some (l.none-of "=&;")) key (l.local key ..component)] (p.either (do @ [_ (l.this "=") value ..component] (form (dictionary.put key value context))) (do @ [_ ($_ p.or (l.one-of "&;") l.end)] (form (dictionary.put key "" context))))) ## if invalid form data, just stop parsing... (:: p.monad wrap context))) (def: #export (parameters raw) (-> Text (Error Context)) (l.run raw (..form context.empty)))