use hexchar in stdlib (#16290)

This commit is contained in:
flywind 2020-12-17 06:41:05 -06:00 • committed by GitHub
commit e1e069dd6c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 68 additions and 75 deletions

View file

@ -172,8 +172,8 @@ runnableExamples:
doAssert dict.getSectionValue(section4, "does_that_mean_anything_special") == "False" doAssert dict.getSectionValue(section4, "does_that_mean_anything_special") == "False"
doAssert dict.getSectionValue(section4, "purpose") == "formatting for readability" doAssert dict.getSectionValue(section4, "purpose") == "formatting for readability"
import import strutils, lexbase, streams, tables
strutils, lexbase, streams, tables import std/private/decode_helpers
include "system/inclrtl" include "system/inclrtl"
@ -247,20 +247,6 @@ proc getFilename*(c: CfgParser): string {.rtl, extern: "npc$1".} =
## Gets the filename of the file that the parser processes. ## Gets the filename of the file that the parser processes.
result = c.filename result = c.filename
proc handleHexChar(c: var CfgParser, xi: var int) =
case c.buf[c.bufpos]
of '0'..'9':
xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('0'))
inc(c.bufpos)
of 'a'..'f':
xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('a') + 10)
inc(c.bufpos)
of 'A'..'F':
xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('A') + 10)
inc(c.bufpos)
else:
discard
proc handleDecChars(c: var CfgParser, xi: var int) = proc handleDecChars(c: var CfgParser, xi: var int) =
while c.buf[c.bufpos] in {'0'..'9'}: while c.buf[c.bufpos] in {'0'..'9'}:
xi = (xi * 10) + (ord(c.buf[c.bufpos]) - ord('0')) xi = (xi * 10) + (ord(c.buf[c.bufpos]) - ord('0'))
@ -305,8 +291,10 @@ proc getEscapedChar(c: var CfgParser, tok: var Token) =
of 'x', 'X': of 'x', 'X':
inc(c.bufpos) inc(c.bufpos)
var xi = 0 var xi = 0
handleHexChar(c, xi) if handleHexChar(c.buf[c.bufpos], xi):
handleHexChar(c, xi) inc(c.bufpos)
if handleHexChar(c.buf[c.bufpos], xi):
inc(c.bufpos)
add(tok.literal, chr(xi)) add(tok.literal, chr(xi))
of '0'..'9': of '0'..'9':
var xi = 0 var xi = 0

View file

@ -11,8 +11,8 @@
## and exported by the ``json`` standard library ## and exported by the ``json`` standard library
## module, but can also be used in its own right. ## module, but can also be used in its own right.
import import strutils, lexbase, streams, unicode
strutils, lexbase, streams, unicode import std/private/decode_helpers
type type
JsonEventKind* = enum ## enumeration of all events that may occur when parsing JsonEventKind* = enum ## enumeration of all events that may occur when parsing
@ -162,18 +162,11 @@ proc errorMsgExpected*(my: JsonParser, e: string): string =
result = "$1($2, $3) Error: $4" % [ result = "$1($2, $3) Error: $4" % [
my.filename, $getLine(my), $getColumn(my), e & " expected"] my.filename, $getLine(my), $getColumn(my), e & " expected"]
proc handleHexChar(c: char, x: var int): bool =
result = true # Success
case c
of '0'..'9': x = (x shl 4) or (ord(c) - ord('0'))
of 'a'..'f': x = (x shl 4) or (ord(c) - ord('a') + 10)
of 'A'..'F': x = (x shl 4) or (ord(c) - ord('A') + 10)
else: result = false # error
proc parseEscapedUTF16*(buf: cstring, pos: var int): int = proc parseEscapedUTF16*(buf: cstring, pos: var int): int =
result = 0 result = 0
#UTF-16 escape is always 4 bytes. #UTF-16 escape is always 4 bytes.
for _ in 0..3: for _ in 0..3:
# if char in '0' .. '9', 'a' .. 'f', 'A' .. 'F'
if handleHexChar(buf[pos], result): if handleHexChar(buf[pos], result):
inc(pos) inc(pos)
else: else:

