Document and test parser type internals
This commit is contained in:
@@ -189,7 +189,7 @@ proc anyUntil*(stopFn: parserFnT): parserFnT {.inline.} =
|
|||||||
manyUntil(anyCh, stopFn)
|
manyUntil(anyCh, stopFn)
|
||||||
|
|
||||||
proc choice*(parserFns: seq[parserFnT]): parserFnT {.inline} =
|
proc choice*(parserFns: seq[parserFnT]): parserFnT {.inline} =
|
||||||
## Creates parser function that checks any of the `parserFns`.
|
## creates parser function that checks any of the `parserFns`.
|
||||||
## Needs one match for a `ParserResult.ok`.
|
## Needs one match for a `ParserResult.ok`.
|
||||||
return proc(parser: Parser): ParserResult {.closure.} =
|
return proc(parser: Parser): ParserResult {.closure.} =
|
||||||
var errors: seq[ParserResult] = newSeq[ParserResult]()
|
var errors: seq[ParserResult] = newSeq[ParserResult]()
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import std/[
|
import std/[
|
||||||
options,
|
|
||||||
strutils,
|
strutils,
|
||||||
strformat,
|
strformat,
|
||||||
collections/sequtils,
|
collections/sequtils,
|
||||||
@@ -47,8 +46,12 @@ type
|
|||||||
|
|
||||||
# -- Initalizers
|
# -- Initalizers
|
||||||
|
|
||||||
func initParserToken*(x: char): ParserToken = ParserToken(kind: parserTokenChar, charValue: x)
|
func initParserToken*(x: char): ParserToken =
|
||||||
func initParserToken*(x: string): ParserToken = ParserToken(kind: parserTokenString, stringValue: x)
|
## Initialize `ParserToken` as `parserTokenChar` with value `x`.
|
||||||
|
ParserToken(kind: parserTokenChar, charValue: x)
|
||||||
|
func initParserToken*(x: string): ParserToken =
|
||||||
|
## Initialize `ParserToken` as `parserTokenString` with value `x`.
|
||||||
|
ParserToken(kind: parserTokenString, stringValue: x)
|
||||||
|
|
||||||
func initParser*(
|
func initParser*(
|
||||||
stream: string,
|
stream: string,
|
||||||
@@ -56,6 +59,7 @@ func initParser*(
|
|||||||
position = -1,
|
position = -1,
|
||||||
lastPosition = 0,
|
lastPosition = 0,
|
||||||
): Parser =
|
): Parser =
|
||||||
|
## Initialize `Parser` with `stream`.
|
||||||
Parser(
|
Parser(
|
||||||
state: ParserState(
|
state: ParserState(
|
||||||
stream: stream,
|
stream: stream,
|
||||||
@@ -71,6 +75,7 @@ func initParserResult*(
|
|||||||
position = -1,
|
position = -1,
|
||||||
lastPosition = 0,
|
lastPosition = 0,
|
||||||
): ParserResult =
|
): ParserResult =
|
||||||
|
## Initialize `ParserResult.ok` with `stream`.
|
||||||
ParserResult.ok(initParser(
|
ParserResult.ok(initParser(
|
||||||
stream,
|
stream,
|
||||||
tokens,
|
tokens,
|
||||||
@@ -78,10 +83,19 @@ func initParserResult*(
|
|||||||
lastPosition,
|
lastPosition,
|
||||||
))
|
))
|
||||||
|
|
||||||
|
# -- Equalizers
|
||||||
|
|
||||||
|
func `==`*(a: ParserToken, b: ParserToken): bool =
|
||||||
|
## Compare two `ParserToken` objects.
|
||||||
|
case ((a.kind, b.kind)):
|
||||||
|
of (parserTokenChar, parserTokenChar): a.charValue == b.charValue
|
||||||
|
of (parserTokenString, parserTokenString): a.stringValue == b.stringValue
|
||||||
|
else: false
|
||||||
|
|
||||||
# -- Getters
|
# -- Getters
|
||||||
|
|
||||||
func toString*(x: ParserToken): string =
|
func toString*(x: ParserToken): string =
|
||||||
## Get the Token value `x` as a string.
|
## Get the `ParserToken` value `x` as a string.
|
||||||
case x.kind:
|
case x.kind:
|
||||||
of parserTokenChar:
|
of parserTokenChar:
|
||||||
$x.charValue
|
$x.charValue
|
||||||
@@ -89,11 +103,13 @@ func toString*(x: ParserToken): string =
|
|||||||
x.stringValue
|
x.stringValue
|
||||||
|
|
||||||
func toString*(tokens: seq[ParserToken]): string =
|
func toString*(tokens: seq[ParserToken]): string =
|
||||||
|
## Get the seq `ParserToken` value `x` as a string.
|
||||||
tokens.foldl(a & b.toString(), "")
|
tokens.foldl(a & b.toString(), "")
|
||||||
|
|
||||||
# -- Modifiers
|
# -- Modifiers
|
||||||
|
|
||||||
func flattenTokens*(parser: Parser): Parser =
|
func flattenTokens*(parser: Parser): Parser =
|
||||||
|
## Flatten tokens in `parser` as a string `ParserToken`.
|
||||||
let token = initParserToken(parser.tokens.foldl(a & b.toString(), ""))
|
let token = initParserToken(parser.tokens.foldl(a & b.toString(), ""))
|
||||||
Parser(
|
Parser(
|
||||||
state: parser.state,
|
state: parser.state,
|
||||||
@@ -101,6 +117,7 @@ func flattenTokens*(parser: Parser): Parser =
|
|||||||
)
|
)
|
||||||
|
|
||||||
func emptyTokens*(parser: Parser): Parser =
|
func emptyTokens*(parser: Parser): Parser =
|
||||||
|
## Empty `parser` tokens.
|
||||||
Parser(
|
Parser(
|
||||||
state: parser.state,
|
state: parser.state,
|
||||||
tokens: newSeq[ParserToken](),
|
tokens: newSeq[ParserToken](),
|
||||||
@@ -108,14 +125,15 @@ func emptyTokens*(parser: Parser): Parser =
|
|||||||
|
|
||||||
func foldTokens*[T](
|
func foldTokens*[T](
|
||||||
parserResult: ParserResult,
|
parserResult: ParserResult,
|
||||||
onError: ParserError -> T,
|
onErrorFn: ParserError -> T,
|
||||||
onSuccess: seq[ParserToken] -> T,
|
onSuccessFn: seq[ParserToken] -> T,
|
||||||
): T =
|
): T =
|
||||||
|
## Fold over `tokens` inside `ParserResult` with `onSuccessFn` or `onErrorFn`.
|
||||||
if parserResult.isOk():
|
if parserResult.isOk():
|
||||||
onSuccess(parserResult.unsafeGet().tokens)
|
onSuccessFn(parserResult.unsafeGet().tokens)
|
||||||
else:
|
else:
|
||||||
let err = parserResult.error()
|
let err = parserResult.error()
|
||||||
onError(err)
|
onErrorFn(err)
|
||||||
|
|
||||||
func tokensToString*(parserResult: ParserResult, fallback = ""): string =
|
func tokensToString*(parserResult: ParserResult, fallback = ""): string =
|
||||||
parserResult.foldTokens(
|
parserResult.foldTokens(
|
||||||
@@ -264,30 +282,48 @@ func `$`*(x: ParserError): string =
|
|||||||
else: "ParseError"
|
else: "ParseError"
|
||||||
|
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
let test1 = """ABC
|
block testEqualizers:
|
||||||
|
assert initParserToken("a") == initParserToken("a")
|
||||||
|
assert initParserToken('a') == initParserToken('a')
|
||||||
|
assert initParserToken("a") != initParserToken('a')
|
||||||
|
|
||||||
D
|
block testGetters:
|
||||||
|
# toString
|
||||||
|
assert initParserToken("a").toString() == "a"
|
||||||
|
assert initParserToken('a').toString() == "a"
|
||||||
|
|
||||||
EFG"""
|
block testModifiers:
|
||||||
# echo test1.highlightStreamPosition2(test1.find("B"))
|
let testTokensSeq = @[initParserToken("a"), initParserToken('b'), initParserToken("c")]
|
||||||
# echo "=============="
|
let testExpectedStr = "abc"
|
||||||
# echo test1.highlightStreamPosition2(test1.find("C"))
|
let testTokensSeqParser = initParser(
|
||||||
# echo "=============="
|
stream = testExpectedStr,
|
||||||
# echo test1.highlightStreamPosition2(test1.find("D"))
|
tokens = testTokensSeq,
|
||||||
# echo "=============="
|
position = testTokensSeq.len - 1,
|
||||||
# echo test1.highlightStreamPosition2(test1.find("\n"))
|
)
|
||||||
# echo "=============="
|
let testTokensSeqParserResult = ParserResult.ok(testTokensSeqParser)
|
||||||
# echo test1.highlightStreamPosition2(test1.find("\n", test1.find("\n") + 1))
|
let testTokensSeqParserResultErr = ParserResult.err(ParserError(
|
||||||
|
kind: charMismatchErr,
|
||||||
|
unexpected: "a",
|
||||||
|
expected: "b",
|
||||||
|
index: 0,
|
||||||
|
parser: testTokensSeqParser,
|
||||||
|
))
|
||||||
|
|
||||||
|
# flattenTokens
|
||||||
|
assert testTokensSeqParser.flattenTokens().tokens[0] == initParserToken("abc")
|
||||||
|
|
||||||
# echo "\n1\n".rfind('\n', 0, 2)
|
# emptyTokens
|
||||||
|
assert testTokensSeqParser.emptyTokens().tokens.len == 0
|
||||||
|
|
||||||
# block highlightStreamPosition:
|
# foldTokens
|
||||||
# let s = "abc"
|
assert testTokensSeqParserResult.foldTokens(
|
||||||
# # Out of bounds
|
err => "Failure",
|
||||||
# assert s.highlightStreamPosition(-1) == s
|
xs => xs.toString(),
|
||||||
# assert s.highlightStreamPosition(s.len) == s
|
) == testExpectedStr
|
||||||
# # Regular highlighting
|
assert testTokensSeqParserResultErr.foldTokens(
|
||||||
# assert s.highlightStreamPosition(0) == LEFT_HIGHLIGHT_CHAR & "a" & RIGHT_HIGHLIGHT_CHAR & "bc"
|
err => "Failure",
|
||||||
# assert s.highlightStreamPosition(1) == "a" & LEFT_HIGHLIGHT_CHAR & "b" & RIGHT_HIGHLIGHT_CHAR & "c"
|
xs => xs.toString(),
|
||||||
# assert s.highlightStreamPosition(2) == "ab" & LEFT_HIGHLIGHT_CHAR & "c" & RIGHT_HIGHLIGHT_CHAR
|
) == "Failure"
|
||||||
|
|
||||||
|
# tokensToString
|
||||||
|
assert testTokensSeqParserResult.tokensToString() == testExpectedStr
|
||||||
|
|||||||
Reference in New Issue
Block a user