Build text parser
This commit is contained in:
17
src/org/org_builder.nim
Normal file
17
src/org/org_builder.nim
Normal file
@@ -0,0 +1,17 @@
|
||||
import ./org_types
|
||||
import ../parser/parser_types
|
||||
|
||||
type OrgBuilderT* = seq[OrgElement]
|
||||
type StringBuilder* = Builder[OrgBuilderT]
|
||||
type OrgBuilderResult* = BuilderResult[OrgBuilderT]
|
||||
|
||||
proc concat*(typeInfo: OrgBuilderT): (seq[ParserToken], seq[OrgBuilderT]) -> seq[OrgBuilderT] =
|
||||
return proc(xs: seq[ParserToken], ys: seq[OrgBuilderT]): seq[OrgBuilderT] =
|
||||
return ys & xs.foldl(a & b.tokenStringValue() & seperator, typeInfo)
|
||||
|
||||
proc initStringBuilder*(str: string): StringBuilderResult =
|
||||
StringBuilderResult
|
||||
.ok(StringBuilder((
|
||||
parser: initParser(str),
|
||||
tree: newSeq[OrgBuilderT](),
|
||||
)))
|
||||
@@ -1,12 +1,16 @@
|
||||
import std/sugar
|
||||
import std/collections/sequtils
|
||||
import results
|
||||
import fusion/matching
|
||||
import ./org_types
|
||||
import ../utils/fp
|
||||
import ../parser/parser_internals
|
||||
import ../parser/parser_types
|
||||
|
||||
let parseBetweenDelimiter* = proc(delimiterParser: (Parser -> ParserResult)): (Parser -> ParserResult) {.closure.} =
|
||||
ignore(delimiterParser) + anyUntil(delimiterParser + whitespace) + ignore(delimiterParser)
|
||||
ignore(delimiterParser) +
|
||||
anyUntil(delimiterParser + whitespace) +
|
||||
ignore(delimiterParser)
|
||||
|
||||
let boldParser* = parseBetweenDelimiter(ch('*'))
|
||||
let italicParser* = parseBetweenDelimiter(ch('/'))
|
||||
@@ -15,5 +19,71 @@ let verbatimParser* = parseBetweenDelimiter(ch('='))
|
||||
let codeParser* = parseBetweenDelimiter(ch('~'))
|
||||
let strikeThroughParser* = parseBetweenDelimiter(ch('+'))
|
||||
|
||||
echo initParser("""_foo bar *_
|
||||
""").underlinedParser()
|
||||
|
||||
# until parser != delimiterparser
|
||||
# takeChar and save to current parser
|
||||
# else:
|
||||
# saveTokens to new text block
|
||||
# saveBlock delimiterparser
|
||||
|
||||
# let delimiterParser* = anyUntil(choice(@[
|
||||
# boldParser,
|
||||
# italicParser,
|
||||
# underlinedParser,
|
||||
# verbatimParser,
|
||||
# codeParser,
|
||||
# strikeThroughParser,
|
||||
# ]), newline)
|
||||
|
||||
|
||||
type OrgBuilderT* = OrgElement
|
||||
type OrgBuilder* = Builder[OrgBuilderT]
|
||||
type OrgBuilderResult* = BuilderResult[OrgBuilderT]
|
||||
|
||||
proc makeBoldTokens*(content: string): OrgBuilderT =
|
||||
OrgBuilderT(
|
||||
kind: orgBoldText,
|
||||
content: content,
|
||||
)
|
||||
|
||||
proc makeOrgToken*(orgTokenFn: string -> OrgBuilderT): (seq[ParserToken], seq[OrgBuilderT]) -> seq[OrgBuilderT] =
|
||||
return proc(parserTokens: seq[ParserToken], builderTokens: seq[OrgBuilderT]): seq[OrgBuilderT] =
|
||||
return builderTokens & parserTokens.foldl(a & b.tokenStringValue(), "").orgTokenFn()
|
||||
|
||||
proc textParser[T](
|
||||
builder: Builder[T],
|
||||
builderFns: seq[tuple[
|
||||
parserFn: Parser -> ParserResult,
|
||||
tokenFoldFn: (seq[ParserToken], seq[T]) -> seq[T],
|
||||
]],
|
||||
stopFn = newline,
|
||||
): BuilderResult[T] =
|
||||
let (parser, tree) = builder
|
||||
|
||||
var parserAcc: ParserResult = parser.ok()
|
||||
var builderAcc: Builder = builder
|
||||
|
||||
while parser.isOk() and parserAcc.flatMap(stopFn).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 it's tokens
|
||||
# Otherwise leave the raw tokens
|
||||
var found = false
|
||||
for builderFn in builderFns:
|
||||
let (parserFn, tokenFoldFn) = builderFn
|
||||
let parseResult = emptyParser.flatMap(parserFn)
|
||||
|
||||
if parseResult.isOk():
|
||||
let okParser = parseResult.unsafeGet()
|
||||
|
||||
found = true
|
||||
parserAcc = parseResult
|
||||
builderAcc = builder.initBuilder(
|
||||
okParser,
|
||||
tokenFoldFn(okParser.tokens, builderAcc[1]),
|
||||
)
|
||||
break
|
||||
|
||||
if not found:
|
||||
parserAcc = parserAcc.flatMap(anyCh)
|
||||
|
||||
13
src/org/org_types.nim
Normal file
13
src/org/org_types.nim
Normal file
@@ -0,0 +1,13 @@
|
||||
type
|
||||
orgElementKind* = enum
|
||||
orgRawText,
|
||||
orgText,
|
||||
orgBoldText,
|
||||
OrgElement* = ref object
|
||||
children*: seq[OrgElement]
|
||||
content*: string
|
||||
|
||||
case kind*: orgElementKind
|
||||
of orgRawText: discard
|
||||
of orgText: discard
|
||||
of orgBoldText: discard
|
||||
@@ -78,6 +78,8 @@ func ch*(expectedChar: char): (Parser -> ParserResult) {.inline.} =
|
||||
parser: parser,
|
||||
))
|
||||
|
||||
let anyCh* = ch(AllChars)
|
||||
|
||||
func str*(s: string): (Parser -> ParserResult) {.inline.} =
|
||||
return func(parser: Parser): ParserResult =
|
||||
var p = parser.ok()
|
||||
@@ -115,8 +117,8 @@ func manyUntil*(acceptFn: Parser -> ParserResult, stopFn: Parser -> ParserResult
|
||||
res = res.flatMap(acceptFn)
|
||||
return res
|
||||
|
||||
func anyUntil*(stopFn: Parser -> ParserResult): (Parser -> ParserResult) {.inline.} =
|
||||
manyUntil(ch(AllChars), stopFn)
|
||||
proc anyUntil*(stopFn: Parser -> ParserResult): (Parser -> ParserResult) {.inline.} =
|
||||
manyUntil(anyCh, stopFn)
|
||||
|
||||
func choice*(parsers: seq[Parser -> ParserResult]): (Parser -> ParserResult) {.inline.} =
|
||||
return proc(parser: Parser): ParserResult =
|
||||
|
||||
@@ -155,6 +155,7 @@ proc applyParsersSeq*[T](
|
||||
]]): BuilderResult[T] =
|
||||
xs.foldl(a.flatMap((x: Builder[T]) => x.applyParsers(b[0], b[1])), builder)
|
||||
|
||||
|
||||
proc foldBuilder*[T, T2](
|
||||
builderResult: BuilderResult[T],
|
||||
onError: string -> T2,
|
||||
|
||||
@@ -19,3 +19,13 @@ proc initStringBuilder*(str: string): StringBuilderResult =
|
||||
parser: initParser(str),
|
||||
tree: newSeq[StringBuilderT](),
|
||||
)))
|
||||
|
||||
proc fold*[T, E, T2](
|
||||
self: Result[T, E],
|
||||
onError: E -> T2,
|
||||
onSuccess: T -> T2,
|
||||
): T2 =
|
||||
if self.isOk():
|
||||
onSuccess(self.unsafeGet())
|
||||
else:
|
||||
onError(self.error())
|
||||
|
||||
0
tests/parser/parser_internals.nim
Normal file
0
tests/parser/parser_internals.nim
Normal file
8
tests/parser/test_parser_internals.nim
Normal file
8
tests/parser/test_parser_internals.nim
Normal file
@@ -0,0 +1,8 @@
|
||||
import unittest
|
||||
import parser/parser_internals
|
||||
import parser/parser_types
|
||||
|
||||
suite "parser/parser_internals":
|
||||
test "whitespace":
|
||||
|
||||
echo whitespace(initParser(" ")) == ParserResult.ok(Parser())
|
||||
Reference in New Issue
Block a user