Stephen Chang <stchang@racket-lang.org>
Parsec implementation in Racket. See [parsec].
A parser is a function that consumes an input-port? and returns a parse result. A parse result is most commonly a char? or a list of chars, but is ultimately determined by each specific parser.
whether a parser consumes input, i.e., whether data was read from the input port,
or whether a parser succeeds or fails.
Specifically, Consumed and Empty struct results indicate input-consumption and no-input-consumption, respectively, while the Ok and Error structs indicate success and failure, respectively. See Parse Result Structs for more details about information contained in the parse result. In general, users should use combinators below to compose parsers and parse results, rather than directly handle the structs.
procedure
( parse-result pinput)→any/c
p:parser?
The input can be either a string, a filepath, or an input port. A string or path input is converted to an input port before parsing begins.
Raises the exn:fail:parsack exception on parser failure.
#\a
parse ERROR: at 1:1:1
unexpected: "1"
expected: "letter"
'(#\a #\b #\c)
'()
The input can be either a string, a filepath, or an input port. A string or path input is converted to an input port before parsing begins.
Raises the exn:fail:parsack exception on parser failure.
If p fails, the error result is returned.
Otherwise, the parse result is passed to f, and continues parsing with the parser created from applying f.
"(a)")#\a
procedure
( >> pq)→parser?
p:parser?q:parser?
Creates a parser that first parses with p, and if successful, ignores the result, then parses with q.
syntax
( parser-compose bind-or-skip...+)
bind-or-skip = (x<-parser)| parserparser = parser?x = identifier?
"[ab]")'(#\a #\b)
syntax
( parser-seq skippable...maybe-combine)
skippable = (~parser)| parserparser = parser?maybe-combine =| #:combine-withcombinecombine = (->any/cany/c)
The default combine function is list so (parser-seq pq) is syntactically equivalent to (parser-compose (x<-p)(y<-q)(return (list xy))).
Use parser-seq instead of parser-compose when you don’t need the result of any parser other than to return it. Use parser-compose when you need the result of one parse to build subsequent parsers, for example when parsing matching html open-close tags, or if you need to do additional processing on the parse result before returning.
'(#\a #\b)
syntax
( parser-cons pq)
p = parser?q = parser?
'(#\a #\b #\c #\d #\e)
syntax
( parser-one p...)
p = (~>parser)| parserparser = parser?
For example, (parser-one p1(~>p2)p3) is syntactically equivalent to (parser-seq (~p1)p2(~p3)#:combine-with(λ (x)x)), which is equivalent to (parser-compose p1(x<-p2)p3(return x)).
#\a
procedure
( <or> pq...)→parser?
p:parser?q:parser?
#1ε
<or> continues to try subsequent parsers so long as each of the previous parsers consumes no input, even if one of the previous parsers returns successfully. Thus <or> implements "longest match" (see [parsec] for more details).
#1ε
See also <any> , a related parser that immediately returns when it encounters a successful parse, even if the parse consumed no input.
'()
But if no parsers consume input, then <or> backtracks to return the result of the first success.
"a"
parse ERROR: at 1:2:2
unexpected: "c"
expected: "b"
'(#\a #\c)
procedure
( <any> pq...)→parser?
p:parser?q:parser?
#1ε
<any> immediately returns when it encounters a successful parse, even if the parse consumed no input.
'()
See also <or> , a related parser that continues to try subsequent parsers so long as each of the previous parsers consumes no input, even if one of the previous parsers returns successfully.
#1ε
procedure
( many p[#:tillend#:ororcomb])→parser?
p:parser?
procedure
( many1 p)→parser?
p:parser?
procedure
( manyTill pend[#:ororcomb])→parser?
p:parser?end:parser?
procedure
( many1Till pend[#:ororcomb])→parser?
p:parser?end:parser?
procedure
( manyUntil pend)→parser?
p:parser?end:parser?
procedure
( many1Until pend)→parser?
p:parser?end:parser?
Equivalent to (many1Till pend#:or<any> ).
Here is an implementation of a basic parser for comma-separated values (CSV).
A series of cells are separated by commas. To parse cells, we use two mutually referential parsers.
'(((#\c #\e #\l #\l #1ε) (#\c #\e #\l #\l #2ε))
((#\c #\e #\l #\l #3ε) (#\c #\e #\l #\l #4ε)))
procedure
( skipMany p)→parser?
p:parser?
procedure
( skipMany1 p)→parser?
p:parser?
procedure
( sepBy psep)→parser?
p:parser?sep:parser?
procedure
( sepBy1 psep)→parser?
p:parser?sep:parser?
procedure
( endBy pend)→parser?
p:parser?end:parser?
procedure
( between openclosep)→parser?
open:parser?close:parser?p:parser?
procedure
( lookAhead p)→parser?
p:parser?
procedure
( notFollowedBy p)→parser?
p:parser?
procedure
( charAnyCase c)→parser?
c:char?
procedure
( oneOfStrings str...)→parser?
str:string?
procedure
( oneOfStringsAnyCase str...)→parser?
str:string?
value
$letter :parser?
value
$digit :parser?
value
$alphaNum :parser?
value
$hexDigit :parser?
value
$space :parser?
value
$spaces :parser?
value
$anyChar :parser?
value
$newline :parser?
value
$tab :parser?
value
$eol :parser?
value
$eof :parser?
value
$identifier :parser?
syntax
( withState ([keyvalue]...)parser)
procedure
( try p)→parser?
p:parser?
(Consumed #<Error>)
(Empty #<Error>)
value
$err :parser?
procedure
( bytestring bstr)→parser?
bstr:bytes?
A parser is a function that consumes an input-port? and returns either a Consumed , or an Empty struct.
In general, users should use the above combinators to connect parsers and parse results, rather than manipulate these structs directly.
(Consumed (Ok #\a))
(Consumed (Ok '(#\a #\b #\c)))
(Consumed #<Error>)
The parse result can be any value and depends on the specific parser that produces the this struct.
(Empty #<Error>)
struct