1 ! Copyright (C) 2008 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: combinators.short-circuit math math.order math.parser
4 kernel sequences sequences.deep peg peg.parsers assocs arrays
5 hashtables strings unicode.case namespaces make ascii logging ;
8 : except ( quot -- parser )
9 [ not ] compose satisfy ; inline
11 : except-these ( quots -- parser )
12 [ 1|| ] curry except ; inline
15 { [ 0 31 between? ] [ 127 = ] } 1|| ;
17 : tspecial? ( ch -- ? )
18 "()<>@,;:\\\"/[]?={} \t" member? ;
20 : 'token' ( -- parser )
21 { [ ctl? ] [ tspecial? ] } except-these repeat1 ;
23 : case-insensitive ( parser -- parser' )
24 [ flatten >string >lower ] action ;
26 : case-sensitive ( parser -- parser' )
27 [ flatten >string ] action ;
29 : 'space' ( -- parser )
30 [ " \t" member? ] satisfy repeat0 hide ;
32 : one-of ( strings -- parser )
33 [ token ] map choice ;
35 : 'http-method' ( -- parser )
36 { "OPTIONS" "GET" "HEAD" "POST" "PUT" "DELETE" "TRACE" "CONNECT" } one-of ;
39 [ " \t\r\n" member? ] except repeat1 case-sensitive ;
41 : 'http-version' ( -- parser )
50 ] seq* [ concat >string ] action ;
52 PEG: parse-request-line ( string -- triple )
53 #! Triple is { method url version }
64 \ parse-request-line DEBUG add-input-logging
66 : 'text' ( -- parser )
69 : 'response-code' ( -- parser )
70 [ digit? ] satisfy 3 exactly-n [ string>number ] action ;
72 : 'response-message' ( -- parser )
73 'text' repeat0 case-sensitive ;
75 PEG: parse-response-line ( string -- triple )
76 #! Triple is { version code message }
86 : 'crlf' ( -- parser )
90 [ " \t" member? ] satisfy repeat1 ;
92 : 'qdtext' ( -- parser )
93 { [ CHAR: " = ] [ ctl? ] } except-these ;
95 : 'quoted-char' ( -- parser )
96 "\\" token hide any-char 2seq ;
98 : 'quoted-string' ( -- parser )
99 'quoted-char' 'qdtext' 2choice repeat0 "\"" "\"" surrounded-by ;
101 : 'ctext' ( -- parser )
102 { [ ctl? ] [ "()" member? ] } except-these ;
104 : 'comment' ( -- parser )
105 'ctext' 'comment' 2choice repeat0 "(" ")" surrounded-by ;
107 : 'field-name' ( -- parser )
108 'token' case-insensitive ;
110 : 'field-content' ( -- parser )
111 'quoted-string' case-sensitive
112 'text' repeat0 case-sensitive
115 PEG: parse-header-line ( string -- pair )
116 #! Pair is either { name value } or { f value }. If f, its a
117 #! continuation of the previous header line.
126 'lws' [ drop f ] action ,
131 : 'word' ( -- parser )
132 'token' 'quoted-string' 2choice ;
134 : 'value' ( -- parser )
136 [ ";" member? ] except repeat0
137 2choice case-sensitive ;
139 : 'attr' ( -- parser )
140 'token' case-insensitive ;
142 : 'av-pair' ( -- parser )
147 [ "=" token , 'space' , 'value' , ] seq* [ peek ] action
148 epsilon [ drop f ] action
153 : 'av-pairs' ( -- parser )
154 'av-pair' ";" token list-of optional ;
156 PEG: (parse-set-cookie) ( string -- alist ) 'av-pairs' just ;
158 : 'cookie-value' ( -- parser )
169 PEG: (parse-cookie) ( string -- alist )
170 'cookie-value' [ ";," member? ] satisfy list-of optional just ;