import std/sugar import std/strformat import std/collections/sequtils import std/strutils import parser/parser import results import utils/fp import fusion/matching {.experimental: "caseStmtMacros".} 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) proc initStringBuilder(str: string): StringBuilderResult = StringBuilderResult .ok(StringBuilder(( parser: initParser(str), tree: newSeq[StringBuilderT](), ))) when isMainModule: let parseHeadingStars = @[ manyUntil(ch('*'), ch(' ')), ignore(ch(' ')) ] proc createTodoKeywordParser(xs: seq[string]): (Parser -> ParserResult) = choice(xs.map((x: string) => str(x) + ignore(ch(' ')))) let todoKeywords = @["TODO"] let doneKeywords = @["DONE"] let parseTodoKeyword = todoKeywords.createTodoKeywordParser() let parseDoneKeyword = doneKeywords.createTodoKeywordParser() let propertiesKeyParser = ignore(ch(':')) + anyUntil(choice(@[str(": "), newline])) let propertiesValueParser = ignore(str(": ")) + anyUntil(newline) + ignore(newline) let propertiesParser = proc(parser: Parser): ParserResult {.closure.} = let keyTokenParser = parser .propertiesKeyParser() .flatMap(flattenParserTokens) let valueTokenParser = keyTokenParser .map(emptyTokens) .flatMap(propertiesValueParser) .flatMap(flattenParserTokens) case (keyTokenParser, valueTokenParser): of (Some(@key), Some(@value)): ok(Parser( state: value.state, tokens: @[ key.tokens[0], value.tokens[0], ] )) else: valueTokenParser let propertiesStartParser = str(":PROPERTIES_START:") + newline let propertiesEndParser = str(":PROPERTIES_END:") + newline let parseProperties = @[ ignore(propertiesStartParser), manyUntil( propertiesParser, propertiesEndParser, ), ignore(propertiesEndParser), ] echo initParserResult(""":PROPERTIES: :PROP_NAME: Value :PROP_NAME: Value :PROP_NAME: Value :PROP_NAME: Value :PROPERTIES_END: """).parseSeq(parseProperties) let parseHeadingText = @[ anyUntil(newline), ignore(newline), ] let sampleBuilder = StringBuilderResult .ok(StringBuilder(( parser: initParser("""**** TODO Some stars :PROPERTIES: :PROP_NAME: Value :PROP_NAME: Value :PROP_NAME: Value :PROP_NAME: Value :PROPERTIES_END: """), tree: newSeq[StringBuilderT](), ))) .applyParsersSeq(@[ (parseHeadingStars, stringConcat("Stars: ")), (@[optional(parseTodoKeyword)], stringConcat("TODO: ")), (@[optional(parseDoneKeyword)], stringConcat("DONE: ")), (parseHeadingText, stringConcat("Text: ")), # (parseProperties, stringConcat("Properties: ")), # (@[optional(choice(parseProperties))], stringConcat("Properties: ")), ]) .foldBuilder( err => &"Error Parsing: {err}", xs => "Parser Succesfull:\n" & xs.join("\n"), ) # echo sampleBuilder