From 20712cef95646dcf5ee9292d558295ce18e38cc1 Mon Sep 17 00:00:00 2001 From: Florian Schroedl Date: Thu, 20 Jan 2022 17:00:00 +0100 Subject: [PATCH] Structure --- src/nim_org_parse.nim | 134 ---------------------------- src/org_parser.nim | 40 +++++++++ src/{test.nim => parser/parser.nim} | 52 +++++------ src/test_cascade.nim | 3 - src/types.nim | 3 +- 5 files changed, 63 insertions(+), 169 deletions(-) delete mode 100644 src/nim_org_parse.nim create mode 100644 src/org_parser.nim rename src/{test.nim => parser/parser.nim} (89%) delete mode 100644 src/test_cascade.nim diff --git a/src/nim_org_parse.nim b/src/nim_org_parse.nim deleted file mode 100644 index 5baa356..0000000 --- a/src/nim_org_parse.nim +++ /dev/null @@ -1,134 +0,0 @@ -import std/strutils -import std/re -import std/parseutils -import std/strformat -import std/sugar -import std/strutils -import std/strformat -import fusion/matching -import fp/maybe -import fp/list -import utils/fp - -{.experimental: "caseStmtMacros".} - -type contentT = string -type headlingLevelT = int -type tagsT = seq[string] - -type lineNumberT = int -type lineCharT = int -type posT = (lineNumberT, lineCharT) - -type - OrgBlockKind* = enum - Document, - Heading, - NotImplemented - OrgBlock* = ref object - # position: posT - case kind*: OrgBlockKind - of Heading: - content*: contentT - level*: headlingLevelT - tags*: Maybe[tagsT] - else: str: string - -proc `$`*(x: OrgBlock): string = - case x: - of Document(): - return &"""OrgBlock( - kind: Document, -)""" - of Heading( - content: @content, - level: @level, - tags: @tags, - ): - return &"""OrgBlock( - kind: Heading, - content: {content}, - level: {level}, - tags: {tags}, -)""" - of NotImplemented(str: @str): - return &"""OrgBlock( - kind: NotImplemented, - str: {str}, -)""" - -proc findHeadlineTagIndex(line: string): Maybe[int] = - line - .just() - .filter(x => x.endsWith(":")) - .map(x => x.rfind({ '\t', ' ' })) - .notNegative() - # Step forward one character and check if it's ':' - .filter(x => line[x + 1] == ':') - -proc parseHeadline(line: string): Maybe[OrgBlock] = - if line.startsWith("*"): - var stars: string - - let contentIndex = line - .parseWhile(stars, validChars = { '*' }) - .just() - .notNegative() - - let tagIndex = line.findHeadlineTagIndex() - - let res = - case (contentIndex, tagIndex): - of (Some(@contentIndex), Some(@tagIndex)): - ( - line[contentIndex + 1 .. tagIndex], - # Remove the first and last characters as they're so we don't have to remove them after the split - Just(line[tagIndex + 2 .. ^2].split(':')), - ) - else: - ( - line[contentIndex.get() + 1 .. ^1], - Nothing[tagsT]() - ) - - (@content, @tags) := res - - Just(OrgBlock( - kind: Heading, - level: 0, - content: content, - tags: tags, - )) - else: - Nothing[OrgBlock]() - -let parsers = @[ - parseHeadline, -] - -proc parseLine(line: string): any = - parsers - .findMaybeFn(line) - # .fold( - # () => OrgBlock(kind: NotImplemented, str: line), - # x => x.get(), - # ) - - -let line = "**** foo: :sdfdsfd:fvf:sdfsd:" - -echo parseLine(line) - - - -# echo line -# .rfind({ '\t', ' ' }) -# .just() -# .notNegative() -# .map(x => x + 1) -# .filter(x => line[x] == ':') -# .map(x => line[x .. ^1]) - -# proc findHeadlineTags(line: string): any = -# if line.endsWith(":"): -# let idx = line.rfind({ '\t', ' ' }) diff --git a/src/org_parser.nim b/src/org_parser.nim new file mode 100644 index 0000000..19cb242 --- /dev/null +++ b/src/org_parser.nim @@ -0,0 +1,40 @@ +import std/sugar +import std/strformat +import std/collections/sequtils +import std/strutils +import parser/parser +import results + +when isMainModule: + let parseHeadingStars = @[ + manyUntil(ch('*'), ch(' ')), + ignore(ch(' ')) + ] + + let parseHeadingText = @[ + anyUntil(endOfStream), + ] + + type StringBuilderT = string + type StringBuilder = Builder[StringBuilderT] + type StringBuilderResult = BuilderResult[StringBuilderT] + 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 + .ok(StringBuilder(( + parser: initParser("**** Some stars"), + tree: newSeq[StringBuilderT](), + ))) + .applyParsersSeq(@[ + (parseHeadingStars, stringConcat("Stars: ")), + (parseHeadingText, stringConcat("Text: ")) + ]) + .foldBuilder( + err => &"Error Parsing: {err}", + xs => "Parser Succesfull:\n" & xs.join("\n"), + ) + + echo sampleBuilder diff --git a/src/test.nim b/src/parser/parser.nim similarity index 89% rename from src/test.nim rename to src/parser/parser.nim index 4dbbfcd..890b731 100644 --- a/src/test.nim +++ b/src/parser/parser.nim @@ -7,8 +7,6 @@ import std/collections/tables import results import fusion/matching import fp/maybe -import print -import types {.experimental: "caseStmtMacros".} @@ -18,7 +16,7 @@ type position, lastPosition: int Token* = ref object - value: char + value*: char Parser* = ref object state: ParserState @@ -42,14 +40,6 @@ type ] BuilderResult*[T] = Result[Builder[T], (Builder[T], string)] -# func prettyPrintError*(err: ParserErrror,) - -func getOrElse*[T, E](self: Result[T, E], otherwise: T): T = - if self.isOk(): - self.v - else: - otherwise - proc indentKey(x: string, count: int): string = var y = x.indent(count) y.delete(0..count - 1) @@ -109,7 +99,7 @@ proc `$`*(x: ParserError): string = {errSpace}^ Expected '{expected}' but got '{unexpected}'""" else: "ParseError" -proc initParser(str: string): Parser = +proc initParser*(str: string): Parser = Parser( state: ParserState( stream: str, @@ -119,7 +109,7 @@ proc initParser(str: string): Parser = tokens: newSeq[Token](), ) -func ch(expectedChars: set[char]): (Parser -> ParserResult) {.inline.} = +func ch*(expectedChars: set[char]): (Parser -> ParserResult) {.inline.} = return func(parser: Parser): ParserResult = let state = parser.state let newIndex = state.position + 1 @@ -151,7 +141,7 @@ func ch(expectedChars: set[char]): (Parser -> ParserResult) {.inline.} = parser: parser, )) -func ch(expectedChar: char): (Parser -> ParserResult) {.inline.} = +func ch*(expectedChar: char): (Parser -> ParserResult) {.inline.} = return func(parser: Parser): ParserResult = let state = parser.state let newIndex = state.position + 1 @@ -183,7 +173,14 @@ func ch(expectedChar: char): (Parser -> ParserResult) {.inline.} = parser: parser, )) -proc endOfStream(parser: Parser): ParserResult = +func str*(s: string): (Parser -> ParserResult) {.inline.} = + return func(parser: Parser): ParserResult = + var p = parser.ok() + for c in s.items: + p = p.flatMap(ch(c)) + return p + +proc endOfStream*(parser: Parser): ParserResult = if parser.state.position == parser.state.stream.len - 1: ok(parser) else: @@ -194,7 +191,7 @@ proc endOfStream(parser: Parser): ParserResult = parser: parser, )) -func ignore(parserFn: Parser -> ParserResult): (Parser -> ParserResult) {.inline.} = +func ignore*(parserFn: Parser -> ParserResult): (Parser -> ParserResult) {.inline.} = ## Parse characters but throw success tokens away return proc(parser: Parser): ParserResult = return parserFn(parser) @@ -203,7 +200,7 @@ func ignore(parserFn: Parser -> ParserResult): (Parser -> ParserResult) {.inline 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 return proc(parser: Parser): ParserResult = var res: ParserResult = acceptFn(parser) @@ -211,10 +208,10 @@ func manyUntil(acceptFn: Parser -> ParserResult, stopFn: Parser -> ParserResult) res = res.flatMap(acceptFn) return res -func anyUntil(stopFn: Parser -> ParserResult): (Parser -> ParserResult) {.inline.} = +func anyUntil*(stopFn: Parser -> ParserResult): (Parser -> ParserResult) {.inline.} = manyUntil(ch(AllChars), stopFn) -func choice(parsers: seq[Parser -> ParserResult]): (Parser -> ParserResult) {.inline.} = +func choice*(parsers: seq[Parser -> ParserResult]): (Parser -> ParserResult) {.inline.} = return proc(parser: Parser): ParserResult = var errors: seq[ParserResult] = newSeq[ParserResult]() var found = Nothing[ParserResult]() @@ -241,17 +238,10 @@ func choice(parsers: seq[Parser -> ParserResult]): (Parser -> ParserResult) {.in proc(x: ParserResult): ParserResult = x, ) -proc parseSeq(parser: ParserResult, xs: seq[Parser -> ParserResult]): ParserResult = +proc parseSeq*(parser: ParserResult, xs: seq[Parser -> ParserResult]): ParserResult = xs.foldl(a.flatMap(b), parser) -func str(s: string): (Parser -> ParserResult) {.inline.} = - return func(parser: Parser): ParserResult = - var p = parser.ok() - for c in s.items: - p = p.flatMap(ch(c)) - return p - -proc foldTokens[T]( +proc foldTokens*[T]( parserResult: ParserResult, onError: ParserError -> T, onSuccess: seq[Token] -> T, @@ -274,7 +264,7 @@ proc mapTree[T](builder: BuilderResult[T], fn: seq[T] -> seq[T]): BuilderResult[ tree: fn(b[1]), ))) -proc applyParsers[T]( +proc applyParsers*[T]( builder: Builder[T], parsers: seq[Parser -> ParserResult], tokenFoldFn: (seq[Token], seq[T]) -> seq[T], @@ -294,7 +284,7 @@ proc applyParsers[T]( ), ) -proc applyParsersSeq[T]( +proc applyParsersSeq*[T]( builder: BuilderResult[T], xs: seq[tuple[ parsers: seq[Parser -> ParserResult], @@ -302,7 +292,7 @@ proc applyParsersSeq[T]( ]]): BuilderResult[T] = xs.foldl(a.flatMap((x: Builder[T]) => x.applyParsers(b[0], b[1])), builder) -proc foldBuilder[T, T2]( +proc foldBuilder*[T, T2]( builderResult: BuilderResult[T], onError: string -> T2, onSuccess: seq[T] -> T2, diff --git a/src/test_cascade.nim b/src/test_cascade.nim deleted file mode 100644 index 4e521ce..0000000 --- a/src/test_cascade.nim +++ /dev/null @@ -1,3 +0,0 @@ -import cascade -import print - diff --git a/src/types.nim b/src/types.nim index 527b3be..a7484f7 100644 --- a/src/types.nim +++ b/src/types.nim @@ -9,8 +9,9 @@ type orgHeadline, orgText, - OrgElement = ref object + OrgElement* = ref object children*: orgElementChildren + id*: string case kind*: OrgElementKind of orgHeadline: