Seperate types & utils to files
This commit is contained in:
@@ -2,6 +2,7 @@ import results
|
||||
import fusion/matching
|
||||
import ../utils/fp
|
||||
import ../parser/parser
|
||||
import ../parser/parser_types
|
||||
|
||||
{.experimental: "caseStmtMacros".}
|
||||
|
||||
|
||||
@@ -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".}
|
||||
|
||||
@@ -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
128
src/parser/parser_types.nim
Normal 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"
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user