Document and move tryParseBuild

This commit is contained in:
Florian Schroedl
2022-01-20 17:00:00 +01:00
parent b1e4a36e36
commit c19dd096c3
3 changed files with 99 additions and 5 deletions

View File

@@ -8,6 +8,7 @@ import ./org_types
import ../utils/fp
import ../parser/parser_internals
import ../parser/parser_types
import ../parser/builder_api
let parseBetweenDelimiter* = proc(start: (Parser -> ParserResult), stop: (Parser -> ParserResult)): (Parser -> ParserResult) {.closure.} =
ignore(start) +
@@ -74,7 +75,7 @@ proc makeOrgToken*(orgTokenFn: string -> OrgBuilderT): (seq[ParserToken], seq[Or
return proc(parserTokens: seq[ParserToken], builderTokens: seq[OrgBuilderT]): seq[OrgBuilderT] =
return builderTokens & parserTokens.foldl(a & b.tokenStringValue(), "").orgTokenFn()
proc parseText[T](
proc tryParseBuild[T](
builder: Builder[T],
builderFns: seq[tuple[
parserFn: Parser -> ParserResult,
@@ -149,7 +150,7 @@ when isMainModule:
parser: initParser("Regular *bold* /italic/ _underline_ =verbatim= ~code~ +strikethrough+"),
tree: newSeq[OrgBuilderT](),
)))
.flatMap((builder: OrgBuilder) => parseText(
.flatMap((builder: OrgBuilder) => tryParseBuild(
builder = builder,
builderFns = @[
(boldParser, makeOrgToken(makeBoldToken)),

View File

@@ -4,7 +4,14 @@ type
orgElementKind* = enum
orgRawText,
orgText,
# Formating
orgBoldText,
orgItalicText,
orgUnderlineText,
orgVerbatimText,
orgCodeText,
orgStrikeThroughText,
OrgElement* = ref object
children*: seq[OrgElement]
content*: string
@@ -12,13 +19,27 @@ type
case kind*: orgElementKind
of orgRawText: discard
of orgText: discard
# Formating
of orgBoldText: discard
of orgItalicText: discard
of orgUnderlineText: discard
of orgVerbatimText: discard
of orgCodeText: discard
of orgStrikeThroughText: discard
proc `$`*(x: orgElementKind): string =
case x:
of orgRawText: "Text (Raw)"
of orgText: "Text"
of orgBoldText: "Text (Bold)"
of orgRawText: "Text (Raw)"
of orgText: "Text"
# Formating
of orgBoldText: "Text (Bold)"
of orgItalicText: "Text (Italic)"
of orgUnderlineText: "Text (Underline)"
of orgVerbatimText: "Text (Verbatim)"
of orgCodeText: "Text (Code)"
of orgStrikeThroughText: "Text (StrikeThrough)"
proc `$`*(x: OrgElement): string =
&"""OrgElement(

View 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,
))