Add push raises (#101)
* Add push raises * Fix gcsafe violation * remove debug code
This commit is contained in:
parent
7340359702
commit
57ff0b8555
|
@ -26,7 +26,7 @@ const
|
|||
|
||||
when not defined(nimscript):
|
||||
import
|
||||
os, terminal,
|
||||
terminal,
|
||||
confutils/shell_completion
|
||||
|
||||
type
|
||||
|
@ -70,6 +70,8 @@ const
|
|||
confutils_description_width {.intdefine.} = 80
|
||||
confutils_narrow_terminal_width {.intdefine.} = 36
|
||||
|
||||
{.push gcsafe, raises: [].}
|
||||
|
||||
func getFieldName(caseField: NimNode): NimNode =
|
||||
result = caseField
|
||||
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
|
||||
# all other exception types.
|
||||
mixin parseCmdArg
|
||||
try:
|
||||
parseCmdArg(T, s)
|
||||
except CatchableError as exc:
|
||||
raise newException(ValueError, exc.msg)
|
||||
|
||||
func completeCmdArg*(T: type enum, val: string): seq[string] =
|
||||
for e in low(T)..high(T):
|
||||
|
@ -1291,3 +1296,5 @@ func load*(f: TypedInputFile): f.ContentType =
|
|||
else:
|
||||
mixin loadFile
|
||||
loadFile(f.Format, f.string, f.ContentType)
|
||||
|
||||
{.pop.}
|
||||
|
|
|
@ -29,6 +29,8 @@ type
|
|||
## or the argument, and the value is not "" if
|
||||
## the option was given a value
|
||||
|
||||
{.push gcsafe, raises: [].}
|
||||
|
||||
func parseWord(s: string, i: int, w: var string,
|
||||
delim: set[char] = {'\t', ' '}): int =
|
||||
result = i
|
||||
|
@ -161,3 +163,4 @@ iterator getopt*(cmds: seq[string],
|
|||
if p.kind == cmdEnd: break
|
||||
yield (p.kind, p.key, p.val)
|
||||
|
||||
{.pop.}
|
||||
|
|
|
@ -12,6 +12,8 @@ import
|
|||
stew/byteutils, testutils/fuzzing,
|
||||
../confutils
|
||||
|
||||
{.push gcsafe, raises: [].}
|
||||
|
||||
template fuzzCliParsing*(Conf: type) =
|
||||
test:
|
||||
block:
|
||||
|
@ -22,3 +24,4 @@ template fuzzCliParsing*(Conf: type) =
|
|||
except ConfigurationError as err:
|
||||
discard
|
||||
|
||||
{.pop.}
|
||||
|
|
|
@ -45,6 +45,8 @@ type
|
|||
|
||||
OriginalToGeneratedFields = OrderedTable[string, GeneratedFieldInfo]
|
||||
|
||||
{.push gcsafe, raises: [].}
|
||||
|
||||
func isOption(n: NimNode): bool =
|
||||
if n.kind != nnkBracketExpr: return false
|
||||
eqIdent(n[0], "Option")
|
||||
|
@ -248,19 +250,20 @@ proc generateTypes(root: ConfFileSection): seq[NimNode] =
|
|||
recList.add generateOptionalField(child.getRenamedName.ident, child.typ)
|
||||
result[index].putRecList(recList)
|
||||
|
||||
proc generateSettersPaths(node: ConfFileSection, result: var OriginalToGeneratedFields) =
|
||||
var path {.global.}: seq[string]
|
||||
path.add node.getRenamedName
|
||||
proc generateSettersPaths(node: ConfFileSection,
|
||||
result: var OriginalToGeneratedFields,
|
||||
pathsCache: var seq[string]) =
|
||||
pathsCache.add node.getRenamedName
|
||||
if node.children.len == 0:
|
||||
result[node.fieldName] = (node.isCommandOrArgument, path)
|
||||
result[node.fieldName] = (node.isCommandOrArgument, pathsCache)
|
||||
else:
|
||||
for child in node.children:
|
||||
generateSettersPaths(child, result)
|
||||
path.del path.len - 1
|
||||
generateSettersPaths(child, result, pathsCache)
|
||||
pathsCache.del pathsCache.len - 1
|
||||
|
||||
proc generateSettersPaths(root: ConfFileSection): OriginalToGeneratedFields =
|
||||
proc generateSettersPaths(root: ConfFileSection, pathsCache: var seq[string]): OriginalToGeneratedFields =
|
||||
for child in root.children:
|
||||
generateSettersPaths(child, result)
|
||||
generateSettersPaths(child, result, pathsCache)
|
||||
|
||||
template cfSetter(a, b: untyped): untyped =
|
||||
when a is Option:
|
||||
|
@ -346,9 +349,13 @@ macro generateSecondarySources*(ConfType: type): untyped =
|
|||
let
|
||||
model = generateConfigFileModel(ConfType)
|
||||
modelType = generateTypes(model)
|
||||
var
|
||||
pathsCache: seq[string]
|
||||
|
||||
result = newTree(nnkStmtList)
|
||||
result.add newTree(nnkTypeSection, modelType)
|
||||
|
||||
let settersPaths = model.generateSettersPaths
|
||||
let settersPaths = model.generateSettersPaths(pathsCache)
|
||||
result.add generateConfigFileSetters(ConfType, result[^1], settersPaths)
|
||||
|
||||
{.pop.}
|
||||
|
|
|
@ -45,6 +45,8 @@ type
|
|||
|
||||
SomeDistinctString = InputFile|InputDir|OutPath|OutDir|OutFile
|
||||
|
||||
{.push gcsafe, raises: [].}
|
||||
|
||||
template `/`*(dir: InputDir|OutDir, path: string): auto =
|
||||
string(dir) / path
|
||||
|
||||
|
@ -70,3 +72,5 @@ template implicitlySelectable* {.pragma.}
|
|||
## to allow the value of the discriminator to be determined
|
||||
## implicitly when the user specifies any of the sub-options
|
||||
## that depend on the disciminator value.
|
||||
|
||||
{.pop.}
|
||||
|
|
|
@ -24,13 +24,21 @@ const
|
|||
WORDBREAKS = "\"'@><=;|&(:"
|
||||
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)
|
||||
l.preserveTrailingWs = preserveTrailingWs
|
||||
l.mergeWordBreaks = false
|
||||
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
|
||||
while true:
|
||||
case l.buf[pos]:
|
||||
|
@ -62,7 +70,7 @@ proc parseQuoted(l: var ShellLexer, pos: int, isSingle: bool, output: var string
|
|||
inc(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
|
||||
|
||||
# Skip the initial whitespace
|
||||
|
@ -179,6 +187,8 @@ proc shellPathEscape*(path: string): string =
|
|||
result.add('\\')
|
||||
result.add(ch)
|
||||
|
||||
{.pop.}
|
||||
|
||||
when isMainModule:
|
||||
# Test data lifted from python's shlex unit-tests
|
||||
const data = """
|
||||
|
@ -265,9 +275,9 @@ foo\ bar|foo bar|
|
|||
echo "expected ", expected
|
||||
doAssert(false)
|
||||
|
||||
doAssert(quoteWord("") == "''")
|
||||
doAssert(quoteWord("\\\"") == "'\\\"'")
|
||||
doAssert(quoteWord("foobar") == "foobar")
|
||||
doAssert(quoteWord("foo$bar") == "'foo$bar'")
|
||||
doAssert(quoteWord("foo bar") == "'foo bar'")
|
||||
doAssert(quoteWord("foo'bar") == "'foo\\'bar'")
|
||||
doAssert(shellQuote("") == "''")
|
||||
doAssert(shellQuote("\\\"") == "'\\\"'")
|
||||
doAssert(shellQuote("foobar") == "foobar")
|
||||
doAssert(shellQuote("foo$bar") == "'foo$bar'")
|
||||
doAssert(shellQuote("foo bar") == "'foo bar'")
|
||||
doAssert(shellQuote("foo'bar") == "'foo\\'bar'")
|
||||
|
|
|
@ -11,14 +11,16 @@ import std/net
|
|||
from std/parseutils import parseInt
|
||||
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)
|
||||
|
||||
func completeCmdArg*(T: type IpAddress, val: string): seq[string] =
|
||||
# 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 =
|
||||
raise newException(ValueError,
|
||||
"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] =
|
||||
@[]
|
||||
|
||||
{.pop.}
|
||||
|
|
|
@ -13,6 +13,8 @@ import
|
|||
export
|
||||
toml_serialization, confutilsDefs
|
||||
|
||||
{.push gcsafe, raises: [].}
|
||||
|
||||
template readConfutilsType(T: type) =
|
||||
template readValue*(r: var TomlReader, val: var T) =
|
||||
val = T r.readValue(string)
|
||||
|
@ -22,3 +24,5 @@ readConfutilsType InputDir
|
|||
readConfutilsType OutPath
|
||||
readConfutilsType OutDir
|
||||
readConfutilsType OutFile
|
||||
|
||||
{.pop.}
|
||||
|
|
|
@ -14,16 +14,20 @@ import
|
|||
export
|
||||
net, toml_serialization
|
||||
|
||||
{.push gcsafe, raises: [].}
|
||||
|
||||
proc readValue*(r: var TomlReader, val: var IpAddress)
|
||||
{.raises: [SerializationError, IOError, Defect].} =
|
||||
{.raises: [SerializationError, IOError].} =
|
||||
val = try: parseIpAddress(r.readValue(string))
|
||||
except ValueError as err:
|
||||
r.lex.raiseUnexpectedValue("IP address")
|
||||
r.lex.raiseUnexpectedValue("IP address " & err.msg)
|
||||
|
||||
proc readValue*(r: var TomlReader, val: var Port)
|
||||
{.raises: [SerializationError, IOError, Defect].} =
|
||||
{.raises: [SerializationError, IOError].} =
|
||||
let port = try: r.readValue(uint16)
|
||||
except ValueError:
|
||||
r.lex.raiseUnexpectedValue("Port")
|
||||
except ValueError as exc:
|
||||
r.lex.raiseUnexpectedValue("Port " & exc.msg)
|
||||
|
||||
val = Port port
|
||||
|
||||
{.pop.}
|
||||
|
|
|
@ -14,9 +14,12 @@ import
|
|||
export
|
||||
uri, toml_serialization
|
||||
|
||||
{.push gcsafe, raises: [].}
|
||||
|
||||
proc readValue*(r: var TomlReader, val: var Uri)
|
||||
{.raises: [SerializationError, IOError, Defect].} =
|
||||
{.raises: [SerializationError, IOError].} =
|
||||
val = try: parseUri(r.readValue(string))
|
||||
except ValueError as err:
|
||||
r.lex.raiseUnexpectedValue("URI")
|
||||
r.lex.raiseUnexpectedValue("URI " & err.msg)
|
||||
|
||||
{.pop.}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
import
|
||||
tables, typetraits, options,
|
||||
serialization/[object_serialization],
|
||||
serialization/[object_serialization, errors],
|
||||
./utils, ./types
|
||||
|
||||
type
|
||||
|
@ -24,11 +24,13 @@ type
|
|||
deserializedField*: string
|
||||
innerException*: ref CatchableError
|
||||
|
||||
{.push gcsafe, raises: [].}
|
||||
|
||||
proc handleReadException*(r: WinregReader,
|
||||
Record: type,
|
||||
fieldName: string,
|
||||
field: auto,
|
||||
err: ref CatchableError) =
|
||||
err: ref CatchableError) {.gcsafe, raises: [WinregError].} =
|
||||
var ex = new GenericWinregReaderError
|
||||
ex.deserializedField = fieldName
|
||||
ex.innerException = err
|
||||
|
@ -39,7 +41,8 @@ proc init*(T: type WinregReader,
|
|||
result.hKey = hKey
|
||||
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
|
||||
# TODO: reduce allocation
|
||||
|
||||
|
@ -88,3 +91,5 @@ proc readValue*[T](r: var WinregReader, value: var T) =
|
|||
else:
|
||||
const typeName = typetraits.name(T)
|
||||
{.fatal: "Failed to convert from Winreg an unsupported type: " & typeName.}
|
||||
|
||||
{.pop.}
|
||||
|
|
|
@ -26,5 +26,9 @@ const
|
|||
HKCR* = HKEY_CLASSES_ROOT
|
||||
HKU* = HKEY_USERS
|
||||
|
||||
{.push gcsafe, raises: [].}
|
||||
|
||||
proc `==`*(a, b: HKEY): bool {.borrow.}
|
||||
proc `==`*(a, b: RegType): bool {.borrow.}
|
||||
|
||||
{.pop.}
|
||||
|
|
|
@ -26,6 +26,8 @@ const
|
|||
RT_QWORD* = 0x00000040
|
||||
RT_ANY* = 0x0000ffff
|
||||
|
||||
{.push gcsafe, raises: [].}
|
||||
|
||||
proc regGetValue(hKey: HKEY, lpSubKey, lpValue: cstring,
|
||||
dwFlags: int32, pdwType: ptr RegType,
|
||||
pvData: pointer, pcbData: ptr int32): int32 {.
|
||||
|
@ -39,12 +41,18 @@ template call(f) =
|
|||
if f != 0:
|
||||
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 =
|
||||
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)
|
||||
else:
|
||||
var dw = cast[int64](val)
|
||||
var dw = int64.safeCast(val)
|
||||
call regSetValue(hKey, path, key, REG_QWORD, dw.addr, sizeof(dw).int32)
|
||||
result = true
|
||||
|
||||
|
@ -160,3 +168,5 @@ func constructPath*(root: string, keys: openArray[string]): string =
|
|||
result.add keys[i]
|
||||
if i < keys.len-2:
|
||||
result. add '\\'
|
||||
|
||||
{.pop.}
|
||||
|
|
|
@ -14,6 +14,8 @@ import
|
|||
export
|
||||
serialization, reader, writer, types
|
||||
|
||||
{.push gcsafe, raises: [].}
|
||||
|
||||
serializationFormat Winreg
|
||||
|
||||
Winreg.setReader WinregReader
|
||||
|
@ -65,3 +67,5 @@ template saveFile*(_: type Winreg, filename: string, value: auto, params: vararg
|
|||
let (hKey, path) = parseWinregPath(filename)
|
||||
var writer = unpackArgs(init, [WinregWriter, hKey, path, params])
|
||||
writer.writeValue(value)
|
||||
|
||||
{.pop.}
|
||||
|
|
|
@ -18,6 +18,8 @@ type
|
|||
path: string
|
||||
key: seq[string]
|
||||
|
||||
{.push gcsafe, raises: [].}
|
||||
|
||||
proc init*(T: type WinregWriter,
|
||||
hKey: HKEY, path: string): T =
|
||||
result.hKey = hKey
|
||||
|
@ -55,3 +57,5 @@ proc writeValue*(w: var WinregWriter, value: auto) {.raises: [IOError].} =
|
|||
else:
|
||||
const typeName = typetraits.name(value.type)
|
||||
{.fatal: "Failed to convert to Winreg an unsupported type: " & typeName.}
|
||||
|
||||
{.pop.}
|
||||
|
|
|
@ -20,10 +20,7 @@ type
|
|||
field_a: int
|
||||
field_b: string
|
||||
|
||||
CheckPoint = int
|
||||
RuntimePreset = int
|
||||
GraffitiBytes = array[16, byte]
|
||||
WalletName = string
|
||||
|
||||
VCStartUpCmd = enum
|
||||
VCNoCommand
|
||||
|
|
|
@ -34,10 +34,6 @@ type
|
|||
abbr: "d"
|
||||
name: "data-dir" }: OutDir
|
||||
|
||||
func defaultObject(conf: TestConf): SomeObject =
|
||||
discard
|
||||
|
||||
|
||||
func completeCmdArg(T: type SomeObject, val: string): seq[string] =
|
||||
@[]
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import
|
|||
std/[strutils],
|
||||
unittest2,
|
||||
../confutils,
|
||||
./specialint
|
||||
./private/specialint
|
||||
|
||||
type
|
||||
TestConf* = object
|
||||
|
|
Loading…
Reference in New Issue