View file

@ -12,8 +12,8 @@
## ##
## Unstable API. ## Unstable API.
import import strutils, lexbase
strutils, lexbase import std/private/decode_helpers
# ------------------- scanner ------------------------------------------------- # ------------------- scanner -------------------------------------------------
@ -72,20 +72,6 @@ proc getColumn(L: SqlLexer): int =
proc getLine(L: SqlLexer): int = proc getLine(L: SqlLexer): int =
result = L.lineNumber result = L.lineNumber
proc handleHexChar(c: var SqlLexer, xi: var int) =
case c.buf[c.bufpos]
of '0'..'9':
xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('0'))
inc(c.bufpos)
of 'a'..'f':
xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('a') + 10)
inc(c.bufpos)
of 'A'..'F':
xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('A') + 10)
inc(c.bufpos)
else:
discard
proc handleOctChar(c: var SqlLexer, xi: var int) = proc handleOctChar(c: var SqlLexer, xi: var int) =
if c.buf[c.bufpos] in {'0'..'7'}: if c.buf[c.bufpos] in {'0'..'7'}:
xi = (xi shl 3) or (ord(c.buf[c.bufpos]) - ord('0')) xi = (xi shl 3) or (ord(c.buf[c.bufpos]) - ord('0'))
@ -130,8 +116,10 @@ proc getEscapedChar(c: var SqlLexer, tok: var Token) =
of 'x', 'X': of 'x', 'X':
inc(c.bufpos) inc(c.bufpos)
var xi = 0 var xi = 0
handleHexChar(c, xi) if handleHexChar(c.buf[c.bufpos], xi):
handleHexChar(c, xi) inc(c.bufpos)
if handleHexChar(c.buf[c.bufpos], xi):
inc(c.bufpos)
add(tok.literal, chr(xi)) add(tok.literal, chr(xi))
of '0'..'7': of '0'..'7':
var xi = 0 var xi = 0

View file

@ -21,6 +21,7 @@ const
useUnicode = true ## change this to deactivate proper UTF-8 support useUnicode = true ## change this to deactivate proper UTF-8 support
import strutils, macros import strutils, macros
import std/private/decode_helpers
when useUnicode: when useUnicode:
import unicode import unicode
@ -1466,19 +1467,6 @@ proc errorStr(L: PegLexer, msg: string, line = -1, col = -1): string =
var col = if col < 0: getColumn(L) else: col var col = if col < 0: getColumn(L) else: col
result = "$1($2, $3) Error: $4" % [L.filename, $line, $col, msg] result = "$1($2, $3) Error: $4" % [L.filename, $line, $col, msg]
proc handleHexChar(c: var PegLexer, xi: var int) =
case c.buf[c.bufpos]
of '0'..'9':
xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('0'))
inc(c.bufpos)
of 'a'..'f':
xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('a') + 10)
inc(c.bufpos)
of 'A'..'F':
xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('A') + 10)
inc(c.bufpos)
else: discard
proc getEscapedChar(c: var PegLexer, tok: var Token) = proc getEscapedChar(c: var PegLexer, tok: var Token) =
inc(c.bufpos) inc(c.bufpos)
if c.bufpos >= len(c.buf): if c.bufpos >= len(c.buf):
@ -1515,8 +1503,10 @@ proc getEscapedChar(c: var PegLexer, tok: var Token) =
tok.kind = tkInvalid tok.kind = tkInvalid
return return
var xi = 0 var xi = 0
handleHexChar(c, xi) if handleHexChar(c.buf[c.bufpos], xi):
handleHexChar(c, xi) inc(c.bufpos)
if handleHexChar(c.buf[c.bufpos], xi):
inc(c.bufpos)
if xi == 0: tok.kind = tkInvalid if xi == 0: tok.kind = tkInvalid
else: add(tok.literal, chr(xi)) else: add(tok.literal, chr(xi))
of '0'..'9': of '0'..'9':

