Add push raises (#101)

* Add push raises

* Fix gcsafe violation

* remove debug code
This commit is contained in:
andri lim 2024-02-12 12:39:19 +07:00 committed by GitHub
parent 7340359702
commit 57ff0b8555
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 111 additions and 42 deletions

View File

@ -26,7 +26,7 @@ const
when not defined(nimscript): when not defined(nimscript):
import import
os, terminal, terminal,
confutils/shell_completion confutils/shell_completion
type type
@ -70,6 +70,8 @@ const
confutils_description_width {.intdefine.} = 80 confutils_description_width {.intdefine.} = 80
confutils_narrow_terminal_width {.intdefine.} = 36 confutils_narrow_terminal_width {.intdefine.} = 36
{.push gcsafe, raises: [].}
func getFieldName(caseField: NimNode): NimNode = func getFieldName(caseField: NimNode): NimNode =
result = caseField result = caseField
if result.kind == nnkIdentDefs: result = result[0] if result.kind == nnkIdentDefs: result = result[0]
@ -565,7 +567,10 @@ proc parseCmdArgAux(T: type, s: string): T {.raises: [ValueError].} =
# If you have provided your own specializations, please handle # If you have provided your own specializations, please handle
# all other exception types. # all other exception types.
mixin parseCmdArg mixin parseCmdArg
try:
parseCmdArg(T, s) parseCmdArg(T, s)
except CatchableError as exc:
raise newException(ValueError, exc.msg)
func completeCmdArg*(T: type enum, val: string): seq[string] = func completeCmdArg*(T: type enum, val: string): seq[string] =
for e in low(T)..high(T): for e in low(T)..high(T):
@ -1291,3 +1296,5 @@ func load*(f: TypedInputFile): f.ContentType =
else: else:
mixin loadFile mixin loadFile
loadFile(f.Format, f.string, f.ContentType) loadFile(f.Format, f.string, f.ContentType)
{.pop.}

View File

@ -29,6 +29,8 @@ type
## or the argument, and the value is not "" if ## or the argument, and the value is not "" if
## the option was given a value ## the option was given a value
{.push gcsafe, raises: [].}
func parseWord(s: string, i: int, w: var string, func parseWord(s: string, i: int, w: var string,
delim: set[char] = {'\t', ' '}): int = delim: set[char] = {'\t', ' '}): int =
result = i result = i
@ -161,3 +163,4 @@ iterator getopt*(cmds: seq[string],
if p.kind == cmdEnd: break if p.kind == cmdEnd: break
yield (p.kind, p.key, p.val) yield (p.kind, p.key, p.val)
{.pop.}

View File

@ -12,6 +12,8 @@ import
stew/byteutils, testutils/fuzzing, stew/byteutils, testutils/fuzzing,
../confutils ../confutils
{.push gcsafe, raises: [].}
template fuzzCliParsing*(Conf: type) = template fuzzCliParsing*(Conf: type) =
test: test:
block: block:
@ -22,3 +24,4 @@ template fuzzCliParsing*(Conf: type) =
except ConfigurationError as err: except ConfigurationError as err:
discard discard
{.pop.}

View File

@ -45,6 +45,8 @@ type
OriginalToGeneratedFields = OrderedTable[string, GeneratedFieldInfo] OriginalToGeneratedFields = OrderedTable[string, GeneratedFieldInfo]
{.push gcsafe, raises: [].}
func isOption(n: NimNode): bool = func isOption(n: NimNode): bool =
if n.kind != nnkBracketExpr: return false if n.kind != nnkBracketExpr: return false
eqIdent(n[0], "Option") eqIdent(n[0], "Option")
@ -248,19 +250,20 @@ proc generateTypes(root: ConfFileSection): seq[NimNode] =
recList.add generateOptionalField(child.getRenamedName.ident, child.typ) recList.add generateOptionalField(child.getRenamedName.ident, child.typ)
result[index].putRecList(recList) result[index].putRecList(recList)
proc generateSettersPaths(node: ConfFileSection, result: var OriginalToGeneratedFields) = proc generateSettersPaths(node: ConfFileSection,
var path {.global.}: seq[string] result: var OriginalToGeneratedFields,
path.add node.getRenamedName pathsCache: var seq[string]) =
pathsCache.add node.getRenamedName
if node.children.len == 0: if node.children.len == 0:
result[node.fieldName] = (node.isCommandOrArgument, path) result[node.fieldName] = (node.isCommandOrArgument, pathsCache)
else: else:
for child in node.children: for child in node.children:
generateSettersPaths(child, result) generateSettersPaths(child, result, pathsCache)
path.del path.len - 1 pathsCache.del pathsCache.len - 1
proc generateSettersPaths(root: ConfFileSection): OriginalToGeneratedFields = proc generateSettersPaths(root: ConfFileSection, pathsCache: var seq[string]): OriginalToGeneratedFields =
for child in root.children: for child in root.children:
generateSettersPaths(child, result) generateSettersPaths(child, result, pathsCache)
template cfSetter(a, b: untyped): untyped = template cfSetter(a, b: untyped): untyped =
when a is Option: when a is Option:
@ -346,9 +349,13 @@ macro generateSecondarySources*(ConfType: type): untyped =
let let
model = generateConfigFileModel(ConfType) model = generateConfigFileModel(ConfType)
modelType = generateTypes(model) modelType = generateTypes(model)
var
pathsCache: seq[string]
result = newTree(nnkStmtList) result = newTree(nnkStmtList)
result.add newTree(nnkTypeSection, modelType) result.add newTree(nnkTypeSection, modelType)
let settersPaths = model.generateSettersPaths let settersPaths = model.generateSettersPaths(pathsCache)
result.add generateConfigFileSetters(ConfType, result[^1], settersPaths) result.add generateConfigFileSetters(ConfType, result[^1], settersPaths)
{.pop.}

View File

@ -45,6 +45,8 @@ type
SomeDistinctString = InputFile|InputDir|OutPath|OutDir|OutFile SomeDistinctString = InputFile|InputDir|OutPath|OutDir|OutFile
{.push gcsafe, raises: [].}
template `/`*(dir: InputDir|OutDir, path: string): auto = template `/`*(dir: InputDir|OutDir, path: string): auto =
string(dir) / path string(dir) / path
@ -70,3 +72,5 @@ template implicitlySelectable* {.pragma.}
## to allow the value of the discriminator to be determined ## to allow the value of the discriminator to be determined
## implicitly when the user specifies any of the sub-options ## implicitly when the user specifies any of the sub-options
## that depend on the disciminator value. ## that depend on the disciminator value.
{.pop.}

View File

@ -24,13 +24,21 @@ const
WORDBREAKS = "\"'@><=;|&(:" WORDBREAKS = "\"'@><=;|&(:"
SAFE_CHARS = {'a'..'z', 'A'..'Z', '0'..'9', '@', '%', '+', '=', ':', ',', '.', '/', '-'} SAFE_CHARS = {'a'..'z', 'A'..'Z', '0'..'9', '@', '%', '+', '=', ':', ',', '.', '/', '-'}
proc open(l: var ShellLexer, input: Stream, wordBreakChars: string = WORDBREAKS, preserveTrailingWs = true) = {.push gcsafe, raises: [].}
proc open(l: var ShellLexer,
input: Stream,
wordBreakChars: string = WORDBREAKS,
preserveTrailingWs = true) {.gcsafe, raises: [IOError, OSError].} =
lexbase.open(l, input) lexbase.open(l, input)
l.preserveTrailingWs = preserveTrailingWs l.preserveTrailingWs = preserveTrailingWs
l.mergeWordBreaks = false l.mergeWordBreaks = false
l.wordBreakChars = wordBreakChars l.wordBreakChars = wordBreakChars
proc parseQuoted(l: var ShellLexer, pos: int, isSingle: bool, output: var string): int = proc parseQuoted(l: var ShellLexer,
pos: int,
isSingle: bool,
output: var string): int {.gcsafe, raises: [IOError, OSError].} =
var pos = pos var pos = pos
while true: while true:
case l.buf[pos]: case l.buf[pos]:
@ -62,7 +70,7 @@ proc parseQuoted(l: var ShellLexer, pos: int, isSingle: bool, output: var string
inc(pos) inc(pos)
return pos return pos
proc getTok(l: var ShellLexer): Option[string] = proc getTok(l: var ShellLexer): Option[string] {.gcsafe, raises: [IOError, OSError].} =
var pos = l.bufpos var pos = l.bufpos
# Skip the initial whitespace # Skip the initial whitespace
@ -179,6 +187,8 @@ proc shellPathEscape*(path: string): string =
result.add('\\') result.add('\\')
result.add(ch) result.add(ch)
{.pop.}
when isMainModule: when isMainModule:
# Test data lifted from python's shlex unit-tests # Test data lifted from python's shlex unit-tests
const data = """ const data = """
@ -265,9 +275,9 @@ foo\ bar|foo bar|
echo "expected ", expected echo "expected ", expected
doAssert(false) doAssert(false)
doAssert(quoteWord("") == "''") doAssert(shellQuote("") == "''")
doAssert(quoteWord("\\\"") == "'\\\"'") doAssert(shellQuote("\\\"") == "'\\\"'")
doAssert(quoteWord("foobar") == "foobar") doAssert(shellQuote("foobar") == "foobar")
doAssert(quoteWord("foo$bar") == "'foo$bar'") doAssert(shellQuote("foo$bar") == "'foo$bar'")
doAssert(quoteWord("foo bar") == "'foo bar'") doAssert(shellQuote("foo bar") == "'foo bar'")
doAssert(quoteWord("foo'bar") == "'foo\\'bar'") doAssert(shellQuote("foo'bar") == "'foo\\'bar'")

View File

@ -11,14 +11,16 @@ import std/net
from std/parseutils import parseInt from std/parseutils import parseInt
export net export net
func parseCmdArg*(T: type IpAddress, s: string): T = {.push gcsafe, raises: [].}
func parseCmdArg*(T: type IpAddress, s: string): T {.gcsafe, raises: [ValueError].} =
parseIpAddress(s) parseIpAddress(s)
func completeCmdArg*(T: type IpAddress, val: string): seq[string] = func completeCmdArg*(T: type IpAddress, val: string): seq[string] =
# TODO: Maybe complete the local IP address? # TODO: Maybe complete the local IP address?
@[] @[]
func parseCmdArg*(T: type Port, s: string): T = func parseCmdArg*(T: type Port, s: string): T {.gcsafe, raises: [ValueError].} =
template fail = template fail =
raise newException(ValueError, raise newException(ValueError,
"The supplied port must be an integer value in the range 1-65535") "The supplied port must be an integer value in the range 1-65535")
@ -34,3 +36,5 @@ func parseCmdArg*(T: type Port, s: string): T =
func completeCmdArg*(T: type Port, val: string): seq[string] = func completeCmdArg*(T: type Port, val: string): seq[string] =
@[] @[]
{.pop.}

View File

@ -13,6 +13,8 @@ import
export export
toml_serialization, confutilsDefs toml_serialization, confutilsDefs
{.push gcsafe, raises: [].}
template readConfutilsType(T: type) = template readConfutilsType(T: type) =
template readValue*(r: var TomlReader, val: var T) = template readValue*(r: var TomlReader, val: var T) =
val = T r.readValue(string) val = T r.readValue(string)
@ -22,3 +24,5 @@ readConfutilsType InputDir
readConfutilsType OutPath readConfutilsType OutPath
readConfutilsType OutDir readConfutilsType OutDir
readConfutilsType OutFile readConfutilsType OutFile
{.pop.}

View File

@ -14,16 +14,20 @@ import
export export
net, toml_serialization net, toml_serialization
{.push gcsafe, raises: [].}
proc readValue*(r: var TomlReader, val: var IpAddress) proc readValue*(r: var TomlReader, val: var IpAddress)
{.raises: [SerializationError, IOError, Defect].} = {.raises: [SerializationError, IOError].} =
val = try: parseIpAddress(r.readValue(string)) val = try: parseIpAddress(r.readValue(string))
except ValueError as err: except ValueError as err:
r.lex.raiseUnexpectedValue("IP address") r.lex.raiseUnexpectedValue("IP address " & err.msg)
proc readValue*(r: var TomlReader, val: var Port) proc readValue*(r: var TomlReader, val: var Port)
{.raises: [SerializationError, IOError, Defect].} = {.raises: [SerializationError, IOError].} =
let port = try: r.readValue(uint16) let port = try: r.readValue(uint16)
except ValueError: except ValueError as exc:
r.lex.raiseUnexpectedValue("Port") r.lex.raiseUnexpectedValue("Port " & exc.msg)
val = Port port val = Port port
{.pop.}

View File

@ -14,9 +14,12 @@ import
export export
uri, toml_serialization uri, toml_serialization
{.push gcsafe, raises: [].}
proc readValue*(r: var TomlReader, val: var Uri) proc readValue*(r: var TomlReader, val: var Uri)
{.raises: [SerializationError, IOError, Defect].} = {.raises: [SerializationError, IOError].} =
val = try: parseUri(r.readValue(string)) val = try: parseUri(r.readValue(string))
except ValueError as err: except ValueError as err:
r.lex.raiseUnexpectedValue("URI") r.lex.raiseUnexpectedValue("URI " & err.msg)
{.pop.}

View File

@ -9,7 +9,7 @@
import import
tables, typetraits, options, tables, typetraits, options,
serialization/[object_serialization], serialization/[object_serialization, errors],
./utils, ./types ./utils, ./types
type type
@ -24,11 +24,13 @@ type
deserializedField*: string deserializedField*: string
innerException*: ref CatchableError innerException*: ref CatchableError
{.push gcsafe, raises: [].}
proc handleReadException*(r: WinregReader, proc handleReadException*(r: WinregReader,
Record: type, Record: type,
fieldName: string, fieldName: string,
field: auto, field: auto,
err: ref CatchableError) = err: ref CatchableError) {.gcsafe, raises: [WinregError].} =
var ex = new GenericWinregReaderError var ex = new GenericWinregReaderError
ex.deserializedField = fieldName ex.deserializedField = fieldName
ex.innerException = err ex.innerException = err
@ -39,7 +41,8 @@ proc init*(T: type WinregReader,
result.hKey = hKey result.hKey = hKey
result.path = path result.path = path
proc readValue*[T](r: var WinregReader, value: var T) = proc readValue*[T](r: var WinregReader, value: var T)
{.gcsafe, raises: [SerializationError, IOError].} =
mixin readValue mixin readValue
# TODO: reduce allocation # TODO: reduce allocation
@ -88,3 +91,5 @@ proc readValue*[T](r: var WinregReader, value: var T) =
else: else:
const typeName = typetraits.name(T) const typeName = typetraits.name(T)
{.fatal: "Failed to convert from Winreg an unsupported type: " & typeName.} {.fatal: "Failed to convert from Winreg an unsupported type: " & typeName.}
{.pop.}

View File

@ -26,5 +26,9 @@ const
HKCR* = HKEY_CLASSES_ROOT HKCR* = HKEY_CLASSES_ROOT
HKU* = HKEY_USERS HKU* = HKEY_USERS
{.push gcsafe, raises: [].}
proc `==`*(a, b: HKEY): bool {.borrow.} proc `==`*(a, b: HKEY): bool {.borrow.}
proc `==`*(a, b: RegType): bool {.borrow.} proc `==`*(a, b: RegType): bool {.borrow.}
{.pop.}

View File

@ -26,6 +26,8 @@ const
RT_QWORD* = 0x00000040 RT_QWORD* = 0x00000040
RT_ANY* = 0x0000ffff RT_ANY* = 0x0000ffff
{.push gcsafe, raises: [].}
proc regGetValue(hKey: HKEY, lpSubKey, lpValue: cstring, proc regGetValue(hKey: HKEY, lpSubKey, lpValue: cstring,
dwFlags: int32, pdwType: ptr RegType, dwFlags: int32, pdwType: ptr RegType,
pvData: pointer, pcbData: ptr int32): int32 {. pvData: pointer, pcbData: ptr int32): int32 {.
@ -39,12 +41,18 @@ template call(f) =
if f != 0: if f != 0:
return false return false
template safeCast(destType: type, src: typed): auto =
when sizeof(src) < sizeof(destType):
destType(src)
else:
cast[destType](src)
proc setValue*(hKey: HKEY, path, key: string, val: SomePrimitives): bool = proc setValue*(hKey: HKEY, path, key: string, val: SomePrimitives): bool =
when sizeof(val) < 8: when sizeof(val) < 8:
var dw = cast[int32](val) var dw = int32.safeCast(val)
call regSetValue(hKey, path, key, REG_DWORD, dw.addr, sizeof(dw).int32) call regSetValue(hKey, path, key, REG_DWORD, dw.addr, sizeof(dw).int32)
else: else:
var dw = cast[int64](val) var dw = int64.safeCast(val)
call regSetValue(hKey, path, key, REG_QWORD, dw.addr, sizeof(dw).int32) call regSetValue(hKey, path, key, REG_QWORD, dw.addr, sizeof(dw).int32)
result = true result = true
@ -160,3 +168,5 @@ func constructPath*(root: string, keys: openArray[string]): string =
result.add keys[i] result.add keys[i]
if i < keys.len-2: if i < keys.len-2:
result. add '\\' result. add '\\'
{.pop.}

View File

@ -14,6 +14,8 @@ import
export export
serialization, reader, writer, types serialization, reader, writer, types
{.push gcsafe, raises: [].}
serializationFormat Winreg serializationFormat Winreg
Winreg.setReader WinregReader Winreg.setReader WinregReader
@ -65,3 +67,5 @@ template saveFile*(_: type Winreg, filename: string, value: auto, params: vararg
let (hKey, path) = parseWinregPath(filename) let (hKey, path) = parseWinregPath(filename)
var writer = unpackArgs(init, [WinregWriter, hKey, path, params]) var writer = unpackArgs(init, [WinregWriter, hKey, path, params])
writer.writeValue(value) writer.writeValue(value)
{.pop.}

View File

@ -18,6 +18,8 @@ type
path: string path: string
key: seq[string] key: seq[string]
{.push gcsafe, raises: [].}
proc init*(T: type WinregWriter, proc init*(T: type WinregWriter,
hKey: HKEY, path: string): T = hKey: HKEY, path: string): T =
result.hKey = hKey result.hKey = hKey
@ -55,3 +57,5 @@ proc writeValue*(w: var WinregWriter, value: auto) {.raises: [IOError].} =
else: else:
const typeName = typetraits.name(value.type) const typeName = typetraits.name(value.type)
{.fatal: "Failed to convert to Winreg an unsupported type: " & typeName.} {.fatal: "Failed to convert to Winreg an unsupported type: " & typeName.}
{.pop.}

View File

@ -20,10 +20,7 @@ type
field_a: int field_a: int
field_b: string field_b: string
CheckPoint = int
RuntimePreset = int
GraffitiBytes = array[16, byte] GraffitiBytes = array[16, byte]
WalletName = string
VCStartUpCmd = enum VCStartUpCmd = enum
VCNoCommand VCNoCommand

View File

@ -34,10 +34,6 @@ type
abbr: "d" abbr: "d"
name: "data-dir" }: OutDir name: "data-dir" }: OutDir
func defaultObject(conf: TestConf): SomeObject =
discard
func completeCmdArg(T: type SomeObject, val: string): seq[string] = func completeCmdArg(T: type SomeObject, val: string): seq[string] =
@[] @[]

View File

@ -2,7 +2,7 @@ import
std/[strutils], std/[strutils],
unittest2, unittest2,
../confutils, ../confutils,
./specialint ./private/specialint
type type
TestConf* = object TestConf* = object