documented hygienic templates; made tests green; fixed system.clamp
This commit is contained in:
parent
a95e958046
commit
f893179889
11 changed files with 123 additions and 48 deletions
|
|
@ -52,7 +52,9 @@ proc symChoice(c: PContext, n: PNode, s: PSym): PNode =
|
||||||
if i > 1: break
|
if i > 1: break
|
||||||
if i <= 1:
|
if i <= 1:
|
||||||
# XXX this makes more sense but breaks bootstrapping for now:
|
# XXX this makes more sense but breaks bootstrapping for now:
|
||||||
# and s.kind notin routineKinds:
|
# (s.kind notin routineKinds or s.magic != mNone):
|
||||||
|
# for some reason 'nextTry' is copied and considered as a candidate in
|
||||||
|
# tables.nim
|
||||||
result = newSymNode(s, n.info)
|
result = newSymNode(s, n.info)
|
||||||
markUsed(n, s)
|
markUsed(n, s)
|
||||||
else:
|
else:
|
||||||
|
|
@ -68,12 +70,19 @@ proc symChoice(c: PContext, n: PNode, s: PSym): PNode =
|
||||||
proc semBindStmt(c: PContext, n: PNode, toBind: var TIntSet): PNode =
|
proc semBindStmt(c: PContext, n: PNode, toBind: var TIntSet): PNode =
|
||||||
for i in 0 .. < n.len:
|
for i in 0 .. < n.len:
|
||||||
var a = n.sons[i]
|
var a = n.sons[i]
|
||||||
# If 'a' is an overloaded symbol, we use the first symbol as a 'witness'
|
# If 'a' is an overloaded symbol, we used to use the first symbol
|
||||||
# and use the fact that subsequent lookups will yield the same symbol!
|
# as a 'witness' and use the fact that subsequent lookups will yield
|
||||||
# This is currently the case due to the hash table's implementation...
|
# the same symbol!
|
||||||
|
# This is however not true anymore for hygienic templates as semantic
|
||||||
|
# processing for them changes the symbol table...
|
||||||
let s = QualifiedLookUp(c, a)
|
let s = QualifiedLookUp(c, a)
|
||||||
if s != nil:
|
if s != nil:
|
||||||
toBind.incl(s.id)
|
# we need to mark all symbols:
|
||||||
|
let sc = symChoice(c, n, s)
|
||||||
|
if sc.kind == nkSym:
|
||||||
|
toBind.incl(sc.sym.id)
|
||||||
|
else:
|
||||||
|
for x in items(sc): toBind.incl(x.sym.id)
|
||||||
else:
|
else:
|
||||||
illFormedAst(a)
|
illFormedAst(a)
|
||||||
result = newNodeI(nkEmpty, n.info)
|
result = newNodeI(nkEmpty, n.info)
|
||||||
|
|
|
||||||
|
|
@ -2967,8 +2967,8 @@ In templates identifiers can be constructed with the backticks notation:
|
||||||
|
|
||||||
template typedef(name: expr, typ: typeDesc) {.immediate.} =
|
template typedef(name: expr, typ: typeDesc) {.immediate.} =
|
||||||
type
|
type
|
||||||
`T name`* = typ
|
`T name`* {.inject.} = typ
|
||||||
`P name`* = ref `T name`
|
`P name`* {.inject.} = ref `T name`
|
||||||
|
|
||||||
typedef(myint, int)
|
typedef(myint, int)
|
||||||
var x: PMyInt
|
var x: PMyInt
|
||||||
|
|
@ -2982,7 +2982,7 @@ Lookup rules for template parameters
|
||||||
|
|
||||||
A parameter ``p`` in a template is even substituted in the expression ``x.p``.
|
A parameter ``p`` in a template is even substituted in the expression ``x.p``.
|
||||||
Thus template arguments can be used as field names and a global symbol can be
|
Thus template arguments can be used as field names and a global symbol can be
|
||||||
covered by the same argument name even when fully qualified:
|
shadowed by the same argument name even when fully qualified:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
# module 'm'
|
# module 'm'
|
||||||
|
|
@ -3017,6 +3017,61 @@ But the global symbol can properly be captured by a ``bind`` statement:
|
||||||
tstLev(levA)
|
tstLev(levA)
|
||||||
# produces: 'levA levB'
|
# produces: 'levA levB'
|
||||||
|
|
||||||
|
|
||||||
|
Hygiene in templates
|
||||||
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Per default templates are `hygienic`:idx:\: Local identifiers declared in a
|
||||||
|
template cannot be accessed in the instantiation context:
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
|
||||||
|
template newException*(exceptn: typeDesc, message: string): expr =
|
||||||
|
var
|
||||||
|
e: ref exceptn # e is implicitely gensym'ed here
|
||||||
|
new(e)
|
||||||
|
e.msg = message
|
||||||
|
e
|
||||||
|
|
||||||
|
# so this works:
|
||||||
|
let e = "message"
|
||||||
|
raise newException(EIO, e)
|
||||||
|
|
||||||
|
|
||||||
|
Whether a symbol that is declared in a template is exposed to the instantiation
|
||||||
|
scope is controlled by the `inject`:idx: and `gensym`:idx: pragmas: gensym'ed
|
||||||
|
symbols are not exposed but inject'ed are.
|
||||||
|
|
||||||
|
The default for symbols of entity ``type``, ``var``, ``let`` and ``const``
|
||||||
|
is ``gensym`` and for ``proc``, ``iterator``, ``converter``, ``template``,
|
||||||
|
``macro`` is ``inject``. However, if the name of the entity is passed as a
|
||||||
|
template parameter, it is an inject'ed symbol:
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
template withFile(f, fn, mode: expr, actions: stmt): stmt {.immediate.} =
|
||||||
|
block:
|
||||||
|
var f: TFile # since 'f' is a template param, it's injected implicitely
|
||||||
|
...
|
||||||
|
|
||||||
|
withFile(txt, "ttempl3.txt", fmWrite):
|
||||||
|
txt.writeln("line 1")
|
||||||
|
txt.writeln("line 2")
|
||||||
|
|
||||||
|
|
||||||
|
The ``inject`` and ``gensym`` pragmas are second class annotations; they have
|
||||||
|
no semantics outside of a template definition and cannot be abstracted over:
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
{.pragma myInject: inject.}
|
||||||
|
|
||||||
|
template t() =
|
||||||
|
var x {.myInject.}: int # does NOT work
|
||||||
|
|
||||||
|
|
||||||
|
To get rid of hygiene in templates, one can use the `dirty`:idx: pragma for
|
||||||
|
a template. ``inject`` and ``gensym`` have no effect in ``dirty`` templates.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Macros
|
Macros
|
||||||
------
|
------
|
||||||
|
|
|
||||||
|
|
@ -487,7 +487,7 @@ objects as `shallow`:idx:\:
|
||||||
.. code-block:: Nimrod
|
.. code-block:: Nimrod
|
||||||
var s = "abc"
|
var s = "abc"
|
||||||
shallow(s) # mark 's' as shallow string
|
shallow(s) # mark 's' as shallow string
|
||||||
var x = s # now might does not copy the string!
|
var x = s # now might not copy the string!
|
||||||
|
|
||||||
Usage of ``shallow`` is always safe once you know the string won't be modified
|
Usage of ``shallow`` is always safe once you know the string won't be modified
|
||||||
anymore, similar to Ruby's `freeze`:idx:.
|
anymore, similar to Ruby's `freeze`:idx:.
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,9 @@
|
||||||
## to do so, the 'next' and 'prev' pointers are not hidden from you and can
|
## to do so, the 'next' and 'prev' pointers are not hidden from you and can
|
||||||
## be manipulated directly for efficiency.
|
## be manipulated directly for efficiency.
|
||||||
|
|
||||||
|
when not defined(nimhygiene):
|
||||||
|
{.pragma: dirty.}
|
||||||
|
|
||||||
type
|
type
|
||||||
TDoublyLinkedNode* {.pure,
|
TDoublyLinkedNode* {.pure,
|
||||||
final.}[T] = object ## a node a doubly linked list consists of
|
final.}[T] = object ## a node a doubly linked list consists of
|
||||||
|
|
@ -62,13 +65,13 @@ proc newSinglyLinkedNode*[T](value: T): PSinglyLinkedNode[T] =
|
||||||
new(result)
|
new(result)
|
||||||
result.value = value
|
result.value = value
|
||||||
|
|
||||||
template itemsListImpl() =
|
template itemsListImpl() {.dirty.} =
|
||||||
var it = L.head
|
var it = L.head
|
||||||
while it != nil:
|
while it != nil:
|
||||||
yield it.value
|
yield it.value
|
||||||
it = it.next
|
it = it.next
|
||||||
|
|
||||||
template itemsRingImpl() =
|
template itemsRingImpl() {.dirty.} =
|
||||||
var it = L.head
|
var it = L.head
|
||||||
if it != nil:
|
if it != nil:
|
||||||
while true:
|
while true:
|
||||||
|
|
@ -76,14 +79,14 @@ template itemsRingImpl() =
|
||||||
it = it.next
|
it = it.next
|
||||||
if it == L.head: break
|
if it == L.head: break
|
||||||
|
|
||||||
template nodesListImpl() =
|
template nodesListImpl() {.dirty.} =
|
||||||
var it = L.head
|
var it = L.head
|
||||||
while it != nil:
|
while it != nil:
|
||||||
var nxt = it.next
|
var nxt = it.next
|
||||||
yield it
|
yield it
|
||||||
it = nxt
|
it = nxt
|
||||||
|
|
||||||
template nodesRingImpl() =
|
template nodesRingImpl() {.dirty.} =
|
||||||
var it = L.head
|
var it = L.head
|
||||||
if it != nil:
|
if it != nil:
|
||||||
while true:
|
while true:
|
||||||
|
|
@ -92,7 +95,7 @@ template nodesRingImpl() =
|
||||||
it = nxt
|
it = nxt
|
||||||
if it == L.head: break
|
if it == L.head: break
|
||||||
|
|
||||||
template findImpl() =
|
template findImpl() {.dirty.} =
|
||||||
for x in nodes(L):
|
for x in nodes(L):
|
||||||
if x.value == value: return x
|
if x.value == value: return x
|
||||||
|
|
||||||
|
|
@ -132,7 +135,7 @@ iterator nodes*[T](L: TDoublyLinkedRing[T]): PDoublyLinkedNode[T] =
|
||||||
## list during traversal is supported.
|
## list during traversal is supported.
|
||||||
nodesRingImpl()
|
nodesRingImpl()
|
||||||
|
|
||||||
template dollarImpl() =
|
template dollarImpl() {.dirty.} =
|
||||||
result = "["
|
result = "["
|
||||||
for x in nodes(L):
|
for x in nodes(L):
|
||||||
if result.len > 1: result.add(", ")
|
if result.len > 1: result.add(", ")
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,9 @@
|
||||||
## **Note**: This interface will change as soon as the compiler supports
|
## **Note**: This interface will change as soon as the compiler supports
|
||||||
## closures and proper coroutines.
|
## closures and proper coroutines.
|
||||||
|
|
||||||
|
when not defined(nimhygiene):
|
||||||
|
{.pragma: dirty.}
|
||||||
|
|
||||||
proc concat*[T](seqs: varargs[seq[T]]): seq[T] =
|
proc concat*[T](seqs: varargs[seq[T]]): seq[T] =
|
||||||
## Takes several sequences' items and returns them inside of one sequence.
|
## Takes several sequences' items and returns them inside of one sequence.
|
||||||
var L = 0
|
var L = 0
|
||||||
|
|
@ -50,7 +53,7 @@ proc filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): seq[T] =
|
||||||
## Returns all items in a sequence that fulfilled the predicate.
|
## Returns all items in a sequence that fulfilled the predicate.
|
||||||
accumulateResult(filter(seq1, pred))
|
accumulateResult(filter(seq1, pred))
|
||||||
|
|
||||||
template filterIt*(seq1, pred: expr): expr {.immediate.} =
|
template filterIt*(seq1, pred: expr): expr {.immediate, dirty.} =
|
||||||
## Finds a specific item in a sequence as long as the
|
## Finds a specific item in a sequence as long as the
|
||||||
## predicate returns true. The predicate needs to be an expression
|
## predicate returns true. The predicate needs to be an expression
|
||||||
## containing ``it``: ``filterIt("abcxyz", it == 'x')``.
|
## containing ``it``: ``filterIt("abcxyz", it == 'x')``.
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@ import
|
||||||
os, hashes, math
|
os, hashes, math
|
||||||
|
|
||||||
{.pragma: myShallow.}
|
{.pragma: myShallow.}
|
||||||
|
when not defined(nimhygiene):
|
||||||
|
{.pragma: dirty.}
|
||||||
|
|
||||||
type
|
type
|
||||||
TSlotEnum = enum seEmpty, seFilled, seDeleted
|
TSlotEnum = enum seEmpty, seFilled, seDeleted
|
||||||
|
|
@ -48,7 +50,7 @@ proc mustRehash(length, counter: int): bool {.inline.} =
|
||||||
proc nextTry(h, maxHash: THash): THash {.inline.} =
|
proc nextTry(h, maxHash: THash): THash {.inline.} =
|
||||||
result = ((5 * h) + 1) and maxHash
|
result = ((5 * h) + 1) and maxHash
|
||||||
|
|
||||||
template rawGetImpl() =
|
template rawGetImpl() {.dirty.} =
|
||||||
var h: THash = hash(key) and high(s.data) # start with real hash value
|
var h: THash = hash(key) and high(s.data) # start with real hash value
|
||||||
while s.data[h].slot != seEmpty:
|
while s.data[h].slot != seEmpty:
|
||||||
if s.data[h].key == key and s.data[h].slot == seFilled:
|
if s.data[h].key == key and s.data[h].slot == seFilled:
|
||||||
|
|
@ -56,7 +58,7 @@ template rawGetImpl() =
|
||||||
h = nextTry(h, high(s.data))
|
h = nextTry(h, high(s.data))
|
||||||
result = -1
|
result = -1
|
||||||
|
|
||||||
template rawInsertImpl() =
|
template rawInsertImpl() {.dirty.} =
|
||||||
var h: THash = hash(key) and high(data)
|
var h: THash = hash(key) and high(data)
|
||||||
while data[h].slot == seFilled:
|
while data[h].slot == seFilled:
|
||||||
h = nextTry(h, high(data))
|
h = nextTry(h, high(data))
|
||||||
|
|
@ -81,14 +83,14 @@ proc Enlarge[A](s: var TSet[A]) =
|
||||||
if s.data[i].slot == seFilled: RawInsert(s, n, s.data[i].key)
|
if s.data[i].slot == seFilled: RawInsert(s, n, s.data[i].key)
|
||||||
swap(s.data, n)
|
swap(s.data, n)
|
||||||
|
|
||||||
template inclImpl() =
|
template inclImpl() {.dirty.} =
|
||||||
var index = RawGet(s, key)
|
var index = RawGet(s, key)
|
||||||
if index < 0:
|
if index < 0:
|
||||||
if mustRehash(len(s.data), s.counter): Enlarge(s)
|
if mustRehash(len(s.data), s.counter): Enlarge(s)
|
||||||
RawInsert(s, s.data, key)
|
RawInsert(s, s.data, key)
|
||||||
inc(s.counter)
|
inc(s.counter)
|
||||||
|
|
||||||
template containsOrInclImpl() =
|
template containsOrInclImpl() {.dirty.} =
|
||||||
var index = RawGet(s, key)
|
var index = RawGet(s, key)
|
||||||
if index >= 0:
|
if index >= 0:
|
||||||
result = true
|
result = true
|
||||||
|
|
@ -125,7 +127,7 @@ proc toSet*[A](keys: openarray[A]): TSet[A] =
|
||||||
result = initSet[A](nextPowerOfTwo(keys.len+10))
|
result = initSet[A](nextPowerOfTwo(keys.len+10))
|
||||||
for key in items(keys): result.incl(key)
|
for key in items(keys): result.incl(key)
|
||||||
|
|
||||||
template dollarImpl(): stmt =
|
template dollarImpl(): stmt {.dirty.} =
|
||||||
result = "{"
|
result = "{"
|
||||||
for key in items(s):
|
for key in items(s):
|
||||||
if result.len > 1: result.add(", ")
|
if result.len > 1: result.add(", ")
|
||||||
|
|
@ -155,7 +157,7 @@ proc card*[A](s: TOrderedSet[A]): int {.inline.} =
|
||||||
## alias for `len`.
|
## alias for `len`.
|
||||||
result = s.counter
|
result = s.counter
|
||||||
|
|
||||||
template forAllOrderedPairs(yieldStmt: stmt) =
|
template forAllOrderedPairs(yieldStmt: stmt) {.dirty.} =
|
||||||
var h = s.first
|
var h = s.first
|
||||||
while h >= 0:
|
while h >= 0:
|
||||||
var nxt = s.data[h].next
|
var nxt = s.data[h].next
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,9 @@ type
|
||||||
data: TKeyValuePairSeq[A, B]
|
data: TKeyValuePairSeq[A, B]
|
||||||
counter: int
|
counter: int
|
||||||
|
|
||||||
|
when not defined(nimhygiene):
|
||||||
|
{.pragma: dirty.}
|
||||||
|
|
||||||
proc len*[A, B](t: TTable[A, B]): int =
|
proc len*[A, B](t: TTable[A, B]): int =
|
||||||
## returns the number of keys in `t`.
|
## returns the number of keys in `t`.
|
||||||
result = t.counter
|
result = t.counter
|
||||||
|
|
@ -66,7 +69,7 @@ proc mustRehash(length, counter: int): bool {.inline.} =
|
||||||
proc nextTry(h, maxHash: THash): THash {.inline.} =
|
proc nextTry(h, maxHash: THash): THash {.inline.} =
|
||||||
result = ((5 * h) + 1) and maxHash
|
result = ((5 * h) + 1) and maxHash
|
||||||
|
|
||||||
template rawGetImpl() =
|
template rawGetImpl() {.dirty.} =
|
||||||
var h: THash = hash(key) and high(t.data) # start with real hash value
|
var h: THash = hash(key) and high(t.data) # start with real hash value
|
||||||
while t.data[h].slot != seEmpty:
|
while t.data[h].slot != seEmpty:
|
||||||
if t.data[h].key == key and t.data[h].slot == seFilled:
|
if t.data[h].key == key and t.data[h].slot == seFilled:
|
||||||
|
|
@ -74,7 +77,7 @@ template rawGetImpl() =
|
||||||
h = nextTry(h, high(t.data))
|
h = nextTry(h, high(t.data))
|
||||||
result = -1
|
result = -1
|
||||||
|
|
||||||
template rawInsertImpl() =
|
template rawInsertImpl() {.dirty.} =
|
||||||
var h: THash = hash(key) and high(data)
|
var h: THash = hash(key) and high(data)
|
||||||
while data[h].slot == seFilled:
|
while data[h].slot == seFilled:
|
||||||
h = nextTry(h, high(data))
|
h = nextTry(h, high(data))
|
||||||
|
|
@ -115,12 +118,12 @@ proc Enlarge[A, B](t: var TTable[A, B]) =
|
||||||
if t.data[i].slot == seFilled: RawInsert(t, n, t.data[i].key, t.data[i].val)
|
if t.data[i].slot == seFilled: RawInsert(t, n, t.data[i].key, t.data[i].val)
|
||||||
swap(t.data, n)
|
swap(t.data, n)
|
||||||
|
|
||||||
template AddImpl() =
|
template AddImpl() {.dirty.} =
|
||||||
if mustRehash(len(t.data), t.counter): Enlarge(t)
|
if mustRehash(len(t.data), t.counter): Enlarge(t)
|
||||||
RawInsert(t, t.data, key, val)
|
RawInsert(t, t.data, key, val)
|
||||||
inc(t.counter)
|
inc(t.counter)
|
||||||
|
|
||||||
template PutImpl() =
|
template PutImpl() {.dirty.} =
|
||||||
var index = RawGet(t, key)
|
var index = RawGet(t, key)
|
||||||
if index >= 0:
|
if index >= 0:
|
||||||
t.data[index].val = val
|
t.data[index].val = val
|
||||||
|
|
@ -129,7 +132,7 @@ template PutImpl() =
|
||||||
|
|
||||||
when false:
|
when false:
|
||||||
# not yet used:
|
# not yet used:
|
||||||
template HasKeyOrPutImpl() =
|
template HasKeyOrPutImpl() {.dirty.} =
|
||||||
var index = RawGet(t, key)
|
var index = RawGet(t, key)
|
||||||
if index >= 0:
|
if index >= 0:
|
||||||
t.data[index].val = val
|
t.data[index].val = val
|
||||||
|
|
@ -168,7 +171,7 @@ proc toTable*[A, B](pairs: openarray[tuple[key: A,
|
||||||
result = initTable[A, B](nextPowerOfTwo(pairs.len+10))
|
result = initTable[A, B](nextPowerOfTwo(pairs.len+10))
|
||||||
for key, val in items(pairs): result[key] = val
|
for key, val in items(pairs): result[key] = val
|
||||||
|
|
||||||
template dollarImpl(): stmt =
|
template dollarImpl(): stmt {.dirty.} =
|
||||||
if t.len == 0:
|
if t.len == 0:
|
||||||
result = "{:}"
|
result = "{:}"
|
||||||
else:
|
else:
|
||||||
|
|
@ -199,7 +202,7 @@ proc len*[A, B](t: TOrderedTable[A, B]): int {.inline.} =
|
||||||
## returns the number of keys in `t`.
|
## returns the number of keys in `t`.
|
||||||
result = t.counter
|
result = t.counter
|
||||||
|
|
||||||
template forAllOrderedPairs(yieldStmt: stmt) =
|
template forAllOrderedPairs(yieldStmt: stmt) {.dirty.} =
|
||||||
var h = t.first
|
var h = t.first
|
||||||
while h >= 0:
|
while h >= 0:
|
||||||
var nxt = t.data[h].next
|
var nxt = t.data[h].next
|
||||||
|
|
|
||||||
|
|
@ -31,19 +31,19 @@ var
|
||||||
|
|
||||||
checkpoints: seq[string] = @[]
|
checkpoints: seq[string] = @[]
|
||||||
|
|
||||||
template TestSetupIMPL*: stmt = nil
|
template TestSetupIMPL*: stmt {.dirty.} = nil
|
||||||
template TestTeardownIMPL*: stmt = nil
|
template TestTeardownIMPL*: stmt {.dirty.} = nil
|
||||||
|
|
||||||
proc shouldRun(testName: string): bool =
|
proc shouldRun(testName: string): bool =
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
template suite*(name: expr, body: stmt): stmt =
|
template suite*(name: expr, body: stmt): stmt {.dirty.} =
|
||||||
block:
|
block:
|
||||||
template setup*(setupBody: stmt): stmt =
|
template setup*(setupBody: stmt): stmt {.dirty.} =
|
||||||
template TestSetupIMPL: stmt = setupBody
|
template TestSetupIMPL: stmt {.dirty.} = setupBody
|
||||||
|
|
||||||
template teardown*(teardownBody: stmt): stmt =
|
template teardown*(teardownBody: stmt): stmt {.dirty.} =
|
||||||
template TestTeardownIMPL: stmt = teardownBody
|
template TestTeardownIMPL: stmt {.dirty.} = teardownBody
|
||||||
|
|
||||||
body
|
body
|
||||||
|
|
||||||
|
|
@ -59,12 +59,12 @@ proc testDone(name: string, s: TTestStatus) =
|
||||||
else:
|
else:
|
||||||
echo "[", $s, "] ", name, "\n"
|
echo "[", $s, "] ", name, "\n"
|
||||||
|
|
||||||
template test*(name: expr, body: stmt): stmt =
|
template test*(name: expr, body: stmt): stmt {.dirty.} =
|
||||||
bind shouldRun, checkpoints, testDone
|
bind shouldRun, checkpoints, testDone
|
||||||
|
|
||||||
if shouldRun(name):
|
if shouldRun(name):
|
||||||
checkpoints = @[]
|
checkpoints = @[]
|
||||||
var TestStatusIMPL = OK
|
var TestStatusIMPL {.inject.} = OK
|
||||||
|
|
||||||
try:
|
try:
|
||||||
TestSetupIMPL()
|
TestSetupIMPL()
|
||||||
|
|
@ -146,13 +146,14 @@ macro check*(conditions: stmt): stmt =
|
||||||
var ast = conditions.treeRepr
|
var ast = conditions.treeRepr
|
||||||
error conditions.lineinfo & ": Malformed check statement:\n" & ast
|
error conditions.lineinfo & ": Malformed check statement:\n" & ast
|
||||||
|
|
||||||
template require*(conditions: stmt): stmt =
|
template require*(conditions: stmt): stmt {.dirty.} =
|
||||||
block:
|
block:
|
||||||
const AbortOnError = true
|
const AbortOnError {.inject.} = true
|
||||||
check conditions
|
check conditions
|
||||||
|
|
||||||
macro expect*(exp: stmt): stmt =
|
macro expect*(exp: stmt): stmt =
|
||||||
template expectBody(errorTypes, lineInfoLit: expr, body: stmt): PNimrodNode =
|
template expectBody(errorTypes, lineInfoLit: expr,
|
||||||
|
body: stmt): PNimrodNode {.dirty.} =
|
||||||
try:
|
try:
|
||||||
body
|
body
|
||||||
checkpoint(lineInfoLit & ": Expect Failed, no exception was thrown.")
|
checkpoint(lineInfoLit & ": Expect Failed, no exception was thrown.")
|
||||||
|
|
|
||||||
|
|
@ -1259,8 +1259,8 @@ proc max*[T](x: varargs[T]): T =
|
||||||
|
|
||||||
proc clamp*[T](x, a, b: T): T =
|
proc clamp*[T](x, a, b: T): T =
|
||||||
## limits the value ``x`` within the interval [a, b]
|
## limits the value ``x`` within the interval [a, b]
|
||||||
if x > a: return a
|
if x < a: return a
|
||||||
if x < b: return b
|
if x > b: return b
|
||||||
return x
|
return x
|
||||||
|
|
||||||
iterator items*[T](a: openarray[T]): T {.inline.} =
|
iterator items*[T](a: openarray[T]): T {.inline.} =
|
||||||
|
|
@ -1657,9 +1657,9 @@ proc echo*[T](x: varargs[T, `$`]) {.magic: "Echo", noSideEffect.}
|
||||||
## side effects, so that it can be used for debugging routines marked as
|
## side effects, so that it can be used for debugging routines marked as
|
||||||
## ``noSideEffect``.
|
## ``noSideEffect``.
|
||||||
|
|
||||||
template newException*(exceptn: typeDesc, message: string): expr =
|
template newException*(exceptn: typeDesc, message: string): expr =
|
||||||
## creates an exception object of type ``exceptn`` and sets its ``msg`` field
|
## creates an exception object of type ``exceptn`` and sets its ``msg`` field
|
||||||
## to `message`. Returns the new exception object.
|
## to `message`. Returns the new exception object.
|
||||||
# block: # open a new scope
|
# block: # open a new scope
|
||||||
var
|
var
|
||||||
e: ref exceptn
|
e: ref exceptn
|
||||||
|
|
|
||||||
|
|
@ -866,7 +866,7 @@ template `=~`*(s: string, pattern: TPeg): expr =
|
||||||
## echo("syntax error")
|
## echo("syntax error")
|
||||||
##
|
##
|
||||||
when not definedInScope(matches):
|
when not definedInScope(matches):
|
||||||
var matches: array[0..maxSubpatterns-1, string]
|
var matches {.inject.}: array[0..maxSubpatterns-1, string]
|
||||||
match(s, pattern, matches)
|
match(s, pattern, matches)
|
||||||
|
|
||||||
# ------------------------- more string handling ------------------------------
|
# ------------------------- more string handling ------------------------------
|
||||||
|
|
|
||||||
3
todo.txt
3
todo.txt
|
|
@ -1,9 +1,8 @@
|
||||||
version 0.9.0
|
version 0.9.0
|
||||||
=============
|
=============
|
||||||
|
|
||||||
- make templates hygienic by default: 'gensym', 'inject' pragmas;
|
|
||||||
document 'gensym', 'inject' and 'dirty'
|
|
||||||
- make 'bind' default for templates and introduce 'mixin'
|
- make 'bind' default for templates and introduce 'mixin'
|
||||||
|
- implement 'bind' for macros
|
||||||
- use ``\`` for comment continuations
|
- use ``\`` for comment continuations
|
||||||
- ``final`` should be the default for objects
|
- ``final`` should be the default for objects
|
||||||
- implement "closure tuple consists of a single 'ref'" optimization
|
- implement "closure tuple consists of a single 'ref'" optimization
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue