Structure
This commit is contained in:
@@ -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
40
src/org_parser.nim
Normal 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
|
||||||
@@ -7,8 +7,6 @@ import std/collections/tables
|
|||||||
import results
|
import results
|
||||||
import fusion/matching
|
import fusion/matching
|
||||||
import fp/maybe
|
import fp/maybe
|
||||||
import print
|
|
||||||
import types
|
|
||||||
|
|
||||||
{.experimental: "caseStmtMacros".}
|
{.experimental: "caseStmtMacros".}
|
||||||
|
|
||||||
@@ -18,7 +16,7 @@ type
|
|||||||
position, lastPosition: int
|
position, lastPosition: int
|
||||||
|
|
||||||
Token* = ref object
|
Token* = ref object
|
||||||
value: char
|
value*: char
|
||||||
|
|
||||||
Parser* = ref object
|
Parser* = ref object
|
||||||
state: ParserState
|
state: ParserState
|
||||||
@@ -42,14 +40,6 @@ type
|
|||||||
]
|
]
|
||||||
BuilderResult*[T] = Result[Builder[T], (Builder[T], string)]
|
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 =
|
proc indentKey(x: string, count: int): string =
|
||||||
var y = x.indent(count)
|
var y = x.indent(count)
|
||||||
y.delete(0..count - 1)
|
y.delete(0..count - 1)
|
||||||
@@ -109,7 +99,7 @@ proc `$`*(x: ParserError): string =
|
|||||||
{errSpace}^ Expected '{expected}' but got '{unexpected}'"""
|
{errSpace}^ Expected '{expected}' but got '{unexpected}'"""
|
||||||
else: "ParseError"
|
else: "ParseError"
|
||||||
|
|
||||||
proc initParser(str: string): Parser =
|
proc initParser*(str: string): Parser =
|
||||||
Parser(
|
Parser(
|
||||||
state: ParserState(
|
state: ParserState(
|
||||||
stream: str,
|
stream: str,
|
||||||
@@ -119,7 +109,7 @@ proc initParser(str: string): Parser =
|
|||||||
tokens: newSeq[Token](),
|
tokens: newSeq[Token](),
|
||||||
)
|
)
|
||||||
|
|
||||||
func ch(expectedChars: set[char]): (Parser -> ParserResult) {.inline.} =
|
func ch*(expectedChars: set[char]): (Parser -> ParserResult) {.inline.} =
|
||||||
return func(parser: Parser): ParserResult =
|
return func(parser: Parser): ParserResult =
|
||||||
let state = parser.state
|
let state = parser.state
|
||||||
let newIndex = state.position + 1
|
let newIndex = state.position + 1
|
||||||
@@ -151,7 +141,7 @@ func ch(expectedChars: set[char]): (Parser -> ParserResult) {.inline.} =
|
|||||||
parser: parser,
|
parser: parser,
|
||||||
))
|
))
|
||||||
|
|
||||||
func ch(expectedChar: char): (Parser -> ParserResult) {.inline.} =
|
func ch*(expectedChar: char): (Parser -> ParserResult) {.inline.} =
|
||||||
return func(parser: Parser): ParserResult =
|
return func(parser: Parser): ParserResult =
|
||||||
let state = parser.state
|
let state = parser.state
|
||||||
let newIndex = state.position + 1
|
let newIndex = state.position + 1
|
||||||
@@ -183,7 +173,14 @@ func ch(expectedChar: char): (Parser -> ParserResult) {.inline.} =
|
|||||||
parser: parser,
|
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:
|
if parser.state.position == parser.state.stream.len - 1:
|
||||||
ok(parser)
|
ok(parser)
|
||||||
else:
|
else:
|
||||||
@@ -194,7 +191,7 @@ proc endOfStream(parser: Parser): ParserResult =
|
|||||||
parser: parser,
|
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
|
## Parse characters but throw success tokens away
|
||||||
return proc(parser: Parser): ParserResult =
|
return proc(parser: Parser): ParserResult =
|
||||||
return parserFn(parser)
|
return parserFn(parser)
|
||||||
@@ -203,7 +200,7 @@ func ignore(parserFn: Parser -> ParserResult): (Parser -> ParserResult) {.inline
|
|||||||
tokens: parser.tokens,
|
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
|
## Parse characters but throw success tokens away
|
||||||
return proc(parser: Parser): ParserResult =
|
return proc(parser: Parser): ParserResult =
|
||||||
var res: ParserResult = acceptFn(parser)
|
var res: ParserResult = acceptFn(parser)
|
||||||
@@ -211,10 +208,10 @@ func manyUntil(acceptFn: Parser -> ParserResult, stopFn: Parser -> ParserResult)
|
|||||||
res = res.flatMap(acceptFn)
|
res = res.flatMap(acceptFn)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
func anyUntil(stopFn: Parser -> ParserResult): (Parser -> ParserResult) {.inline.} =
|
func anyUntil*(stopFn: Parser -> ParserResult): (Parser -> ParserResult) {.inline.} =
|
||||||
manyUntil(ch(AllChars), stopFn)
|
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 =
|
return proc(parser: Parser): ParserResult =
|
||||||
var errors: seq[ParserResult] = newSeq[ParserResult]()
|
var errors: seq[ParserResult] = newSeq[ParserResult]()
|
||||||
var found = Nothing[ParserResult]()
|
var found = Nothing[ParserResult]()
|
||||||
@@ -241,17 +238,10 @@ func choice(parsers: seq[Parser -> ParserResult]): (Parser -> ParserResult) {.in
|
|||||||
proc(x: ParserResult): ParserResult = x,
|
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)
|
xs.foldl(a.flatMap(b), parser)
|
||||||
|
|
||||||
func str(s: string): (Parser -> ParserResult) {.inline.} =
|
proc foldTokens*[T](
|
||||||
return func(parser: Parser): ParserResult =
|
|
||||||
var p = parser.ok()
|
|
||||||
for c in s.items:
|
|
||||||
p = p.flatMap(ch(c))
|
|
||||||
return p
|
|
||||||
|
|
||||||
proc foldTokens[T](
|
|
||||||
parserResult: ParserResult,
|
parserResult: ParserResult,
|
||||||
onError: ParserError -> T,
|
onError: ParserError -> T,
|
||||||
onSuccess: seq[Token] -> 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]),
|
tree: fn(b[1]),
|
||||||
)))
|
)))
|
||||||
|
|
||||||
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[Token], seq[T]) -> seq[T],
|
||||||
@@ -294,7 +284,7 @@ proc applyParsers[T](
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
proc applyParsersSeq[T](
|
proc applyParsersSeq*[T](
|
||||||
builder: BuilderResult[T],
|
builder: BuilderResult[T],
|
||||||
xs: seq[tuple[
|
xs: seq[tuple[
|
||||||
parsers: seq[Parser -> ParserResult],
|
parsers: seq[Parser -> ParserResult],
|
||||||
@@ -302,7 +292,7 @@ proc applyParsersSeq[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)
|
||||||
|
|
||||||
proc foldBuilder[T, T2](
|
proc foldBuilder*[T, T2](
|
||||||
builderResult: BuilderResult[T],
|
builderResult: BuilderResult[T],
|
||||||
onError: string -> T2,
|
onError: string -> T2,
|
||||||
onSuccess: seq[T] -> T2,
|
onSuccess: seq[T] -> T2,
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
import cascade
|
|
||||||
import print
|
|
||||||
|
|
||||||
@@ -9,8 +9,9 @@ type
|
|||||||
orgHeadline,
|
orgHeadline,
|
||||||
orgText,
|
orgText,
|
||||||
|
|
||||||
OrgElement = ref object
|
OrgElement* = ref object
|
||||||
children*: orgElementChildren
|
children*: orgElementChildren
|
||||||
|
id*: string
|
||||||
|
|
||||||
case kind*: OrgElementKind
|
case kind*: OrgElementKind
|
||||||
of orgHeadline:
|
of orgHeadline:
|
||||||
|
|||||||
Reference in New Issue
Block a user