From 6bbcd9b6a3cac42c21870c683be360bf2d3c67df Mon Sep 17 00:00:00 2001 From: Jonathan Bernard Date: Tue, 18 Apr 2023 00:53:52 -0500 Subject: [PATCH] lexer: Support multiple nested bookmarks. --- src/vcard/private/lexer.nim | 121 +++++++++++++++++++++++++++++------- 1 file changed, 98 insertions(+), 23 deletions(-) diff --git a/src/vcard/private/lexer.nim b/src/vcard/private/lexer.nim index d159b20..f7580e5 100644 --- a/src/vcard/private/lexer.nim +++ b/src/vcard/private/lexer.nim @@ -3,14 +3,14 @@ import std/[streams, unicode] type VCardLexer* = object of RootObj input: Stream - buffer*: string # buffer of bytes read - bufStart: int # starting boundary for the buffer - bufEnd: int # ending boundary for the buffer - pos*: int # current read position - bookmark*: int # bookmark to support rewind functionality - bookmarkVal*: string # value that has been read since the bookmark was set - lineNumber*: int # how many newlines have we seen so far - lineStart: int # index into the buffer for the start of the current line + buffer*: string # buffer of bytes read + bufStart: int # starting boundary for the buffer + bufEnd: int # ending boundary for the buffer + pos*: int # current read position + bookmark*: seq[int] # bookmark to support rewind functionality + bookmarkVal*: seq[string] # value read since the bookmark was set + lineNumber*: int # how many newlines have we seen so far + lineStart: int # buffer index buffer for the start of the current line proc skipUtf8Bom(vcl: var VCardLexer) = if (vcl.buffer[0] == '\xEF') and (vcl.buffer[1] == '\xBB') and (vcl.buffer[2] == '\xBF'): @@ -19,7 +19,7 @@ proc skipUtf8Bom(vcl: var VCardLexer) = template wrappedIdx(idx: untyped): int = idx mod vcl.buffer.len proc newStartIdx(vcl: VCardLexer): int = - if vcl.bookmark > 0: vcl.bookmark else: vcl.pos + if vcl.bookmark.len > 0: vcl.bookmark[0] else: vcl.pos func isFull(vcl: VCardLexer): bool {.inline.} = return wrappedIdx(vcl.bufEnd + 1) == vcl.newStartIdx @@ -41,7 +41,7 @@ proc doubleBuffer(vcl: var VCardLexer) = vcl.pos -= vcl.bufStart vcl.lineStart -= vcl.bufStart - if vcl.bookmark >= 0: vcl.bookmark -= vcl.bufStart + if vcl.bookmark.len > 0: vcl.bookmark[0] -= vcl.bufStart vcl.bufStart = 0 vcl.bufEnd = newIdx @@ -84,7 +84,7 @@ proc open*(vcl: var VCardLexer, input: Stream, bufLen = 16384) = assert(input != nil) vcl.input = input vcl.pos = 0 - vcl.bookmark = -1 + vcl.bookmark = @[] vcl.buffer = newString(bufLen) vcl.bufStart = 0 vcl.bufEnd = 0 @@ -94,18 +94,27 @@ proc open*(vcl: var VCardLexer, input: Stream, bufLen = 16384) = vcl.skipUtf8Bom proc setBookmark*(vcl: var VCardLexer) = - vcl.bookmark = vcl.pos - vcl.bookmarkVal = newStringOfCap(32) + vcl.bookmark.add(vcl.pos) + vcl.bookmarkVal.add(newStringOfCap(32)) proc returnToBookmark*(vcl: var VCardLexer) = - vcl.pos = vcl.bookmark - vcl.bookmark = -1 + if vcl.bookmark.len == 0: return + vcl.pos = vcl.bookmark.pop() + let valRead = vcl.bookmarkVal.pop() + for idx in 0.. valRead.len: + vcl.bookmarkVal[idx] = vcl.bookmarkVal[idx][0 ..< ^valRead.len] proc unsetBookmark*(vcl: var VCardLexer) = - vcl.bookmark = -1 + if vcl.bookmark.len == 0: return + discard vcl.bookmark.pop() + discard vcl.bookmarkVal.pop() proc readSinceBookmark*(vcl: var VCardLexer): string = - return vcl.bookmarkVal + if vcl.bookmarkVal.len > 0: + return vcl.bookmarkVal[^1] + else: return "" + #[ if vcl.pos < vcl.bookmark: # p e s b @@ -151,7 +160,8 @@ proc read*(vcl: var VCardLexer, peek = false): char = result = vcl.buffer[vcl.pos] if not peek: - if vcl.bookmark != -1: vcl.bookmarkVal.add(result) + for idx in 0..