-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathparser.plm
More file actions
68 lines (60 loc) · 1.64 KB
/
parser.plm
File metadata and controls
68 lines (60 loc) · 1.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
require "mod:thomasvergne/plume-combinator"
require "mod:thomasvergne/plume-combinator/library/char"
type Request {
Request(
str, // method
str, // path
Map<str, str> // headers
)
}
fn cat_maybes<A extends equality>(ls: list<Option<A>>): list<A> =>
ls.foldl(fn(acc, x) => switch x {
case Some(x) => [x] + acc
case None => acc
}, [])
extend show<Request> {
fn show_prec(m, i) => switch m {
case Request(method, path, headers) =>
"Request($method, $path, " + headers.show() + ")"
}
}
parse_first_line: Parser<Option<(str, str)>> =
none_of([' ', '\n', '\r'])
.many1()
.map(implode)
.sep_by_1(space)
.lex()
>>= fn (ls) => switch ls {
case [method, path, ?] => pure(Some((method, path)))
case ? => pure(None)
}
parse_header: Parser<Option<(str, str)>> =
none_of(['\n', '\r', ':'])
.many1().lex()
.map(implode)
.sep_by_1(character(':'))
.lex()
>>= fn (ls) => switch ls {
case [key, ..vs] => pure(Some((key, vs.join_str(":"))))
case ? => pure(None)
}
parse_http: Parser<Option<Request>> =
parse_first_line
.bind(fn (first_line) => switch first_line {
case Some((method, path)) =>
newline.many() >>
parse_header
.sep_by_1(newline.many1())
.lex()
.bind(fn (headers) {
return pure(Some(Request(method, path, headers.cat_maybes())))
}) << newline.many()
case None => pure(None)
})
fn parse_request(s: str): Result<Request, str> {
s_ = s.explode()
return parse_http.bind(fn(p) => switch p {
case Some(r) => pure(r)
case None => parse_error("parse err")
}).run_parser(s_).fst()
}