1
+
2
+ namespace ZMidi.Internal
3
+
4
+ module ParserMonad =
5
+
6
+ open System.IO
7
+
8
+ open ZMidi.Internal .Utils
9
+
10
+ /// Status is either OFF of the previous VoiceEvent * Channel.
11
+ type VoiceEvent =
12
+ | StatusOff
13
+ | NoteOn of byte
14
+ | NoteOff of byte
15
+ | NoteAftertoucuh of byte
16
+ | Control of byte
17
+ | Program of byte
18
+ | ChannelAftertouch of byte
19
+ | PitchBend of byte
20
+
21
+
22
+ type Pos = int
23
+
24
+ type ErrMsg = string
25
+
26
+ type State =
27
+ { Position: Pos
28
+ RunningStatus: VoiceEvent
29
+ }
30
+
31
+
32
+ type ParserMonad < 'a > =
33
+ private ParserMonad of ( byte [] -> State -> Result < 'a * State , ErrMsg > )
34
+
35
+ let inline private apply1 ( parser : ParserMonad < 'a >)
36
+ ( midiData : byte [])
37
+ ( state : State ) : Result < 'a * State , ErrMsg > =
38
+ let ( ParserMonad fn ) = parser in fn midiData state
39
+
40
+ let inline mreturn ( x : 'a ) : ParserMonad < 'a > =
41
+ ParserMonad <| fun _ st -> Ok ( x, st)
42
+
43
+ let inline private bindM ( parser : ParserMonad < 'a >)
44
+ ( next : 'a -> ParserMonad < 'b >) : ParserMonad < 'b > =
45
+ ParserMonad <| fun input state ->
46
+ match apply1 parser input state with
47
+ | Error msg -> Error msg
48
+ | Ok ( ans, st1) -> apply1 ( next ans) input st1
49
+
50
+ let mzero () : ParserMonad < 'a > =
51
+ ParserMonad <| fun _ _ -> Error " mzero"
52
+
53
+ let inline mplus ( parser1 : ParserMonad < 'a >) ( parser2 : ParserMonad < 'a >) : ParserMonad < 'a > =
54
+ ParserMonad <| fun input state ->
55
+ match apply1 parser1 input state with
56
+ | Error _ -> apply1 parser2 input state
57
+ | Ok res -> Ok res
58
+
59
+ let inline private delayM ( fn : unit -> ParserMonad < 'a >) : ParserMonad < 'a > =
60
+ bindM ( mreturn ()) fn
61
+
62
+
63
+ type ParserBuilder () =
64
+ member self.Return x = mreturn x
65
+ member self.Bind ( p , f ) = bindM p f
66
+ member self.Zero () = mzero ()
67
+ member self.Combine ( ma , mb ) = mplus ma mb
68
+ member self.ReturnFrom ( ma : ParserMonad < 'a >) : ParserMonad < 'a > = ma
69
+
70
+ let ( parseMidi : ParserBuilder ) = new ParserBuilder()
71
+
72
+ /// Run the parser on a file.
73
+ let runParseMidi ( ma : ParserMonad < 'a >) ( inputPath : string ) : Result < 'a , ErrMsg > =
74
+ use stream = File.Open( path = inputPath, mode = FileMode.Open, access = FileAccess.Read)
75
+ use memory = new MemoryStream()
76
+ stream.CopyTo( memory)
77
+ let input : byte [] = memory.ToArray()
78
+ match apply1 ma input { Position = 0 ; RunningStatus = StatusOff} with
79
+ | Ok ( ans, _) -> Ok ans
80
+ | Error msg -> Error msg
81
+
82
+ /// Throw a parse error
83
+ let parseError ( genMessage : Pos -> string ) : ParserMonad < 'a > =
84
+ ParserMonad <| fun _ st -> Error ( genMessage st.Position)
85
+
86
+ /// Run the parser, if it fails swap the error message.
87
+ let ( <??> ) ( parser : ParserMonad < 'a >) ( genMessage : Pos -> string ) : ParserMonad < 'a > =
88
+ ParserMonad <| fun input st ->
89
+ match apply1 parser input st with
90
+ | Ok result -> Ok result
91
+ | Error _ -> Error ( genMessage st.Position)
92
+
93
+
94
+ let getRunningEvent : ParserMonad < VoiceEvent > =
95
+ ParserMonad <| fun _ st -> Ok ( st.RunningStatus , st)
96
+
97
+ let setRunningEvent ( runningStatus : VoiceEvent ) : ParserMonad < unit > =
98
+ ParserMonad <| fun _ st -> Ok ((), { st with RunningStatus = runningStatus })
99
+
100
+ let getPos : ParserMonad < int > =
101
+ ParserMonad <| fun _ st -> Ok ( st.Position, st)
102
+
103
+ let peek : ParserMonad < byte > =
104
+ ParserMonad <| fun input st ->
105
+ try
106
+ let a1 = input.[ st.Position]
107
+ Ok ( a1, st)
108
+ with
109
+ | _ -> Error " peek - position error"
110
+
111
+ /// Conditionally get a byte (word8) . Fails if input is finished.
112
+ /// Consumes data on if predicate succeeds, does not consume if
113
+ /// predicate fails.
114
+ let cond ( test : byte -> bool ) : ParserMonad < byte option > =
115
+ ParserMonad <| fun input st ->
116
+ try
117
+ let a1 = input.[ st.Position]
118
+ if test a1 then
119
+ Ok ( Some a1, st)
120
+ else Ok ( None, st)
121
+ with
122
+ | _ -> Error " cond - position error"
123
+
124
+ let count ( length : int ) ( parser : ParserMonad < 'a >) : ParserMonad < 'a []> =
125
+ ParserMonad <| fun input state ->
126
+ let rec work ( i : int )
127
+ ( st : State )
128
+ ( fk : ErrMsg -> Result < 'a list * State , ErrMsg >)
129
+ ( sk : State -> 'a list -> Result < 'a list * State , ErrMsg >) =
130
+ if i <= 0 then
131
+ sk st []
132
+ else
133
+ match apply1 parser input st with
134
+ | Error msg -> fk msg
135
+ | Ok ( a1, st1) ->
136
+ work ( i-1 ) st1 fk ( fun st2 ac ->
137
+ sk st2 ( a1 :: ac))
138
+ work length state ( fun msg -> Error msg) ( fun st ac -> Ok ( ac, st))
139
+ |> Result.map ( fun ( ans , st ) -> ( List.toArray ans, st))
140
+
141
+
142
+ /// Drop a byte (word8)
143
+ let dropByte : ParserMonad < unit > =
144
+ ParserMonad <| fun input st ->
145
+ if st.Position < input.Length then
146
+ Ok ((), { st with Position = st.Position + 1 })
147
+ else
148
+ Error " dropByte - no more data"
149
+
150
+ /// Parse a byte (Word8).
151
+ let readByte : ParserMonad < byte >=
152
+ ParserMonad <| fun input st ->
153
+ try
154
+ let a1 = input.[ st.Position]
155
+ Ok ( a1, { st with Position = st.Position + 1 })
156
+
157
+ with
158
+ | _ -> Error ( sprintf " readByte - no more data at %i " st.Position)
159
+
160
+ /// Parse a single byte char.
161
+ let readChar : ParserMonad < char > =
162
+ parseMidi {
163
+ let! a = readByte
164
+ return ( char a)
165
+ }
166
+
167
+ /// Parse a string of the given length.
168
+ let readString ( length : int ) : ParserMonad < string > =
169
+ parseMidi {
170
+ let! arr = count length readChar
171
+ return ( System.String arr)
172
+ }
173
+ <??> sprintf " readString failed at %i "
174
+
175
+
176
+ // Parse a uint16 (big endian).
177
+ let readUint16be : ParserMonad < uint16 >=
178
+ parseMidi {
179
+ let! a = readByte
180
+ let! b = readByte
181
+ return uint16be a b
182
+ }
183
+ <??> sprintf " uint16be: failed at %i "
0 commit comments