Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add push raises #101

Merged
merged 3 commits into from
Feb 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions confutils.nim
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const

when not defined(nimscript):
import
os, terminal,
terminal,
confutils/shell_completion

type
Expand Down Expand Up @@ -70,6 +70,8 @@ const
confutils_description_width {.intdefine.} = 80
confutils_narrow_terminal_width {.intdefine.} = 36

{.push gcsafe, raises: [].}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we tend to put this on top (so that it's part of the file "header" along with copyright comment)


func getFieldName(caseField: NimNode): NimNode =
result = caseField
if result.kind == nnkIdentDefs: result = result[0]
Expand Down Expand Up @@ -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
parseCmdArg(T, s)
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):
Expand Down Expand Up @@ -1291,3 +1296,5 @@ func load*(f: TypedInputFile): f.ContentType =
else:
mixin loadFile
loadFile(f.Format, f.string, f.ContentType)

{.pop.}
3 changes: 3 additions & 0 deletions confutils/cli_parser.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -161,3 +163,4 @@ iterator getopt*(cmds: seq[string],
if p.kind == cmdEnd: break
yield (p.kind, p.key, p.val)

{.pop.}
3 changes: 3 additions & 0 deletions confutils/cli_parsing_fuzzer.nim
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import
stew/byteutils, testutils/fuzzing,
../confutils

{.push gcsafe, raises: [].}

template fuzzCliParsing*(Conf: type) =
test:
block:
Expand All @@ -22,3 +24,4 @@ template fuzzCliParsing*(Conf: type) =
except ConfigurationError as err:
discard

{.pop.}
25 changes: 16 additions & 9 deletions confutils/config_file.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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.}
4 changes: 4 additions & 0 deletions confutils/defs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ type

SomeDistinctString = InputFile|InputDir|OutPath|OutDir|OutFile

{.push gcsafe, raises: [].}

template `/`*(dir: InputDir|OutDir, path: string): auto =
string(dir) / path

Expand All @@ -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.}
28 changes: 19 additions & 9 deletions confutils/shell_completion.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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]:
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 = """
Expand Down Expand Up @@ -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'")
8 changes: 6 additions & 2 deletions confutils/std/net.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -34,3 +36,5 @@ func parseCmdArg*(T: type Port, s: string): T =

func completeCmdArg*(T: type Port, val: string): seq[string] =
@[]

{.pop.}
4 changes: 4 additions & 0 deletions confutils/toml/defs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -22,3 +24,5 @@ readConfutilsType InputDir
readConfutilsType OutPath
readConfutilsType OutDir
readConfutilsType OutFile

{.pop.}
14 changes: 9 additions & 5 deletions confutils/toml/std/net.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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.}
7 changes: 5 additions & 2 deletions confutils/toml/std/uri.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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.}
11 changes: 8 additions & 3 deletions confutils/winreg/reader.nim
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

import
tables, typetraits, options,
serialization/[object_serialization],
serialization/[object_serialization, errors],
./utils, ./types

type
Expand All @@ -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
Expand All @@ -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

Expand Down Expand Up @@ -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.}
4 changes: 4 additions & 0 deletions confutils/winreg/types.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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.}
14 changes: 12 additions & 2 deletions confutils/winreg/utils.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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 {.
Expand All @@ -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

Expand Down Expand Up @@ -160,3 +168,5 @@ func constructPath*(root: string, keys: openArray[string]): string =
result.add keys[i]
if i < keys.len-2:
result. add '\\'

{.pop.}
4 changes: 4 additions & 0 deletions confutils/winreg/winreg_serialization.nim
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import
export
serialization, reader, writer, types

{.push gcsafe, raises: [].}

serializationFormat Winreg

Winreg.setReader WinregReader
Expand Down Expand Up @@ -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.}
4 changes: 4 additions & 0 deletions confutils/winreg/writer.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.}
File renamed without changes.
3 changes: 0 additions & 3 deletions tests/test_config_file.nim
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,7 @@ type
field_a: int
field_b: string

CheckPoint = int
RuntimePreset = int
GraffitiBytes = array[16, byte]
WalletName = string

VCStartUpCmd = enum
VCNoCommand
Expand Down
Loading