Implement Multi type tokens
This commit is contained in:
@@ -5,32 +5,68 @@ import std/strutils
|
|||||||
import parser/parser
|
import parser/parser
|
||||||
import results
|
import results
|
||||||
|
|
||||||
|
type StringBuilderT = string
|
||||||
|
type StringBuilder = Builder[StringBuilderT]
|
||||||
|
type StringBuilderResult = BuilderResult[StringBuilderT]
|
||||||
|
proc stringConcat(typeInfo: StringBuilderT):
|
||||||
|
(seq[ParserToken], seq[StringBuilderT]) -> seq[StringBuilderT] =
|
||||||
|
|
||||||
|
return proc(xs: seq[ParserToken], ys: seq[StringBuilderT]): seq[StringBuilderT] =
|
||||||
|
return ys & xs.foldl(a & b.tokenStringValue(), typeInfo)
|
||||||
|
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
let parseHeadingStars = @[
|
let parseHeadingStars = @[
|
||||||
manyUntil(ch('*'), ch(' ')),
|
manyUntil(ch('*'), ch(' ')),
|
||||||
ignore(ch(' '))
|
ignore(ch(' '))
|
||||||
]
|
]
|
||||||
|
|
||||||
let parseHeadingText = @[
|
proc createTodoKeywordParser(xs: seq[string]): (Parser -> ParserResult) =
|
||||||
anyUntil(endOfStream),
|
choice(xs.map((x: string) => str(x) + ignore(ch(' '))))
|
||||||
|
|
||||||
|
let todoKeywords = @["TODO"]
|
||||||
|
let doneKeywords = @["DONE"]
|
||||||
|
|
||||||
|
let parseTodoKeyword = todoKeywords.createTodoKeywordParser()
|
||||||
|
let parseDoneKeyword = doneKeywords.createTodoKeywordParser()
|
||||||
|
|
||||||
|
let propertiesKeyValueParser = anyUntil(ch(Newlines)) + ignore(ch(NewLines))
|
||||||
|
let propertiesEndParser = str(":PROPERTIES_END:") + ch(Newlines)
|
||||||
|
|
||||||
|
let parseProperties = @[
|
||||||
|
ignore(str(":PROPERTIES:") + ch(Newlines)),
|
||||||
|
manyUntil(
|
||||||
|
propertiesKeyValueParser,
|
||||||
|
propertiesEndParser,
|
||||||
|
),
|
||||||
|
ignore(propertiesEndParser),
|
||||||
]
|
]
|
||||||
|
|
||||||
type StringBuilderT = string
|
let parseHeadingText = @[
|
||||||
type StringBuilder = Builder[StringBuilderT]
|
anyUntil(newline),
|
||||||
type StringBuilderResult = BuilderResult[StringBuilderT]
|
ignore(newline),
|
||||||
proc stringConcat(typeInfo: StringBuilderT):
|
]
|
||||||
(seq[Token], seq[StringBuilderT]) -> seq[StringBuilderT] =
|
|
||||||
return proc(xs: seq[Token], ys: seq[StringBuilderT]): seq[StringBuilderT] =
|
|
||||||
return ys & xs.foldl(a & b.value, typeInfo)
|
|
||||||
|
|
||||||
let sampleBuilder = StringBuilderResult
|
let sampleBuilder = StringBuilderResult
|
||||||
.ok(StringBuilder((
|
.ok(StringBuilder((
|
||||||
parser: initParser("**** Some stars"),
|
parser: initParser("""**** TODO Some stars
|
||||||
|
:PROPERTIES:
|
||||||
|
:PROP_NAME: Value
|
||||||
|
:PROP_NAME: Value
|
||||||
|
:PROP_NAME: Value
|
||||||
|
:PROP_NAME: Value
|
||||||
|
:PROPERTIES_END:
|
||||||
|
"""),
|
||||||
tree: newSeq[StringBuilderT](),
|
tree: newSeq[StringBuilderT](),
|
||||||
)))
|
)))
|
||||||
.applyParsersSeq(@[
|
.applyParsersSeq(@[
|
||||||
(parseHeadingStars, stringConcat("Stars: ")),
|
(parseHeadingStars, stringConcat("Stars: ")),
|
||||||
(parseHeadingText, stringConcat("Text: "))
|
|
||||||
|
(@[optional(parseTodoKeyword)], stringConcat("TODO: ")),
|
||||||
|
(@[optional(parseDoneKeyword)], stringConcat("DONE: ")),
|
||||||
|
|
||||||
|
(parseHeadingText, stringConcat("Text: ")),
|
||||||
|
(parseProperties, stringConcat("Properties: ")),
|
||||||
|
# (@[optional(choice(parseProperties))], stringConcat("Properties: ")),
|
||||||
])
|
])
|
||||||
.foldBuilder(
|
.foldBuilder(
|
||||||
err => &"Error Parsing: {err}",
|
err => &"Error Parsing: {err}",
|
||||||
|
|||||||
@@ -15,12 +15,26 @@ type
|
|||||||
stream: string
|
stream: string
|
||||||
position, lastPosition: int
|
position, lastPosition: int
|
||||||
|
|
||||||
Token* = ref object
|
parserTokenCharValueT* = char
|
||||||
value*: char
|
parserTokenStringValueT* = string
|
||||||
|
parserTokenKeyValuePairValueT* = tuple[k: string, v: string]
|
||||||
|
|
||||||
|
ParserTokenKind* = enum
|
||||||
|
parserTokenChar
|
||||||
|
parserTokenString
|
||||||
|
# parserTokenKeyValuePair
|
||||||
|
ParserToken* = ref object
|
||||||
|
case kind*: ParserTokenKind
|
||||||
|
of parserTokenChar:
|
||||||
|
charValue*: parserTokenCharValueT
|
||||||
|
of parserTokenString:
|
||||||
|
stringValue*: parserTokenStringValueT
|
||||||
|
# of parserTokenKeyValuePair:
|
||||||
|
# keyValuePairValue*: parserTokenKeyValuePairValueT
|
||||||
|
|
||||||
Parser* = ref object
|
Parser* = ref object
|
||||||
state: ParserState
|
state: ParserState
|
||||||
tokens: seq[Token]
|
tokens: seq[ParserToken]
|
||||||
|
|
||||||
ParseErrorKind = enum
|
ParseErrorKind = enum
|
||||||
choiceMismatchErr
|
choiceMismatchErr
|
||||||
@@ -45,9 +59,16 @@ proc indentKey(x: string, count: int): string =
|
|||||||
y.delete(0..count - 1)
|
y.delete(0..count - 1)
|
||||||
y
|
y
|
||||||
|
|
||||||
proc `$`*(x: Token): string =
|
proc tokenStringValue*(x: ParserToken): string =
|
||||||
&"""Token(
|
case x.kind:
|
||||||
value: {x.value},
|
of parserTokenChar:
|
||||||
|
$x.charValue
|
||||||
|
of parserTokenString:
|
||||||
|
x.stringValue
|
||||||
|
|
||||||
|
proc `$`*(x: ParserToken): string =
|
||||||
|
&"""ParserToken(
|
||||||
|
value: {tokenStringValue(x)},
|
||||||
)"""
|
)"""
|
||||||
|
|
||||||
proc `$`*(x: ParserState): string =
|
proc `$`*(x: ParserState): string =
|
||||||
@@ -108,6 +129,10 @@ proc `$`*(x: ParserError): string =
|
|||||||
|
|
||||||
else: "ParseError"
|
else: "ParseError"
|
||||||
|
|
||||||
|
func initParserToken(x: char): ParserToken = ParserToken(kind: parserTokenChar, charValue: x)
|
||||||
|
func initParserToken(x: string): ParserToken = ParserToken(kind: parserTokenString, stringValue: x)
|
||||||
|
# func initParserToken(x: parserTokenKeyValuePairValueT): ParserToken = ParserToken(kind: parserTokenKeyValuePair, keyValuePairValue: x)
|
||||||
|
|
||||||
proc initParser*(str: string): Parser =
|
proc initParser*(str: string): Parser =
|
||||||
Parser(
|
Parser(
|
||||||
state: ParserState(
|
state: ParserState(
|
||||||
@@ -115,7 +140,7 @@ proc initParser*(str: string): Parser =
|
|||||||
position: -1,
|
position: -1,
|
||||||
lastPosition: 0,
|
lastPosition: 0,
|
||||||
),
|
),
|
||||||
tokens: newSeq[Token](),
|
tokens: newSeq[ParserToken](),
|
||||||
)
|
)
|
||||||
|
|
||||||
proc initParserResult*(str: string): ParserResult =
|
proc initParserResult*(str: string): ParserResult =
|
||||||
@@ -142,7 +167,7 @@ func ch*(expectedChars: set[char]): (Parser -> ParserResult) {.inline.} =
|
|||||||
position: newIndex,
|
position: newIndex,
|
||||||
lastPosition: parser.state.position,
|
lastPosition: parser.state.position,
|
||||||
),
|
),
|
||||||
tokens: parser.tokens & Token(value: foundChar)
|
tokens: parser.tokens & initParserToken(foundChar)
|
||||||
).ok()
|
).ok()
|
||||||
else:
|
else:
|
||||||
return err(ParserError(
|
return err(ParserError(
|
||||||
@@ -174,7 +199,7 @@ func ch*(expectedChar: char): (Parser -> ParserResult) {.inline.} =
|
|||||||
position: newIndex,
|
position: newIndex,
|
||||||
lastPosition: parser.state.position,
|
lastPosition: parser.state.position,
|
||||||
),
|
),
|
||||||
tokens: parser.tokens & Token(value: foundChar)
|
tokens: parser.tokens & initParserToken(foundChar)
|
||||||
).ok()
|
).ok()
|
||||||
else:
|
else:
|
||||||
return err(ParserError(
|
return err(ParserError(
|
||||||
@@ -279,7 +304,7 @@ proc parseSeq*(parser: ParserResult, xs: seq[Parser -> ParserResult]): ParserRes
|
|||||||
proc foldTokens*[T](
|
proc foldTokens*[T](
|
||||||
parserResult: ParserResult,
|
parserResult: ParserResult,
|
||||||
onError: ParserError -> T,
|
onError: ParserError -> T,
|
||||||
onSuccess: seq[Token] -> T,
|
onSuccess: seq[ParserToken] -> T,
|
||||||
): T =
|
): T =
|
||||||
if parserResult.isOk():
|
if parserResult.isOk():
|
||||||
onSuccess(parserResult.unsafeGet().tokens)
|
onSuccess(parserResult.unsafeGet().tokens)
|
||||||
@@ -302,7 +327,7 @@ proc mapTree[T](builder: BuilderResult[T], fn: seq[T] -> seq[T]): BuilderResult[
|
|||||||
proc applyParsers*[T](
|
proc applyParsers*[T](
|
||||||
builder: Builder[T],
|
builder: Builder[T],
|
||||||
parsers: seq[Parser -> ParserResult],
|
parsers: seq[Parser -> ParserResult],
|
||||||
tokenFoldFn: (seq[Token], seq[T]) -> seq[T],
|
tokenFoldFn: (seq[ParserToken], seq[T]) -> seq[T],
|
||||||
): BuilderResult[T] =
|
): BuilderResult[T] =
|
||||||
# proc nested(b: Builder[T]): BuilderResult[T] =
|
# proc nested(b: Builder[T]): BuilderResult[T] =
|
||||||
let newParser = ParserResult.ok(Parser(
|
let newParser = ParserResult.ok(Parser(
|
||||||
@@ -314,7 +339,7 @@ proc applyParsers*[T](
|
|||||||
newParser
|
newParser
|
||||||
.foldTokens(
|
.foldTokens(
|
||||||
(err: ParserError) => BuilderResult[T].err((builder, "foo")),
|
(err: ParserError) => BuilderResult[T].err((builder, "foo")),
|
||||||
(newTokens: seq[Token]) => BuilderResult[T].ok(
|
(newTokens: seq[ParserToken]) => BuilderResult[T].ok(
|
||||||
builder.merge(newParser.unsafeGet(), tokenFoldFn(newTokens, builder[1]))
|
builder.merge(newParser.unsafeGet(), tokenFoldFn(newTokens, builder[1]))
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -323,7 +348,7 @@ proc applyParsersSeq*[T](
|
|||||||
builder: BuilderResult[T],
|
builder: BuilderResult[T],
|
||||||
xs: seq[tuple[
|
xs: seq[tuple[
|
||||||
parsers: seq[Parser -> ParserResult],
|
parsers: seq[Parser -> ParserResult],
|
||||||
tokenFoldFn: (seq[Token], seq[T]) -> seq[T],
|
tokenFoldFn: (seq[ParserToken], seq[T]) -> seq[T],
|
||||||
]]): BuilderResult[T] =
|
]]): BuilderResult[T] =
|
||||||
xs.foldl(a.flatMap((x: Builder[T]) => x.applyParsers(b[0], b[1])), builder)
|
xs.foldl(a.flatMap((x: Builder[T]) => x.applyParsers(b[0], b[1])), builder)
|
||||||
|
|
||||||
@@ -340,32 +365,32 @@ proc foldBuilder*[T, T2](
|
|||||||
|
|
||||||
|
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
proc getTokens(x: ParserResult): seq[char] =
|
proc getTokens(x: ParserResult): seq[string] =
|
||||||
x.foldTokens(
|
x.foldTokens(
|
||||||
proc(err: ParserError): seq[char] =
|
proc(err: ParserError): seq[string] =
|
||||||
echo err
|
echo err
|
||||||
@[],
|
@[],
|
||||||
proc(xs: seq[Token]): seq[char] = xs.map((x: Token) => x.value),
|
proc(xs: seq[ParserToken]): seq[string] = xs.map((x: ParserToken) => x.tokenStringValue()),
|
||||||
)
|
)
|
||||||
|
|
||||||
proc testParser(x: string, ps: seq[Parser -> ParserResult]): seq[char] =
|
proc testParser(x: string, ps: seq[Parser -> ParserResult]): seq[string] =
|
||||||
initParserResult(x).parseSeq(ps).getTokens()
|
initParserResult(x).parseSeq(ps).getTokens()
|
||||||
|
|
||||||
let optionalPrefixParser = @[
|
let optionalPrefixParser = @[
|
||||||
optional(ch('_')),
|
optional(ch('_')),
|
||||||
str("ABC")
|
str("ABC")
|
||||||
]
|
]
|
||||||
assert: "_ABC".testParser(optionalPrefixParser) == @['_', 'A', 'B', 'C']
|
assert: "_ABC".testParser(optionalPrefixParser) == @["_", "A", "B", "C"]
|
||||||
assert: "ABC".testParser(optionalPrefixParser) == @['A', 'B', 'C']
|
assert: "ABC".testParser(optionalPrefixParser) == @["A", "B", "C"]
|
||||||
|
|
||||||
let andParser = @[
|
let andParser = @[
|
||||||
(ch('A') + ch('B')),
|
(ch('A') + ch('B')),
|
||||||
ch('C'),
|
ch('C'),
|
||||||
]
|
]
|
||||||
assert: "ABC".testParser(andParser) == @['A', 'B', 'C']
|
assert: "ABC".testParser(andParser) == @["A", "B", "C"]
|
||||||
|
|
||||||
let newlineParserTest = @[
|
let newlineParserTest = @[
|
||||||
str("ABC"),
|
str("ABC"),
|
||||||
newline
|
newline
|
||||||
]
|
]
|
||||||
assert "ABC\n".testParser(newlineParserTest) == @['A', 'B', 'C', '\n']
|
assert "ABC\n".testParser(newlineParserTest) == @["A", "B", "C", "\n"]
|
||||||
|
|||||||
Reference in New Issue
Block a user