Document and move tryParseBuild
This commit is contained in:
72
src/parser/builder_api.nim
Normal file
72
src/parser/builder_api.nim
Normal file
@@ -0,0 +1,72 @@
|
||||
import std/sugar
|
||||
import std/collections/sequtils
|
||||
import std/strformat
|
||||
import std/strutils
|
||||
import results
|
||||
import fusion/matching
|
||||
import ./parser_internals
|
||||
import ./parser_types
|
||||
|
||||
proc tryParseBuild*[T](
|
||||
builder: Builder[T],
|
||||
builderFns: seq[tuple[
|
||||
parserFn: Parser -> ParserResult,
|
||||
concatFn: (seq[ParserToken], seq[T]) -> seq[T],
|
||||
]],
|
||||
defaultBuilderFn: (seq[ParserToken]) -> seq[T],
|
||||
stopAtParserFn = newline,
|
||||
): BuilderResult[T] =
|
||||
## Parse remaining text in `builder` by going checking in the `builderFns` list for a sucessful `parserFn`.
|
||||
## The `ok` `parserFn` result will be merged into the `Builder[T].tree` by using the `concatFn`.
|
||||
## Otherwise continue taking any character until the `stopAtParserFn` condition is found.
|
||||
## Any non-matching tokens will be converted using the `defaultBuilderFn`.
|
||||
let (parser, tree) = builder
|
||||
|
||||
# Mutating accumulators
|
||||
var parserAcc: ParserResult = ParserResult.ok(parser)
|
||||
var builderAcc: Builder[T] = builder
|
||||
|
||||
while parserAcc.isOk() and parserAcc.flatMap(stopAtParserFn).isErr():
|
||||
# Empty the parser tokens as we want to seperate them for the next parser in the sequence
|
||||
let emptyParser = parserAcc.map(emptyTokens)
|
||||
|
||||
# Find the first matching parser and convert its tokens
|
||||
var found = false
|
||||
for builderFn in builderFns:
|
||||
let (parserFn, concatFn) = builderFn
|
||||
|
||||
let parseResult = emptyParser.flatMap(parserFn)
|
||||
if parseResult.isOk():
|
||||
let okParser = parseResult.unsafeGet()
|
||||
|
||||
# Convert all previous unmatched tokens via the `defaultBuilderTokens`
|
||||
let defaultBuilderTokens = parserAcc
|
||||
.foldTokens(
|
||||
onError = _ => newSeq[T](),
|
||||
onSuccess = defaultBuilderFn,
|
||||
)
|
||||
|
||||
found = true
|
||||
parserAcc = parseResult.map(emptyTokens)
|
||||
builderAcc = builder.initBuilder(
|
||||
okParser,
|
||||
concatFn(
|
||||
okParser.tokens,
|
||||
builderAcc[1] & defaultBuilderTokens,
|
||||
),
|
||||
)
|
||||
break
|
||||
|
||||
if not found:
|
||||
parserAcc = parserAcc.flatMap(anyCh)
|
||||
|
||||
let defaultBuilderTokens = parserAcc
|
||||
.foldTokens(
|
||||
onError = _ => newSeq[T](),
|
||||
onSuccess = defaultBuilderFn,
|
||||
)
|
||||
|
||||
BuilderResult[T].ok(builder.initBuilder(
|
||||
builderAcc[0],
|
||||
builderAcc[1] & defaultBuilderTokens,
|
||||
))
|
||||
Reference in New Issue
Block a user