View file

@ -1,9 +1,25 @@
proc handleHexChar*(c: char, x: var int, f: var bool) {.inline.} = proc handleHexChar*(c: char, x: var int): bool {.inline.} =
## Converts `%xx` hexadecimal to the ordinal number and adds the result to `x`.
## Returns `true` if `c` is hexadecimal.
##
## When `c` is hexadecimal, the proc is equal to `x = x shl 4 + hex2Int(c)`.
runnableExamples:
var x = 0
assert handleHexChar('a', x)
assert x == 10
assert handleHexChar('B', x)
assert x == 171 # 10 shl 4 + 11
assert not handleHexChar('?', x)
assert x == 171 # unchanged
result = true
case c case c
of '0'..'9': x = (x shl 4) or (ord(c) - ord('0')) of '0'..'9': x = (x shl 4) or (ord(c) - ord('0'))
of 'a'..'f': x = (x shl 4) or (ord(c) - ord('a') + 10) of 'a'..'f': x = (x shl 4) or (ord(c) - ord('a') + 10)
of 'A'..'F': x = (x shl 4) or (ord(c) - ord('A') + 10) of 'A'..'F': x = (x shl 4) or (ord(c) - ord('A') + 10)
else: f = true else:
result = false
proc decodePercent*(s: openArray[char], i: var int): char = proc decodePercent*(s: openArray[char], i: var int): char =
## Converts `%xx` hexadecimal to the character with ordinal number `xx`. ## Converts `%xx` hexadecimal to the character with ordinal number `xx`.
@ -14,9 +30,6 @@ proc decodePercent*(s: openArray[char], i: var int): char =
result = '%' result = '%'
if i+2 < s.len: if i+2 < s.len:
var x = 0 var x = 0
var failed = false if handleHexChar(s[i+1], x) and handleHexChar(s[i+2], x):
handleHexChar(s[i+1], x, failed)
handleHexChar(s[i+2], x, failed)
if not failed:
result = chr(x) result = chr(x)
inc(i, 2) inc(i, 2)

View file

@ -12,6 +12,8 @@
import import
hashes, strutils, lexbase, streams, unicode, macros hashes, strutils, lexbase, streams, unicode, macros
import std/private/decode_helpers
type type
SexpEventKind* = enum ## enumeration of all events that may occur when parsing SexpEventKind* = enum ## enumeration of all events that may occur when parsing
sexpError, ## an error occurred during parsing sexpError, ## an error occurred during parsing
@ -113,14 +115,6 @@ proc errorMsgExpected*(my: SexpParser, e: string): string =
## other error messages ## other error messages
result = "($1, $2) Error: $3" % [$getLine(my), $getColumn(my), e & " expected"] result = "($1, $2) Error: $3" % [$getLine(my), $getColumn(my), e & " expected"]
proc handleHexChar(c: char, x: var int): bool =
result = true # Success
case c
of '0'..'9': x = (x shl 4) or (ord(c) - ord('0'))
of 'a'..'f': x = (x shl 4) or (ord(c) - ord('a') + 10)
of 'A'..'F': x = (x shl 4) or (ord(c) - ord('A') + 10)
else: result = false # error
proc parseString(my: var SexpParser): TTokKind = proc parseString(my: var SexpParser): TTokKind =
result = tkString result = tkString
var pos = my.bufpos + 1 var pos = my.bufpos + 1

View file

@ -0,0 +1,27 @@
import std/private/decode_helpers
block:
var i = 0
let c = decodePercent("%t9", i)
doAssert (i, c) == (0, '%')
block:
var i = 0
let c = decodePercent("19", i)
doAssert (i, c) == (0, '%')
block:
var i = 0
let c = decodePercent("%19", i)
doAssert (i, c) == (2, '\x19')
block:
var i = 0
let c = decodePercent("%A9", i)
doAssert (i, c) == (2, '\xA9')
block:
var i = 0
let c = decodePercent("%Aa", i)
doAssert (i, c) == (2, '\xAA')