Seperate types & utils to files
This commit is contained in:
@@ -2,6 +2,7 @@ import results
|
|||||||
import fusion/matching
|
import fusion/matching
|
||||||
import ../utils/fp
|
import ../utils/fp
|
||||||
import ../parser/parser
|
import ../parser/parser
|
||||||
|
import ../parser/parser_types
|
||||||
|
|
||||||
{.experimental: "caseStmtMacros".}
|
{.experimental: "caseStmtMacros".}
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,13 @@ import std/sugar
|
|||||||
import std/strformat
|
import std/strformat
|
||||||
import std/collections/sequtils
|
import std/collections/sequtils
|
||||||
import std/strutils
|
import std/strutils
|
||||||
import parser/parser
|
|
||||||
import parser/utils
|
|
||||||
import results
|
import results
|
||||||
import utils/fp
|
import utils/fp
|
||||||
import fusion/matching
|
import fusion/matching
|
||||||
|
|
||||||
|
import ./parser/parser
|
||||||
|
import ./parser/parser_types
|
||||||
|
import ./parser/utils
|
||||||
import ./org/org_properties_block
|
import ./org/org_properties_block
|
||||||
|
|
||||||
{.experimental: "caseStmtMacros".}
|
{.experimental: "caseStmtMacros".}
|
||||||
|
|||||||
@@ -7,153 +7,11 @@ import std/collections/tables
|
|||||||
import results
|
import results
|
||||||
import fusion/matching
|
import fusion/matching
|
||||||
import fp/maybe
|
import fp/maybe
|
||||||
|
import ./parser_types
|
||||||
import ../utils/str
|
import ../utils/str
|
||||||
|
|
||||||
{.experimental: "caseStmtMacros".}
|
{.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.} =
|
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
|
||||||
|
|||||||
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/sugar
|
||||||
import std/collections/sequtils
|
import std/collections/sequtils
|
||||||
import ./parser
|
|
||||||
import results
|
import results
|
||||||
|
import ./parser_types
|
||||||
|
|
||||||
type StringBuilderT* = string
|
type StringBuilderT* = string
|
||||||
type StringBuilder* = Builder[StringBuilderT]
|
type StringBuilder* = Builder[StringBuilderT]
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
import std/strutils
|
import std/strutils
|
||||||
import std/math
|
import std/math
|
||||||
|
import fusion/matching
|
||||||
|
|
||||||
|
{.experimental: "caseStmtMacros".}
|
||||||
|
|
||||||
proc safeDelete*(str: string, slice: Slice[int]): string =
|
proc safeDelete*(str: string, slice: Slice[int]): string =
|
||||||
## Deletes the items `str[slice]`, ignoring elements out of range.
|
## 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 =
|
func deleteAfterNewline*(str: string, start = 0): string =
|
||||||
## Delete string after next Newline from `start`.
|
## Delete string after next Newline from `start`.
|
||||||
findAndDelete(str, Newlines, 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