Skip to content

Commit d0f7017

Browse files
stephentetleysmoothdeveloper
authored andcommitted
ParserMonad - reimplemented boundRepeat in 2CPS.
1 parent 44367b8 commit d0f7017

File tree

2 files changed

+34
-54
lines changed

2 files changed

+34
-54
lines changed

src/ZMidi/Internal/ParserMonad.fs

Lines changed: 30 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,16 @@ module ParserMonad =
195195
let parseError (genMessage : Pos -> string) : ParserMonad<'a> =
196196
ParserMonad <| fun _ st -> Error (mkOtherParseError st genMessage)
197197

198+
let fmapM (modify: 'a -> 'b) (parser : ParserMonad<'a>) : ParserMonad<'b> =
199+
ParserMonad <| fun input state ->
200+
match apply1 parser input state with
201+
| Error err -> Error err
202+
| Ok (a, st2) -> Ok (modify a, st2)
203+
204+
/// Operator for fmapM
205+
let ( <<| ) (modify: 'a -> 'b) (parser : ParserMonad<'a>) : ParserMonad<'b> =
206+
fmapM modify parser
207+
198208
/// Run the parser, if it fails swap the error message.
199209
let inline ( <??> ) (parser : ParserMonad<'a>) (genMessage : Pos -> string) : ParserMonad<'a> =
200210
ParserMonad <| fun input st ->
@@ -301,66 +311,32 @@ module ParserMonad =
301311
work length state (fun msg -> Error msg) (fun st ac -> Ok (ac, st))
302312
|> Result.map (fun (ans, st) -> (List.toArray ans, st))
303313

304-
305314
/// Run a parser within a bounded section of the input stream.
306-
let repeatTillPosition (maxPosition: Pos) (p: ParserMonad<'a>) : ParserMonad<'a array> =
307-
ParserMonad(fun data state ->
308-
let results = ResizeArray()
309-
let mutable firstError = Ok (Array.empty, state)
310-
let mutable lastState = state
311-
let rec loop () =
312-
if lastState.Position < int maxPosition then
313-
match apply1 p data lastState with
314-
| Ok (result, state) ->
315-
lastState <- state
316-
results.Add result
317-
loop ()
318-
| Error e ->
319-
firstError <- Error e
320-
321-
loop ()
322-
match firstError with
323-
| Ok _ ->
324-
Ok(results.ToArray(), lastState)
325-
| Error _ ->
326-
firstError
327-
)
328-
329-
let inline boundRepeat (n: ^T) (p: ParserMonad<'a>) : ParserMonad<'a array> =
330-
ParserMonad(fun data state ->
331-
let result = Array.zeroCreate (int n)
332-
let mutable lastState = state
333-
// revisit with a fold?
334-
let mutable error = Ok (Unchecked.defaultof<_>,lastState)
335-
let mutable i = LanguagePrimitives.GenericZero
336-
let mutable errorOccured = false
337-
logf "bound repeat %i" n
338-
339-
while i < n && not errorOccured do
340-
logf "bound repeat %i/%i" i n
341-
342-
match apply1 p data lastState with
343-
| Ok (item,state) ->
344-
lastState <- state
345-
result.[int i] <- item
346-
| (Error e) ->
347-
error <- Error e
348-
errorOccured <- true
349-
i <- i + LanguagePrimitives.GenericOne
350-
if errorOccured then
351-
error
352-
else
353-
Ok (result, lastState)
354-
)
315+
let repeatTillPosition (maxPosition: Pos) (parser: ParserMonad<'a>) : ParserMonad<'a array> =
316+
ParserMonad <| fun input state ->
317+
let limit = maxPosition
318+
let rec work (st : State)
319+
(fk : ParseError -> Result<'a list * State, ParseError>)
320+
(sk : State -> 'a list -> Result<'a list * State, ParseError>) =
321+
match apply1 parser input st with
322+
| Error a -> fk a
323+
| Ok(a1, st1) ->
324+
match compare st1.Position limit with
325+
| 0 -> sk st1 [a1]
326+
| t when t > 0 -> fk (ParseError(st1.Position, Other "repeatTillPosition - too far"))
327+
| _ ->
328+
work st1 fk (fun st2 ac ->
329+
sk st2 (a1 :: ac))
330+
work state (fun msg -> Error msg) (fun st ac -> Ok (ac, st))
331+
|> Result.map (fun (ans, st) -> (List.toArray ans, st))
355332

356333
/// Apply the parser for /count/ times, derive the final answer
357334
/// from the intermediate list with the supplied function.
358335
let inline gencount (plen: ParserMonad<'T>) (p: ParserMonad<'a>) (constr: ^T -> 'a array -> 'answer) : ParserMonad<'answer> =
359336
parseMidi {
360-
let! l = plen
361-
logf "gen count: l: %i" l
362-
let! items = boundRepeat l p
363-
return constr l items
337+
let! times = plen
338+
let! arr = count (int times) p
339+
return (constr times arr)
364340
}
365341

366342
/// Drop a byte (word8).

src/ZMidi/zmidi-fs-core.fsproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
<DocumentationFile>bin\$(Configuration)\$(TargetFramework)\zmidi-fs-core.XML</DocumentationFile>
88
</PropertyGroup>
99

10+
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netstandard2.0|AnyCPU'">
11+
<Tailcalls>true</Tailcalls>
12+
</PropertyGroup>
13+
1014
<ItemGroup>
1115
<Compile Include="DataTypes.fs" />
1216
<Compile Include="ExtraTypes.fs" />

0 commit comments

Comments
 (0)