@@ -26,18 +26,20 @@ module ParserMonad =
26
26
type ErrMsg =
27
27
| EOF of where : string
28
28
| Other of error : string
29
+
29
30
type State =
30
31
{ Position: Pos
31
32
RunningStatus: VoiceEvent
32
33
}
33
34
35
+ type ParseError = ParseError of position : Pos * message : ErrMsg
34
36
35
37
type ParserMonad < 'a > =
36
- private ParserMonad of ( MidiData -> State -> Result < 'a * State , ErrMsg > )
38
+ ParserMonad of ( MidiData -> State -> Result < 'a * State , ParseError > )
37
39
38
40
let inline private apply1 ( parser : ParserMonad < 'a >)
39
41
( midiData : byte [])
40
- ( state : State ) : Result < 'a * State , ErrMsg > =
42
+ ( state : State ) : Result < 'a * State , ParseError > =
41
43
let ( ParserMonad fn ) = parser in fn midiData state
42
44
43
45
let inline mreturn ( x : 'a ) : ParserMonad < 'a > =
@@ -51,7 +53,7 @@ module ParserMonad =
51
53
| Ok ( ans, st1) -> apply1 ( next ans) input st1
52
54
53
55
let mzero () : ParserMonad < 'a > =
54
- ParserMonad <| fun _ _ -> Error ( EOF " mzero" )
56
+ ParserMonad <| fun _ state -> Error ( ParseError ( state.Position , EOF " mzero" ) )
55
57
56
58
let inline mplus ( parser1 : ParserMonad < 'a >) ( parser2 : ParserMonad < 'a >) : ParserMonad < 'a > =
57
59
ParserMonad <| fun input state ->
@@ -73,7 +75,7 @@ module ParserMonad =
73
75
let ( parseMidi : ParserBuilder ) = new ParserBuilder()
74
76
75
77
/// Run the parser on a file.
76
- let runParseMidi ( ma : ParserMonad < 'a >) ( inputPath : string ) : Result < 'a , ErrMsg > =
78
+ let runParseMidi ( ma : ParserMonad < 'a >) ( inputPath : string ) : Result < 'a , ParseError > =
77
79
use stream = File.Open( path = inputPath, mode = FileMode.Open, access = FileAccess.Read)
78
80
use memory = new MemoryStream()
79
81
stream.CopyTo( memory)
@@ -84,15 +86,17 @@ module ParserMonad =
84
86
85
87
/// Throw a parse error
86
88
let parseError ( genMessage : Pos -> string ) : ParserMonad < 'a > =
87
- ParserMonad <| fun _ st -> Error ( Other ( genMessage st.Position))
89
+ ParserMonad <| fun _ st -> Error ( ParseError ( st.Position , Other ( genMessage st.Position) ))
88
90
89
91
/// Run the parser, if it fails swap the error message.
90
92
let ( <??> ) ( parser : ParserMonad < 'a >) ( genMessage : Pos -> string ) : ParserMonad < 'a > =
91
93
ParserMonad <| fun input st ->
92
94
match apply1 parser input st with
93
95
| Ok result -> Ok result
94
- | Error _ -> Error ( Other ( genMessage st.Position))
96
+ | Error _ -> Error ( ParseError ( st.Position , Other ( genMessage st.Position) ))
95
97
98
+ let fatalError err =
99
+ ParserMonad <| fun _ st -> Error ( ParseError( st.Position, err))
96
100
97
101
let getRunningEvent : ParserMonad < VoiceEvent > =
98
102
ParserMonad <| fun _ st -> Ok ( st.RunningStatus , st)
@@ -109,16 +113,16 @@ module ParserMonad =
109
113
else
110
114
PositionInvalid
111
115
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
- )
116
+ let inline private checkedParseM ( name : string ) ( f : MidiData -> State -> Result <( 'a * State ), ParseError >) =
117
+ ParserMonad
118
+ ( fun input state ->
119
+ try
120
+ match input, state with
121
+ | PositionValid -> f input state
122
+ | PositionInvalid -> Error ( ParseError ( state.Position , EOF name) )
123
+ with
124
+ | e -> Error ( ParseError ( state.Position , ( Other ( sprintf " %A " e)) ))
125
+ )
122
126
123
127
let peek : ParserMonad < byte > =
124
128
checkedParseM " peek" <|
@@ -141,8 +145,8 @@ module ParserMonad =
141
145
ParserMonad <| fun input state ->
142
146
let rec work ( i : int )
143
147
( st : State )
144
- ( fk : ErrMsg -> Result < 'a list * State , ErrMsg >)
145
- ( sk : State -> 'a list -> Result < 'a list * State , ErrMsg >) =
148
+ ( fk : ParseError -> Result < 'a list * State , ParseError >)
149
+ ( sk : State -> 'a list -> Result < 'a list * State , ParseError >) =
146
150
if i <= 0 then
147
151
sk st []
148
152
else
@@ -154,7 +158,7 @@ module ParserMonad =
154
158
work length state ( fun msg -> Error msg) ( fun st ac -> Ok ( ac, st))
155
159
|> Result.map ( fun ( ans , st ) -> ( List.toArray ans, st))
156
160
157
- /// Drop a byte (word8)
161
+ /// Drop a byte (word8).
158
162
let dropByte : ParserMonad < unit > =
159
163
checkedParseM " dropByte" <|
160
164
fun input st -> Ok ((), { st with Position = st.Position + 1 })
@@ -181,20 +185,30 @@ module ParserMonad =
181
185
}
182
186
<??> sprintf " readString failed at %i "
183
187
184
-
185
188
// Parse a uint16 (big endian).
186
- let readUint16be : ParserMonad < uint16 >=
189
+ let readUInt16be : ParserMonad < uint16 >=
187
190
parseMidi {
188
191
let! a = readByte
189
192
let! b = readByte
190
- return uint16be a b
193
+ return word16be a b
191
194
}
192
195
<??> sprintf " uint16be: failed at %i "
193
196
197
+ // Parse a word14 (big endian) from 2 consecutive bytes.
194
198
let readWord14be =
195
199
parseMidi {
196
200
let! a = readByte
197
201
let! b = readByte
198
202
return ( word14be a b)
199
203
}
200
- <??> sprintf " word14be: failed at %i "
204
+ <??> sprintf " word14be: failed at %i "
205
+
206
+ // Parse a word32 (big endian).
207
+ let readUInt32be =
208
+ parseMidi {
209
+ let! a = readByte
210
+ let! b = readByte
211
+ let! c = readByte
212
+ let! d = readByte
213
+ return ( word32be a b c d)
214
+ }
0 commit comments