Structure

This commit is contained in:
Florian Schroedl
2022-01-20 17:00:00 +01:00
parent 5863304456
commit 20712cef95
5 changed files with 63 additions and 169 deletions

View File

@@ -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', ' ' })

40
src/org_parser.nim Normal file
View File

@@ -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

View File

@@ -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,

View File

@@ -1,3 +0,0 @@
import cascade
import print

View File

@@ -9,8 +9,9 @@ type
orgHeadline,
orgText,
OrgElement = ref object
OrgElement* = ref object
children*: orgElementChildren
id*: string
case kind*: OrgElementKind
of orgHeadline: