Seperate types & utils to files

This commit is contained in:
Florian Schroedl
2022-01-20 17:00:00 +01:00
parent 854d5d356d
commit 488d0b173b
6 changed files with 163 additions and 146 deletions

View File

@@ -2,6 +2,7 @@ import results
import fusion/matching
import ../utils/fp
import ../parser/parser
import ../parser/parser_types
{.experimental: "caseStmtMacros".}

View File

@@ -2,11 +2,13 @@ import std/sugar
import std/strformat
import std/collections/sequtils
import std/strutils
import parser/parser
import parser/utils
import results
import utils/fp
import fusion/matching
import ./parser/parser
import ./parser/parser_types
import ./parser/utils
import ./org/org_properties_block
{.experimental: "caseStmtMacros".}

View File

@@ -7,153 +7,11 @@ import std/collections/tables
import results
import fusion/matching
import fp/maybe
import ./parser_types
import ../utils/str
{.experimental: "caseStmtMacros".}
type
ParserState* = ref object
stream: string
position, lastPosition: int
parserTokenCharValueT* = 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
state*: ParserState
tokens*: seq[ParserToken]
ParseErrorKind = enum
choiceMismatchErr
charMismatchErr
endOfStringErr
ParserError = ref object
kind: ParseErrorKind
unexpected: string
expected: string
index: int
parser: Parser
ParserResult* = Result[Parser, ParserError]
Builder*[T] = tuple[
parser: Parser,
tree: seq[T]
]
BuilderResult*[T] = Result[Builder[T], (Builder[T], string)]
proc indentKey(x: string, count: int): string =
var y = x.indent(count)
y.delete(0..count - 1)
y
proc tokenStringValue*(x: ParserToken): string =
case x.kind:
of parserTokenChar:
$x.charValue
of parserTokenString:
x.stringValue
proc `$`*(x: ParserToken): string =
&"""ParserToken(
value: {tokenStringValue(x)},
)"""
proc `$`*(x: ParserState): string =
&"""ParserState(
stream: "{x.stream}",
position: {x.position},
lastPosition: {x.lastPosition},
)"""
proc `$`*(x: Parser): string =
&"""Parser(
state: {indentKey($x.state, 2)},
tokens: {indentKey($x.tokens, 2)},
)"""
proc prettyExpectedSet(x: set[char]): string =
case x:
of AllChars:
"AllChars {'\x00'..'\xFF'}"
of Digits:
"Digits {'0'..'9'}"
of HexDigits:
"HexDigits {'0'..'9', 'A'..'F', 'a'..'f'}"
of Letters:
"Letters {'A'..'Z', 'a'..'z'}"
of Newlines:
"Newlines {'\r', '\n'}"
of Whitespace:
"Whitespace {' ', '\t', '\v', '\r', '\n', '\f'}"
else:
$x
proc `$`*(x: ParserError): string =
case x:
of charMismatchErr(expected: @expected, parser: @parser, index: @index, unexpected: @unexpected):
# TODO: Only works for single line right now
let original = parser.state.stream
.deleteAfterNewline(parser.state.position)
let errSpace = " ".repeat(max(0, index))
$index & $parser &
&"""Parsing Error (Character Mismatch Error):
{original}
{errSpace}^ Expected '{expected}' but got '{unexpected}'"""
of choiceMismatchErr(expected: @expected, parser: @parser, index: @index, unexpected: @unexpected):
let original = parser.state.stream
.deleteAfterNewline(parser.state.position)
let errSpace = " ".repeat(max(0, index))
$index & $parser &
&"""Parsing Error (Character Mismatch Error):
{original}
{errSpace}^ Expected '{expected}' but got '{unexpected}'"""
of endOfStringErr(parser: @parser, index: @index):
let original = parser.state.stream
.deleteAfterNewline(parser.state.position)
let errSpace = " ".repeat(max(0, index))
$index & $parser &
&"""Parsing Error (EndOfString Expected):
{original}
{errSpace}^ Expected 'EndOfString' at {index} but got {original.len - 1}"""
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 =
Parser(
state: ParserState(
stream: str,
position: -1,
lastPosition: 0,
),
tokens: newSeq[ParserToken](),
)
proc initParserResult*(str: string): ParserResult =
ParserResult.ok(initParser(str))
func ch*(expectedChars: set[char]): (Parser -> ParserResult) {.inline.} =
return func(parser: Parser): ParserResult =
let state = parser.state

128
src/parser/parser_types.nim Normal file
View File

@@ -0,0 +1,128 @@
import std/strutils
import std/strformat
import results
import fusion/matching
import ../utils/str
{.experimental: "caseStmtMacros".}
type
ParserState* = ref object
stream*: string
position*, lastPosition*: int
parserTokenCharValueT* = char
parserTokenStringValueT* = string
ParserTokenKind* = enum
parserTokenChar
parserTokenString
ParserToken* = ref object
case kind*: ParserTokenKind
of parserTokenChar:
charValue*: parserTokenCharValueT
of parserTokenString:
stringValue*: parserTokenStringValueT
Parser* = ref object
state*: ParserState
tokens*: seq[ParserToken]
ParseErrorKind* = enum
choiceMismatchErr
charMismatchErr
endOfStringErr
ParserError* = ref object
kind*: ParseErrorKind
unexpected*: string
expected*: string
index*: int
parser*: Parser
ParserResult* = Result[Parser, ParserError]
Builder*[T] = tuple[
parser: Parser,
tree: seq[T]
]
BuilderResult*[T] = Result[Builder[T], (Builder[T], string)]
# -- Initalizers
func initParserToken*(x: char): ParserToken = ParserToken(kind: parserTokenChar, charValue: x)
func initParserToken*(x: string): ParserToken = ParserToken(kind: parserTokenString, stringValue: x)
proc initParser*(str: string): Parser =
Parser(
state: ParserState(
stream: str,
position: -1,
lastPosition: 0,
),
tokens: newSeq[ParserToken](),
)
proc initParserResult*(str: string): ParserResult =
ParserResult.ok(initParser(str))
# -- Getters
proc tokenStringValue*(x: ParserToken): string =
## Get the Token value `x` as a string.
case x.kind:
of parserTokenChar:
$x.charValue
of parserTokenString:
x.stringValue
# -- Stringifiers
proc `$`*(x: ParserToken): string =
&"""ParserToken(
value: {tokenStringValue(x)},
)"""
proc `$`*(x: ParserState): string =
&"""ParserState(
stream: "{x.stream}",
position: {x.position},
lastPosition: {x.lastPosition},
)"""
proc `$`*(x: Parser): string =
&"""Parser(
state: {indentAfterNewline($x.state, 2)},
tokens: {indentAfterNewline($x.tokens, 2)},
)"""
proc `$`*(x: ParserError): string =
case x:
of charMismatchErr(expected: @expected, parser: @parser, index: @index, unexpected: @unexpected):
# TODO: Only works for single line right now
let original = parser.state.stream
.deleteAfterNewline(parser.state.position)
let errSpace = " ".repeat(max(0, index))
$index & $parser &
&"""Parsing Error (Character Mismatch Error):
{original}
{errSpace}^ Expected '{expected}' but got '{unexpected}'"""
of choiceMismatchErr(expected: @expected, parser: @parser, index: @index, unexpected: @unexpected):
let original = parser.state.stream
.deleteAfterNewline(parser.state.position)
let errSpace = " ".repeat(max(0, index))
$index & $parser &
&"""Parsing Error (Character Mismatch Error):
{original}
{errSpace}^ Expected '{expected}' but got '{unexpected}'"""
of endOfStringErr(parser: @parser, index: @index):
let original = parser.state.stream
.deleteAfterNewline(parser.state.position)
let errSpace = " ".repeat(max(0, index))
$index & $parser &
&"""Parsing Error (EndOfString Expected):
{original}
{errSpace}^ Expected 'EndOfString' at {index} but got {original.len - 1}"""
else: "ParseError"

View File

@@ -1,7 +1,7 @@
import std/sugar
import std/collections/sequtils
import ./parser
import results
import ./parser_types
type StringBuilderT* = string
type StringBuilder* = Builder[StringBuilderT]

View File

@@ -1,5 +1,8 @@
import std/strutils
import std/math
import fusion/matching
{.experimental: "caseStmtMacros".}
proc safeDelete*(str: string, slice: Slice[int]): string =
## Deletes the items `str[slice]`, ignoring elements out of range.
@@ -25,3 +28,28 @@ func findAndDelete*(str: string, chars: set[char], start = 0, last = str.len - 1
func deleteAfterNewline*(str: string, start = 0): string =
## Delete string after next Newline from `start`.
findAndDelete(str, Newlines, start)
proc indentAfterNewline*(str: string, count: int): string =
## Indent lines following the first line of `str` by `count`.
## Useful for indenting nested keys of stringify functions.
var strDup = str.indent(count)
strDup.delete(0..count - 1)
strDup
proc prettyExpectedSet*(x: set[char]): string =
## Pretty print value for a set `x` of characters
case x:
of AllChars:
"AllChars {'\x00'..'\xFF'}"
of Digits:
"Digits {'0'..'9'}"
of HexDigits:
"HexDigits {'0'..'9', 'A'..'F', 'a'..'f'}"
of Letters:
"Letters {'A'..'Z', 'a'..'z'}"
of Newlines:
"Newlines {'\r', '\n'}"
of Whitespace:
"Whitespace {' ', '\t', '\v', '\r', '\n', '\f'}"
else:
$x