1212# # This JSON implementation has a similar API to [pkg/jsony](https://github.com/treeform/jsony)
1313# # but is designed to work with memory-mapped files and provide a more flexible and extensible
1414# # serialization/deserialization mechanism.
15-
1615import std/ [macros, macrocache, json, sequtils,
1716 strutils, options, tables, enumutils, memfiles,
1817 critbits, typetraits]
4645 # # deserialization
4746
4847 #
49- # JSON Parser
48+ # JSON JsonParser
5049 #
51- TokenKind = enum
50+ TokenKind * = enum
5251 tkEof,
5352 tkLBrace = " {"
5453 tkRBrace = " }"
6665 line, col: int
6766 current: char
6867
69- Token = ref object
70- kind: TokenKind
71- value: string
72- line, col: int
68+ Token * = ref object
69+ kind* : TokenKind
70+ value* : string
71+ line* , col* : int
7372
74- Parser = object
73+ JsonParser * = object
7574 lexer: Lexer
76- prev, curr, next: Token
75+ prev* , curr* , next* : Token
7776 options: JsonOptions
7877 lvl: int # indentation level
7978
@@ -92,7 +91,7 @@ proc error(l: var Lexer, msg: string) =
9291 # Raise a lexer error
9392 raise newException (OpenParserJsonError , (" Error ($1:$2) " % [$ l.line, $ l.col]) & msg)
9493
95- proc error (p: var Parser , msg: string ) =
94+ proc error (p: var JsonParser , msg: string ) =
9695 # Raise a parsing error with the current lexer position
9796 raise newException (OpenParserJsonError , (" Error ($1:$2) " % [$ p.lexer.line, $ p.lexer.col]) & msg)
9897
@@ -107,7 +106,8 @@ proc isMapped*(m: MemFile): bool {.inline.} =
107106
108107
109108#
110- # JSONY object variants
109+ # JSONY object variants utility macros
110+ # https://github.com/treeform/jsony
111111#
112112proc hasKind (node: NimNode , kind: NimNodeKind ): bool =
113113 for c in node.children:
@@ -121,11 +121,11 @@ proc `[]`(node: NimNode, kind: NimNodeKind): NimNode =
121121 return c
122122 return nil
123123
124- template fieldPairs * [T: ref object ](x: T): untyped =
124+ template fieldPairs [T: ref object ](x: T): untyped =
125125 x[].fieldPairs
126126
127- macro isObjectVariant * (v: typed ): bool =
128- # # Is this an object variant?
127+ macro isObjectVariant (v: typed ): bool =
128+ # Is this an object variant?
129129 var typ = v.getTypeImpl ()
130130 if typ.kind == nnkSym:
131131 return ident (" false" )
@@ -136,25 +136,25 @@ macro isObjectVariant*(v: typed): bool =
136136 else :
137137 ident (" false" )
138138
139- proc discriminator * (v: NimNode ): NimNode =
139+ proc discriminator (v: NimNode ): NimNode =
140140 var typ = v.getTypeImpl ()
141141 while typ.kind != nnkObjectTy:
142142 typ = typ[0 ].getTypeImpl ()
143143 return typ[nnkRecList][nnkRecCase][nnkIdentDefs][nnkSym]
144144
145- macro discriminatorFieldName * (v: typed ): untyped =
146- # # Turns into the discriminator field.
145+ macro discriminatorFieldName (v: typed ): untyped =
146+ # Turns into the discriminator field.
147147 return newLit ($ discriminator (v))
148148
149- macro discriminatorField * (v: typed ): untyped =
150- # # Turns into the discriminator field.
149+ macro discriminatorField (v: typed ): untyped =
150+ # Turns into the discriminator field.
151151 let
152152 fieldName = discriminator (v)
153153 return quote do :
154154 `v`.`fieldName`
155155
156- macro new * (v: typed , d: typed ): untyped =
157- # # Creates a new object variant with the discriminator field.
156+ macro new (v: typed , d: typed ): untyped =
157+ # Creates a new object variant with the discriminator field.
158158 let
159159 typ = v.getTypeInst ()
160160 fieldName = discriminator (v)
@@ -399,10 +399,11 @@ proc arrayToJson*(v, valImpl: NimNode, opts: JsonOptions = nil): NimNode =
399399 dumpHook (str, item)
400400 str.add (" ]" )
401401 move (str) # return the JSON string
402+
402403#
403- # JSON Parser
404+ # Lexer API
404405#
405- proc `$` * (tk: TokenKind ): string =
406+ proc `$` (tk: TokenKind ): string =
406407 # # Convert TokenKind to string
407408 result =
408409 case tk
@@ -415,13 +416,13 @@ proc `$`*(tk: TokenKind): string =
415416 of tkTrue, tkFalse: " <boolean>"
416417 of tkNull: " <null>"
417418
418- proc `$` * (tk: Token ): string =
419+ proc `$` (tk: Token ): string =
419420 # # Convert Token to string
420421 result = " TOKEN<kind: " & $ tk.kind &
421422 (if tk.value.len > 0 : " , value:" & tk.value else : " " ) &
422423 " , line:" & $ tk.line & " , col:" & $ tk.col & " >"
423424
424- proc nextToken (parser: var Parser ): Token {.discardable .}
425+ proc nextToken (parser: var JsonParser ): Token {.discardable .}
425426
426427proc charAt (l: Lexer , idx: int ): char {.inline .} =
427428 if idx < 0 or idx >= l.len: return '\0 '
@@ -444,16 +445,6 @@ proc advance(l: var Lexer) =
444445 l.pos = l.len
445446 l.current = '\0 '
446447
447- proc peekChar (l: var Lexer ): char =
448- l.charAt (l.pos + 1 )
449-
450- proc peekUntil (parser: var Parser , stopChar: char ): string =
451- var tempPos = parser.lexer.pos
452- result = " "
453- while tempPos < parser.lexer.len and parser.lexer.charAt (tempPos) != stopChar:
454- result .add (parser.lexer.charAt (tempPos))
455- inc tempPos
456-
457448proc matchKeyword (l: var Lexer , kw: string ): bool =
458449 if l.pos + kw.len > l.len: return false
459450 for i, c in kw:
@@ -542,8 +533,7 @@ proc readNumber(l: var Lexer): string =
542533#
543534# JSON Parsing implementation to Nim objects
544535#
545-
546- proc nextToken (parser: var Parser ): Token =
536+ proc nextToken (parser: var JsonParser ): Token =
547537 # Get the next token from the lexer
548538 skipWhitespace (parser.lexer)
549539 result = Token (line: parser.lexer.line, col: parser.lexer.col)
@@ -593,29 +583,29 @@ proc nextToken(parser: var Parser): Token =
593583 else :
594584 parser.lexer.error (unexpectedChar % [$ parser.lexer.current])
595585
596- proc walk (parser: var Parser ): Token {.discardable .} =
586+ #
587+ # Parse Hooks for JSON Deserialization
588+ #
589+ proc parseHook * (parser: var JsonParser , field: string , v: var string )
590+ proc parseHook * [T: float | float32 | float64 ](parser: var JsonParser , field: string , v: var T)
591+ proc parseHook * (parser: var JsonParser , field: string , v: var bool )
592+ proc parseHook * [T](parser: var JsonParser , field: string , v: var seq [T])
593+ proc parseHook * [T: ref object ](parser: var JsonParser , field: string , v: var T)
594+ proc parseHook * [T: enum ](parser: var JsonParser , field: string , v: var T)
595+ proc parseHook * [K: string , V](parser: var JsonParser , field: string , v: var AnyTable [K, V])
596+ proc parseHook * [T](parser: var JsonParser , field: string , v: var set [T])
597+ proc parseHook * [T: Integers ](parser: var JsonParser , field: string , v: var T)
598+
599+ proc skipValue * (parser: var JsonParser )
600+
601+ proc walk * (parser: var JsonParser ): Token {.discardable .} =
597602 # Advance to the next token and return it
598603 parser.prev = parser.curr
599604 parser.curr = parser.next
600605 parser.next = parser.nextToken ()
601606 result = parser.curr
602607
603- #
604- # Parse Hooks for JSON Deserialization
605- #
606- proc parseHook * (parser: var Parser , field: string , v: var string )
607- proc parseHook * [T: float | float32 | float64 ](parser: var Parser , field: string , v: var T)
608- proc parseHook * (parser: var Parser , field: string , v: var bool )
609- proc parseHook * [T](parser: var Parser , field: string , v: var seq [T])
610- proc parseHook * [T: ref object ](parser: var Parser , field: string , v: var T)
611- proc parseHook * [T: enum ](parser: var Parser , field: string , v: var T)
612- proc parseHook * [K: string , V](parser: var Parser , field: string , v: var AnyTable [K, V])
613- proc parseHook * [T](parser: var Parser , field: string , v: var set [T])
614- proc parseHook * [T: Integers ](parser: var Parser , field: string , v: var T)
615-
616- proc skipValue * (parser: var Parser )
617-
618- proc expectSkip (parser: var Parser , tkind: TokenKind ) =
608+ proc expectSkip (parser: var JsonParser , tkind: TokenKind ) =
619609 if parser.curr.kind != tkind:
620610 if parser.curr.kind == tkEof:
621611 parser.error (errorEndOfFile % $ parser.curr.kind)
@@ -644,7 +634,7 @@ template withKey(body: untyped) {.inject.} =
644634#
645635# Skip Values
646636#
647- proc skipValue * (parser: var Parser ) =
637+ proc skipValue * (parser: var JsonParser ) =
648638 # # Skip the current value in the parser
649639 case parser.curr.kind
650640 of tkLBrace:
@@ -670,22 +660,22 @@ proc skipValue*(parser: var Parser) =
670660#
671661# Parse Hooks
672662#
673- proc parseHook * (parser: var Parser , field: string , v: var string ) =
663+ proc parseHook * (parser: var JsonParser , field: string , v: var string ) =
674664 # # A hook to parse string fields
675665 v = parser.curr.value
676666 parser.walk ()
677667
678- proc parseHook * [T: float | float32 | float64 ](parser: var Parser , field: string , v: var T) =
668+ proc parseHook * [T: float | float32 | float64 ](parser: var JsonParser , field: string , v: var T) =
679669 # # A hook to parse integer fields
680670 v = parser.curr.value.parseFloat ()
681671 parser.walk ()
682672
683- proc parseHook * (parser: var Parser , field: string , v: var bool ) =
673+ proc parseHook * (parser: var JsonParser , field: string , v: var bool ) =
684674 # # A hook to parse boolean fields
685675 v = parser.curr.kind == tkTrue
686676 parser.walk ()
687677
688- proc parseHook * [K: string , V](parser: var Parser , field: string , v: var AnyTable [K, V]) =
678+ proc parseHook * [K: string , V](parser: var JsonParser , field: string , v: var AnyTable [K, V]) =
689679 # # Parse JSON object into Table/OrderedTable and ref variants.
690680 when v is TableRef [K, V] or v is OrderedTableRef [K, V]:
691681 if parser.curr.kind == tkNull:
@@ -734,7 +724,7 @@ proc parseHook*[K: string, V](parser: var Parser, field: string, v: var AnyTable
734724
735725 parser.expectSkip (tkRBrace)
736726
737- proc parseHook * [T: enum ](parser: var Parser , field: string , v: var T) =
727+ proc parseHook * [T: enum ](parser: var JsonParser , field: string , v: var T) =
738728 # # A hook to parse enum fields
739729 if parser.curr.kind == tkString:
740730 let enumStr = parser.curr.value
@@ -747,7 +737,7 @@ proc parseHook*[T: enum](parser: var Parser, field: string, v: var T) =
747737 else :
748738 parser.error (unexpectedTokenExpected % [$ parser.curr.kind, " string or number" ])
749739
750- proc parseHook * [T](parser: var Parser , field: string , v: var set [T]) =
740+ proc parseHook * [T](parser: var JsonParser , field: string , v: var set [T]) =
751741 # # A hook to parse set fields from JSON arrays
752742 parser.expectSkip (tkLBracket) # start of array
753743 while parser.curr.kind != tkRBracket:
@@ -758,14 +748,14 @@ proc parseHook*[T](parser: var Parser, field: string, v: var set[T]) =
758748 parser.walk ()
759749 parser.expectSkip (tkRBracket) # end of array
760750
761- proc parseHook * [T: distinct ](parser: var Parser , field: string , v: var T) =
751+ proc parseHook * [T: distinct ](parser: var JsonParser , field: string , v: var T) =
762752 # # A hook to parse distinct types by parsing their base type and then converting
763753 var tmp: T.distinctBase
764754 parser.parseHook (" " , tmp)
765755 v = T (tmp)
766756 parser.walk ()
767757
768- proc parseHook * [T: Integers ](parser: var Parser , field: string , v: var T) =
758+ proc parseHook * [T: Integers ](parser: var JsonParser , field: string , v: var T) =
769759 # # A hook to parse integer fields
770760 v = cast [v.type ](parser.curr.value.parseInt ())
771761 parser.walk ()
@@ -790,7 +780,7 @@ macro getObjectFields(obj: typed): untyped =
790780 else : discard
791781 result = newStmtList ().add (nnkPrefix.newTree (ident " @" , fieldList))
792782
793- proc parseHook * [T: object | ref object ](parser: var Parser , field: string , v: var T) =
783+ proc parseHook * [T: object | ref object ](parser: var JsonParser , field: string , v: var T) =
794784 parser.expectSkip (tkLBrace) # start of object
795785 const objectFields: seq [string ] = getObjectFields (v)
796786
@@ -848,7 +838,7 @@ proc parseHook*[T: object|ref object](parser: var Parser, field: string, v: var
848838
849839 parser.expectSkip (tkRBrace)
850840
851- proc parseHook * [T: ref object ](parser: var Parser , field: string , v: var T) =
841+ proc parseHook * [T: ref object ](parser: var JsonParser , field: string , v: var T) =
852842 # # A hook to parse ref object fields
853843 if parser.curr.kind == tkNull:
854844 v = nil
@@ -858,7 +848,7 @@ proc parseHook*[T: ref object](parser: var Parser, field: string, v: var T) =
858848 new (v)
859849 parser.parseHook (" " , v[])
860850
861- proc parseHook * [T](parser: var Parser , field: string , v: var seq [T]) =
851+ proc parseHook * [T](parser: var JsonParser , field: string , v: var seq [T]) =
862852 # # A hook to parse sequence fields
863853 parser.expectSkip (tkLBracket) # start of array
864854 while parser.curr.kind != tkRBracket:
@@ -872,16 +862,17 @@ proc parseHook*[T](parser: var Parser, field: string, v: var seq[T]) =
872862#
873863# JsonNode Objects
874864#
865+
875866#
876867# Forward decl for JSON parsing
877868#
878- proc parseObject (parser: var Parser , obj: var JsonNode )
879- proc parseArray (parser: var Parser , arr: var JsonNode )
869+ proc parseObject (parser: var JsonParser , obj: var JsonNode )
870+ proc parseArray (parser: var JsonParser , arr: var JsonNode )
880871
881872#
882873# JSON Parsing Implementation
883874#
884- proc parseObject (parser: var Parser , obj: var JsonNode ) =
875+ proc parseObject (parser: var JsonParser , obj: var JsonNode ) =
885876 # Parse a JSON object
886877 while parser.curr.kind != tkRBrace:
887878 let token = parser.walk ()
@@ -925,7 +916,7 @@ proc parseObject(parser: var Parser, obj: var JsonNode) =
925916 parser.error (unexpectedToken % [$ token.kind])
926917 parser.walk () # consume the closing '}'
927918
928- proc parseArray (parser: var Parser , arr: var JsonNode ) =
919+ proc parseArray (parser: var JsonParser , arr: var JsonNode ) =
929920 # Parse a JSON array to JsonNode
930921 while parser.curr.kind != tkRBracket:
931922 let token = parser.walk ()
@@ -960,12 +951,12 @@ proc parseArray(parser: var Parser, arr: var JsonNode) =
960951 parser.error (unexpectedToken % [$ token.kind])
961952 parser.walk () # consume the closing ']'
962953
963- proc initParser (lexer: Lexer ): Parser =
964- result = Parser (lexer: lexer)
954+ proc initParser (lexer: Lexer ): JsonParser =
955+ result = JsonParser (lexer: lexer)
965956 result .curr = result .nextToken ()
966957 result .next = result .nextToken ()
967958
968- proc parseAnyRoot (parser: var Parser ): JsonNode =
959+ proc parseAnyRoot (parser: var JsonParser ): JsonNode =
969960 case parser.curr.kind
970961 of tkLBrace:
971962 result = newJObject ()
@@ -976,7 +967,7 @@ proc parseAnyRoot(parser: var Parser): JsonNode =
976967 else :
977968 parser.error (unexpectedToken % [$ parser.curr.kind])
978969
979- proc parseAnyRootL (parser: var Parser ): JsonNode =
970+ proc parseAnyRootL (parser: var JsonParser ): JsonNode =
980971 result = newJArray ()
981972 while parser.curr.kind != tkEof:
982973 case parser.curr.kind
@@ -1026,7 +1017,7 @@ proc fromJsonLFile*(filename: string): JsonNode =
10261017#
10271018# Nim Objects
10281019#
1029- proc parseJson [T: object | ref object ](parser: var Parser , v: var T) =
1020+ proc parseJson [T: object | ref object ](parser: var JsonParser , v: var T) =
10301021 case parser.curr.kind
10311022 of tkLBrace:
10321023 parser.parseHook (" " , v)
@@ -1043,7 +1034,7 @@ macro fromJsonMacro(x: typed, str: typed): untyped =
10431034 add blockStmtList, quote do :
10441035 var
10451036 tmp = `objIdent` ()
1046- parser = Parser (lexer: newLexer (`str`))
1037+ parser = JsonParser (lexer: newLexer (`str`))
10471038 parser.curr = parser.nextToken ()
10481039 parser.next = parser.nextToken ()
10491040 parser.parseJson (tmp)
0 commit comments