Document and move tryParseBuild
This commit is contained in:
@@ -8,6 +8,7 @@ import ./org_types
|
|||||||
import ../utils/fp
|
import ../utils/fp
|
||||||
import ../parser/parser_internals
|
import ../parser/parser_internals
|
||||||
import ../parser/parser_types
|
import ../parser/parser_types
|
||||||
|
import ../parser/builder_api
|
||||||
|
|
||||||
let parseBetweenDelimiter* = proc(start: (Parser -> ParserResult), stop: (Parser -> ParserResult)): (Parser -> ParserResult) {.closure.} =
|
let parseBetweenDelimiter* = proc(start: (Parser -> ParserResult), stop: (Parser -> ParserResult)): (Parser -> ParserResult) {.closure.} =
|
||||||
ignore(start) +
|
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 proc(parserTokens: seq[ParserToken], builderTokens: seq[OrgBuilderT]): seq[OrgBuilderT] =
|
||||||
return builderTokens & parserTokens.foldl(a & b.tokenStringValue(), "").orgTokenFn()
|
return builderTokens & parserTokens.foldl(a & b.tokenStringValue(), "").orgTokenFn()
|
||||||
|
|
||||||
proc parseText[T](
|
proc tryParseBuild[T](
|
||||||
builder: Builder[T],
|
builder: Builder[T],
|
||||||
builderFns: seq[tuple[
|
builderFns: seq[tuple[
|
||||||
parserFn: Parser -> ParserResult,
|
parserFn: Parser -> ParserResult,
|
||||||
@@ -149,7 +150,7 @@ when isMainModule:
|
|||||||
parser: initParser("Regular *bold* /italic/ _underline_ =verbatim= ~code~ +strikethrough+"),
|
parser: initParser("Regular *bold* /italic/ _underline_ =verbatim= ~code~ +strikethrough+"),
|
||||||
tree: newSeq[OrgBuilderT](),
|
tree: newSeq[OrgBuilderT](),
|
||||||
)))
|
)))
|
||||||
.flatMap((builder: OrgBuilder) => parseText(
|
.flatMap((builder: OrgBuilder) => tryParseBuild(
|
||||||
builder = builder,
|
builder = builder,
|
||||||
builderFns = @[
|
builderFns = @[
|
||||||
(boldParser, makeOrgToken(makeBoldToken)),
|
(boldParser, makeOrgToken(makeBoldToken)),
|
||||||
|
|||||||
@@ -4,7 +4,14 @@ type
|
|||||||
orgElementKind* = enum
|
orgElementKind* = enum
|
||||||
orgRawText,
|
orgRawText,
|
||||||
orgText,
|
orgText,
|
||||||
|
|
||||||
|
# Formating
|
||||||
orgBoldText,
|
orgBoldText,
|
||||||
|
orgItalicText,
|
||||||
|
orgUnderlineText,
|
||||||
|
orgVerbatimText,
|
||||||
|
orgCodeText,
|
||||||
|
orgStrikeThroughText,
|
||||||
OrgElement* = ref object
|
OrgElement* = ref object
|
||||||
children*: seq[OrgElement]
|
children*: seq[OrgElement]
|
||||||
content*: string
|
content*: string
|
||||||
@@ -12,13 +19,27 @@ type
|
|||||||
case kind*: orgElementKind
|
case kind*: orgElementKind
|
||||||
of orgRawText: discard
|
of orgRawText: discard
|
||||||
of orgText: discard
|
of orgText: discard
|
||||||
|
|
||||||
|
# Formating
|
||||||
of orgBoldText: discard
|
of orgBoldText: discard
|
||||||
|
of orgItalicText: discard
|
||||||
|
of orgUnderlineText: discard
|
||||||
|
of orgVerbatimText: discard
|
||||||
|
of orgCodeText: discard
|
||||||
|
of orgStrikeThroughText: discard
|
||||||
|
|
||||||
proc `$`*(x: orgElementKind): string =
|
proc `$`*(x: orgElementKind): string =
|
||||||
case x:
|
case x:
|
||||||
of orgRawText: "Text (Raw)"
|
of orgRawText: "Text (Raw)"
|
||||||
of orgText: "Text"
|
of orgText: "Text"
|
||||||
|
|
||||||
|
# Formating
|
||||||
of orgBoldText: "Text (Bold)"
|
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 =
|
proc `$`*(x: OrgElement): string =
|
||||||
&"""OrgElement(
|
&"""OrgElement(
|
||||||
|
|||||||
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