-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathXmasListParser.fsx
115 lines (83 loc) · 2.77 KB
/
XmasListParser.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
#r "FParsec\\FParsecCS.dll"
#r "FParsec\\FParsec.dll"
open FParsec
module Domain =
type Behaviour = Naughty | Nice
type Gift = {
Gift: string
Quantity: int
}
type Child = {
Name: string
Behaviour: Behaviour
Gifts: Gift list
}
module Parser =
type Line =
| Child of string * Domain.Behaviour
| QuantifiedGift of string * int
| SingleGift of string
//Helper function for Whitespace around a single char.
let wsAround c =
spaces >>. skipChar c >>. spaces
let startOfGiftName = wsAround '-'
let pQuantifiedGift =
let endOfQty = wsAround '*'
let pGiftName =
startOfGiftName >>. manyCharsTill anyChar endOfQty
pGiftName .>>. pint32 |>> QuantifiedGift
let pSingleGift =
let allTillEOL = manyChars (noneOf "\n")
startOfGiftName >>. allTillEOL |>> SingleGift
let pChild =
let pName =
let endOfName = wsAround ':'
many1CharsTill anyChar endOfName |>> string
let pBehaviour =
(pstringCI "nice" >>% Domain.Nice)
<|>
(pstringCI "naughty" >>% Domain.Naughty)
pName .>>. pBehaviour |>> Child
let pLine =
attempt pQuantifiedGift
<|>
attempt pSingleGift
<|>
pChild
let parseInput input =
run (sepBy pLine newline) input
module Translation =
open Domain
open Parser
let foldLine line state =
let cList, gList = state
let addChild name behaviour =
{ Name = name; Behaviour = behaviour; Gifts = gList; } :: cList
let addGift name quantity =
{ Gift = name; Quantity = quantity; } :: gList
match line with
| Child (name, behaviour) -> addChild name behaviour, []
| SingleGift name -> cList, addGift name 1
| QuantifiedGift (name, quantity) -> cList, addGift name quantity
let mapLinesToDomain lines =
let initState = [],[]
let mapped =
match lines with
| Success (lines, _, _) -> Seq.foldBack foldLine lines initState
| Failure (err, _, _) -> failwith err
fst mapped
module Program =
open System.IO
let input = File.ReadAllText("examples.txt").Trim()
let nl = System.Environment.NewLine
let formatGifts (gifts : Domain.Gift list) =
gifts
|> Seq.map (fun gift -> sprintf "%s * %d" gift.Gift gift.Quantity)
|> String.concat nl
let printChild (child: Domain.Child) =
printfn "%s: %A%s%s" child.Name child.Behaviour nl (formatGifts child.Gifts)
let main() =
Parser.parseInput input
|> Translation.mapLinesToDomain
|> Seq.iter printChild
Program.main()