Restructure
This commit is contained in:
@@ -12,6 +12,8 @@ import ../utils/str
|
|||||||
|
|
||||||
{.experimental: "caseStmtMacros".}
|
{.experimental: "caseStmtMacros".}
|
||||||
|
|
||||||
|
# -- Parsing Functions
|
||||||
|
|
||||||
func ch*(expectedChars: set[char]): (Parser -> ParserResult) {.inline.} =
|
func ch*(expectedChars: set[char]): (Parser -> ParserResult) {.inline.} =
|
||||||
return func(parser: Parser): ParserResult =
|
return func(parser: Parser): ParserResult =
|
||||||
let state = parser.state
|
let state = parser.state
|
||||||
@@ -84,46 +86,7 @@ func str*(s: string): (Parser -> ParserResult) {.inline.} =
|
|||||||
return p
|
return p
|
||||||
|
|
||||||
|
|
||||||
proc endOfStream*(parser: Parser): ParserResult =
|
# -- Parsing Helper Functions
|
||||||
let index = parser.state.position + 1
|
|
||||||
if index == parser.state.stream.len:
|
|
||||||
ok(parser)
|
|
||||||
else:
|
|
||||||
err(ParserError(
|
|
||||||
kind: endOfStringErr,
|
|
||||||
expected: &"EndOfString",
|
|
||||||
index: index,
|
|
||||||
parser: parser,
|
|
||||||
))
|
|
||||||
|
|
||||||
func ignore*(parserFn: Parser -> ParserResult): (Parser -> ParserResult) {.inline.} =
|
|
||||||
## Parse characters but throw success tokens away
|
|
||||||
return proc(parser: Parser): ParserResult =
|
|
||||||
return parserFn(parser)
|
|
||||||
.map((x: Parser) => Parser(
|
|
||||||
state: x.state,
|
|
||||||
tokens: parser.tokens,
|
|
||||||
))
|
|
||||||
|
|
||||||
|
|
||||||
func flattenParserTokens*(parser: Parser): ParserResult =
|
|
||||||
return ParserResult.ok(
|
|
||||||
Parser(
|
|
||||||
state: parser.state,
|
|
||||||
tokens: @[
|
|
||||||
ParserToken(
|
|
||||||
kind: parserTokenString,
|
|
||||||
stringValue: parser.tokens.foldl(a & b.tokenStringValue(), "")
|
|
||||||
)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
func emptyTokens*(parser: Parser): Parser =
|
|
||||||
Parser(
|
|
||||||
state: parser.state,
|
|
||||||
tokens: newSeq[ParserToken](),
|
|
||||||
)
|
|
||||||
|
|
||||||
func optional*(parserFn: Parser -> ParserResult): (Parser -> ParserResult) {.inline.} =
|
func optional*(parserFn: Parser -> ParserResult): (Parser -> ParserResult) {.inline.} =
|
||||||
## Parse characters and ignore failure
|
## Parse characters and ignore failure
|
||||||
@@ -135,6 +98,15 @@ func optional*(parserFn: Parser -> ParserResult): (Parser -> ParserResult) {.inl
|
|||||||
else:
|
else:
|
||||||
parser.ok()
|
parser.ok()
|
||||||
|
|
||||||
|
func ignore*(parserFn: Parser -> ParserResult): (Parser -> ParserResult) {.inline.} =
|
||||||
|
## Parse characters but throw success tokens away
|
||||||
|
return proc(parser: Parser): ParserResult =
|
||||||
|
return parserFn(parser)
|
||||||
|
.map((x: Parser) => Parser(
|
||||||
|
state: x.state,
|
||||||
|
tokens: parser.tokens,
|
||||||
|
))
|
||||||
|
|
||||||
func manyUntil*(acceptFn: Parser -> ParserResult, stopFn: Parser -> ParserResult): (Parser -> ParserResult) {.inline.} =
|
func manyUntil*(acceptFn: Parser -> ParserResult, stopFn: Parser -> ParserResult): (Parser -> ParserResult) {.inline.} =
|
||||||
## Parse characters but throw success tokens away
|
## Parse characters but throw success tokens away
|
||||||
return proc(parser: Parser): ParserResult =
|
return proc(parser: Parser): ParserResult =
|
||||||
@@ -174,19 +146,28 @@ func choice*(parsers: seq[Parser -> ParserResult]): (Parser -> ParserResult) {.i
|
|||||||
proc(x: ParserResult): ParserResult = x,
|
proc(x: ParserResult): ParserResult = x,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
proc `+`*(parserFnA: Parser -> ParserResult, parserFnB: Parser -> ParserResult): (Parser -> ParserResult) {.inline.} =
|
proc `+`*(parserFnA: Parser -> ParserResult, parserFnB: Parser -> ParserResult): (Parser -> ParserResult) {.inline.} =
|
||||||
## Parse characters and ignore failure
|
## Parse characters and ignore failure
|
||||||
return proc(parser: Parser): ParserResult =
|
return proc(parser: Parser): ParserResult =
|
||||||
parserFnA(parser).flatMap(parserFnB)
|
parserFnA(parser).flatMap(parserFnB)
|
||||||
|
|
||||||
proc setErrorExpectedField(err: ParserError, expected: string): ParserError =
|
proc parseSeq*(parser: ParserResult, xs: seq[Parser -> ParserResult]): ParserResult =
|
||||||
ParserError(
|
xs.foldl(a.flatMap(b), parser)
|
||||||
kind: err.kind,
|
|
||||||
unexpected: err.unexpected,
|
# -- Parsing Aliases
|
||||||
expected: expected,
|
|
||||||
index: err.index,
|
proc endOfStream*(parser: Parser): ParserResult =
|
||||||
parser: err.parser,
|
let index = parser.state.position + 1
|
||||||
)
|
if index == parser.state.stream.len:
|
||||||
|
ok(parser)
|
||||||
|
else:
|
||||||
|
err(ParserError(
|
||||||
|
kind: endOfStringErr,
|
||||||
|
expected: &"EndOfString",
|
||||||
|
index: index,
|
||||||
|
parser: parser,
|
||||||
|
))
|
||||||
|
|
||||||
let newlineParser = choice(@[
|
let newlineParser = choice(@[
|
||||||
ch(NewLines),
|
ch(NewLines),
|
||||||
@@ -196,99 +177,34 @@ proc newline*(parser: Parser): ParserResult =
|
|||||||
newlineParser(parser)
|
newlineParser(parser)
|
||||||
.mapErr((x: ParserError) => x.setErrorExpectedField("Newline"))
|
.mapErr((x: ParserError) => x.setErrorExpectedField("Newline"))
|
||||||
|
|
||||||
proc parseSeq*(parser: ParserResult, xs: seq[Parser -> ParserResult]): ParserResult =
|
|
||||||
xs.foldl(a.flatMap(b), parser)
|
|
||||||
|
|
||||||
proc foldTokens*[T](
|
# when isMainModule:
|
||||||
parserResult: ParserResult,
|
# proc getTokens(x: ParserResult): seq[string] =
|
||||||
onError: ParserError -> T,
|
# x.foldTokens(
|
||||||
onSuccess: seq[ParserToken] -> T,
|
# proc(err: ParserError): seq[string] =
|
||||||
): T =
|
# echo err
|
||||||
if parserResult.isOk():
|
# @[],
|
||||||
onSuccess(parserResult.unsafeGet().tokens)
|
# proc(xs: seq[ParserToken]): seq[string] = xs.map((x: ParserToken) => x.tokenStringValue()),
|
||||||
else:
|
# )
|
||||||
let err = parserResult.error()
|
|
||||||
onError(err)
|
|
||||||
|
|
||||||
proc merge[T](t: Builder[T], parser: Parser, tree: seq[T]): Builder[T] =
|
# proc testParser(x: string, ps: seq[Parser -> ParserResult]): seq[string] =
|
||||||
Builder[T]((
|
# initParserResult(x).parseSeq(ps).getTokens()
|
||||||
parser,
|
|
||||||
tree
|
|
||||||
))
|
|
||||||
|
|
||||||
proc mapTree[T](builder: BuilderResult[T], fn: seq[T] -> seq[T]): BuilderResult[T] =
|
# let optionalPrefixParser = @[
|
||||||
builder.map(proc(b: Builder[T]): Builder[T] = Builder((
|
# optional(ch('_')),
|
||||||
parser: b[0],
|
# str("ABC")
|
||||||
tree: fn(b[1]),
|
# ]
|
||||||
)))
|
# assert: "_ABC".testParser(optionalPrefixParser) == @["_", "A", "B", "C"]
|
||||||
|
# assert: "ABC".testParser(optionalPrefixParser) == @["A", "B", "C"]
|
||||||
|
|
||||||
proc applyParsers*[T](
|
# let andParser = @[
|
||||||
builder: Builder[T],
|
# (ch('A') + ch('B')),
|
||||||
parsers: seq[Parser -> ParserResult],
|
# ch('C'),
|
||||||
tokenFoldFn: (seq[ParserToken], seq[T]) -> seq[T],
|
# ]
|
||||||
): BuilderResult[T] =
|
# assert: "ABC".testParser(andParser) == @["A", "B", "C"]
|
||||||
# proc nested(b: Builder[T]): BuilderResult[T] =
|
|
||||||
let newParser = ParserResult.ok(Parser(
|
|
||||||
state: builder[0].state,
|
|
||||||
tokens: @[]
|
|
||||||
))
|
|
||||||
.parseSeq(parsers)
|
|
||||||
|
|
||||||
newParser
|
# let newlineParserTest = @[
|
||||||
.foldTokens(
|
# str("ABC"),
|
||||||
(err: ParserError) => BuilderResult[T].err((builder, "foo")),
|
# newline
|
||||||
(newTokens: seq[ParserToken]) => BuilderResult[T].ok(
|
# ]
|
||||||
builder.merge(newParser.unsafeGet(), tokenFoldFn(newTokens, builder[1]))
|
# assert "ABC\n".testParser(newlineParserTest) == @["A", "B", "C", "\n"]
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
proc applyParsersSeq*[T](
|
|
||||||
builder: BuilderResult[T],
|
|
||||||
xs: seq[tuple[
|
|
||||||
parsers: seq[Parser -> ParserResult],
|
|
||||||
tokenFoldFn: (seq[ParserToken], seq[T]) -> seq[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,
|
|
||||||
onSuccess: seq[T] -> T2,
|
|
||||||
): T =
|
|
||||||
if builderResult.isOk():
|
|
||||||
onSuccess(builderResult.unsafeGet().tree)
|
|
||||||
else:
|
|
||||||
let err = builderResult.error()
|
|
||||||
onError(err[1])
|
|
||||||
|
|
||||||
|
|
||||||
when isMainModule:
|
|
||||||
proc getTokens(x: ParserResult): seq[string] =
|
|
||||||
x.foldTokens(
|
|
||||||
proc(err: ParserError): seq[string] =
|
|
||||||
echo err
|
|
||||||
@[],
|
|
||||||
proc(xs: seq[ParserToken]): seq[string] = xs.map((x: ParserToken) => x.tokenStringValue()),
|
|
||||||
)
|
|
||||||
|
|
||||||
proc testParser(x: string, ps: seq[Parser -> ParserResult]): seq[string] =
|
|
||||||
initParserResult(x).parseSeq(ps).getTokens()
|
|
||||||
|
|
||||||
let optionalPrefixParser = @[
|
|
||||||
optional(ch('_')),
|
|
||||||
str("ABC")
|
|
||||||
]
|
|
||||||
assert: "_ABC".testParser(optionalPrefixParser) == @["_", "A", "B", "C"]
|
|
||||||
assert: "ABC".testParser(optionalPrefixParser) == @["A", "B", "C"]
|
|
||||||
|
|
||||||
let andParser = @[
|
|
||||||
(ch('A') + ch('B')),
|
|
||||||
ch('C'),
|
|
||||||
]
|
|
||||||
assert: "ABC".testParser(andParser) == @["A", "B", "C"]
|
|
||||||
|
|
||||||
let newlineParserTest = @[
|
|
||||||
str("ABC"),
|
|
||||||
newline
|
|
||||||
]
|
|
||||||
assert "ABC\n".testParser(newlineParserTest) == @["A", "B", "C", "\n"]
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import std/strutils
|
import std/strutils
|
||||||
import std/strformat
|
import std/strformat
|
||||||
|
import std/collections/sequtils
|
||||||
|
import std/sugar
|
||||||
import results
|
import results
|
||||||
import fusion/matching
|
import fusion/matching
|
||||||
import ../utils/str
|
import ../utils/str
|
||||||
@@ -62,6 +64,12 @@ proc initParser*(str: string): Parser =
|
|||||||
proc initParserResult*(str: string): ParserResult =
|
proc initParserResult*(str: string): ParserResult =
|
||||||
ParserResult.ok(initParser(str))
|
ParserResult.ok(initParser(str))
|
||||||
|
|
||||||
|
proc initBuilder*[T](t: Builder[T], parser: Parser, tree: seq[T]): Builder[T] =
|
||||||
|
Builder[T]((
|
||||||
|
parser,
|
||||||
|
tree
|
||||||
|
))
|
||||||
|
|
||||||
# -- Getters
|
# -- Getters
|
||||||
|
|
||||||
proc tokenStringValue*(x: ParserToken): string =
|
proc tokenStringValue*(x: ParserToken): string =
|
||||||
@@ -72,6 +80,93 @@ proc tokenStringValue*(x: ParserToken): string =
|
|||||||
of parserTokenString:
|
of parserTokenString:
|
||||||
x.stringValue
|
x.stringValue
|
||||||
|
|
||||||
|
# -- Modifiers
|
||||||
|
|
||||||
|
func flattenParserTokens*(parser: Parser): ParserResult =
|
||||||
|
return ParserResult.ok(
|
||||||
|
Parser(
|
||||||
|
state: parser.state,
|
||||||
|
tokens: @[
|
||||||
|
ParserToken(
|
||||||
|
kind: parserTokenString,
|
||||||
|
stringValue: parser.tokens.foldl(a & b.tokenStringValue(), "")
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
func emptyTokens*(parser: Parser): Parser =
|
||||||
|
Parser(
|
||||||
|
state: parser.state,
|
||||||
|
tokens: newSeq[ParserToken](),
|
||||||
|
)
|
||||||
|
|
||||||
|
proc foldTokens*[T](
|
||||||
|
parserResult: ParserResult,
|
||||||
|
onError: ParserError -> T,
|
||||||
|
onSuccess: seq[ParserToken] -> T,
|
||||||
|
): T =
|
||||||
|
if parserResult.isOk():
|
||||||
|
onSuccess(parserResult.unsafeGet().tokens)
|
||||||
|
else:
|
||||||
|
let err = parserResult.error()
|
||||||
|
onError(err)
|
||||||
|
|
||||||
|
proc setErrorExpectedField*(err: ParserError, expected: string): ParserError =
|
||||||
|
ParserError(
|
||||||
|
kind: err.kind,
|
||||||
|
unexpected: err.unexpected,
|
||||||
|
expected: expected,
|
||||||
|
index: err.index,
|
||||||
|
parser: err.parser,
|
||||||
|
)
|
||||||
|
|
||||||
|
proc mapTree*[T](builder: BuilderResult[T], fn: seq[T] -> seq[T]): BuilderResult[T] =
|
||||||
|
builder.map(proc(b: Builder[T]): Builder[T] = Builder((
|
||||||
|
parser: b[0],
|
||||||
|
tree: fn(b[1]),
|
||||||
|
)))
|
||||||
|
|
||||||
|
proc applyParsers*[T](
|
||||||
|
builder: Builder[T],
|
||||||
|
parsers: seq[Parser -> ParserResult],
|
||||||
|
tokenFoldFn: (seq[ParserToken], seq[T]) -> seq[T],
|
||||||
|
): BuilderResult[T] =
|
||||||
|
# proc nested(b: Builder[T]): BuilderResult[T] =
|
||||||
|
let newParser = ParserResult.ok(Parser(
|
||||||
|
state: builder[0].state,
|
||||||
|
tokens: @[]
|
||||||
|
))
|
||||||
|
.parseSeq(parsers)
|
||||||
|
|
||||||
|
newParser
|
||||||
|
.foldTokens(
|
||||||
|
(err: ParserError) => BuilderResult[T].err((builder, "foo")),
|
||||||
|
(newTokens: seq[ParserToken]) => BuilderResult[T].ok(
|
||||||
|
builder.initBuilder(newParser.unsafeGet(), tokenFoldFn(newTokens, builder[1]))
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
proc applyParsersSeq*[T](
|
||||||
|
builder: BuilderResult[T],
|
||||||
|
xs: seq[tuple[
|
||||||
|
parsers: seq[Parser -> ParserResult],
|
||||||
|
tokenFoldFn: (seq[ParserToken], seq[T]) -> seq[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,
|
||||||
|
onSuccess: seq[T] -> T2,
|
||||||
|
): T =
|
||||||
|
if builderResult.isOk():
|
||||||
|
onSuccess(builderResult.unsafeGet().tree)
|
||||||
|
else:
|
||||||
|
let err = builderResult.error()
|
||||||
|
onError(err[1])
|
||||||
|
|
||||||
|
|
||||||
# -- Stringifiers
|
# -- Stringifiers
|
||||||
|
|
||||||
proc `$`*(x: ParserToken): string =
|
proc `$`*(x: ParserToken): string =
|
||||||
|
|||||||
Reference in New Issue
Block a user