@@ -18,19 +18,22 @@ module ParserMonad =
18
18
| ChannelAftertouch of byte
19
19
| PitchBend of byte
20
20
21
+
22
+ type MidiData = byte array
21
23
22
24
type Pos = int
23
25
24
- type ErrMsg = string
25
-
26
+ type ErrMsg =
27
+ | EOF of where : string
28
+ | Other of error : string
26
29
type State =
27
30
{ Position: Pos
28
31
RunningStatus: VoiceEvent
29
32
}
30
33
31
34
32
35
type ParserMonad < 'a > =
33
- private ParserMonad of ( byte [] -> State -> Result < 'a * State , ErrMsg > )
36
+ private ParserMonad of ( MidiData -> State -> Result < 'a * State , ErrMsg > )
34
37
35
38
let inline private apply1 ( parser : ParserMonad < 'a >)
36
39
( midiData : byte [])
@@ -48,7 +51,7 @@ module ParserMonad =
48
51
| Ok ( ans, st1) -> apply1 ( next ans) input st1
49
52
50
53
let mzero () : ParserMonad < 'a > =
51
- ParserMonad <| fun _ _ -> Error " mzero"
54
+ ParserMonad <| fun _ _ -> Error ( EOF " mzero" )
52
55
53
56
let inline mplus ( parser1 : ParserMonad < 'a >) ( parser2 : ParserMonad < 'a >) : ParserMonad < 'a > =
54
57
ParserMonad <| fun input state ->
@@ -81,14 +84,14 @@ module ParserMonad =
81
84
82
85
/// Throw a parse error
83
86
let parseError ( genMessage : Pos -> string ) : ParserMonad < 'a > =
84
- ParserMonad <| fun _ st -> Error ( genMessage st.Position)
87
+ ParserMonad <| fun _ st -> Error ( Other ( genMessage st.Position) )
85
88
86
89
/// Run the parser, if it fails swap the error message.
87
90
let ( <??> ) ( parser : ParserMonad < 'a >) ( genMessage : Pos -> string ) : ParserMonad < 'a > =
88
91
ParserMonad <| fun input st ->
89
92
match apply1 parser input st with
90
93
| Ok result -> Ok result
91
- | Error _ -> Error ( genMessage st.Position)
94
+ | Error _ -> Error ( Other ( genMessage st.Position) )
92
95
93
96
94
97
let getRunningEvent : ParserMonad < VoiceEvent > =
@@ -100,26 +103,37 @@ module ParserMonad =
100
103
let getPos : ParserMonad < int > =
101
104
ParserMonad <| fun _ st -> Ok ( st.Position, st)
102
105
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.
112
128
/// Consumes data on if predicate succeeds, does not consume if
113
129
/// predicate fails.
114
130
let cond ( test : byte -> bool ) : ParserMonad < byte option > =
115
- ParserMonad <| fun input st ->
116
- try
131
+ checkedParseM " cond " <|
132
+ fun input st ->
117
133
let a1 = input.[ st.Position]
118
134
if test a1 then
119
- Ok ( Some a1, st)
135
+ Ok ( Some a1, st)
120
136
else Ok ( None, st)
121
- with
122
- | _ -> Error " cond - position error"
123
137
124
138
let count ( length : int ) ( parser : ParserMonad < 'a >) : ParserMonad < 'a []> =
125
139
ParserMonad <| fun input state ->
@@ -141,22 +155,16 @@ module ParserMonad =
141
155
142
156
/// Drop a byte (word8)
143
157
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 })
149
160
150
161
/// Parse a byte (Word8).
151
162
let readByte : ParserMonad < byte >=
152
- ParserMonad <| fun input st ->
153
- try
163
+ checkedParseM " dropByte " <|
164
+ fun input st ->
154
165
let a1 = input.[ st.Position]
155
166
Ok ( a1, { st with Position = st.Position + 1 })
156
-
157
- with
158
- | _ -> Error ( sprintf " readByte - no more data at %i " st.Position)
159
-
167
+
160
168
/// Parse a single byte char.
161
169
let readChar : ParserMonad < char > =
162
170
parseMidi {
0 commit comments