'assert' hides EAssertionFailsure; stdlib makes use of 'tags'
This commit is contained in:
parent
7f6633a06f
commit
3c0a6a8962
16 changed files with 242 additions and 161 deletions
|
|
@ -59,6 +59,7 @@ proc InitDefines*() =
|
||||||
DefineSymbol("nimhygiene")
|
DefineSymbol("nimhygiene")
|
||||||
DefineSymbol("niminheritable")
|
DefineSymbol("niminheritable")
|
||||||
DefineSymbol("nimmixin")
|
DefineSymbol("nimmixin")
|
||||||
|
DefineSymbol("nimeffects")
|
||||||
|
|
||||||
# add platform specific symbols:
|
# add platform specific symbols:
|
||||||
case targetCPU
|
case targetCPU
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,8 @@ proc addEffect(a: PEffects, e: PNode, useLineInfo=true) =
|
||||||
throws(a.exc, e)
|
throws(a.exc, e)
|
||||||
|
|
||||||
proc mergeEffects(a: PEffects, b: PNode, useLineInfo: bool) =
|
proc mergeEffects(a: PEffects, b: PNode, useLineInfo: bool) =
|
||||||
for effect in items(b): addEffect(a, effect, useLineInfo)
|
if not b.isNil:
|
||||||
|
for effect in items(b): addEffect(a, effect, useLineInfo)
|
||||||
|
|
||||||
proc addTag(a: PEffects, e: PNode, useLineInfo=true) =
|
proc addTag(a: PEffects, e: PNode, useLineInfo=true) =
|
||||||
var aa = a.tags
|
var aa = a.tags
|
||||||
|
|
@ -113,7 +114,8 @@ proc addTag(a: PEffects, e: PNode, useLineInfo=true) =
|
||||||
throws(a.tags, e)
|
throws(a.tags, e)
|
||||||
|
|
||||||
proc mergeTags(a: PEffects, b: PNode, useLineInfo: bool) =
|
proc mergeTags(a: PEffects, b: PNode, useLineInfo: bool) =
|
||||||
for effect in items(b): addTag(a, effect, useLineInfo)
|
if not b.isNil:
|
||||||
|
for effect in items(b): addTag(a, effect, useLineInfo)
|
||||||
|
|
||||||
proc listEffects(a: PEffects) =
|
proc listEffects(a: PEffects) =
|
||||||
for e in items(a.exc): Message(e.info, hintUser, typeToString(e.typ))
|
for e in items(a.exc): Message(e.info, hintUser, typeToString(e.typ))
|
||||||
|
|
@ -125,7 +127,7 @@ proc catches(tracked: PEffects, e: PType) =
|
||||||
var i = tracked.bottom
|
var i = tracked.bottom
|
||||||
while i < L:
|
while i < L:
|
||||||
# r supertype of e?
|
# r supertype of e?
|
||||||
if inheritanceDiff(tracked.exc[i].excType, e) <= 0:
|
if safeInheritanceDiff(tracked.exc[i].excType, e) <= 0:
|
||||||
tracked.exc.sons[i] = tracked.exc.sons[L-1]
|
tracked.exc.sons[i] = tracked.exc.sons[L-1]
|
||||||
dec L
|
dec L
|
||||||
else:
|
else:
|
||||||
|
|
@ -272,7 +274,7 @@ proc checkRaisesSpec(spec, real: PNode, msg: string, hints: bool) =
|
||||||
for r in items(real):
|
for r in items(real):
|
||||||
block search:
|
block search:
|
||||||
for s in 0 .. <spec.len:
|
for s in 0 .. <spec.len:
|
||||||
if inheritanceDiff(r.excType, spec[s].typ) <= 0:
|
if safeInheritanceDiff(r.excType, spec[s].typ) <= 0:
|
||||||
used.incl(s)
|
used.incl(s)
|
||||||
break search
|
break search
|
||||||
# XXX call graph analysis would be nice here!
|
# XXX call graph analysis would be nice here!
|
||||||
|
|
@ -341,6 +343,6 @@ proc trackProc*(s: PSym, body: PNode) =
|
||||||
let tagsSpec = effectSpec(p, wTags)
|
let tagsSpec = effectSpec(p, wTags)
|
||||||
if not isNil(tagsSpec):
|
if not isNil(tagsSpec):
|
||||||
checkRaisesSpec(tagsSpec, t.tags, "can have an unlisted effect: ",
|
checkRaisesSpec(tagsSpec, t.tags, "can have an unlisted effect: ",
|
||||||
hints=on)
|
hints=off)
|
||||||
# after the check, use the formal spec:
|
# after the check, use the formal spec:
|
||||||
effects.sons[tagEffects] = tagsSpec
|
effects.sons[tagEffects] = tagsSpec
|
||||||
|
|
|
||||||
|
|
@ -1190,16 +1190,23 @@ proc baseOfDistinct*(t: PType): PType =
|
||||||
internalAssert parent != nil
|
internalAssert parent != nil
|
||||||
parent.sons[0] = it.sons[0]
|
parent.sons[0] = it.sons[0]
|
||||||
|
|
||||||
|
proc safeInheritanceDiff*(a, b: PType): int =
|
||||||
|
# same as inheritanceDiff but checks for tyError:
|
||||||
|
if a.kind == tyError or b.kind == tyError:
|
||||||
|
result = -1
|
||||||
|
else:
|
||||||
|
result = inheritanceDiff(a, b)
|
||||||
|
|
||||||
proc compatibleEffectsAux(se, re: PNode): bool =
|
proc compatibleEffectsAux(se, re: PNode): bool =
|
||||||
if re.isNil: return false
|
if re.isNil: return false
|
||||||
for r in items(re):
|
for r in items(re):
|
||||||
block search:
|
block search:
|
||||||
for s in items(se):
|
for s in items(se):
|
||||||
if inheritanceDiff(r.typ, s.typ) <= 0:
|
if safeInheritanceDiff(r.typ, s.typ) <= 0:
|
||||||
break search
|
break search
|
||||||
return false
|
return false
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
proc compatibleEffects*(formal, actual: PType): bool =
|
proc compatibleEffects*(formal, actual: PType): bool =
|
||||||
# for proc type compatibility checking:
|
# for proc type compatibility checking:
|
||||||
assert formal.kind == tyProc and actual.kind == tyProc
|
assert formal.kind == tyProc and actual.kind == tyProc
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,13 @@ type
|
||||||
## in preventDeadlocks-mode guarantees re-entrancy.
|
## in preventDeadlocks-mode guarantees re-entrancy.
|
||||||
TCond* = TSysCond ## Nimrod condition variable
|
TCond* = TSysCond ## Nimrod condition variable
|
||||||
|
|
||||||
|
FLock* = object of TEffect ## effect that denotes that some lock operation
|
||||||
|
## is performed
|
||||||
|
FAquireLock* = object of FLock ## effect that denotes that some lock is
|
||||||
|
## aquired
|
||||||
|
FReleaseLock* = object of FLock ## effect that denotes that some lock is
|
||||||
|
## released
|
||||||
|
|
||||||
const
|
const
|
||||||
noDeadlocks = defined(preventDeadlocks)
|
noDeadlocks = defined(preventDeadlocks)
|
||||||
maxLocksPerThread* = 10 ## max number of locks a thread can hold
|
maxLocksPerThread* = 10 ## max number of locks a thread can hold
|
||||||
|
|
@ -51,7 +58,7 @@ proc DeinitLock*(lock: var TLock) {.inline.} =
|
||||||
## Frees the resources associated with the lock.
|
## Frees the resources associated with the lock.
|
||||||
DeinitSys(lock)
|
DeinitSys(lock)
|
||||||
|
|
||||||
proc TryAcquire*(lock: var TLock): bool =
|
proc TryAcquire*(lock: var TLock): bool {.tags: [FAquireLock].} =
|
||||||
## Tries to acquire the given lock. Returns `true` on success.
|
## Tries to acquire the given lock. Returns `true` on success.
|
||||||
result = TryAcquireSys(lock)
|
result = TryAcquireSys(lock)
|
||||||
when noDeadlocks:
|
when noDeadlocks:
|
||||||
|
|
@ -83,7 +90,7 @@ proc TryAcquire*(lock: var TLock): bool =
|
||||||
inc(locksLen)
|
inc(locksLen)
|
||||||
assert OrderedLocks()
|
assert OrderedLocks()
|
||||||
|
|
||||||
proc Acquire*(lock: var TLock) =
|
proc Acquire*(lock: var TLock) {.tags: [FAquireLock].} =
|
||||||
## Acquires the given lock.
|
## Acquires the given lock.
|
||||||
when nodeadlocks:
|
when nodeadlocks:
|
||||||
var p = addr(lock)
|
var p = addr(lock)
|
||||||
|
|
@ -128,7 +135,7 @@ proc Acquire*(lock: var TLock) =
|
||||||
else:
|
else:
|
||||||
AcquireSys(lock)
|
AcquireSys(lock)
|
||||||
|
|
||||||
proc Release*(lock: var TLock) =
|
proc Release*(lock: var TLock) {.tags: [FReleaseLock].} =
|
||||||
## Releases the given lock.
|
## Releases the given lock.
|
||||||
when nodeadlocks:
|
when nodeadlocks:
|
||||||
var p = addr(lock)
|
var p = addr(lock)
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,10 @@ type
|
||||||
EDb* = object of EIO ## exception that is raised if a database error occurs
|
EDb* = object of EIO ## exception that is raised if a database error occurs
|
||||||
TDbConn* = TMongo ## a database connection; alias for ``TMongo``
|
TDbConn* = TMongo ## a database connection; alias for ``TMongo``
|
||||||
|
|
||||||
|
FDb* = object of FIO ## effect that denotes a database operation
|
||||||
|
FReadDb* = object of FReadIO ## effect that denotes a read operation
|
||||||
|
FWriteDb* = object of FWriteIO ## effect that denotes a write operation
|
||||||
|
|
||||||
proc dbError*(db: TDbConn, msg: string) {.noreturn.} =
|
proc dbError*(db: TDbConn, msg: string) {.noreturn.} =
|
||||||
## raises an EDb exception with message `msg`.
|
## raises an EDb exception with message `msg`.
|
||||||
var e: ref EDb
|
var e: ref EDb
|
||||||
|
|
@ -43,12 +47,13 @@ proc dbError*(db: TDbConn, msg: string) {.noreturn.} =
|
||||||
e.msg = $db.err & " " & msg
|
e.msg = $db.err & " " & msg
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
proc Close*(db: var TDbConn) =
|
proc Close*(db: var TDbConn) {.tags: [FDB].} =
|
||||||
## closes the database connection.
|
## closes the database connection.
|
||||||
disconnect(db)
|
disconnect(db)
|
||||||
destroy(db)
|
destroy(db)
|
||||||
|
|
||||||
proc Open*(host: string = defaultHost, port: int = defaultPort): TDbConn =
|
proc Open*(host: string = defaultHost, port: int = defaultPort): TDbConn {.
|
||||||
|
tags: [FDB].} =
|
||||||
## opens a database connection. Raises `EDb` if the connection could not
|
## opens a database connection. Raises `EDb` if the connection could not
|
||||||
## be established.
|
## be established.
|
||||||
init(result)
|
init(result)
|
||||||
|
|
@ -108,7 +113,8 @@ proc getId*(obj: var TBSon): TOid =
|
||||||
else:
|
else:
|
||||||
raise newException(EInvalidIndex, "_id not in object")
|
raise newException(EInvalidIndex, "_id not in object")
|
||||||
|
|
||||||
proc insertID*(db: var TDbConn, namespace: string, data: PJsonNode): TOid =
|
proc insertID*(db: var TDbConn, namespace: string, data: PJsonNode): TOid {.
|
||||||
|
tags: [FWriteDb].} =
|
||||||
## converts `data` to BSON format and inserts it in `namespace`. Returns
|
## converts `data` to BSON format and inserts it in `namespace`. Returns
|
||||||
## the generated OID for the ``_id`` field.
|
## the generated OID for the ``_id`` field.
|
||||||
result = genOid()
|
result = genOid()
|
||||||
|
|
@ -116,11 +122,13 @@ proc insertID*(db: var TDbConn, namespace: string, data: PJsonNode): TOid =
|
||||||
insert(db, namespace, x)
|
insert(db, namespace, x)
|
||||||
destroy(x)
|
destroy(x)
|
||||||
|
|
||||||
proc insert*(db: var TDbConn, namespace: string, data: PJsonNode) =
|
proc insert*(db: var TDbConn, namespace: string, data: PJsonNode) {.
|
||||||
|
tags: [FWriteDb].} =
|
||||||
## converts `data` to BSON format and inserts it in `namespace`.
|
## converts `data` to BSON format and inserts it in `namespace`.
|
||||||
discard InsertID(db, namespace, data)
|
discard InsertID(db, namespace, data)
|
||||||
|
|
||||||
proc update*(db: var TDbConn, namespace: string, obj: var TBSon) =
|
proc update*(db: var TDbConn, namespace: string, obj: var TBSon) {.
|
||||||
|
tags: [FReadDB, FWriteDb].} =
|
||||||
## updates `obj` in `namespace`.
|
## updates `obj` in `namespace`.
|
||||||
var cond: TBson
|
var cond: TBson
|
||||||
init(cond)
|
init(cond)
|
||||||
|
|
@ -129,13 +137,15 @@ proc update*(db: var TDbConn, namespace: string, obj: var TBSon) =
|
||||||
update(db, namespace, cond, obj, ord(UPDATE_UPSERT))
|
update(db, namespace, cond, obj, ord(UPDATE_UPSERT))
|
||||||
destroy(cond)
|
destroy(cond)
|
||||||
|
|
||||||
proc update*(db: var TDbConn, namespace: string, oid: TOid, obj: PJsonNode) =
|
proc update*(db: var TDbConn, namespace: string, oid: TOid, obj: PJsonNode) {.
|
||||||
|
tags: [FReadDB, FWriteDb].} =
|
||||||
## updates the data with `oid` to have the new data `obj`.
|
## updates the data with `oid` to have the new data `obj`.
|
||||||
var a = jsonToBSon(obj, oid)
|
var a = jsonToBSon(obj, oid)
|
||||||
Update(db, namespace, a)
|
Update(db, namespace, a)
|
||||||
destroy(a)
|
destroy(a)
|
||||||
|
|
||||||
proc delete*(db: var TDbConn, namespace: string, oid: TOid) =
|
proc delete*(db: var TDbConn, namespace: string, oid: TOid) {.
|
||||||
|
tags: [FWriteDb].} =
|
||||||
## Deletes the object belonging to `oid`.
|
## Deletes the object belonging to `oid`.
|
||||||
var cond: TBson
|
var cond: TBson
|
||||||
init(cond)
|
init(cond)
|
||||||
|
|
@ -144,11 +154,13 @@ proc delete*(db: var TDbConn, namespace: string, oid: TOid) =
|
||||||
discard remove(db, namespace, cond)
|
discard remove(db, namespace, cond)
|
||||||
destroy(cond)
|
destroy(cond)
|
||||||
|
|
||||||
proc delete*(db: var TDbConn, namespace: string, obj: var TBSon) =
|
proc delete*(db: var TDbConn, namespace: string, obj: var TBSon) {.
|
||||||
|
tags: [FWriteDb].} =
|
||||||
## Deletes the object `obj`.
|
## Deletes the object `obj`.
|
||||||
delete(db, namespace, getId(obj))
|
delete(db, namespace, getId(obj))
|
||||||
|
|
||||||
iterator find*(db: var TDbConn, namespace: string): var TBSon =
|
iterator find*(db: var TDbConn, namespace: string): var TBSon {.
|
||||||
|
tags: [FReadDB].} =
|
||||||
## iterates over any object in `namespace`.
|
## iterates over any object in `namespace`.
|
||||||
var cursor: TCursor
|
var cursor: TCursor
|
||||||
init(cursor, db, namespace)
|
init(cursor, db, namespace)
|
||||||
|
|
@ -157,7 +169,7 @@ iterator find*(db: var TDbConn, namespace: string): var TBSon =
|
||||||
destroy(cursor)
|
destroy(cursor)
|
||||||
|
|
||||||
iterator find*(db: var TDbConn, namespace: string,
|
iterator find*(db: var TDbConn, namespace: string,
|
||||||
query, fields: var TBSon): var TBSon =
|
query, fields: var TBSon): var TBSon {.tags: [FReadDB].} =
|
||||||
## yields the `fields` of any document that suffices `query`.
|
## yields the `fields` of any document that suffices `query`.
|
||||||
var cursor = find(db, namespace, query, fields, 0'i32, 0'i32, 0'i32)
|
var cursor = find(db, namespace, query, fields, 0'i32, 0'i32, 0'i32)
|
||||||
if cursor != nil:
|
if cursor != nil:
|
||||||
|
|
@ -171,7 +183,8 @@ proc setupFieldnames(fields: varargs[string]): TBSon =
|
||||||
finish(result)
|
finish(result)
|
||||||
|
|
||||||
iterator find*(db: var TDbConn, namespace: string,
|
iterator find*(db: var TDbConn, namespace: string,
|
||||||
query: var TBSon, fields: varargs[string]): var TBSon =
|
query: var TBSon, fields: varargs[string]): var TBSon {.
|
||||||
|
tags: [FReadDB].} =
|
||||||
## yields the `fields` of any document that suffices `query`. If `fields`
|
## yields the `fields` of any document that suffices `query`. If `fields`
|
||||||
## is ``[]`` the whole document is yielded.
|
## is ``[]`` the whole document is yielded.
|
||||||
var f = setupFieldnames(fields)
|
var f = setupFieldnames(fields)
|
||||||
|
|
@ -188,7 +201,8 @@ proc setupQuery(query: string): TBSon =
|
||||||
finish(result)
|
finish(result)
|
||||||
|
|
||||||
iterator find*(db: var TDbConn, namespace: string,
|
iterator find*(db: var TDbConn, namespace: string,
|
||||||
query: string, fields: varargs[string]): var TBSon =
|
query: string, fields: varargs[string]): var TBSon {.
|
||||||
|
tags: [FReadDB].} =
|
||||||
## yields the `fields` of any document that suffices `query`. If `fields`
|
## yields the `fields` of any document that suffices `query`. If `fields`
|
||||||
## is ``[]`` the whole document is yielded.
|
## is ``[]`` the whole document is yielded.
|
||||||
var f = setupFieldnames(fields)
|
var f = setupFieldnames(fields)
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,11 @@ type
|
||||||
EDb* = object of EIO ## exception that is raised if a database error occurs
|
EDb* = object of EIO ## exception that is raised if a database error occurs
|
||||||
|
|
||||||
TSqlQuery* = distinct string ## an SQL query string
|
TSqlQuery* = distinct string ## an SQL query string
|
||||||
|
|
||||||
|
FDb* = object of FIO ## effect that denotes a database operation
|
||||||
|
FReadDb* = object of FReadIO ## effect that denotes a read operation
|
||||||
|
FWriteDb* = object of FWriteIO ## effect that denotes a write operation
|
||||||
|
|
||||||
proc dbError(db: TDbConn) {.noreturn.} =
|
proc dbError(db: TDbConn) {.noreturn.} =
|
||||||
## raises an EDb exception.
|
## raises an EDb exception.
|
||||||
var e: ref EDb
|
var e: ref EDb
|
||||||
|
|
@ -60,12 +64,18 @@ proc dbFormat(formatstr: TSqlQuery, args: varargs[string]): string =
|
||||||
else:
|
else:
|
||||||
add(result, c)
|
add(result, c)
|
||||||
|
|
||||||
proc TryExec*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]): bool =
|
proc TryExec*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]): bool {.
|
||||||
|
tags: [FReadDB, FWriteDb].} =
|
||||||
## tries to execute the query and returns true if successful, false otherwise.
|
## tries to execute the query and returns true if successful, false otherwise.
|
||||||
var q = dbFormat(query, args)
|
var q = dbFormat(query, args)
|
||||||
return mysql.RealQuery(db, q, q.len) == 0'i32
|
return mysql.RealQuery(db, q, q.len) == 0'i32
|
||||||
|
|
||||||
proc Exec*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]) =
|
proc rawExec(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]) =
|
||||||
|
var q = dbFormat(query, args)
|
||||||
|
if mysql.RealQuery(db, q, q.len) != 0'i32: dbError(db)
|
||||||
|
|
||||||
|
proc Exec*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]) {.
|
||||||
|
tags: [FReadDB, FWriteDb].} =
|
||||||
## executes the query and raises EDB if not successful.
|
## executes the query and raises EDB if not successful.
|
||||||
var q = dbFormat(query, args)
|
var q = dbFormat(query, args)
|
||||||
if mysql.RealQuery(db, q, q.len) != 0'i32: dbError(db)
|
if mysql.RealQuery(db, q, q.len) != 0'i32: dbError(db)
|
||||||
|
|
@ -80,11 +90,11 @@ proc properFreeResult(sqlres: mysql.PRES, row: cstringArray) =
|
||||||
mysql.FreeResult(sqlres)
|
mysql.FreeResult(sqlres)
|
||||||
|
|
||||||
iterator FastRows*(db: TDbConn, query: TSqlQuery,
|
iterator FastRows*(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string, `$`]): TRow =
|
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
|
||||||
## executes the query and iterates over the result dataset. This is very
|
## executes the query and iterates over the result dataset. This is very
|
||||||
## fast, but potenially dangerous: If the for-loop-body executes another
|
## fast, but potenially dangerous: If the for-loop-body executes another
|
||||||
## query, the results can be undefined. For MySQL this is the case!.
|
## query, the results can be undefined. For MySQL this is the case!.
|
||||||
Exec(db, query, args)
|
rawExec(db, query, args)
|
||||||
var sqlres = mysql.UseResult(db)
|
var sqlres = mysql.UseResult(db)
|
||||||
if sqlres != nil:
|
if sqlres != nil:
|
||||||
var L = int(mysql.NumFields(sqlres))
|
var L = int(mysql.NumFields(sqlres))
|
||||||
|
|
@ -100,9 +110,9 @@ iterator FastRows*(db: TDbConn, query: TSqlQuery,
|
||||||
properFreeResult(sqlres, row)
|
properFreeResult(sqlres, row)
|
||||||
|
|
||||||
proc getRow*(db: TDbConn, query: TSqlQuery,
|
proc getRow*(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string, `$`]): TRow =
|
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
|
||||||
## retrieves a single row.
|
## retrieves a single row.
|
||||||
Exec(db, query, args)
|
rawExec(db, query, args)
|
||||||
var sqlres = mysql.UseResult(db)
|
var sqlres = mysql.UseResult(db)
|
||||||
if sqlres != nil:
|
if sqlres != nil:
|
||||||
var L = int(mysql.NumFields(sqlres))
|
var L = int(mysql.NumFields(sqlres))
|
||||||
|
|
@ -115,10 +125,10 @@ proc getRow*(db: TDbConn, query: TSqlQuery,
|
||||||
properFreeResult(sqlres, row)
|
properFreeResult(sqlres, row)
|
||||||
|
|
||||||
proc GetAllRows*(db: TDbConn, query: TSqlQuery,
|
proc GetAllRows*(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string, `$`]): seq[TRow] =
|
args: varargs[string, `$`]): seq[TRow] {.tags: [FReadDB].} =
|
||||||
## executes the query and returns the whole result dataset.
|
## executes the query and returns the whole result dataset.
|
||||||
result = @[]
|
result = @[]
|
||||||
Exec(db, query, args)
|
rawExec(db, query, args)
|
||||||
var sqlres = mysql.UseResult(db)
|
var sqlres = mysql.UseResult(db)
|
||||||
if sqlres != nil:
|
if sqlres != nil:
|
||||||
var L = int(mysql.NumFields(sqlres))
|
var L = int(mysql.NumFields(sqlres))
|
||||||
|
|
@ -134,12 +144,12 @@ proc GetAllRows*(db: TDbConn, query: TSqlQuery,
|
||||||
mysql.FreeResult(sqlres)
|
mysql.FreeResult(sqlres)
|
||||||
|
|
||||||
iterator Rows*(db: TDbConn, query: TSqlQuery,
|
iterator Rows*(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string, `$`]): TRow =
|
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
|
||||||
## same as `FastRows`, but slower and safe.
|
## same as `FastRows`, but slower and safe.
|
||||||
for r in items(GetAllRows(db, query, args)): yield r
|
for r in items(GetAllRows(db, query, args)): yield r
|
||||||
|
|
||||||
proc GetValue*(db: TDbConn, query: TSqlQuery,
|
proc GetValue*(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string, `$`]): string =
|
args: varargs[string, `$`]): string {.tags: [FReadDB].} =
|
||||||
## executes the query and returns the result dataset's the first column
|
## executes the query and returns the result dataset's the first column
|
||||||
## of the first row. Returns "" if the dataset contains no rows. This uses
|
## of the first row. Returns "" if the dataset contains no rows. This uses
|
||||||
## `FastRows`, so it inherits its fragile behaviour.
|
## `FastRows`, so it inherits its fragile behaviour.
|
||||||
|
|
@ -149,7 +159,7 @@ proc GetValue*(db: TDbConn, query: TSqlQuery,
|
||||||
break
|
break
|
||||||
|
|
||||||
proc TryInsertID*(db: TDbConn, query: TSqlQuery,
|
proc TryInsertID*(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string, `$`]): int64 =
|
args: varargs[string, `$`]): int64 {.tags: [FWriteDb].} =
|
||||||
## executes the query (typically "INSERT") and returns the
|
## executes the query (typically "INSERT") and returns the
|
||||||
## generated ID for the row or -1 in case of an error.
|
## generated ID for the row or -1 in case of an error.
|
||||||
var q = dbFormat(query, args)
|
var q = dbFormat(query, args)
|
||||||
|
|
@ -159,24 +169,26 @@ proc TryInsertID*(db: TDbConn, query: TSqlQuery,
|
||||||
result = mysql.InsertId(db)
|
result = mysql.InsertId(db)
|
||||||
|
|
||||||
proc InsertID*(db: TDbConn, query: TSqlQuery,
|
proc InsertID*(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string, `$`]): int64 =
|
args: varargs[string, `$`]): int64 {.tags: [FWriteDb].} =
|
||||||
## executes the query (typically "INSERT") and returns the
|
## executes the query (typically "INSERT") and returns the
|
||||||
## generated ID for the row.
|
## generated ID for the row.
|
||||||
result = TryInsertID(db, query, args)
|
result = TryInsertID(db, query, args)
|
||||||
if result < 0: dbError(db)
|
if result < 0: dbError(db)
|
||||||
|
|
||||||
proc ExecAffectedRows*(db: TDbConn, query: TSqlQuery,
|
proc ExecAffectedRows*(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string, `$`]): int64 =
|
args: varargs[string, `$`]): int64 {.
|
||||||
|
tags: [FReadDB, FWriteDb].} =
|
||||||
## runs the query (typically "UPDATE") and returns the
|
## runs the query (typically "UPDATE") and returns the
|
||||||
## number of affected rows
|
## number of affected rows
|
||||||
Exec(db, query, args)
|
rawExec(db, query, args)
|
||||||
result = mysql.AffectedRows(db)
|
result = mysql.AffectedRows(db)
|
||||||
|
|
||||||
proc Close*(db: TDbConn) =
|
proc Close*(db: TDbConn) {.tags: [FDb].} =
|
||||||
## closes the database connection.
|
## closes the database connection.
|
||||||
if db != nil: mysql.Close(db)
|
if db != nil: mysql.Close(db)
|
||||||
|
|
||||||
proc Open*(connection, user, password, database: string): TDbConn =
|
proc Open*(connection, user, password, database: string): TDbConn {.
|
||||||
|
tags: [FDb].} =
|
||||||
## opens a database connection. Raises `EDb` if the connection could not
|
## opens a database connection. Raises `EDb` if the connection could not
|
||||||
## be established.
|
## be established.
|
||||||
result = mysql.Init(nil)
|
result = mysql.Init(nil)
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,10 @@ type
|
||||||
EDb* = object of EIO ## exception that is raised if a database error occurs
|
EDb* = object of EIO ## exception that is raised if a database error occurs
|
||||||
|
|
||||||
TSqlQuery* = distinct string ## an SQL query string
|
TSqlQuery* = distinct string ## an SQL query string
|
||||||
|
|
||||||
|
FDb* = object of FIO ## effect that denotes a database operation
|
||||||
|
FReadDb* = object of FReadIO ## effect that denotes a read operation
|
||||||
|
FWriteDb* = object of FWriteIO ## effect that denotes a write operation
|
||||||
|
|
||||||
proc sql*(query: string): TSqlQuery {.noSideEffect, inline.} =
|
proc sql*(query: string): TSqlQuery {.noSideEffect, inline.} =
|
||||||
## constructs a TSqlQuery from the string `query`. This is supposed to be
|
## constructs a TSqlQuery from the string `query`. This is supposed to be
|
||||||
|
|
@ -60,14 +64,15 @@ proc dbFormat(formatstr: TSqlQuery, args: varargs[string]): string =
|
||||||
add(result, c)
|
add(result, c)
|
||||||
|
|
||||||
proc TryExec*(db: TDbConn, query: TSqlQuery,
|
proc TryExec*(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string, `$`]): bool =
|
args: varargs[string, `$`]): bool {.tags: [FReadDB, FWriteDb].} =
|
||||||
## tries to execute the query and returns true if successful, false otherwise.
|
## tries to execute the query and returns true if successful, false otherwise.
|
||||||
var q = dbFormat(query, args)
|
var q = dbFormat(query, args)
|
||||||
var res = PQExec(db, q)
|
var res = PQExec(db, q)
|
||||||
result = PQresultStatus(res) == PGRES_COMMAND_OK
|
result = PQresultStatus(res) == PGRES_COMMAND_OK
|
||||||
PQclear(res)
|
PQclear(res)
|
||||||
|
|
||||||
proc Exec*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]) =
|
proc Exec*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]) {.
|
||||||
|
tags: [FReadDB, FWriteDb].} =
|
||||||
## executes the query and raises EDB if not successful.
|
## executes the query and raises EDB if not successful.
|
||||||
var q = dbFormat(query, args)
|
var q = dbFormat(query, args)
|
||||||
var res = PQExec(db, q)
|
var res = PQExec(db, q)
|
||||||
|
|
@ -91,7 +96,7 @@ proc setRow(res: PPGresult, r: var TRow, line, cols: int32) =
|
||||||
add(r[col], x)
|
add(r[col], x)
|
||||||
|
|
||||||
iterator FastRows*(db: TDbConn, query: TSqlQuery,
|
iterator FastRows*(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string, `$`]): TRow =
|
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
|
||||||
## executes the query and iterates over the result dataset. This is very
|
## executes the query and iterates over the result dataset. This is very
|
||||||
## fast, but potenially dangerous: If the for-loop-body executes another
|
## fast, but potenially dangerous: If the for-loop-body executes another
|
||||||
## query, the results can be undefined. For Postgres it is safe though.
|
## query, the results can be undefined. For Postgres it is safe though.
|
||||||
|
|
@ -104,7 +109,7 @@ iterator FastRows*(db: TDbConn, query: TSqlQuery,
|
||||||
PQclear(res)
|
PQclear(res)
|
||||||
|
|
||||||
proc getRow*(db: TDbConn, query: TSqlQuery,
|
proc getRow*(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string, `$`]): TRow =
|
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
|
||||||
## retrieves a single row.
|
## retrieves a single row.
|
||||||
var res = setupQuery(db, query, args)
|
var res = setupQuery(db, query, args)
|
||||||
var L = PQnfields(res)
|
var L = PQnfields(res)
|
||||||
|
|
@ -113,38 +118,39 @@ proc getRow*(db: TDbConn, query: TSqlQuery,
|
||||||
PQclear(res)
|
PQclear(res)
|
||||||
|
|
||||||
proc GetAllRows*(db: TDbConn, query: TSqlQuery,
|
proc GetAllRows*(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string, `$`]): seq[TRow] =
|
args: varargs[string, `$`]): seq[TRow] {.tags: [FReadDB].} =
|
||||||
## executes the query and returns the whole result dataset.
|
## executes the query and returns the whole result dataset.
|
||||||
result = @[]
|
result = @[]
|
||||||
for r in FastRows(db, query, args):
|
for r in FastRows(db, query, args):
|
||||||
result.add(r)
|
result.add(r)
|
||||||
|
|
||||||
iterator Rows*(db: TDbConn, query: TSqlQuery,
|
iterator Rows*(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string, `$`]): TRow =
|
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
|
||||||
## same as `FastRows`, but slower and safe.
|
## same as `FastRows`, but slower and safe.
|
||||||
for r in items(GetAllRows(db, query, args)): yield r
|
for r in items(GetAllRows(db, query, args)): yield r
|
||||||
|
|
||||||
proc GetValue*(db: TDbConn, query: TSqlQuery,
|
proc GetValue*(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string, `$`]): string =
|
args: varargs[string, `$`]): string {.tags: [FReadDB].} =
|
||||||
## executes the query and returns the result dataset's the first column
|
## executes the query and returns the result dataset's the first column
|
||||||
## of the first row. Returns "" if the dataset contains no rows.
|
## of the first row. Returns "" if the dataset contains no rows.
|
||||||
var x = PQgetvalue(setupQuery(db, query, args), 0, 0)
|
var x = PQgetvalue(setupQuery(db, query, args), 0, 0)
|
||||||
result = if isNil(x): "" else: $x
|
result = if isNil(x): "" else: $x
|
||||||
|
|
||||||
proc TryInsertID*(db: TDbConn, query: TSqlQuery,
|
proc TryInsertID*(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string, `$`]): int64 =
|
args: varargs[string, `$`]): int64 {.tags: [FWriteDb].}=
|
||||||
## executes the query (typically "INSERT") and returns the
|
## executes the query (typically "INSERT") and returns the
|
||||||
## generated ID for the row or -1 in case of an error. For Postgre this adds
|
## generated ID for the row or -1 in case of an error. For Postgre this adds
|
||||||
## ``RETURNING id`` to the query, so it only works if your primary key is
|
## ``RETURNING id`` to the query, so it only works if your primary key is
|
||||||
## named ``id``.
|
## named ``id``.
|
||||||
var val = GetValue(db, TSqlQuery(string(query) & " RETURNING id"), args)
|
var x = PQgetvalue(setupQuery(db, TSqlQuery(string(query) & " RETURNING id"),
|
||||||
if val.len > 0:
|
args), 0, 0)
|
||||||
result = ParseBiggestInt(val)
|
if not isNil(x):
|
||||||
|
result = ParseBiggestInt($x)
|
||||||
else:
|
else:
|
||||||
result = -1
|
result = -1
|
||||||
|
|
||||||
proc InsertID*(db: TDbConn, query: TSqlQuery,
|
proc InsertID*(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string, `$`]): int64 =
|
args: varargs[string, `$`]): int64 {.tags: [FWriteDb].} =
|
||||||
## executes the query (typically "INSERT") and returns the
|
## executes the query (typically "INSERT") and returns the
|
||||||
## generated ID for the row. For Postgre this adds
|
## generated ID for the row. For Postgre this adds
|
||||||
## ``RETURNING id`` to the query, so it only works if your primary key is
|
## ``RETURNING id`` to the query, so it only works if your primary key is
|
||||||
|
|
@ -153,7 +159,8 @@ proc InsertID*(db: TDbConn, query: TSqlQuery,
|
||||||
if result < 0: dbError(db)
|
if result < 0: dbError(db)
|
||||||
|
|
||||||
proc ExecAffectedRows*(db: TDbConn, query: TSqlQuery,
|
proc ExecAffectedRows*(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string, `$`]): int64 =
|
args: varargs[string, `$`]): int64 {.tags: [
|
||||||
|
FReadDB, FWriteDb].} =
|
||||||
## executes the query (typically "UPDATE") and returns the
|
## executes the query (typically "UPDATE") and returns the
|
||||||
## number of affected rows.
|
## number of affected rows.
|
||||||
var q = dbFormat(query, args)
|
var q = dbFormat(query, args)
|
||||||
|
|
@ -162,11 +169,12 @@ proc ExecAffectedRows*(db: TDbConn, query: TSqlQuery,
|
||||||
result = parseBiggestInt($PQcmdTuples(res))
|
result = parseBiggestInt($PQcmdTuples(res))
|
||||||
PQclear(res)
|
PQclear(res)
|
||||||
|
|
||||||
proc Close*(db: TDbConn) =
|
proc Close*(db: TDbConn) {.tags: [FDb].} =
|
||||||
## closes the database connection.
|
## closes the database connection.
|
||||||
if db != nil: PQfinish(db)
|
if db != nil: PQfinish(db)
|
||||||
|
|
||||||
proc Open*(connection, user, password, database: string): TDbConn =
|
proc Open*(connection, user, password, database: string): TDbConn {.
|
||||||
|
tags: [FDb].} =
|
||||||
## opens a database connection. Raises `EDb` if the connection could not
|
## opens a database connection. Raises `EDb` if the connection could not
|
||||||
## be established.
|
## be established.
|
||||||
result = PQsetdbLogin(nil, nil, nil, nil, database, user, password)
|
result = PQsetdbLogin(nil, nil, nil, nil, database, user, password)
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,10 @@ type
|
||||||
|
|
||||||
TSqlQuery* = distinct string ## an SQL query string
|
TSqlQuery* = distinct string ## an SQL query string
|
||||||
|
|
||||||
|
FDb* = object of FIO ## effect that denotes a database operation
|
||||||
|
FReadDb* = object of FReadIO ## effect that denotes a read operation
|
||||||
|
FWriteDb* = object of FWriteIO ## effect that denotes a write operation
|
||||||
|
|
||||||
proc sql*(query: string): TSqlQuery {.noSideEffect, inline.} =
|
proc sql*(query: string): TSqlQuery {.noSideEffect, inline.} =
|
||||||
## constructs a TSqlQuery from the string `query`. This is supposed to be
|
## constructs a TSqlQuery from the string `query`. This is supposed to be
|
||||||
## used as a raw-string-literal modifier:
|
## used as a raw-string-literal modifier:
|
||||||
|
|
@ -60,7 +64,7 @@ proc dbFormat(formatstr: TSqlQuery, args: varargs[string]): string =
|
||||||
add(result, c)
|
add(result, c)
|
||||||
|
|
||||||
proc TryExec*(db: TDbConn, query: TSqlQuery,
|
proc TryExec*(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string, `$`]): bool =
|
args: varargs[string, `$`]): bool {.tags: [FReadDB, FWriteDb].} =
|
||||||
## tries to execute the query and returns true if successful, false otherwise.
|
## tries to execute the query and returns true if successful, false otherwise.
|
||||||
var q = dbFormat(query, args)
|
var q = dbFormat(query, args)
|
||||||
var stmt: sqlite3.PStmt
|
var stmt: sqlite3.PStmt
|
||||||
|
|
@ -68,7 +72,8 @@ proc TryExec*(db: TDbConn, query: TSqlQuery,
|
||||||
if step(stmt) == SQLITE_DONE:
|
if step(stmt) == SQLITE_DONE:
|
||||||
result = finalize(stmt) == SQLITE_OK
|
result = finalize(stmt) == SQLITE_OK
|
||||||
|
|
||||||
proc Exec*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]) =
|
proc Exec*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]) {.
|
||||||
|
tags: [FReadDB, FWriteDb].} =
|
||||||
## executes the query and raises EDB if not successful.
|
## executes the query and raises EDB if not successful.
|
||||||
if not TryExec(db, query, args): dbError(db)
|
if not TryExec(db, query, args): dbError(db)
|
||||||
|
|
||||||
|
|
@ -89,7 +94,7 @@ proc setRow(stmt: PStmt, r: var TRow, cols: cint) =
|
||||||
if not isNil(x): add(r[col], x)
|
if not isNil(x): add(r[col], x)
|
||||||
|
|
||||||
iterator FastRows*(db: TDbConn, query: TSqlQuery,
|
iterator FastRows*(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string, `$`]): TRow =
|
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
|
||||||
## executes the query and iterates over the result dataset. This is very
|
## executes the query and iterates over the result dataset. This is very
|
||||||
## fast, but potenially dangerous: If the for-loop-body executes another
|
## fast, but potenially dangerous: If the for-loop-body executes another
|
||||||
## query, the results can be undefined. For Sqlite it is safe though.
|
## query, the results can be undefined. For Sqlite it is safe though.
|
||||||
|
|
@ -102,7 +107,7 @@ iterator FastRows*(db: TDbConn, query: TSqlQuery,
|
||||||
if finalize(stmt) != SQLITE_OK: dbError(db)
|
if finalize(stmt) != SQLITE_OK: dbError(db)
|
||||||
|
|
||||||
proc getRow*(db: TDbConn, query: TSqlQuery,
|
proc getRow*(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string, `$`]): TRow =
|
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
|
||||||
## retrieves a single row.
|
## retrieves a single row.
|
||||||
var stmt = setupQuery(db, query, args)
|
var stmt = setupQuery(db, query, args)
|
||||||
var L = (columnCount(stmt))
|
var L = (columnCount(stmt))
|
||||||
|
|
@ -112,19 +117,19 @@ proc getRow*(db: TDbConn, query: TSqlQuery,
|
||||||
if finalize(stmt) != SQLITE_OK: dbError(db)
|
if finalize(stmt) != SQLITE_OK: dbError(db)
|
||||||
|
|
||||||
proc GetAllRows*(db: TDbConn, query: TSqlQuery,
|
proc GetAllRows*(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string, `$`]): seq[TRow] =
|
args: varargs[string, `$`]): seq[TRow] {.tags: [FReadDB].} =
|
||||||
## executes the query and returns the whole result dataset.
|
## executes the query and returns the whole result dataset.
|
||||||
result = @[]
|
result = @[]
|
||||||
for r in FastRows(db, query, args):
|
for r in FastRows(db, query, args):
|
||||||
result.add(r)
|
result.add(r)
|
||||||
|
|
||||||
iterator Rows*(db: TDbConn, query: TSqlQuery,
|
iterator Rows*(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string, `$`]): TRow =
|
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
|
||||||
## same as `FastRows`, but slower and safe.
|
## same as `FastRows`, but slower and safe.
|
||||||
for r in FastRows(db, query, args): yield r
|
for r in FastRows(db, query, args): yield r
|
||||||
|
|
||||||
proc GetValue*(db: TDbConn, query: TSqlQuery,
|
proc GetValue*(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string, `$`]): string =
|
args: varargs[string, `$`]): string {.tags: [FReadDB].} =
|
||||||
## executes the query and returns the result dataset's the first column
|
## executes the query and returns the result dataset's the first column
|
||||||
## of the first row. Returns "" if the dataset contains no rows.
|
## of the first row. Returns "" if the dataset contains no rows.
|
||||||
var stmt = setupQuery(db, query, args)
|
var stmt = setupQuery(db, query, args)
|
||||||
|
|
@ -140,16 +145,19 @@ proc GetValue*(db: TDbConn, query: TSqlQuery,
|
||||||
result = ""
|
result = ""
|
||||||
|
|
||||||
proc TryInsertID*(db: TDbConn, query: TSqlQuery,
|
proc TryInsertID*(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string, `$`]): int64 =
|
args: varargs[string, `$`]): int64 {.tags: [FWriteDb].} =
|
||||||
## executes the query (typically "INSERT") and returns the
|
## executes the query (typically "INSERT") and returns the
|
||||||
## generated ID for the row or -1 in case of an error.
|
## generated ID for the row or -1 in case of an error.
|
||||||
if tryExec(db, query, args):
|
var q = dbFormat(query, args)
|
||||||
result = last_insert_rowid(db)
|
var stmt: sqlite3.PStmt
|
||||||
else:
|
if prepare_v2(db, q, q.len.cint, stmt, nil) == SQLITE_OK:
|
||||||
result = -1
|
if step(stmt) == SQLITE_DONE:
|
||||||
|
if finalize(stmt) == SQLITE_OK:
|
||||||
|
return last_insert_rowid(db)
|
||||||
|
result = -1
|
||||||
|
|
||||||
proc InsertID*(db: TDbConn, query: TSqlQuery,
|
proc InsertID*(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string, `$`]): int64 =
|
args: varargs[string, `$`]): int64 {.tags: [FWriteDb].} =
|
||||||
## executes the query (typically "INSERT") and returns the
|
## executes the query (typically "INSERT") and returns the
|
||||||
## generated ID for the row. For Postgre this adds
|
## generated ID for the row. For Postgre this adds
|
||||||
## ``RETURNING id`` to the query, so it only works if your primary key is
|
## ``RETURNING id`` to the query, so it only works if your primary key is
|
||||||
|
|
@ -158,17 +166,19 @@ proc InsertID*(db: TDbConn, query: TSqlQuery,
|
||||||
if result < 0: dbError(db)
|
if result < 0: dbError(db)
|
||||||
|
|
||||||
proc ExecAffectedRows*(db: TDbConn, query: TSqlQuery,
|
proc ExecAffectedRows*(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string, `$`]): int64 =
|
args: varargs[string, `$`]): int64 {.
|
||||||
|
tags: [FReadDB, FWriteDb].} =
|
||||||
## executes the query (typically "UPDATE") and returns the
|
## executes the query (typically "UPDATE") and returns the
|
||||||
## number of affected rows.
|
## number of affected rows.
|
||||||
Exec(db, query, args)
|
Exec(db, query, args)
|
||||||
result = changes(db)
|
result = changes(db)
|
||||||
|
|
||||||
proc Close*(db: TDbConn) =
|
proc Close*(db: TDbConn) {.tags: [FDB].} =
|
||||||
## closes the database connection.
|
## closes the database connection.
|
||||||
if sqlite3.close(db) != SQLITE_OK: dbError(db)
|
if sqlite3.close(db) != SQLITE_OK: dbError(db)
|
||||||
|
|
||||||
proc Open*(connection, user, password, database: string): TDbConn =
|
proc Open*(connection, user, password, database: string): TDbConn {.
|
||||||
|
tags: [FDB].} =
|
||||||
## opens a database connection. Raises `EDb` if the connection could not
|
## opens a database connection. Raises `EDb` if the connection could not
|
||||||
## be established. Only the ``connection`` parameter is used for ``sqlite``.
|
## be established. Only the ``connection`` parameter is used for ``sqlite``.
|
||||||
var db: TDbConn
|
var db: TDbConn
|
||||||
|
|
|
||||||
|
|
@ -14,12 +14,14 @@
|
||||||
## wanted functionality.
|
## wanted functionality.
|
||||||
|
|
||||||
when defined(Windows):
|
when defined(Windows):
|
||||||
proc ReadLineFromStdin*(prompt: string): TaintedString =
|
proc ReadLineFromStdin*(prompt: string): TaintedString {.
|
||||||
|
tags: [FReadIO, FWriteIO].} =
|
||||||
## Reads a line from stdin.
|
## Reads a line from stdin.
|
||||||
stdout.write(prompt)
|
stdout.write(prompt)
|
||||||
result = readLine(stdin)
|
result = readLine(stdin)
|
||||||
|
|
||||||
proc ReadLineFromStdin*(prompt: string, line: var TaintedString): bool =
|
proc ReadLineFromStdin*(prompt: string, line: var TaintedString): bool {.
|
||||||
|
tags: [FReadIO, FWriteIO].} =
|
||||||
## Reads a `line` from stdin. `line` must not be
|
## Reads a `line` from stdin. `line` must not be
|
||||||
## ``nil``! May throw an IO exception.
|
## ``nil``! May throw an IO exception.
|
||||||
## A line of text may be delimited by ``CR``, ``LF`` or
|
## A line of text may be delimited by ``CR``, ``LF`` or
|
||||||
|
|
@ -32,7 +34,8 @@ when defined(Windows):
|
||||||
else:
|
else:
|
||||||
import readline, history
|
import readline, history
|
||||||
|
|
||||||
proc ReadLineFromStdin*(prompt: string): TaintedString =
|
proc ReadLineFromStdin*(prompt: string): TaintedString {.
|
||||||
|
tags: [FReadIO, FWriteIO].} =
|
||||||
var buffer = readline.readLine(prompt)
|
var buffer = readline.readLine(prompt)
|
||||||
if isNil(buffer): quit(0)
|
if isNil(buffer): quit(0)
|
||||||
result = TaintedString($buffer)
|
result = TaintedString($buffer)
|
||||||
|
|
@ -40,7 +43,8 @@ else:
|
||||||
add_history(buffer)
|
add_history(buffer)
|
||||||
readline.free(buffer)
|
readline.free(buffer)
|
||||||
|
|
||||||
proc ReadLineFromStdin*(prompt: string, line: var TaintedString): bool =
|
proc ReadLineFromStdin*(prompt: string, line: var TaintedString): bool {.
|
||||||
|
tags: [FReadIO, FWriteIO].} =
|
||||||
var buffer = readline.readLine(prompt)
|
var buffer = readline.readLine(prompt)
|
||||||
if isNil(buffer): quit(0)
|
if isNil(buffer): quit(0)
|
||||||
line = TaintedString($buffer)
|
line = TaintedString($buffer)
|
||||||
|
|
|
||||||
|
|
@ -58,5 +58,5 @@ proc URLretrieveString*(url: string): TaintedString =
|
||||||
result = stream.data.TaintedString
|
result = stream.data.TaintedString
|
||||||
|
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
echo URLretrieveString("http://nimrod.ethexor.com/")
|
echo URLretrieveString("http://nimrod-code.org/")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,11 +43,12 @@ type
|
||||||
proc execProcess*(command: string,
|
proc execProcess*(command: string,
|
||||||
options: set[TProcessOption] = {poStdErrToStdOut,
|
options: set[TProcessOption] = {poStdErrToStdOut,
|
||||||
poUseShell}): TaintedString {.
|
poUseShell}): TaintedString {.
|
||||||
rtl, extern: "nosp$1".}
|
rtl, extern: "nosp$1",
|
||||||
|
tags: [FExecIO, FReadIO].}
|
||||||
## A convenience procedure that executes ``command`` with ``startProcess``
|
## A convenience procedure that executes ``command`` with ``startProcess``
|
||||||
## and returns its output as a string.
|
## and returns its output as a string.
|
||||||
|
|
||||||
proc execCmd*(command: string): int {.rtl, extern: "nosp$1".}
|
proc execCmd*(command: string): int {.rtl, extern: "nosp$1", tags: [FExecIO].}
|
||||||
## Executes ``command`` and returns its error code. Standard input, output,
|
## Executes ``command`` and returns its error code. Standard input, output,
|
||||||
## error streams are inherited from the calling process. This operation
|
## error streams are inherited from the calling process. This operation
|
||||||
## is also often called `system`:idx:.
|
## is also often called `system`:idx:.
|
||||||
|
|
@ -57,7 +58,7 @@ proc startProcess*(command: string,
|
||||||
args: openarray[string] = [],
|
args: openarray[string] = [],
|
||||||
env: PStringTable = nil,
|
env: PStringTable = nil,
|
||||||
options: set[TProcessOption] = {poStdErrToStdOut}):
|
options: set[TProcessOption] = {poStdErrToStdOut}):
|
||||||
PProcess {.rtl, extern: "nosp$1".}
|
PProcess {.rtl, extern: "nosp$1", tags: [FExecIO].}
|
||||||
## Starts a process. `Command` is the executable file, `workingDir` is the
|
## Starts a process. `Command` is the executable file, `workingDir` is the
|
||||||
## process's working directory. If ``workingDir == ""`` the current directory
|
## process's working directory. If ``workingDir == ""`` the current directory
|
||||||
## is used. `args` are the command line arguments that are passed to the
|
## is used. `args` are the command line arguments that are passed to the
|
||||||
|
|
@ -73,7 +74,7 @@ proc startProcess*(command: string,
|
||||||
## but ``EOS`` is raised in case of an error.
|
## but ``EOS`` is raised in case of an error.
|
||||||
|
|
||||||
proc startCmd*(command: string, options: set[TProcessOption] = {
|
proc startCmd*(command: string, options: set[TProcessOption] = {
|
||||||
poStdErrToStdOut, poUseShell}): PProcess =
|
poStdErrToStdOut, poUseShell}): PProcess {.tags: [FExecIO].} =
|
||||||
## a simpler version of `startProcess` that parses the command line into
|
## a simpler version of `startProcess` that parses the command line into
|
||||||
## program and arguments and then calls `startProcess` with the empty string
|
## program and arguments and then calls `startProcess` with the empty string
|
||||||
## for `workingDir` and the nil string table for `env`.
|
## for `workingDir` and the nil string table for `env`.
|
||||||
|
|
@ -83,38 +84,39 @@ proc startCmd*(command: string, options: set[TProcessOption] = {
|
||||||
for i in 1 .. c.len-1: a[i-1] = c[i]
|
for i in 1 .. c.len-1: a[i-1] = c[i]
|
||||||
result = startProcess(command=c[0], args=a, options=options)
|
result = startProcess(command=c[0], args=a, options=options)
|
||||||
|
|
||||||
proc close*(p: PProcess) {.rtl, extern: "nosp$1".}
|
proc close*(p: PProcess) {.rtl, extern: "nosp$1", tags: [].}
|
||||||
## When the process has finished executing, cleanup related handles
|
## When the process has finished executing, cleanup related handles
|
||||||
|
|
||||||
proc suspend*(p: PProcess) {.rtl, extern: "nosp$1".}
|
proc suspend*(p: PProcess) {.rtl, extern: "nosp$1", tags: [].}
|
||||||
## Suspends the process `p`.
|
## Suspends the process `p`.
|
||||||
|
|
||||||
proc resume*(p: PProcess) {.rtl, extern: "nosp$1".}
|
proc resume*(p: PProcess) {.rtl, extern: "nosp$1", tags: [].}
|
||||||
## Resumes the process `p`.
|
## Resumes the process `p`.
|
||||||
|
|
||||||
proc terminate*(p: PProcess) {.rtl, extern: "nosp$1".}
|
proc terminate*(p: PProcess) {.rtl, extern: "nosp$1", tags: [].}
|
||||||
## Terminates the process `p`.
|
## Terminates the process `p`.
|
||||||
|
|
||||||
proc running*(p: PProcess): bool {.rtl, extern: "nosp$1".}
|
proc running*(p: PProcess): bool {.rtl, extern: "nosp$1", tags: [].}
|
||||||
## Returns true iff the process `p` is still running. Returns immediately.
|
## Returns true iff the process `p` is still running. Returns immediately.
|
||||||
|
|
||||||
proc processID*(p: PProcess): int {.rtl, extern: "nosp$1".} =
|
proc processID*(p: PProcess): int {.rtl, extern: "nosp$1".} =
|
||||||
## returns `p`'s process ID.
|
## returns `p`'s process ID.
|
||||||
return p.id
|
return p.id
|
||||||
|
|
||||||
proc waitForExit*(p: PProcess, timeout: int = -1): int {.rtl, extern: "nosp$1".}
|
proc waitForExit*(p: PProcess, timeout: int = -1): int {.rtl,
|
||||||
|
extern: "nosp$1", tags: [].}
|
||||||
## waits for the process to finish and returns `p`'s error code.
|
## waits for the process to finish and returns `p`'s error code.
|
||||||
|
|
||||||
proc peekExitCode*(p: PProcess): int
|
proc peekExitCode*(p: PProcess): int {.tags: [].}
|
||||||
## return -1 if the process is still running. Otherwise the process' exit code
|
## return -1 if the process is still running. Otherwise the process' exit code
|
||||||
|
|
||||||
proc inputStream*(p: PProcess): PStream {.rtl, extern: "nosp$1".}
|
proc inputStream*(p: PProcess): PStream {.rtl, extern: "nosp$1", tags: [].}
|
||||||
## opens ``p``'s input stream for writing to
|
## opens ``p``'s input stream for writing to
|
||||||
|
|
||||||
proc outputStream*(p: PProcess): PStream {.rtl, extern: "nosp$1".}
|
proc outputStream*(p: PProcess): PStream {.rtl, extern: "nosp$1", tags: [].}
|
||||||
## opens ``p``'s output stream for reading from
|
## opens ``p``'s output stream for reading from
|
||||||
|
|
||||||
proc errorStream*(p: PProcess): PStream {.rtl, extern: "nosp$1".}
|
proc errorStream*(p: PProcess): PStream {.rtl, extern: "nosp$1", tags: [].}
|
||||||
## opens ``p``'s output stream for reading from
|
## opens ``p``'s output stream for reading from
|
||||||
|
|
||||||
when defined(macosx) or defined(bsd):
|
when defined(macosx) or defined(bsd):
|
||||||
|
|
@ -156,7 +158,8 @@ proc countProcessors*(): int {.rtl, extern: "nosp$1".} =
|
||||||
|
|
||||||
proc execProcesses*(cmds: openArray[string],
|
proc execProcesses*(cmds: openArray[string],
|
||||||
options = {poStdErrToStdOut, poParentStreams},
|
options = {poStdErrToStdOut, poParentStreams},
|
||||||
n = countProcessors()): int {.rtl, extern: "nosp$1".} =
|
n = countProcessors()): int {.rtl, extern: "nosp$1",
|
||||||
|
tags: [FExecIO].} =
|
||||||
## executes the commands `cmds` in parallel. Creates `n` processes
|
## executes the commands `cmds` in parallel. Creates `n` processes
|
||||||
## that execute in parallel. The highest return value of all processes
|
## that execute in parallel. The highest return value of all processes
|
||||||
## is returned.
|
## is returned.
|
||||||
|
|
@ -731,7 +734,7 @@ elif not defined(useNimRtl):
|
||||||
proc execCmdEx*(command: string, options: set[TProcessOption] = {
|
proc execCmdEx*(command: string, options: set[TProcessOption] = {
|
||||||
poStdErrToStdOut, poUseShell}): tuple[
|
poStdErrToStdOut, poUseShell}): tuple[
|
||||||
output: TaintedString,
|
output: TaintedString,
|
||||||
exitCode: int] =
|
exitCode: int] {.tags: [FExecIO, FReadIO].} =
|
||||||
## a convenience proc that runs the `command`, grabs all its output and
|
## a convenience proc that runs the `command`, grabs all its output and
|
||||||
## exit code and returns both.
|
## exit code and returns both.
|
||||||
var p = startCmd(command, options)
|
var p = startCmd(command, options)
|
||||||
|
|
|
||||||
|
|
@ -23,14 +23,15 @@ type
|
||||||
## here shouldn't be used directly. They are
|
## here shouldn't be used directly. They are
|
||||||
## accessible so that a stream implementation
|
## accessible so that a stream implementation
|
||||||
## can override them.
|
## can override them.
|
||||||
closeImpl*: proc (s: PStream) {.nimcall.}
|
closeImpl*: proc (s: PStream) {.nimcall, tags: [].}
|
||||||
atEndImpl*: proc (s: PStream): bool {.nimcall.}
|
atEndImpl*: proc (s: PStream): bool {.nimcall, tags: [].}
|
||||||
setPositionImpl*: proc (s: PStream, pos: int) {.nimcall.}
|
setPositionImpl*: proc (s: PStream, pos: int) {.nimcall, tags: [].}
|
||||||
getPositionImpl*: proc (s: PStream): int {.nimcall.}
|
getPositionImpl*: proc (s: PStream): int {.nimcall, tags: [].}
|
||||||
readDataImpl*: proc (s: PStream, buffer: pointer,
|
readDataImpl*: proc (s: PStream, buffer: pointer,
|
||||||
bufLen: int): int {.nimcall.}
|
bufLen: int): int {.nimcall, tags: [FReadIO].}
|
||||||
writeDataImpl*: proc (s: PStream, buffer: pointer, bufLen: int) {.nimcall.}
|
writeDataImpl*: proc (s: PStream, buffer: pointer, bufLen: int) {.nimcall,
|
||||||
flushImpl*: proc (s: PStream) {.nimcall.}
|
tags: [FWriteIO].}
|
||||||
|
flushImpl*: proc (s: PStream) {.nimcall, tags: [FWriteIO].}
|
||||||
|
|
||||||
proc flush*(s: PStream) =
|
proc flush*(s: PStream) =
|
||||||
## flushes the buffers that the stream `s` might use.
|
## flushes the buffers that the stream `s` might use.
|
||||||
|
|
|
||||||
|
|
@ -1080,21 +1080,21 @@ proc equalMem*(a, b: Pointer, size: int): bool {.
|
||||||
## otherwise. Like any procedure dealing with raw memory this is
|
## otherwise. Like any procedure dealing with raw memory this is
|
||||||
## *unsafe*.
|
## *unsafe*.
|
||||||
|
|
||||||
proc alloc*(size: int): pointer {.noconv, rtl.}
|
proc alloc*(size: int): pointer {.noconv, rtl, tags: [].}
|
||||||
## allocates a new memory block with at least ``size`` bytes. The
|
## allocates a new memory block with at least ``size`` bytes. The
|
||||||
## block has to be freed with ``realloc(block, 0)`` or
|
## block has to be freed with ``realloc(block, 0)`` or
|
||||||
## ``dealloc(block)``. The block is not initialized, so reading
|
## ``dealloc(block)``. The block is not initialized, so reading
|
||||||
## from it before writing to it is undefined behaviour!
|
## from it before writing to it is undefined behaviour!
|
||||||
## The allocated memory belongs to its allocating thread!
|
## The allocated memory belongs to its allocating thread!
|
||||||
## Use `allocShared` to allocate from a shared heap.
|
## Use `allocShared` to allocate from a shared heap.
|
||||||
proc alloc0*(size: int): pointer {.noconv, rtl.}
|
proc alloc0*(size: int): pointer {.noconv, rtl, tags: [].}
|
||||||
## allocates a new memory block with at least ``size`` bytes. The
|
## allocates a new memory block with at least ``size`` bytes. The
|
||||||
## block has to be freed with ``realloc(block, 0)`` or
|
## block has to be freed with ``realloc(block, 0)`` or
|
||||||
## ``dealloc(block)``. The block is initialized with all bytes
|
## ``dealloc(block)``. The block is initialized with all bytes
|
||||||
## containing zero, so it is somewhat safer than ``alloc``.
|
## containing zero, so it is somewhat safer than ``alloc``.
|
||||||
## The allocated memory belongs to its allocating thread!
|
## The allocated memory belongs to its allocating thread!
|
||||||
## Use `allocShared0` to allocate from a shared heap.
|
## Use `allocShared0` to allocate from a shared heap.
|
||||||
proc realloc*(p: Pointer, newsize: int): pointer {.noconv, rtl.}
|
proc realloc*(p: Pointer, newsize: int): pointer {.noconv, rtl, tags: [].}
|
||||||
## grows or shrinks a given memory block. If p is **nil** then a new
|
## grows or shrinks a given memory block. If p is **nil** then a new
|
||||||
## memory block is returned. In either way the block has at least
|
## memory block is returned. In either way the block has at least
|
||||||
## ``newsize`` bytes. If ``newsize == 0`` and p is not **nil**
|
## ``newsize`` bytes. If ``newsize == 0`` and p is not **nil**
|
||||||
|
|
@ -1102,7 +1102,7 @@ proc realloc*(p: Pointer, newsize: int): pointer {.noconv, rtl.}
|
||||||
## be freed with ``dealloc``.
|
## be freed with ``dealloc``.
|
||||||
## The allocated memory belongs to its allocating thread!
|
## The allocated memory belongs to its allocating thread!
|
||||||
## Use `reallocShared` to reallocate from a shared heap.
|
## Use `reallocShared` to reallocate from a shared heap.
|
||||||
proc dealloc*(p: Pointer) {.noconv, rtl.}
|
proc dealloc*(p: Pointer) {.noconv, rtl, tags: [].}
|
||||||
## frees the memory allocated with ``alloc``, ``alloc0`` or
|
## frees the memory allocated with ``alloc``, ``alloc0`` or
|
||||||
## ``realloc``. This procedure is dangerous! If one forgets to
|
## ``realloc``. This procedure is dangerous! If one forgets to
|
||||||
## free the memory a leak occurs; if one tries to access freed
|
## free the memory a leak occurs; if one tries to access freed
|
||||||
|
|
@ -1618,7 +1618,7 @@ var
|
||||||
## do when setting this. If ``localRaiseHook`` returns false, the exception
|
## do when setting this. If ``localRaiseHook`` returns false, the exception
|
||||||
## is caught and does not propagate further through the call stack.
|
## is caught and does not propagate further through the call stack.
|
||||||
|
|
||||||
outOfMemHook*: proc () {.nimcall.}
|
outOfMemHook*: proc () {.nimcall, tags: [].}
|
||||||
## set this variable to provide a procedure that should be called
|
## set this variable to provide a procedure that should be called
|
||||||
## in case of an `out of memory`:idx: event. The standard handler
|
## in case of an `out of memory`:idx: event. The standard handler
|
||||||
## writes an error message and terminates the program. `outOfMemHook` can
|
## writes an error message and terminates the program. `outOfMemHook` can
|
||||||
|
|
@ -1668,7 +1668,7 @@ else:
|
||||||
|
|
||||||
proc add*(x: var cstring, y: cstring) {.magic: "AppendStrStr".}
|
proc add*(x: var cstring, y: cstring) {.magic: "AppendStrStr".}
|
||||||
|
|
||||||
proc echo*[T](x: varargs[T, `$`]) {.magic: "Echo".}
|
proc echo*[T](x: varargs[T, `$`]) {.magic: "Echo", tags: [FWriteIO].}
|
||||||
## special built-in that takes a variable number of arguments. Each argument
|
## special built-in that takes a variable number of arguments. Each argument
|
||||||
## is converted to a string via ``$``, so it works for user-defined
|
## is converted to a string via ``$``, so it works for user-defined
|
||||||
## types that have an overloaded ``$`` operator.
|
## types that have an overloaded ``$`` operator.
|
||||||
|
|
@ -1677,7 +1677,8 @@ proc echo*[T](x: varargs[T, `$`]) {.magic: "Echo".}
|
||||||
## Unlike other IO operations this is guaranteed to be thread-safe as
|
## Unlike other IO operations this is guaranteed to be thread-safe as
|
||||||
## ``echo`` is very often used for debugging convenience.
|
## ``echo`` is very often used for debugging convenience.
|
||||||
|
|
||||||
proc debugEcho*[T](x: varargs[T, `$`]) {.magic: "Echo", noSideEffect.}
|
proc debugEcho*[T](x: varargs[T, `$`]) {.magic: "Echo", noSideEffect,
|
||||||
|
tags: [], raises: [].}
|
||||||
## Same as ``echo``, but as a special semantic rule, ``debugEcho`` pretends
|
## Same as ``echo``, but as a special semantic rule, ``debugEcho`` pretends
|
||||||
## to be free of side effects, so that it can be used for debugging routines
|
## to be free of side effects, so that it can be used for debugging routines
|
||||||
## marked as ``noSideEffect``.
|
## marked as ``noSideEffect``.
|
||||||
|
|
@ -1780,14 +1781,14 @@ when not defined(EcmaScript) and not defined(NimrodVM):
|
||||||
## to ``stderr``.
|
## to ``stderr``.
|
||||||
|
|
||||||
proc Open*(f: var TFile, filename: string,
|
proc Open*(f: var TFile, filename: string,
|
||||||
mode: TFileMode = fmRead, bufSize: int = -1): Bool
|
mode: TFileMode = fmRead, bufSize: int = -1): Bool {.tags: [].}
|
||||||
## Opens a file named `filename` with given `mode`.
|
## Opens a file named `filename` with given `mode`.
|
||||||
##
|
##
|
||||||
## Default mode is readonly. Returns true iff the file could be opened.
|
## Default mode is readonly. Returns true iff the file could be opened.
|
||||||
## This throws no exception if the file could not be opened.
|
## This throws no exception if the file could not be opened.
|
||||||
|
|
||||||
proc Open*(f: var TFile, filehandle: TFileHandle,
|
proc Open*(f: var TFile, filehandle: TFileHandle,
|
||||||
mode: TFileMode = fmRead): Bool
|
mode: TFileMode = fmRead): Bool {.tags: [].}
|
||||||
## Creates a ``TFile`` from a `filehandle` with given `mode`.
|
## Creates a ``TFile`` from a `filehandle` with given `mode`.
|
||||||
##
|
##
|
||||||
## Default mode is readonly. Returns true iff the file could be opened.
|
## Default mode is readonly. Returns true iff the file could be opened.
|
||||||
|
|
@ -1801,56 +1802,57 @@ when not defined(EcmaScript) and not defined(NimrodVM):
|
||||||
if not open(result, filename, mode, bufSize):
|
if not open(result, filename, mode, bufSize):
|
||||||
raise newException(EIO, "cannot open: " & filename)
|
raise newException(EIO, "cannot open: " & filename)
|
||||||
|
|
||||||
proc reopen*(f: TFile, filename: string, mode: TFileMode = fmRead): bool
|
proc reopen*(f: TFile, filename: string, mode: TFileMode = fmRead): bool {.
|
||||||
|
tags: [].}
|
||||||
## reopens the file `f` with given `filename` and `mode`. This
|
## reopens the file `f` with given `filename` and `mode`. This
|
||||||
## is often used to redirect the `stdin`, `stdout` or `stderr`
|
## is often used to redirect the `stdin`, `stdout` or `stderr`
|
||||||
## file variables.
|
## file variables.
|
||||||
##
|
##
|
||||||
## Default mode is readonly. Returns true iff the file could be reopened.
|
## Default mode is readonly. Returns true iff the file could be reopened.
|
||||||
|
|
||||||
proc Close*(f: TFile) {.importc: "fclose", nodecl.}
|
proc Close*(f: TFile) {.importc: "fclose", nodecl, tags: [].}
|
||||||
## Closes the file.
|
## Closes the file.
|
||||||
|
|
||||||
proc EndOfFile*(f: TFile): Bool
|
proc EndOfFile*(f: TFile): Bool {.tags: [].}
|
||||||
## Returns true iff `f` is at the end.
|
## Returns true iff `f` is at the end.
|
||||||
|
|
||||||
proc readChar*(f: TFile): char {.importc: "fgetc", nodecl.}
|
proc readChar*(f: TFile): char {.importc: "fgetc", nodecl, tags: [FReadIO].}
|
||||||
## Reads a single character from the stream `f`. If the stream
|
## Reads a single character from the stream `f`. If the stream
|
||||||
## has no more characters, `EEndOfFile` is raised.
|
## has no more characters, `EEndOfFile` is raised.
|
||||||
proc FlushFile*(f: TFile) {.importc: "fflush", noDecl.}
|
proc FlushFile*(f: TFile) {.importc: "fflush", noDecl, tags: [FWriteIO].}
|
||||||
## Flushes `f`'s buffer.
|
## Flushes `f`'s buffer.
|
||||||
|
|
||||||
proc readAll*(file: TFile): TaintedString
|
proc readAll*(file: TFile): TaintedString {.tags: [FReadIO].}
|
||||||
## Reads all data from the stream `file`. Raises an IO exception
|
## Reads all data from the stream `file`. Raises an IO exception
|
||||||
## in case of an error
|
## in case of an error
|
||||||
|
|
||||||
proc readFile*(filename: string): TaintedString
|
proc readFile*(filename: string): TaintedString {.tags: [FReadIO].}
|
||||||
## Opens a file named `filename` for reading. Then calls `readAll`
|
## Opens a file named `filename` for reading. Then calls `readAll`
|
||||||
## and closes the file afterwards. Returns the string.
|
## and closes the file afterwards. Returns the string.
|
||||||
## Raises an IO exception in case of an error.
|
## Raises an IO exception in case of an error.
|
||||||
|
|
||||||
proc writeFile*(filename, content: string)
|
proc writeFile*(filename, content: string) {.tags: [FWriteIO].}
|
||||||
## Opens a file named `filename` for writing. Then writes the
|
## Opens a file named `filename` for writing. Then writes the
|
||||||
## `content` completely to the file and closes the file afterwards.
|
## `content` completely to the file and closes the file afterwards.
|
||||||
## Raises an IO exception in case of an error.
|
## Raises an IO exception in case of an error.
|
||||||
|
|
||||||
proc write*(f: TFile, r: float)
|
proc write*(f: TFile, r: float) {.tags: [FWriteIO].}
|
||||||
proc write*(f: TFile, i: int)
|
proc write*(f: TFile, i: int) {.tags: [FWriteIO].}
|
||||||
proc write*(f: TFile, i: biggestInt)
|
proc write*(f: TFile, i: biggestInt) {.tags: [FWriteIO].}
|
||||||
proc write*(f: TFile, r: biggestFloat)
|
proc write*(f: TFile, r: biggestFloat) {.tags: [FWriteIO].}
|
||||||
proc write*(f: TFile, s: string)
|
proc write*(f: TFile, s: string) {.tags: [FWriteIO].}
|
||||||
proc write*(f: TFile, b: Bool)
|
proc write*(f: TFile, b: Bool) {.tags: [FWriteIO].}
|
||||||
proc write*(f: TFile, c: char)
|
proc write*(f: TFile, c: char) {.tags: [FWriteIO].}
|
||||||
proc write*(f: TFile, c: cstring)
|
proc write*(f: TFile, c: cstring) {.tags: [FWriteIO].}
|
||||||
proc write*(f: TFile, a: varargs[string, `$`])
|
proc write*(f: TFile, a: varargs[string, `$`]) {.tags: [FWriteIO].}
|
||||||
## Writes a value to the file `f`. May throw an IO exception.
|
## Writes a value to the file `f`. May throw an IO exception.
|
||||||
|
|
||||||
proc readLine*(f: TFile): TaintedString
|
proc readLine*(f: TFile): TaintedString {.tags: [FReadIO].}
|
||||||
## reads a line of text from the file `f`. May throw an IO exception.
|
## reads a line of text from the file `f`. May throw an IO exception.
|
||||||
## A line of text may be delimited by ``CR``, ``LF`` or
|
## A line of text may be delimited by ``CR``, ``LF`` or
|
||||||
## ``CRLF``. The newline character(s) are not part of the returned string.
|
## ``CRLF``. The newline character(s) are not part of the returned string.
|
||||||
|
|
||||||
proc readLine*(f: TFile, line: var TaintedString): bool
|
proc readLine*(f: TFile, line: var TaintedString): bool {.tags: [FReadIO].}
|
||||||
## reads a line of text from the file `f` into `line`. `line` must not be
|
## reads a line of text from the file `f` into `line`. `line` must not be
|
||||||
## ``nil``! May throw an IO exception.
|
## ``nil``! May throw an IO exception.
|
||||||
## A line of text may be delimited by ``CR``, ``LF`` or
|
## A line of text may be delimited by ``CR``, ``LF`` or
|
||||||
|
|
@ -1858,39 +1860,44 @@ when not defined(EcmaScript) and not defined(NimrodVM):
|
||||||
## Returns ``false`` if the end of the file has been reached, ``true``
|
## Returns ``false`` if the end of the file has been reached, ``true``
|
||||||
## otherwise. If ``false`` is returned `line` contains no new data.
|
## otherwise. If ``false`` is returned `line` contains no new data.
|
||||||
|
|
||||||
proc writeln*[Ty](f: TFile, x: varargs[Ty, `$`]) {.inline.}
|
proc writeln*[Ty](f: TFile, x: varargs[Ty, `$`]) {.inline, tags: [FWriteIO].}
|
||||||
## writes the values `x` to `f` and then writes "\n".
|
## writes the values `x` to `f` and then writes "\n".
|
||||||
## May throw an IO exception.
|
## May throw an IO exception.
|
||||||
|
|
||||||
proc getFileSize*(f: TFile): int64
|
proc getFileSize*(f: TFile): int64 {.tags: [FReadIO].}
|
||||||
## retrieves the file size (in bytes) of `f`.
|
## retrieves the file size (in bytes) of `f`.
|
||||||
|
|
||||||
proc ReadBytes*(f: TFile, a: var openarray[int8], start, len: int): int
|
proc ReadBytes*(f: TFile, a: var openarray[int8], start, len: int): int {.
|
||||||
|
tags: [FReadIO].}
|
||||||
## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns
|
## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns
|
||||||
## the actual number of bytes that have been read which may be less than
|
## the actual number of bytes that have been read which may be less than
|
||||||
## `len` (if not as many bytes are remaining), but not greater.
|
## `len` (if not as many bytes are remaining), but not greater.
|
||||||
|
|
||||||
proc ReadChars*(f: TFile, a: var openarray[char], start, len: int): int
|
proc ReadChars*(f: TFile, a: var openarray[char], start, len: int): int {.
|
||||||
|
tags: [FReadIO].}
|
||||||
## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns
|
## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns
|
||||||
## the actual number of bytes that have been read which may be less than
|
## the actual number of bytes that have been read which may be less than
|
||||||
## `len` (if not as many bytes are remaining), but not greater.
|
## `len` (if not as many bytes are remaining), but not greater.
|
||||||
|
|
||||||
proc readBuffer*(f: TFile, buffer: pointer, len: int): int
|
proc readBuffer*(f: TFile, buffer: pointer, len: int): int {.tags: [FReadIO].}
|
||||||
## reads `len` bytes into the buffer pointed to by `buffer`. Returns
|
## reads `len` bytes into the buffer pointed to by `buffer`. Returns
|
||||||
## the actual number of bytes that have been read which may be less than
|
## the actual number of bytes that have been read which may be less than
|
||||||
## `len` (if not as many bytes are remaining), but not greater.
|
## `len` (if not as many bytes are remaining), but not greater.
|
||||||
|
|
||||||
proc writeBytes*(f: TFile, a: openarray[int8], start, len: int): int
|
proc writeBytes*(f: TFile, a: openarray[int8], start, len: int): int {.
|
||||||
|
tags: [FWriteIO].}
|
||||||
## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns
|
## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns
|
||||||
## the number of actual written bytes, which may be less than `len` in case
|
## the number of actual written bytes, which may be less than `len` in case
|
||||||
## of an error.
|
## of an error.
|
||||||
|
|
||||||
proc writeChars*(f: tFile, a: openarray[char], start, len: int): int
|
proc writeChars*(f: tFile, a: openarray[char], start, len: int): int {.
|
||||||
|
tags: [FWriteIO].}
|
||||||
## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns
|
## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns
|
||||||
## the number of actual written bytes, which may be less than `len` in case
|
## the number of actual written bytes, which may be less than `len` in case
|
||||||
## of an error.
|
## of an error.
|
||||||
|
|
||||||
proc writeBuffer*(f: TFile, buffer: pointer, len: int): int
|
proc writeBuffer*(f: TFile, buffer: pointer, len: int): int {.
|
||||||
|
tags: [FWriteIO].}
|
||||||
## writes the bytes of buffer pointed to by the parameter `buffer` to the
|
## writes the bytes of buffer pointed to by the parameter `buffer` to the
|
||||||
## file `f`. Returns the number of actual written bytes, which may be less
|
## file `f`. Returns the number of actual written bytes, which may be less
|
||||||
## than `len` in case of an error.
|
## than `len` in case of an error.
|
||||||
|
|
@ -1971,7 +1978,7 @@ when not defined(EcmaScript) and not defined(NimrodVM):
|
||||||
## allows you to override the behaviour of your application when CTRL+C
|
## allows you to override the behaviour of your application when CTRL+C
|
||||||
## is pressed. Only one such hook is supported.
|
## is pressed. Only one such hook is supported.
|
||||||
|
|
||||||
proc writeStackTrace*()
|
proc writeStackTrace*() {.tags: [FWriteIO].}
|
||||||
## writes the current stack trace to ``stderr``. This is only works
|
## writes the current stack trace to ``stderr``. This is only works
|
||||||
## for debug builds.
|
## for debug builds.
|
||||||
when hostOS != "standalone":
|
when hostOS != "standalone":
|
||||||
|
|
@ -2029,7 +2036,7 @@ when not defined(EcmaScript) and not defined(NimrodVM):
|
||||||
when hasThreadSupport:
|
when hasThreadSupport:
|
||||||
include "system/channels"
|
include "system/channels"
|
||||||
|
|
||||||
iterator lines*(filename: string): TaintedString =
|
iterator lines*(filename: string): TaintedString {.tags: [FReadIO].} =
|
||||||
## Iterate over any line in the file named `filename`.
|
## Iterate over any line in the file named `filename`.
|
||||||
## If the file does not exist `EIO` is raised.
|
## If the file does not exist `EIO` is raised.
|
||||||
var f = open(filename)
|
var f = open(filename)
|
||||||
|
|
@ -2037,7 +2044,7 @@ when not defined(EcmaScript) and not defined(NimrodVM):
|
||||||
while f.readLine(res): yield res
|
while f.readLine(res): yield res
|
||||||
close(f)
|
close(f)
|
||||||
|
|
||||||
iterator lines*(f: TFile): TaintedString =
|
iterator lines*(f: TFile): TaintedString {.tags: [FReadIO].} =
|
||||||
## Iterate over any line in the file `f`.
|
## Iterate over any line in the file `f`.
|
||||||
var res = TaintedString(newStringOfCap(80))
|
var res = TaintedString(newStringOfCap(80))
|
||||||
while f.readLine(res): yield TaintedString(res)
|
while f.readLine(res): yield TaintedString(res)
|
||||||
|
|
@ -2308,18 +2315,25 @@ proc InstantiationInfo*(index = -1): tuple[filename: string, line: int] {.
|
||||||
|
|
||||||
proc raiseAssert*(msg: string) {.noinline.} =
|
proc raiseAssert*(msg: string) {.noinline.} =
|
||||||
raise newException(EAssertionFailed, msg)
|
raise newException(EAssertionFailed, msg)
|
||||||
|
|
||||||
|
when true:
|
||||||
|
proc hiddenRaiseAssert(msg: string) {.raises: [].} =
|
||||||
|
# trick the compiler to not list ``EAssertionFailed`` when called
|
||||||
|
# by ``assert``.
|
||||||
|
type THide = proc (msg: string) {.noinline, raises: [], noSideEffect.}
|
||||||
|
THide(raiseAssert)(msg)
|
||||||
|
|
||||||
template assert*(cond: bool, msg = "") =
|
template assert*(cond: bool, msg = "") =
|
||||||
## provides a means to implement `programming by contracts`:idx: in Nimrod.
|
## provides a means to implement `programming by contracts`:idx: in Nimrod.
|
||||||
## ``assert`` evaluates expression ``cond`` and if ``cond`` is false, it
|
## ``assert`` evaluates expression ``cond`` and if ``cond`` is false, it
|
||||||
## raises an ``EAssertionFailure`` exception. However, the compiler may
|
## raises an ``EAssertionFailure`` exception. However, the compiler may
|
||||||
## not generate any code at all for ``assert`` if it is advised to do so.
|
## not generate any code at all for ``assert`` if it is advised to do so.
|
||||||
## Use ``assert`` for debugging purposes only.
|
## Use ``assert`` for debugging purposes only.
|
||||||
bind InstantiationInfo
|
bind InstantiationInfo, hiddenRaiseAssert
|
||||||
when compileOption("assertions"):
|
when compileOption("assertions"):
|
||||||
{.line.}:
|
{.line.}:
|
||||||
if not cond:
|
if not cond:
|
||||||
raiseAssert(astToStr(cond) & ' ' & msg)
|
hiddenRaiseAssert(astToStr(cond) & ' ' & msg)
|
||||||
|
|
||||||
template doAssert*(cond: bool, msg = "") =
|
template doAssert*(cond: bool, msg = "") =
|
||||||
## same as `assert` but is always turned on and not affected by the
|
## same as `assert` but is always turned on and not affected by the
|
||||||
|
|
|
||||||
|
|
@ -16,23 +16,25 @@
|
||||||
# of the standard library!
|
# of the standard library!
|
||||||
|
|
||||||
|
|
||||||
proc fputs(c: cstring, f: TFile) {.importc: "fputs", noDecl.}
|
proc fputs(c: cstring, f: TFile) {.importc: "fputs", noDecl, tags: [FWriteIO].}
|
||||||
proc fgets(c: cstring, n: int, f: TFile): cstring {.importc: "fgets", noDecl.}
|
proc fgets(c: cstring, n: int, f: TFile): cstring {.importc: "fgets", noDecl,
|
||||||
proc fgetc(stream: TFile): cint {.importc: "fgetc", nodecl.}
|
tags: [FReadIO].}
|
||||||
proc ungetc(c: cint, f: TFile) {.importc: "ungetc", nodecl.}
|
proc fgetc(stream: TFile): cint {.importc: "fgetc", nodecl, tags: [FReadIO].}
|
||||||
proc putc(c: Char, stream: TFile) {.importc: "putc", nodecl.}
|
proc ungetc(c: cint, f: TFile) {.importc: "ungetc", nodecl, tags: [].}
|
||||||
proc fprintf(f: TFile, frmt: CString) {.importc: "fprintf", nodecl, varargs.}
|
proc putc(c: Char, stream: TFile) {.importc: "putc", nodecl, tags: [FWriteIO].}
|
||||||
proc strlen(c: cstring): int {.importc: "strlen", nodecl.}
|
proc fprintf(f: TFile, frmt: CString) {.importc: "fprintf", nodecl, varargs,
|
||||||
|
tags: [FWriteIO].}
|
||||||
|
proc strlen(c: cstring): int {.importc: "strlen", nodecl, tags: [].}
|
||||||
|
|
||||||
|
|
||||||
# C routine that is used here:
|
# C routine that is used here:
|
||||||
proc fread(buf: Pointer, size, n: int, f: TFile): int {.
|
proc fread(buf: Pointer, size, n: int, f: TFile): int {.
|
||||||
importc: "fread", noDecl.}
|
importc: "fread", noDecl, tags: [FReadIO].}
|
||||||
proc fseek(f: TFile, offset: clong, whence: int): int {.
|
proc fseek(f: TFile, offset: clong, whence: int): int {.
|
||||||
importc: "fseek", noDecl.}
|
importc: "fseek", noDecl, tags: [].}
|
||||||
proc ftell(f: TFile): int {.importc: "ftell", noDecl.}
|
proc ftell(f: TFile): int {.importc: "ftell", noDecl, tags: [].}
|
||||||
proc setvbuf(stream: TFile, buf: pointer, typ, size: cint): cint {.
|
proc setvbuf(stream: TFile, buf: pointer, typ, size: cint): cint {.
|
||||||
importc, nodecl.}
|
importc, nodecl, tags: [].}
|
||||||
|
|
||||||
proc write(f: TFile, c: cstring) = fputs(c, f)
|
proc write(f: TFile, c: cstring) = fputs(c, f)
|
||||||
|
|
||||||
|
|
|
||||||
2
todo.txt
2
todo.txt
|
|
@ -1,7 +1,9 @@
|
||||||
version 0.9.2
|
version 0.9.2
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
- make the stdlib aware of tags: sockets, os
|
||||||
- test&finish first class iterators:
|
- test&finish first class iterators:
|
||||||
|
* allow return in first class iterators
|
||||||
* nested iterators
|
* nested iterators
|
||||||
* arglist as a type?
|
* arglist as a type?
|
||||||
* tyIterator?
|
* tyIterator?
|
||||||
|
|
|
||||||
|
|
@ -19,13 +19,6 @@ between threads, so no "stop the world" mechanism is necessary. An unsafe
|
||||||
shared memory heap is also provided for the increased efficiency that results
|
shared memory heap is also provided for the increased efficiency that results
|
||||||
from that model.
|
from that model.
|
||||||
|
|
||||||
..
|
|
||||||
Don't give me that marketing crap. What is Nimrod?
|
|
||||||
--------------------------------------------------
|
|
||||||
|
|
||||||
Nimrod = Mutable value based datatypes + static binding + sugar to make
|
|
||||||
this programming modell as convenient as possible
|
|
||||||
|
|
||||||
|
|
||||||
Why is it named Nimrod?
|
Why is it named Nimrod?
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
@ -57,10 +50,11 @@ memory heap.
|
||||||
How is Nimrod licensed?
|
How is Nimrod licensed?
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
The Nimrod compiler is GPL licensed, the runtime library is LGPL licensed.
|
The Nimrod compiler is GPL licensed, the runtime library is LGPL licensed
|
||||||
|
with a special exception that allows for static linking.
|
||||||
This means that you can use any license for your own programs developed with
|
This means that you can use any license for your own programs developed with
|
||||||
Nimrod. If I receive enough requests with good arguments, I may change the
|
Nimrod.
|
||||||
license of Nimrod to the BSD license.
|
|
||||||
|
|
||||||
How stable is Nimrod?
|
How stable is Nimrod?
|
||||||
---------------------
|
---------------------
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue