Allow void macro result (#11286)
* allow void macro result * add test for void macro result type
This commit is contained in:
parent
68b5e3e3fe
commit
f94ec363ab
25 changed files with 143 additions and 60 deletions
|
|
@ -36,8 +36,12 @@
|
||||||
|
|
||||||
- Compile time checks for integer and float conversions are now stricter. For example, `const x = uint32(-1)` now gives a compile time error instead of being equivalent to `const x = 0xFFFFFFFF'u32`.
|
- Compile time checks for integer and float conversions are now stricter. For example, `const x = uint32(-1)` now gives a compile time error instead of being equivalent to `const x = 0xFFFFFFFF'u32`.
|
||||||
|
|
||||||
- A bug allowed ``macro foo(): int = 123`` to compile even though a
|
- Using `typed` as the result type in templates/macros now means
|
||||||
macros has to return a ``NimNode``. This has been fixed.
|
"expression with a type". The old meaning of `typed` is preserved
|
||||||
|
as `void` or no result type at all.
|
||||||
|
|
||||||
|
- A bug allowed `macro foo(): int = 123` to compile even though a
|
||||||
|
macros has to return a `NimNode`. This has been fixed.
|
||||||
|
|
||||||
#### Breaking changes in the standard library
|
#### Breaking changes in the standard library
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -759,7 +759,7 @@ proc getLinkCmd(conf: ConfigRef; output: AbsoluteFile,
|
||||||
template getLinkCmd(conf: ConfigRef; output: AbsoluteFile, objfiles: string): string =
|
template getLinkCmd(conf: ConfigRef; output: AbsoluteFile, objfiles: string): string =
|
||||||
getLinkCmd(conf, output, objfiles, optGenDynLib in conf.globalOptions)
|
getLinkCmd(conf, output, objfiles, optGenDynLib in conf.globalOptions)
|
||||||
|
|
||||||
template tryExceptOSErrorMessage(conf: ConfigRef; errorPrefix: string = "", body: untyped): typed =
|
template tryExceptOSErrorMessage(conf: ConfigRef; errorPrefix: string = "", body: untyped) =
|
||||||
try:
|
try:
|
||||||
body
|
body
|
||||||
except OSError:
|
except OSError:
|
||||||
|
|
|
||||||
|
|
@ -407,12 +407,11 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
|
||||||
else:
|
else:
|
||||||
case s.typ.sons[0].kind
|
case s.typ.sons[0].kind
|
||||||
of tyUntyped:
|
of tyUntyped:
|
||||||
# BUGFIX: we cannot expect a type here, because module aliases would not
|
# Not expecting a type here allows templates like in ``tmodulealias.in``.
|
||||||
# work then (see the ``tmodulealias`` test)
|
|
||||||
# semExprWithType(c, result)
|
|
||||||
result = semExpr(c, result, flags)
|
result = semExpr(c, result, flags)
|
||||||
of tyTyped:
|
of tyTyped:
|
||||||
result = semStmt(c, result, flags)
|
# More restrictive version.
|
||||||
|
result = semExprWithType(c, result, flags)
|
||||||
of tyTypeDesc:
|
of tyTypeDesc:
|
||||||
if result.kind == nkStmtList: result.kind = nkStmtListType
|
if result.kind == nkStmtList: result.kind = nkStmtListType
|
||||||
var typ = semTypeNode(c, result, nil)
|
var typ = semTypeNode(c, result, nil)
|
||||||
|
|
|
||||||
|
|
@ -1985,7 +1985,7 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
|
||||||
|
|
||||||
if ids.len > 0:
|
if ids.len > 0:
|
||||||
dummyTemplate.sons[paramsPos] = newNodeI(nkFormalParams, n.info)
|
dummyTemplate.sons[paramsPos] = newNodeI(nkFormalParams, n.info)
|
||||||
dummyTemplate[paramsPos].add getSysSym(c.graph, n.info, "typed").newSymNode # return type
|
dummyTemplate[paramsPos].add getSysSym(c.graph, n.info, "untyped").newSymNode # return type
|
||||||
ids.add getSysSym(c.graph, n.info, "untyped").newSymNode # params type
|
ids.add getSysSym(c.graph, n.info, "untyped").newSymNode # params type
|
||||||
ids.add c.graph.emptyNode # no default value
|
ids.add c.graph.emptyNode # no default value
|
||||||
dummyTemplate[paramsPos].add newNode(nkIdentDefs, n.info, ids)
|
dummyTemplate[paramsPos].add newNode(nkIdentDefs, n.info, ids)
|
||||||
|
|
|
||||||
|
|
@ -1356,7 +1356,7 @@ proc semBorrow(c: PContext, n: PNode, s: PSym) =
|
||||||
localError(c.config, n.info, errNoSymbolToBorrowFromFound)
|
localError(c.config, n.info, errNoSymbolToBorrowFromFound)
|
||||||
|
|
||||||
proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind) =
|
proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind) =
|
||||||
if t != nil:
|
if owner == skMacro or t != nil:
|
||||||
var s = newSym(skResult, getIdent(c.cache, "result"), getCurrOwner(c), info)
|
var s = newSym(skResult, getIdent(c.cache, "result"), getCurrOwner(c), info)
|
||||||
s.typ = t
|
s.typ = t
|
||||||
incl(s.flags, sfUsed)
|
incl(s.flags, sfUsed)
|
||||||
|
|
@ -1550,17 +1550,17 @@ proc activate(c: PContext, n: PNode) =
|
||||||
discard
|
discard
|
||||||
|
|
||||||
proc maybeAddResult(c: PContext, s: PSym, n: PNode) =
|
proc maybeAddResult(c: PContext, s: PSym, n: PNode) =
|
||||||
if s.typ.sons[0] != nil and not isInlineIterator(s):
|
if s.kind == skMacro:
|
||||||
let resultType =
|
let resultType =
|
||||||
if s.kind == skMacro:
|
if s.typ.sons[0] != nil and s.typ.sons[0].kind == tyTypeDesc:
|
||||||
if s.typ.sons[0].kind == tyTypeDesc:
|
|
||||||
s.typ.sons[0]
|
|
||||||
else:
|
|
||||||
sysTypeFromName(c.graph, n.info, "NimNode")
|
|
||||||
else:
|
|
||||||
s.typ.sons[0]
|
s.typ.sons[0]
|
||||||
|
else:
|
||||||
|
sysTypeFromName(c.graph, n.info, "NimNode")
|
||||||
addResult(c, resultType, n.info, s.kind)
|
addResult(c, resultType, n.info, s.kind)
|
||||||
addResultNode(c, n)
|
addResultNode(c, n)
|
||||||
|
elif s.typ.sons[0] != nil and not isInlineIterator(s):
|
||||||
|
addResult(c, s.typ.sons[0], n.info, s.kind)
|
||||||
|
addResultNode(c, n)
|
||||||
|
|
||||||
proc canonType(c: PContext, t: PType): PType =
|
proc canonType(c: PContext, t: PType): PType =
|
||||||
if t.kind == tySequence:
|
if t.kind == tySequence:
|
||||||
|
|
@ -1888,7 +1888,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
# context as it may even be evaluated in 'system.compiles':
|
# context as it may even be evaluated in 'system.compiles':
|
||||||
trackProc(c, s, s.ast[bodyPos])
|
trackProc(c, s, s.ast[bodyPos])
|
||||||
else:
|
else:
|
||||||
if s.typ.sons[0] != nil and kind != skIterator:
|
if (s.typ.sons[0] != nil and kind != skIterator) or kind == skMacro:
|
||||||
addDecl(c, newSym(skUnknown, getIdent(c.cache, "result"), nil, n.info))
|
addDecl(c, newSym(skUnknown, getIdent(c.cache, "result"), nil, n.info))
|
||||||
|
|
||||||
openScope(c)
|
openScope(c)
|
||||||
|
|
@ -2015,7 +2015,6 @@ proc semMacroDef(c: PContext, n: PNode): PNode =
|
||||||
let param = t.n.sons[i].sym
|
let param = t.n.sons[i].sym
|
||||||
if param.typ.kind != tyUntyped: allUntyped = false
|
if param.typ.kind != tyUntyped: allUntyped = false
|
||||||
if allUntyped: incl(s.flags, sfAllUntyped)
|
if allUntyped: incl(s.flags, sfAllUntyped)
|
||||||
if t.sons[0] == nil: localError(c.config, n.info, "macro needs a return type")
|
|
||||||
if n.sons[bodyPos].kind == nkEmpty:
|
if n.sons[bodyPos].kind == nkEmpty:
|
||||||
localError(c.config, n.info, errImplOfXexpected % s.name.s)
|
localError(c.config, n.info, errImplOfXexpected % s.name.s)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -606,11 +606,6 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
|
||||||
if n.sons[genericParamsPos].kind == nkEmpty:
|
if n.sons[genericParamsPos].kind == nkEmpty:
|
||||||
# we have a list of implicit type parameters:
|
# we have a list of implicit type parameters:
|
||||||
n.sons[genericParamsPos] = gp
|
n.sons[genericParamsPos] = gp
|
||||||
# no explicit return type? -> use tyTyped
|
|
||||||
if n.sons[paramsPos].sons[0].kind == nkEmpty:
|
|
||||||
# use ``stmt`` as implicit result type
|
|
||||||
s.typ.sons[0] = newTypeS(tyTyped, c)
|
|
||||||
s.typ.n.sons[0] = newNodeIT(nkType, n.info, s.typ.sons[0])
|
|
||||||
else:
|
else:
|
||||||
s.typ = newTypeS(tyProc, c)
|
s.typ = newTypeS(tyProc, c)
|
||||||
# XXX why do we need tyTyped as a return type again?
|
# XXX why do we need tyTyped as a return type again?
|
||||||
|
|
|
||||||
|
|
@ -855,6 +855,7 @@ proc findEnforcedStaticType(t: PType): PType =
|
||||||
# This handles types such as `static[T] and Foo`,
|
# This handles types such as `static[T] and Foo`,
|
||||||
# which are subset of `static[T]`, hence they could
|
# which are subset of `static[T]`, hence they could
|
||||||
# be treated in the same way
|
# be treated in the same way
|
||||||
|
if t == nil: return nil
|
||||||
if t.kind == tyStatic: return t
|
if t.kind == tyStatic: return t
|
||||||
if t.kind == tyAnd:
|
if t.kind == tyAnd:
|
||||||
for s in t.sons:
|
for s in t.sons:
|
||||||
|
|
@ -868,7 +869,7 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
|
||||||
var a = copySym(param)
|
var a = copySym(param)
|
||||||
a.typ = staticType.base
|
a.typ = staticType.base
|
||||||
addDecl(c, a)
|
addDecl(c, a)
|
||||||
elif param.typ.kind == tyTypeDesc:
|
elif param.typ != nil and param.typ.kind == tyTypeDesc:
|
||||||
addDecl(c, param)
|
addDecl(c, param)
|
||||||
else:
|
else:
|
||||||
# within a macro, every param has the type NimNode!
|
# within a macro, every param has the type NimNode!
|
||||||
|
|
@ -1194,6 +1195,18 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||||
if n.sons[0].kind != nkEmpty:
|
if n.sons[0].kind != nkEmpty:
|
||||||
r = semTypeNode(c, n.sons[0], nil)
|
r = semTypeNode(c, n.sons[0], nil)
|
||||||
|
|
||||||
|
if r != nil and kind in {skMacro, skTemplate} and r.kind == tyTyped:
|
||||||
|
# XXX: To implement the propesed change in the warning, just
|
||||||
|
# delete this entire if block. The rest is (at least at time of
|
||||||
|
# writing this comment) already implemented.
|
||||||
|
let info = n.sons[0].info
|
||||||
|
const msg = "`typed` will change its meaning in future versions of Nim. " &
|
||||||
|
"`void` or no return type declaration at all has the same " &
|
||||||
|
"meaning as the current meaning of `typed` as return type " &
|
||||||
|
"declaration."
|
||||||
|
message(c.config, info, warnDeprecated, msg)
|
||||||
|
r = nil
|
||||||
|
|
||||||
if r != nil:
|
if r != nil:
|
||||||
# turn explicit 'void' return type into 'nil' because the rest of the
|
# turn explicit 'void' return type into 'nil' because the rest of the
|
||||||
# compiler only checks for 'nil':
|
# compiler only checks for 'nil':
|
||||||
|
|
|
||||||
|
|
@ -1104,7 +1104,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
#echo "new pc ", newPc, " calling: ", prc.name.s
|
#echo "new pc ", newPc, " calling: ", prc.name.s
|
||||||
var newFrame = PStackFrame(prc: prc, comesFrom: pc, next: tos)
|
var newFrame = PStackFrame(prc: prc, comesFrom: pc, next: tos)
|
||||||
newSeq(newFrame.slots, prc.offset+ord(isClosure))
|
newSeq(newFrame.slots, prc.offset+ord(isClosure))
|
||||||
if not isEmptyType(prc.typ.sons[0]) or prc.kind == skMacro:
|
if not isEmptyType(prc.typ.sons[0]):
|
||||||
putIntoReg(newFrame.slots[0], getNullValue(prc.typ.sons[0], prc.info, c.config))
|
putIntoReg(newFrame.slots[0], getNullValue(prc.typ.sons[0], prc.info, c.config))
|
||||||
for i in 1 .. rc-1:
|
for i in 1 .. rc-1:
|
||||||
newFrame.slots[i] = regs[rb+i]
|
newFrame.slots[i] = regs[rb+i]
|
||||||
|
|
|
||||||
|
|
@ -567,7 +567,7 @@ proc quote*(bl: typed, op = "``"): NimNode {.magic: "QuoteAst", noSideEffect.}
|
||||||
##
|
##
|
||||||
## .. code-block:: nim
|
## .. code-block:: nim
|
||||||
##
|
##
|
||||||
## macro check(ex: untyped): typed =
|
## macro check(ex: untyped) =
|
||||||
## # this is a simplified version of the check macro from the
|
## # this is a simplified version of the check macro from the
|
||||||
## # unittest module.
|
## # unittest module.
|
||||||
##
|
##
|
||||||
|
|
|
||||||
|
|
@ -572,7 +572,7 @@ when not useUnicode:
|
||||||
proc isTitle(a: char): bool {.inline.} = return false
|
proc isTitle(a: char): bool {.inline.} = return false
|
||||||
proc isWhiteSpace(a: char): bool {.inline.} = return a in {' ', '\9'..'\13'}
|
proc isWhiteSpace(a: char): bool {.inline.} = return a in {' ', '\9'..'\13'}
|
||||||
|
|
||||||
template matchOrParse(mopProc: untyped): typed =
|
template matchOrParse(mopProc: untyped) =
|
||||||
# Used to make the main matcher proc *rawMatch* as well as event parser
|
# Used to make the main matcher proc *rawMatch* as well as event parser
|
||||||
# procs. For the former, *enter* and *leave* event handler code generators
|
# procs. For the former, *enter* and *leave* event handler code generators
|
||||||
# are provided which just return *discard*.
|
# are provided which just return *discard*.
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ template onFailedAssert*(msg, code: untyped): untyped {.dirty.} =
|
||||||
let msg = msgIMPL
|
let msg = msgIMPL
|
||||||
code
|
code
|
||||||
|
|
||||||
template doAssertRaises*(exception: typedesc, code: untyped): typed =
|
template doAssertRaises*(exception: typedesc, code: untyped) =
|
||||||
## Raises ``AssertionError`` if specified ``code`` does not raise the
|
## Raises ``AssertionError`` if specified ``code`` does not raise the
|
||||||
## specified exception. Example:
|
## specified exception. Example:
|
||||||
##
|
##
|
||||||
|
|
|
||||||
|
|
@ -8,5 +8,5 @@ $nimsuggest --tester $file
|
||||||
>sug $1
|
>sug $1
|
||||||
sug;;skMacro;;tsug_template.tmpb;;macro (){.noSideEffect, gcsafe, locks: 0.};;$file;;2;;6;;"";;0;;Prefix
|
sug;;skMacro;;tsug_template.tmpb;;macro (){.noSideEffect, gcsafe, locks: 0.};;$file;;2;;6;;"";;0;;Prefix
|
||||||
sug;;skConverter;;tsug_template.tmpc;;converter ();;$file;;3;;10;;"";;0;;Prefix
|
sug;;skConverter;;tsug_template.tmpc;;converter ();;$file;;3;;10;;"";;0;;Prefix
|
||||||
sug;;skTemplate;;tsug_template.tmpa;;template (): typed;;$file;;1;;9;;"";;0;;Prefix
|
sug;;skTemplate;;tsug_template.tmpa;;template ();;$file;;1;;9;;"";;0;;Prefix
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
# bug #1679
|
# bug #1679
|
||||||
import macros, tables, hashes
|
import macros, tables, hashes
|
||||||
proc hash(v: NimNode): Hash = 4 # performance is for suckers
|
proc hash(v: NimNode): Hash = 4 # performance is for suckers
|
||||||
macro test(body: untyped): typed =
|
macro test(body: untyped) =
|
||||||
var a = initCountTable[NimNode]()
|
var a = initCountTable[NimNode]()
|
||||||
a.inc(body)
|
a.inc(body)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ block ttemplate:
|
||||||
for name, value in (n: "v").fieldPairs:
|
for name, value in (n: "v").fieldPairs:
|
||||||
echo name
|
echo name
|
||||||
|
|
||||||
template wrapper: typed =
|
template wrapper(): void =
|
||||||
for name, value in (n: "v").fieldPairs:
|
for name, value in (n: "v").fieldPairs:
|
||||||
echo name
|
echo name
|
||||||
wrapper()
|
wrapper()
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ import unittest, macros
|
||||||
|
|
||||||
# bug #4555
|
# bug #4555
|
||||||
|
|
||||||
macro memo(n: untyped): typed =
|
macro memo(n: untyped) =
|
||||||
result = n
|
result = n
|
||||||
|
|
||||||
proc fastFib(n: int): int {.memo.} = 40
|
proc fastFib(n: int): int {.memo.} = 40
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ proc foo(): seq[NimNode] {.compiletime.} =
|
||||||
result.add test()
|
result.add test()
|
||||||
result.add parseExpr("echo(5+56)")
|
result.add parseExpr("echo(5+56)")
|
||||||
|
|
||||||
macro bar(): typed =
|
macro bar() =
|
||||||
result = newNimNode(nnkStmtList)
|
result = newNimNode(nnkStmtList)
|
||||||
let x = foo()
|
let x = foo()
|
||||||
for xx in x:
|
for xx in x:
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ proc symToIdent(x: NimNode): NimNode =
|
||||||
result.add symToIdent(c)
|
result.add symToIdent(c)
|
||||||
|
|
||||||
# check getTypeInst and getTypeImpl for given symbol x
|
# check getTypeInst and getTypeImpl for given symbol x
|
||||||
macro testX(x,inst0: typed; recurse: static[bool]; implX: typed): typed =
|
macro testX(x,inst0: typed; recurse: static[bool]; implX: typed) =
|
||||||
# check that getTypeInst(x) equals inst0
|
# check that getTypeInst(x) equals inst0
|
||||||
let inst = x.getTypeInst
|
let inst = x.getTypeInst
|
||||||
let instr = inst.symToIdent.treeRepr
|
let instr = inst.symToIdent.treeRepr
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ macro importImpl_forward(name, returns: untyped): untyped =
|
||||||
decls.add res
|
decls.add res
|
||||||
echo(repr(res))
|
echo(repr(res))
|
||||||
|
|
||||||
macro importImpl(name, returns, body: untyped): typed =
|
macro importImpl(name, returns, body: untyped) =
|
||||||
#var res = getAST(importImpl_forward(name, returns))
|
#var res = getAST(importImpl_forward(name, returns))
|
||||||
discard getAST(importImpl_forward(name, returns))
|
discard getAST(importImpl_forward(name, returns))
|
||||||
var res = copyNimTree(decls[decls.high])
|
var res = copyNimTree(decls[decls.high])
|
||||||
|
|
@ -46,7 +46,7 @@ macro importImpl(name, returns, body: untyped): typed =
|
||||||
echo repr(res)
|
echo repr(res)
|
||||||
impls.add res
|
impls.add res
|
||||||
|
|
||||||
macro okayy: typed =
|
macro okayy() =
|
||||||
result = newNimNode(nnkStmtList)
|
result = newNimNode(nnkStmtList)
|
||||||
for node in decls: result.add node
|
for node in decls: result.add node
|
||||||
for node in impls: result.add node
|
for node in impls: result.add node
|
||||||
|
|
|
||||||
75
tests/macros/tmacro6.nim
Normal file
75
tests/macros/tmacro6.nim
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
discard """
|
||||||
|
errormsg: "expression '123' is of type 'int literal(123)' and has to be discarded"
|
||||||
|
line: 71
|
||||||
|
"""
|
||||||
|
|
||||||
|
import macros
|
||||||
|
|
||||||
|
proc foo(a,b,c: int): int =
|
||||||
|
result += a
|
||||||
|
result += b
|
||||||
|
result += c
|
||||||
|
|
||||||
|
macro bar(a,b,c: int): int =
|
||||||
|
result = newCall(ident"echo")
|
||||||
|
result.add a
|
||||||
|
result.add b
|
||||||
|
result.add c
|
||||||
|
|
||||||
|
macro baz(a,b,c: int): int =
|
||||||
|
let stmt = nnkStmtListExpr.newTree()
|
||||||
|
stmt.add newCall(ident"echo", a)
|
||||||
|
stmt.add newCall(ident"echo", b)
|
||||||
|
stmt.add newCall(ident"echo", c)
|
||||||
|
stmt.add newLit(123)
|
||||||
|
return c
|
||||||
|
|
||||||
|
# test no result type with explicit return
|
||||||
|
|
||||||
|
macro baz2(a,b,c: int) =
|
||||||
|
let stmt = nnkStmtListExpr.newTree()
|
||||||
|
stmt.add newCall(ident"echo", a)
|
||||||
|
stmt.add newCall(ident"echo", b)
|
||||||
|
stmt.add newCall(ident"echo", c)
|
||||||
|
return stmt
|
||||||
|
|
||||||
|
# test explicit void type with explicit return
|
||||||
|
|
||||||
|
macro baz3(a,b,c: int): void =
|
||||||
|
let stmt = nnkStmtListExpr.newTree()
|
||||||
|
stmt.add newCall(ident"echo", a)
|
||||||
|
stmt.add newCall(ident"echo", b)
|
||||||
|
stmt.add newCall(ident"echo", c)
|
||||||
|
return stmt
|
||||||
|
|
||||||
|
# test no result type with result variable
|
||||||
|
|
||||||
|
macro baz4(a,b,c: int) =
|
||||||
|
result = nnkStmtListExpr.newTree()
|
||||||
|
result.add newCall(ident"echo", a)
|
||||||
|
result.add newCall(ident"echo", b)
|
||||||
|
result.add newCall(ident"echo", c)
|
||||||
|
|
||||||
|
# test explicit void type with result variable
|
||||||
|
|
||||||
|
macro baz5(a,b,c: int): void =
|
||||||
|
let result = nnkStmtListExpr.newTree()
|
||||||
|
result.add newCall(ident"echo", a)
|
||||||
|
result.add newCall(ident"echo", b)
|
||||||
|
result.add newCall(ident"echo", c)
|
||||||
|
|
||||||
|
macro foobar1(): int =
|
||||||
|
result = quote do:
|
||||||
|
echo "Hello World"
|
||||||
|
1337
|
||||||
|
|
||||||
|
echo foobar1()
|
||||||
|
|
||||||
|
# this should create an error message, because 123 has to be discarded.
|
||||||
|
|
||||||
|
macro foobar2() =
|
||||||
|
result = quote do:
|
||||||
|
echo "Hello World"
|
||||||
|
123
|
||||||
|
|
||||||
|
echo foobar2()
|
||||||
|
|
@ -18,15 +18,16 @@ case_token: inc i
|
||||||
|
|
||||||
#bug #488
|
#bug #488
|
||||||
|
|
||||||
macro foo: typed =
|
macro foo() =
|
||||||
var exp = newCall("whatwhat", newIntLitNode(1))
|
var exp = newCall("whatwhat", newIntLitNode(1))
|
||||||
if compiles(getAst(exp)): return exp
|
if compiles(getAst(exp)):
|
||||||
|
return exp
|
||||||
else: echo "Does not compute! (test OK)"
|
else: echo "Does not compute! (test OK)"
|
||||||
|
|
||||||
foo()
|
foo()
|
||||||
|
|
||||||
#------------------------------------
|
#------------------------------------
|
||||||
# bug #8287
|
# bug #8287
|
||||||
type MyString = distinct string
|
type MyString = distinct string
|
||||||
|
|
||||||
proc `$` (c: MyString): string {.borrow.}
|
proc `$` (c: MyString): string {.borrow.}
|
||||||
|
|
@ -37,7 +38,7 @@ proc `!!` (c: cstring): int =
|
||||||
proc f(name: MyString): int =
|
proc f(name: MyString): int =
|
||||||
!! $ name
|
!! $ name
|
||||||
|
|
||||||
macro repr_and_parse(fn: typed): typed =
|
macro repr_and_parse(fn: typed) =
|
||||||
let fn_impl = fn.getImpl
|
let fn_impl = fn.getImpl
|
||||||
fn_impl.name = genSym(nskProc, $fn_impl.name)
|
fn_impl.name = genSym(nskProc, $fn_impl.name)
|
||||||
echo fn_impl.repr
|
echo fn_impl.repr
|
||||||
|
|
@ -51,7 +52,7 @@ repr_and_parse(f)
|
||||||
|
|
||||||
|
|
||||||
#------------------------------------
|
#------------------------------------
|
||||||
# bugs #8343 and #8344
|
# bugs #8343 and #8344
|
||||||
proc one_if_proc(x, y : int): int =
|
proc one_if_proc(x, y : int): int =
|
||||||
if x < y: result = x
|
if x < y: result = x
|
||||||
else: result = y
|
else: result = y
|
||||||
|
|
@ -76,7 +77,7 @@ proc test_cond_stmtlist(x, y: int): int =
|
||||||
|
|
||||||
#------------------------------------
|
#------------------------------------
|
||||||
# bug #8762
|
# bug #8762
|
||||||
proc t2(a, b: int): int =
|
proc t2(a, b: int): int =
|
||||||
`+`(a, b)
|
`+`(a, b)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -92,23 +93,23 @@ proc fn2(x, y: float): float =
|
||||||
proc fn3(x, y: int): bool =
|
proc fn3(x, y: int): bool =
|
||||||
(((x and 3) div 4) or (x mod (y xor -1))) == 0 or y notin [1,2]
|
(((x and 3) div 4) or (x mod (y xor -1))) == 0 or y notin [1,2]
|
||||||
|
|
||||||
proc fn4(x: int): int =
|
proc fn4(x: int): int =
|
||||||
if x mod 2 == 0: return x + 2
|
if x mod 2 == 0: return x + 2
|
||||||
else: return 0
|
else: return 0
|
||||||
|
|
||||||
#------------------------------------
|
#------------------------------------
|
||||||
# bug #10807
|
# bug #10807
|
||||||
proc fn_unsafeaddr(x: int): int =
|
proc fn_unsafeaddr(x: int): int =
|
||||||
cast[int](unsafeAddr(x))
|
cast[int](unsafeAddr(x))
|
||||||
|
|
||||||
static:
|
static:
|
||||||
echo fn_unsafeaddr.repr_to_string
|
echo fn_unsafeaddr.repr_to_string
|
||||||
let fn1s = "proc fn1(x, y: int): int =\n result = 2 * (x + y)\n"
|
let fn1s = "proc fn1(x, y: int): int =\n result = 2 * (x + y)\n"
|
||||||
let fn2s = "proc fn2(x, y: float): float =\n result = (y + 2 * x) / (x - y)\n"
|
let fn2s = "proc fn2(x, y: float): float =\n result = (y + 2 * x) / (x - y)\n"
|
||||||
let fn3s = "proc fn3(x, y: int): bool =\n result = ((x and 3) div 4 or x mod (y xor -1)) == 0 or not contains([1, 2], y)\n"
|
let fn3s = "proc fn3(x, y: int): bool =\n result = ((x and 3) div 4 or x mod (y xor -1)) == 0 or not contains([1, 2], y)\n"
|
||||||
let fn4s = "proc fn4(x: int): int =\n if x mod 2 == 0:\n return x + 2\n else:\n return 0\n"
|
let fn4s = "proc fn4(x: int): int =\n if x mod 2 == 0:\n return x + 2\n else:\n return 0\n"
|
||||||
let fnAddr = "proc fn_unsafeaddr(x: int): int =\n result = cast[int](unsafeAddr(x))\n"
|
let fnAddr = "proc fn_unsafeaddr(x: int): int =\n result = cast[int](unsafeAddr(x))\n"
|
||||||
|
|
||||||
doAssert fn1.repr_to_string == fn1s
|
doAssert fn1.repr_to_string == fn1s
|
||||||
doAssert fn2.repr_to_string == fn2s
|
doAssert fn2.repr_to_string == fn2s
|
||||||
doAssert fn3.repr_to_string == fn3s
|
doAssert fn3.repr_to_string == fn3s
|
||||||
|
|
@ -134,4 +135,3 @@ repr_and_parse(test_block)
|
||||||
repr_and_parse(test_cond_stmtlist)
|
repr_and_parse(test_cond_stmtlist)
|
||||||
repr_and_parse(t2)
|
repr_and_parse(t2)
|
||||||
repr_and_parse(test_pure_enums)
|
repr_and_parse(test_pure_enums)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ block t898:
|
||||||
|
|
||||||
|
|
||||||
block t7528:
|
block t7528:
|
||||||
macro bar(n: untyped): typed =
|
macro bar(n: untyped) =
|
||||||
result = newNimNode(nnkStmtList, n)
|
result = newNimNode(nnkStmtList, n)
|
||||||
result.add(newCall("write", newIdentNode("stdout"), n))
|
result.add(newCall("write", newIdentNode("stdout"), n))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ block generic_templates:
|
||||||
block tgetast_typeliar:
|
block tgetast_typeliar:
|
||||||
proc error(s: string) = quit s
|
proc error(s: string) = quit s
|
||||||
|
|
||||||
macro assertOrReturn(condition: bool; message: string): typed =
|
macro assertOrReturn2(condition: bool; message: string) =
|
||||||
var line = condition.lineInfo()
|
var line = condition.lineInfo()
|
||||||
result = quote do:
|
result = quote do:
|
||||||
block:
|
block:
|
||||||
|
|
@ -86,8 +86,10 @@ block tgetast_typeliar:
|
||||||
return
|
return
|
||||||
|
|
||||||
macro assertOrReturn(condition: bool): typed =
|
macro assertOrReturn(condition: bool): typed =
|
||||||
var message = condition.toStrLit()
|
var message : NimNode = newLit(condition.repr)
|
||||||
result = getAst assertOrReturn(condition, message)
|
# echo message
|
||||||
|
result = getAst assertOrReturn2(condition, message)
|
||||||
|
echo result.repr
|
||||||
|
|
||||||
proc point(size: int16): tuple[x, y: int16] =
|
proc point(size: int16): tuple[x, y: int16] =
|
||||||
# returns random point in square area with given `size`
|
# returns random point in square area with given `size`
|
||||||
|
|
@ -245,7 +247,3 @@ block ttempl5:
|
||||||
block templreturntype:
|
block templreturntype:
|
||||||
template `=~` (a: int, b: int): bool = false
|
template `=~` (a: int, b: int): bool = false
|
||||||
var foo = 2 =~ 3
|
var foo = 2 =~ 3
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ proc initOpts(): set[nlOptions] =
|
||||||
|
|
||||||
const cOpts = initOpts()
|
const cOpts = initOpts()
|
||||||
|
|
||||||
macro nlo(): typed =
|
macro nlo() =
|
||||||
nlOpts.incl(nloNone)
|
nlOpts.incl(nloNone)
|
||||||
nlOpts.excl(nloDebug)
|
nlOpts.excl(nloDebug)
|
||||||
result = newEmptyNode()
|
result = newEmptyNode()
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ bb
|
||||||
|
|
||||||
const s = @[1,2,3]
|
const s = @[1,2,3]
|
||||||
|
|
||||||
macro foo: typed =
|
macro foo() =
|
||||||
for e in s:
|
for e in s:
|
||||||
echo e
|
echo e
|
||||||
|
|
||||||
|
|
@ -55,7 +55,7 @@ static:
|
||||||
var m2: TData = data
|
var m2: TData = data
|
||||||
for x in m2.numbers: echo x
|
for x in m2.numbers: echo x
|
||||||
|
|
||||||
macro ff(d: static[TData]): typed =
|
macro ff(d: static[TData]) =
|
||||||
for x in d.letters:
|
for x in d.letters:
|
||||||
echo x
|
echo x
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ nimout: '''
|
||||||
|
|
||||||
#bug #2514
|
#bug #2514
|
||||||
|
|
||||||
macro foo(): typed =
|
macro foo() =
|
||||||
var x = 8'u8
|
var x = 8'u8
|
||||||
var y = 9'u16
|
var y = 9'u16
|
||||||
var z = 17'u32
|
var z = 17'u32
|
||||||
|
|
@ -58,7 +58,7 @@ macro foo(): typed =
|
||||||
var zz = 0x7FFFFFFF'u32
|
var zz = 0x7FFFFFFF'u32
|
||||||
echo zz
|
echo zz
|
||||||
|
|
||||||
macro foo2(): typed =
|
macro foo2() =
|
||||||
var xx = 0x7FFFFFFFFFFFFFFF
|
var xx = 0x7FFFFFFFFFFFFFFF
|
||||||
echo xx
|
echo xx
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue