-
Notifications
You must be signed in to change notification settings - Fork 6
/
EmParsec.Test.fsx
123 lines (93 loc) · 3.39 KB
/
EmParsec.Test.fsx
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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#load "EmParsec.fs"
open System
open EmParsec
let test name parser input expected =
match run parser input with
| Choice1Of2 r ->
if r = expected then
printfn "*** Test '%s' passed" name
else
sprintf "*** Test '%s' failed, expect %A but received %A" name expected r
|> failwith
| Choice2Of2 err ->
failwithf "*** Test '%s' failed with parser error:\n%s" name err
let shouldFailTest name parser input =
match run parser input with
| Choice1Of2 r ->
printfn "*** Test '%s' failed - parsing returned %A" name r
| Choice2Of2 e ->
printfn "*** Test '%s' passed with message:\n%s" name e
let thingP = pstring "thing"
test "pstring with additional" thingP "thing " "thing"
test "pstring exact" thingP "thing" "thing"
test "eof exact match" (thingP .>> eof) "thing" "thing"
shouldFailTest "eof with additional stuff on end" (thingP .>> eof) "thing h"
let quotedString =
between (pchar '"') (pchar '"') (many (satisfy (fun c -> c <> '"') ""))
|>> recompose
test "quotedString" quotedString "\"hello world\"" "hello world"
shouldFailTest "unclosed quotedString" quotedString "\"hello!"
let number =
(many (satisfy Char.IsDigit ""))
|>> recompose
test "number or quoted string (string)" (quotedString <|> number) "\"Boo\"" "Boo"
test "number or quoted string (number)" (quotedString <|> number) "10" "10"
let stringList =
sepBy quotedString (pchar ';')
test "separated strings (empty)" stringList "" []
test "separated strings (single)" stringList "\"hello\"" ["hello"]
test "separated strings (list)" stringList "\"hello\";\"world\"" ["hello";"world"]
let choiceOfThings =
choice [
quotedString
pchar ' ' |>> fun c -> ""
number
]
test "choice (string)" choiceOfThings "\"yeah\"" "yeah"
test "choice (number)" choiceOfThings "22" "22"
test "choice (space)" choiceOfThings " " ""
let operatorWorkout =
int <!> number .>> pchar ' '
.>>. pstring "漢字"
|>> fun (n, s) -> sprintf "%s %d" s n
test "operators" operatorWorkout "10 漢字" "漢字 10"
test "spaces" spaces " " ()
test "spaces with no spaces" spaces "a" ()
test "spaces1" spaces1 " \n\t\r\n" ()
shouldFailTest "spaces1 with no space" spaces1 "a"
// Mini template parser example
type TemplatePart =
| Text of string
| Value of string
let notOpenBracket : UParser<char> =
satisfy (fun c -> c <> char '{') "not open bracket"
let textParser : UParser<TemplatePart> =
many1 notOpenBracket
|>> (fun charList ->
charList
|> List.map string
|> String.concat ""
|> Text)
<?> "<text parser>"
let valueName : UParser<string> =
many1 (satisfy (fun c -> c <> '}' && (not <| System.Char.IsWhiteSpace c)) "")
|>> (fun charList -> charList |> List.map string |> String.concat "")
.>> spaces
let openValue : UParser<unit> =
pchar '{' .>>. spaces
|>> ignore
let closeValue : UParser<unit> =
pchar '}'
|>> ignore
let value : UParser<TemplatePart> =
between openValue closeValue valueName
|>> Value
<?> "<value parser>"
let template : UParser<TemplatePart list> =
many (value <|> textParser)
.>> eof
<?> "<template parser>"
test "mini template 1" template "hello world" [Text "hello world"]
test "mini template 2" template "hello { bob\n }" [Text "hello "; Value "bob"]
test "mini template 3" template "hello { name1 } and {name2}" [Text "hello "; Value "name1"; Text " and "; Value "name2"]
shouldFailTest "mini template 4" template "hello { name"