Skip to content

Commit d73607f

Browse files
factorize EOF handling
1 parent 7124d62 commit d73607f

File tree

1 file changed

+39
-31
lines changed

1 file changed

+39
-31
lines changed

src/ZMidi/Internal/ParserMonad.fs

Lines changed: 39 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,22 @@ module ParserMonad =
1818
| ChannelAftertouch of byte
1919
| PitchBend of byte
2020

21+
22+
type MidiData = byte array
2123

2224
type Pos = int
2325

24-
type ErrMsg = string
25-
26+
type ErrMsg =
27+
| EOF of where: string
28+
| Other of error: string
2629
type State =
2730
{ Position: Pos
2831
RunningStatus: VoiceEvent
2932
}
3033

3134

3235
type ParserMonad<'a> =
33-
private ParserMonad of (byte [] -> State -> Result<'a * State, ErrMsg> )
36+
private ParserMonad of (MidiData -> State -> Result<'a * State, ErrMsg> )
3437

3538
let inline private apply1 (parser : ParserMonad<'a>)
3639
(midiData : byte[])
@@ -48,7 +51,7 @@ module ParserMonad =
4851
| Ok (ans, st1) -> apply1 (next ans) input st1
4952

5053
let mzero () : ParserMonad<'a> =
51-
ParserMonad <| fun _ _ -> Error "mzero"
54+
ParserMonad <| fun _ _ -> Error (EOF "mzero")
5255

5356
let inline mplus (parser1 : ParserMonad<'a>) (parser2 : ParserMonad<'a>) : ParserMonad<'a> =
5457
ParserMonad <| fun input state ->
@@ -81,14 +84,14 @@ module ParserMonad =
8184

8285
/// Throw a parse error
8386
let parseError (genMessage : Pos -> string) : ParserMonad<'a> =
84-
ParserMonad <| fun _ st -> Error (genMessage st.Position)
87+
ParserMonad <| fun _ st -> Error (Other (genMessage st.Position))
8588

8689
/// Run the parser, if it fails swap the error message.
8790
let ( <??> ) (parser : ParserMonad<'a>) (genMessage : Pos -> string) : ParserMonad<'a> =
8891
ParserMonad <| fun input st ->
8992
match apply1 parser input st with
9093
| Ok result -> Ok result
91-
| Error _ -> Error (genMessage st.Position)
94+
| Error _ -> Error (Other (genMessage st.Position))
9295

9396

9497
let getRunningEvent : ParserMonad<VoiceEvent> =
@@ -100,26 +103,37 @@ module ParserMonad =
100103
let getPos : ParserMonad<int> =
101104
ParserMonad <| fun _ st -> Ok (st.Position, st)
102105

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.
106+
let inline private (|PositionValid|PositionInvalid|) (input: MidiData, state: State) =
107+
if state.Position >= 0 && state.Position < input.Length then
108+
PositionValid
109+
else
110+
PositionInvalid
111+
112+
let inline private checkedParseM (name: string) (f: MidiData -> State -> Result<('a * State), ErrMsg>) =
113+
ParserMonad
114+
(fun input state ->
115+
try
116+
match input,state with
117+
| PositionValid -> f input state
118+
| PositionInvalid -> Error (EOF name)
119+
with
120+
| e -> Error (Other (sprintf "%A" e))
121+
)
122+
123+
let peek : ParserMonad<byte> =
124+
checkedParseM "peek" <|
125+
fun input st -> Ok (input.[st.Position], st)
126+
127+
/// Conditionally gets a byte (word8). Fails if input is finished.
112128
/// Consumes data on if predicate succeeds, does not consume if
113129
/// predicate fails.
114130
let cond (test : byte -> bool) : ParserMonad<byte option> =
115-
ParserMonad <| fun input st ->
116-
try
131+
checkedParseM "cond" <|
132+
fun input st ->
117133
let a1 = input.[st.Position]
118134
if test a1 then
119-
Ok (Some a1, st)
135+
Ok (Some a1, st)
120136
else Ok (None, st)
121-
with
122-
| _ -> Error "cond - position error"
123137

124138
let count (length : int) (parser : ParserMonad<'a>) : ParserMonad<'a []> =
125139
ParserMonad <| fun input state ->
@@ -141,22 +155,16 @@ module ParserMonad =
141155

142156
/// Drop a byte (word8)
143157
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"
158+
checkedParseM "dropByte" <|
159+
fun input st -> Ok ((), { st with Position = st.Position + 1 })
149160

150161
/// Parse a byte (Word8).
151162
let readByte : ParserMonad<byte>=
152-
ParserMonad <| fun input st ->
153-
try
163+
checkedParseM "dropByte" <|
164+
fun input st ->
154165
let a1 = input.[st.Position]
155166
Ok (a1, { st with Position = st.Position + 1 })
156-
157-
with
158-
| _ -> Error (sprintf "readByte - no more data at %i" st.Position)
159-
167+
160168
/// Parse a single byte char.
161169
let readChar : ParserMonad<char> =
162170
parseMidi {

0 commit comments

Comments
 (0)