new gensym handling (#11985)
* new .gensym implementation * make astspec test green again * introduce a --useVersion switch to group compatibility switches * fixes #10180 * fixes #11494 * fixes #11483 * object constructor fields and named parameters are also not gensym'ed * disabled broken package
This commit is contained in:
parent
f28a47ea7b
commit
b07694cd90
18 changed files with 346 additions and 114 deletions
|
|
@ -10,6 +10,13 @@
|
||||||
to UTF-8. Use the new switch `-d:nimDontSetUtf8CodePage` to disable this
|
to UTF-8. Use the new switch `-d:nimDontSetUtf8CodePage` to disable this
|
||||||
feature.
|
feature.
|
||||||
|
|
||||||
|
- The language definition and compiler are now stricter about ``gensym``'ed
|
||||||
|
symbols in hygienic templates. See the section in the
|
||||||
|
[manual](https://nim-lang.org/docs/manual.html#templates-hygiene-in-templates)
|
||||||
|
for further details. Use the compiler switch `--useVersion:0.19` for a
|
||||||
|
transition period.
|
||||||
|
|
||||||
|
|
||||||
### Breaking changes in the standard library
|
### Breaking changes in the standard library
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -788,6 +788,15 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||||
of "expandmacro":
|
of "expandmacro":
|
||||||
expectArg(conf, switch, arg, pass, info)
|
expectArg(conf, switch, arg, pass, info)
|
||||||
conf.macrosToExpand[arg] = "T"
|
conf.macrosToExpand[arg] = "T"
|
||||||
|
of "useversion":
|
||||||
|
expectArg(conf, switch, arg, pass, info)
|
||||||
|
case arg
|
||||||
|
of "0.19":
|
||||||
|
conf.globalOptions.incl optNimV019
|
||||||
|
of "1.0":
|
||||||
|
discard "the default"
|
||||||
|
else:
|
||||||
|
localError(conf, info, "unknown Nim version; currently supported values are: {0.19, 1.0}")
|
||||||
of "":
|
of "":
|
||||||
conf.projectName = "-"
|
conf.projectName = "-"
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
## Template evaluation engine. Now hygienic.
|
## Template evaluation engine. Now hygienic.
|
||||||
|
|
||||||
import
|
import
|
||||||
strutils, options, ast, astalgo, msgs, renderer, lineinfos
|
strutils, options, ast, astalgo, msgs, renderer, lineinfos, idents
|
||||||
|
|
||||||
type
|
type
|
||||||
TemplCtx = object
|
TemplCtx = object
|
||||||
|
|
@ -20,6 +20,7 @@ type
|
||||||
mapping: TIdTable # every gensym'ed symbol needs to be mapped to some
|
mapping: TIdTable # every gensym'ed symbol needs to be mapped to some
|
||||||
# new symbol
|
# new symbol
|
||||||
config: ConfigRef
|
config: ConfigRef
|
||||||
|
ic: IdentCache
|
||||||
|
|
||||||
proc copyNode(ctx: TemplCtx, a, b: PNode): PNode =
|
proc copyNode(ctx: TemplCtx, a, b: PNode): PNode =
|
||||||
result = copyNode(a)
|
result = copyNode(a)
|
||||||
|
|
@ -52,7 +53,11 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
|
||||||
#if x.kind == skParam and x.owner.kind == skModule:
|
#if x.kind == skParam and x.owner.kind == skModule:
|
||||||
# internalAssert c.config, false
|
# internalAssert c.config, false
|
||||||
idTablePut(c.mapping, s, x)
|
idTablePut(c.mapping, s, x)
|
||||||
result.add newSymNode(x, if c.instLines: actual.info else: templ.info)
|
if sfGenSym in s.flags and optNimV019 notin c.config.globalOptions:
|
||||||
|
result.add newIdentNode(getIdent(c.ic, x.name.s & "`gensym" & $x.id),
|
||||||
|
if c.instLines: actual.info else: templ.info)
|
||||||
|
else:
|
||||||
|
result.add newSymNode(x, if c.instLines: actual.info else: templ.info)
|
||||||
else:
|
else:
|
||||||
result.add copyNode(c, templ, actual)
|
result.add copyNode(c, templ, actual)
|
||||||
of nkNone..nkIdent, nkType..nkNilLit: # atom
|
of nkNone..nkIdent, nkType..nkNilLit: # atom
|
||||||
|
|
@ -160,7 +165,9 @@ proc wrapInComesFrom*(info: TLineInfo; sym: PSym; res: PNode): PNode =
|
||||||
result.typ = res.typ
|
result.typ = res.typ
|
||||||
|
|
||||||
proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym;
|
proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym;
|
||||||
conf: ConfigRef; fromHlo=false): PNode =
|
conf: ConfigRef;
|
||||||
|
ic: IdentCache;
|
||||||
|
fromHlo=false): PNode =
|
||||||
inc(conf.evalTemplateCounter)
|
inc(conf.evalTemplateCounter)
|
||||||
if conf.evalTemplateCounter > evalTemplateLimit:
|
if conf.evalTemplateCounter > evalTemplateLimit:
|
||||||
globalError(conf, n.info, errTemplateInstantiationTooNested)
|
globalError(conf, n.info, errTemplateInstantiationTooNested)
|
||||||
|
|
@ -172,6 +179,7 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym;
|
||||||
ctx.owner = tmpl
|
ctx.owner = tmpl
|
||||||
ctx.genSymOwner = genSymOwner
|
ctx.genSymOwner = genSymOwner
|
||||||
ctx.config = conf
|
ctx.config = conf
|
||||||
|
ctx.ic = ic
|
||||||
initIdTable(ctx.mapping)
|
initIdTable(ctx.mapping)
|
||||||
|
|
||||||
let body = tmpl.getBody
|
let body = tmpl.getBody
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ import
|
||||||
sem, idents, passes, extccomp,
|
sem, idents, passes, extccomp,
|
||||||
cgen, json, nversion,
|
cgen, json, nversion,
|
||||||
platform, nimconf, passaux, depends, vm, idgen,
|
platform, nimconf, passaux, depends, vm, idgen,
|
||||||
parser, modules,
|
modules,
|
||||||
modulegraphs, tables, rod, lineinfos, pathutils
|
modulegraphs, tables, rod, lineinfos, pathutils
|
||||||
|
|
||||||
when not defined(leanCompiler):
|
when not defined(leanCompiler):
|
||||||
|
|
|
||||||
|
|
@ -84,6 +84,7 @@ type # please make sure we have under 32 options
|
||||||
optDynlibOverrideAll
|
optDynlibOverrideAll
|
||||||
optNimV2
|
optNimV2
|
||||||
optMultiMethods
|
optMultiMethods
|
||||||
|
optNimV019
|
||||||
|
|
||||||
TGlobalOptions* = set[TGlobalOption]
|
TGlobalOptions* = set[TGlobalOption]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
|
||||||
# Note: This is n.info on purpose. It prevents template from creating an info
|
# Note: This is n.info on purpose. It prevents template from creating an info
|
||||||
# context when called from an another template
|
# context when called from an another template
|
||||||
pushInfoContext(c.config, n.info, s.detailedInfo)
|
pushInfoContext(c.config, n.info, s.detailedInfo)
|
||||||
result = evalTemplate(n, s, getCurrOwner(c), c.config, efFromHlo in flags)
|
result = evalTemplate(n, s, getCurrOwner(c), c.config, c.cache, efFromHlo in flags)
|
||||||
if efNoSemCheck notin flags: result = semAfterMacroCall(c, n, result, s, flags)
|
if efNoSemCheck notin flags: result = semAfterMacroCall(c, n, result, s, flags)
|
||||||
popInfoContext(c.config)
|
popInfoContext(c.config)
|
||||||
|
|
||||||
|
|
@ -1236,6 +1236,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
|
||||||
result = newSymNode(s, n.info)
|
result = newSymNode(s, n.info)
|
||||||
else:
|
else:
|
||||||
let info = getCallLineInfo(n)
|
let info = getCallLineInfo(n)
|
||||||
|
#if efInCall notin flags:
|
||||||
markUsed(c, info, s)
|
markUsed(c, info, s)
|
||||||
onUse(info, s)
|
onUse(info, s)
|
||||||
result = newSymNode(s, info)
|
result = newSymNode(s, info)
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,8 @@ type
|
||||||
TSymChoiceRule = enum
|
TSymChoiceRule = enum
|
||||||
scClosed, scOpen, scForceOpen
|
scClosed, scOpen, scForceOpen
|
||||||
|
|
||||||
proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode =
|
proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule;
|
||||||
|
isField = false): PNode =
|
||||||
var
|
var
|
||||||
a: PSym
|
a: PSym
|
||||||
o: TOverloadIter
|
o: TOverloadIter
|
||||||
|
|
@ -63,9 +64,12 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode =
|
||||||
# XXX this makes more sense but breaks bootstrapping for now:
|
# XXX this makes more sense but breaks bootstrapping for now:
|
||||||
# (s.kind notin routineKinds or s.magic != mNone):
|
# (s.kind notin routineKinds or s.magic != mNone):
|
||||||
# for instance 'nextTry' is both in tables.nim and astalgo.nim ...
|
# for instance 'nextTry' is both in tables.nim and astalgo.nim ...
|
||||||
result = newSymNode(s, info)
|
if not isField or sfGenSym notin s.flags:
|
||||||
markUsed(c, info, s)
|
result = newSymNode(s, info)
|
||||||
onUse(info, s)
|
markUsed(c, info, s)
|
||||||
|
onUse(info, s)
|
||||||
|
else:
|
||||||
|
result = n
|
||||||
else:
|
else:
|
||||||
# semantic checking requires a type; ``fitNode`` deals with it
|
# semantic checking requires a type; ``fitNode`` deals with it
|
||||||
# appropriately
|
# appropriately
|
||||||
|
|
@ -74,7 +78,7 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode =
|
||||||
result = newNodeIT(kind, info, newTypeS(tyNone, c))
|
result = newNodeIT(kind, info, newTypeS(tyNone, c))
|
||||||
a = initOverloadIter(o, c, n)
|
a = initOverloadIter(o, c, n)
|
||||||
while a != nil:
|
while a != nil:
|
||||||
if a.kind != skModule:
|
if a.kind != skModule and (not isField or sfGenSym notin s.flags):
|
||||||
incl(a.flags, sfUsed)
|
incl(a.flags, sfUsed)
|
||||||
addSon(result, newSymNode(a, info))
|
addSon(result, newSymNode(a, info))
|
||||||
onUse(info, a)
|
onUse(info, a)
|
||||||
|
|
@ -119,6 +123,7 @@ type
|
||||||
owner: PSym
|
owner: PSym
|
||||||
cursorInBody: bool # only for nimsuggest
|
cursorInBody: bool # only for nimsuggest
|
||||||
scopeN: int
|
scopeN: int
|
||||||
|
noGenSym: int
|
||||||
|
|
||||||
template withBracketExpr(ctx, x, body: untyped) =
|
template withBracketExpr(ctx, x, body: untyped) =
|
||||||
body
|
body
|
||||||
|
|
@ -228,7 +233,7 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
|
||||||
else:
|
else:
|
||||||
replaceIdentBySym(c.c, n, ident)
|
replaceIdentBySym(c.c, n, ident)
|
||||||
|
|
||||||
proc semTemplSymbol(c: PContext, n: PNode, s: PSym): PNode =
|
proc semTemplSymbol(c: PContext, n: PNode, s: PSym; isField: bool): PNode =
|
||||||
incl(s.flags, sfUsed)
|
incl(s.flags, sfUsed)
|
||||||
# we do not call onUse here, as the identifier is not really
|
# we do not call onUse here, as the identifier is not really
|
||||||
# resolved here. We will fixup the used identifiers later.
|
# resolved here. We will fixup the used identifiers later.
|
||||||
|
|
@ -237,15 +242,18 @@ proc semTemplSymbol(c: PContext, n: PNode, s: PSym): PNode =
|
||||||
# Introduced in this pass! Leave it as an identifier.
|
# Introduced in this pass! Leave it as an identifier.
|
||||||
result = n
|
result = n
|
||||||
of OverloadableSyms:
|
of OverloadableSyms:
|
||||||
result = symChoice(c, n, s, scOpen)
|
result = symChoice(c, n, s, scOpen, isField)
|
||||||
of skGenericParam:
|
of skGenericParam:
|
||||||
result = newSymNodeTypeDesc(s, n.info)
|
if isField: result = n
|
||||||
|
else: result = newSymNodeTypeDesc(s, n.info)
|
||||||
of skParam:
|
of skParam:
|
||||||
result = n
|
result = n
|
||||||
of skType:
|
of skType:
|
||||||
result = newSymNodeTypeDesc(s, n.info)
|
if isField: result = n
|
||||||
|
else: result = newSymNodeTypeDesc(s, n.info)
|
||||||
else:
|
else:
|
||||||
result = newSymNode(s, n.info)
|
if isField: result = n
|
||||||
|
else: result = newSymNode(s, n.info)
|
||||||
|
|
||||||
proc semRoutineInTemplName(c: var TemplCtx, n: PNode): PNode =
|
proc semRoutineInTemplName(c: var TemplCtx, n: PNode): PNode =
|
||||||
result = n
|
result = n
|
||||||
|
|
@ -322,22 +330,23 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
|
||||||
if n.ident.id in c.toInject: return n
|
if n.ident.id in c.toInject: return n
|
||||||
let s = qualifiedLookUp(c.c, n, {})
|
let s = qualifiedLookUp(c.c, n, {})
|
||||||
if s != nil:
|
if s != nil:
|
||||||
if s.owner == c.owner and s.kind == skParam:
|
if s.owner == c.owner and s.kind == skParam and
|
||||||
|
(sfGenSym notin s.flags or c.noGenSym == 0):
|
||||||
incl(s.flags, sfUsed)
|
incl(s.flags, sfUsed)
|
||||||
result = newSymNode(s, n.info)
|
result = newSymNode(s, n.info)
|
||||||
onUse(n.info, s)
|
onUse(n.info, s)
|
||||||
elif contains(c.toBind, s.id):
|
elif contains(c.toBind, s.id):
|
||||||
result = symChoice(c.c, n, s, scClosed)
|
result = symChoice(c.c, n, s, scClosed, c.noGenSym > 0)
|
||||||
elif contains(c.toMixin, s.name.id):
|
elif contains(c.toMixin, s.name.id):
|
||||||
result = symChoice(c.c, n, s, scForceOpen)
|
result = symChoice(c.c, n, s, scForceOpen, c.noGenSym > 0)
|
||||||
elif s.owner == c.owner and sfGenSym in s.flags:
|
elif s.owner == c.owner and sfGenSym in s.flags and c.noGenSym == 0:
|
||||||
# template tmp[T](x: var seq[T]) =
|
# template tmp[T](x: var seq[T]) =
|
||||||
# var yz: T
|
# var yz: T
|
||||||
incl(s.flags, sfUsed)
|
incl(s.flags, sfUsed)
|
||||||
result = newSymNode(s, n.info)
|
result = newSymNode(s, n.info)
|
||||||
onUse(n.info, s)
|
onUse(n.info, s)
|
||||||
else:
|
else:
|
||||||
result = semTemplSymbol(c.c, n, s)
|
result = semTemplSymbol(c.c, n, s, c.noGenSym > 0)
|
||||||
of nkBind:
|
of nkBind:
|
||||||
result = semTemplBody(c, n.sons[0])
|
result = semTemplBody(c, n.sons[0])
|
||||||
of nkBindStmt:
|
of nkBindStmt:
|
||||||
|
|
@ -524,12 +533,27 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
|
||||||
onUse(n.info, s)
|
onUse(n.info, s)
|
||||||
return newSymNode(s, n.info)
|
return newSymNode(s, n.info)
|
||||||
elif contains(c.toBind, s.id):
|
elif contains(c.toBind, s.id):
|
||||||
return symChoice(c.c, n, s, scClosed)
|
return symChoice(c.c, n, s, scClosed, c.noGenSym > 0)
|
||||||
elif contains(c.toMixin, s.name.id):
|
elif contains(c.toMixin, s.name.id):
|
||||||
return symChoice(c.c, n, s, scForceOpen)
|
return symChoice(c.c, n, s, scForceOpen, c.noGenSym > 0)
|
||||||
else:
|
else:
|
||||||
return symChoice(c.c, n, s, scOpen)
|
return symChoice(c.c, n, s, scOpen, c.noGenSym > 0)
|
||||||
result = semTemplBodySons(c, n)
|
if n.kind == nkDotExpr:
|
||||||
|
result = n
|
||||||
|
result.sons[0] = semTemplBody(c, n.sons[0])
|
||||||
|
inc c.noGenSym
|
||||||
|
result.sons[1] = semTemplBody(c, n.sons[1])
|
||||||
|
dec c.noGenSym
|
||||||
|
else:
|
||||||
|
result = semTemplBodySons(c, n)
|
||||||
|
of nkExprColonExpr, nkExprEqExpr:
|
||||||
|
if n.len == 2:
|
||||||
|
inc c.noGenSym
|
||||||
|
result.sons[0] = semTemplBody(c, n.sons[0])
|
||||||
|
dec c.noGenSym
|
||||||
|
result.sons[1] = semTemplBody(c, n.sons[1])
|
||||||
|
else:
|
||||||
|
result = semTemplBodySons(c, n)
|
||||||
else:
|
else:
|
||||||
result = semTemplBodySons(c, n)
|
result = semTemplBodySons(c, n)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -261,15 +261,15 @@ proc getQuality(s: PSym): range[0..100] =
|
||||||
if exp.kind in {tyUntyped, tyTyped, tyGenericParam, tyAnything}: return 50
|
if exp.kind in {tyUntyped, tyTyped, tyGenericParam, tyAnything}: return 50
|
||||||
return 100
|
return 100
|
||||||
|
|
||||||
template wholeSymTab(cond, section: untyped) =
|
template wholeSymTab(cond, section: untyped) {.dirty.} =
|
||||||
var isLocal = true
|
var isLocal = true
|
||||||
var scopeN = 0
|
var scopeN = 0
|
||||||
for scope in walkScopes(c.currentScope):
|
for scope in walkScopes(c.currentScope):
|
||||||
if scope == c.topLevelScope: isLocal = false
|
if scope == c.topLevelScope: isLocal = false
|
||||||
dec scopeN
|
dec scopeN
|
||||||
for item in scope.symbols:
|
for item in scope.symbols:
|
||||||
let it {.inject.} = item
|
let it = item
|
||||||
var pm {.inject.}: PrefixMatch
|
var pm: PrefixMatch
|
||||||
if cond:
|
if cond:
|
||||||
outputs.add(symToSuggest(c.config, it, isLocal = isLocal, section, info, getQuality(it),
|
outputs.add(symToSuggest(c.config, it, isLocal = isLocal, section, info, getQuality(it),
|
||||||
pm, c.inTypeContext > 0, scopeN))
|
pm, c.inTypeContext > 0, scopeN))
|
||||||
|
|
|
||||||
|
|
@ -1137,7 +1137,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
let node = regs[rb+i].regToNode
|
let node = regs[rb+i].regToNode
|
||||||
node.info = c.debug[pc]
|
node.info = c.debug[pc]
|
||||||
macroCall.add(node)
|
macroCall.add(node)
|
||||||
var a = evalTemplate(macroCall, prc, genSymOwner, c.config)
|
var a = evalTemplate(macroCall, prc, genSymOwner, c.config, c.cache)
|
||||||
if a.kind == nkStmtList and a.len == 1: a = a[0]
|
if a.kind == nkStmtList and a.len == 1: a = a[0]
|
||||||
a.recSetFlagIsRef
|
a.recSetFlagIsRef
|
||||||
ensureKind(rkNode)
|
ensureKind(rkNode)
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,7 @@ Advanced options:
|
||||||
enable experimental language feature
|
enable experimental language feature
|
||||||
--legacy:$2
|
--legacy:$2
|
||||||
enable obsolete/legacy language feature
|
enable obsolete/legacy language feature
|
||||||
legacy code.
|
--useVersion:0.19|1.0 emulate Nim version X of the Nim compiler
|
||||||
--newruntime use an alternative runtime that uses destructors
|
--newruntime use an alternative runtime that uses destructors
|
||||||
and that uses a shared heap via -d:useMalloc
|
and that uses a shared heap via -d:useMalloc
|
||||||
--profiler:on|off enable profiling; requires `import nimprof`, and
|
--profiler:on|off enable profiling; requires `import nimprof`, and
|
||||||
|
|
|
||||||
|
|
@ -4899,6 +4899,45 @@ no semantics outside of a template definition and cannot be abstracted over:
|
||||||
To get rid of hygiene in templates, one can use the `dirty`:idx: pragma for
|
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.
|
a template. ``inject`` and ``gensym`` have no effect in ``dirty`` templates.
|
||||||
|
|
||||||
|
``gensym``'ed symbols cannot be used as ``field`` in the ``x.field`` syntax.
|
||||||
|
Nor can they be used in the ``ObjectConstruction(field: value)``
|
||||||
|
and ``namedParameterCall(field = value)`` syntactic constructs.
|
||||||
|
|
||||||
|
The reason for this is that code like
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
:test: "nim c $1"
|
||||||
|
|
||||||
|
type
|
||||||
|
T = object
|
||||||
|
f: int
|
||||||
|
|
||||||
|
template tmp(x: T) =
|
||||||
|
let f = 34
|
||||||
|
echo x.f, T(f: 4)
|
||||||
|
|
||||||
|
|
||||||
|
should work as expected.
|
||||||
|
|
||||||
|
However, this means that the method call syntax is not available for
|
||||||
|
``gensym``'ed symbols:
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
:test: "nim c $1"
|
||||||
|
:status: 1
|
||||||
|
|
||||||
|
template tmp(x) =
|
||||||
|
type
|
||||||
|
T {.gensym.} = int
|
||||||
|
|
||||||
|
echo x.T # invalid: instead use: 'echo T(x)'.
|
||||||
|
|
||||||
|
tmp(12)
|
||||||
|
|
||||||
|
|
||||||
|
**Note**: The Nim compiler prior to version 1 was more lenient about this
|
||||||
|
requirement. Use the ``--useVersion:0.19`` switch for a transition period.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Limitations of the method call syntax
|
Limitations of the method call syntax
|
||||||
|
|
|
||||||
|
|
@ -60,11 +60,11 @@ template withLock*(a: Lock, body: untyped) =
|
||||||
## Acquires the given lock, executes the statements in body and
|
## Acquires the given lock, executes the statements in body and
|
||||||
## releases the lock after the statements finish executing.
|
## releases the lock after the statements finish executing.
|
||||||
mixin acquire, release
|
mixin acquire, release
|
||||||
a.acquire()
|
acquire(a)
|
||||||
{.locks: [a].}:
|
{.locks: [a].}:
|
||||||
try:
|
try:
|
||||||
body
|
body
|
||||||
finally:
|
finally:
|
||||||
a.release()
|
release(a)
|
||||||
|
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
|
||||||
|
|
@ -984,7 +984,7 @@ when defined(nimTypeNames):
|
||||||
|
|
||||||
# ---------------------- thread memory region -------------------------------
|
# ---------------------- thread memory region -------------------------------
|
||||||
|
|
||||||
template instantiateForRegion(allocator: untyped) =
|
template instantiateForRegion(allocator: untyped) {.dirty.} =
|
||||||
{.push stackTrace: off.}
|
{.push stackTrace: off.}
|
||||||
|
|
||||||
when defined(fulldebug):
|
when defined(fulldebug):
|
||||||
|
|
@ -1006,8 +1006,8 @@ template instantiateForRegion(allocator: untyped) =
|
||||||
proc dealloc(p: pointer) =
|
proc dealloc(p: pointer) =
|
||||||
dealloc(allocator, p)
|
dealloc(allocator, p)
|
||||||
|
|
||||||
proc realloc(p: pointer, newsize: Natural): pointer =
|
proc realloc(p: pointer, newSize: Natural): pointer =
|
||||||
result = realloc(allocator, p, newsize)
|
result = realloc(allocator, p, newSize)
|
||||||
|
|
||||||
when false:
|
when false:
|
||||||
proc countFreeMem(): int =
|
proc countFreeMem(): int =
|
||||||
|
|
@ -1054,13 +1054,13 @@ template instantiateForRegion(allocator: untyped) =
|
||||||
else:
|
else:
|
||||||
dealloc(p)
|
dealloc(p)
|
||||||
|
|
||||||
proc reallocShared(p: pointer, newsize: Natural): pointer =
|
proc reallocShared(p: pointer, newSize: Natural): pointer =
|
||||||
when hasThreadSupport:
|
when hasThreadSupport:
|
||||||
acquireSys(heapLock)
|
acquireSys(heapLock)
|
||||||
result = realloc(sharedHeap, p, newsize)
|
result = realloc(sharedHeap, p, newSize)
|
||||||
releaseSys(heapLock)
|
releaseSys(heapLock)
|
||||||
else:
|
else:
|
||||||
result = realloc(p, newsize)
|
result = realloc(p, newSize)
|
||||||
|
|
||||||
when hasThreadSupport:
|
when hasThreadSupport:
|
||||||
template sharedMemStatsShared(v: int) =
|
template sharedMemStatsShared(v: int) =
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,9 @@ template pkg(name: string; cmd = "nimble test"; hasDeps = false; url = ""): unty
|
||||||
var packages*: seq[tuple[name, cmd: string; hasDeps: bool; url: string]] = @[]
|
var packages*: seq[tuple[name, cmd: string; hasDeps: bool; url: string]] = @[]
|
||||||
|
|
||||||
|
|
||||||
pkg "argparse"
|
#pkg "argparse"
|
||||||
pkg "arraymancer", "nim c -r src/arraymancer.nim", true
|
pkg "arraymancer", "nim c -r src/arraymancer.nim", true
|
||||||
pkg "ast_pattern_matching", "nim c -r tests/test1.nim"
|
pkg "ast_pattern_matching", "nim c -r --useVersion=0.19 tests/test1.nim"
|
||||||
pkg "binaryheap", "nim c -r binaryheap.nim"
|
pkg "binaryheap", "nim c -r binaryheap.nim"
|
||||||
pkg "blscurve", "", true
|
pkg "blscurve", "", true
|
||||||
pkg "bncurve", "", true
|
pkg "bncurve", "", true
|
||||||
|
|
@ -61,7 +61,7 @@ pkg "npeg"
|
||||||
pkg "ormin", "nim c -o:orminn ormin.nim", true
|
pkg "ormin", "nim c -o:orminn ormin.nim", true
|
||||||
pkg "parsetoml"
|
pkg "parsetoml"
|
||||||
pkg "patty"
|
pkg "patty"
|
||||||
pkg "plotly", "nim c examples/all.nim", true
|
pkg "plotly", "nim c --useVersion:0.19 examples/all.nim", true
|
||||||
pkg "protobuf", "nim c -o:protobuff -r src/protobuf.nim", true
|
pkg "protobuf", "nim c -o:protobuff -r src/protobuf.nim", true
|
||||||
pkg "regex", "nim c src/regex", true
|
pkg "regex", "nim c src/regex", true
|
||||||
pkg "result", "nim c -r result.nim"
|
pkg "result", "nim c -r result.nim"
|
||||||
|
|
@ -71,7 +71,7 @@ pkg "sdl2_nim", "nim c -r sdl2/sdl.nim"
|
||||||
pkg "snip", "", false, "https://github.com/genotrance/snip"
|
pkg "snip", "", false, "https://github.com/genotrance/snip"
|
||||||
pkg "stint", "nim c -o:stintt -r stint.nim"
|
pkg "stint", "nim c -o:stintt -r stint.nim"
|
||||||
pkg "strunicode", "nim c -r src/strunicode.nim", true
|
pkg "strunicode", "nim c -r src/strunicode.nim", true
|
||||||
pkg "telebot", "nim c -o:tbot -r telebot.nim", true
|
pkg "telebot", "nim c -o:tbot --useVersion:0.19 -r telebot.nim", true
|
||||||
pkg "tiny_sqlite"
|
pkg "tiny_sqlite"
|
||||||
pkg "unicodedb"
|
pkg "unicodedb"
|
||||||
pkg "unicodeplus", "", true
|
pkg "unicodeplus", "", true
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,74 @@ action: compile
|
||||||
|
|
||||||
import ../ast_pattern_matching
|
import ../ast_pattern_matching
|
||||||
|
|
||||||
|
template expectNimNode(arg: untyped): NimNode = arg
|
||||||
|
## This template here is just to be injected by `myquote`, so that
|
||||||
|
## a nice error message appears when the captured symbols are not of
|
||||||
|
## type `NimNode`.
|
||||||
|
|
||||||
|
proc substitudeComments(symbols, values, n: NimNode): NimNode =
|
||||||
|
## substitudes all nodes of kind nnkCommentStmt to parameter
|
||||||
|
## symbols. Consumes the argument `n`.
|
||||||
|
if n.kind == nnkCommentStmt:
|
||||||
|
values.add newCall(bindSym"newCommentStmtNode", newLit(n.strVal))
|
||||||
|
# Gensym doesn't work for parameters. These identifiers won't
|
||||||
|
# clash unless an argument is constructed to clash here.
|
||||||
|
symbols.add ident("comment" & $values.len & "_XObBdOnh6meCuJK2smZV")
|
||||||
|
return symbols[^1]
|
||||||
|
for i in 0 ..< n.len:
|
||||||
|
n[i] = substitudeComments(symbols, values, n[i])
|
||||||
|
return n
|
||||||
|
|
||||||
|
macro myquote*(args: varargs[untyped]): untyped =
|
||||||
|
expectMinLen(args, 1)
|
||||||
|
|
||||||
|
# This is a workaround for #10430 where comments are removed in
|
||||||
|
# template expansions. This workaround lifts all comments
|
||||||
|
# statements to be arguments of the temporary template.
|
||||||
|
|
||||||
|
let extraCommentSymbols = newNimNode(nnkBracket)
|
||||||
|
let extraCommentGenExpr = newNimNode(nnkBracket)
|
||||||
|
let body = substitudeComments(
|
||||||
|
extraCommentSymbols, extraCommentGenExpr, args[^1]
|
||||||
|
)
|
||||||
|
|
||||||
|
let formalParams = nnkFormalParams.newTree(ident"untyped")
|
||||||
|
for i in 0 ..< args.len-1:
|
||||||
|
formalParams.add nnkIdentDefs.newTree(
|
||||||
|
args[i], ident"untyped", newEmptyNode()
|
||||||
|
)
|
||||||
|
for sym in extraCommentSymbols:
|
||||||
|
formalParams.add nnkIdentDefs.newTree(
|
||||||
|
sym, ident"untyped", newEmptyNode()
|
||||||
|
)
|
||||||
|
|
||||||
|
let templateSym = genSym(nskTemplate)
|
||||||
|
let templateDef = nnkTemplateDef.newTree(
|
||||||
|
templateSym,
|
||||||
|
newEmptyNode(),
|
||||||
|
newEmptyNode(),
|
||||||
|
formalParams,
|
||||||
|
nnkPragma.newTree(ident"dirty"),
|
||||||
|
newEmptyNode(),
|
||||||
|
args[^1]
|
||||||
|
)
|
||||||
|
|
||||||
|
let templateCall = newCall(templateSym)
|
||||||
|
for i in 0 ..< args.len-1:
|
||||||
|
let symName = args[i]
|
||||||
|
# identifiers and quoted identifiers are allowed.
|
||||||
|
if symName.kind == nnkAccQuoted:
|
||||||
|
symName.expectLen 1
|
||||||
|
symName[0].expectKind nnkIdent
|
||||||
|
else:
|
||||||
|
symName.expectKind nnkIdent
|
||||||
|
templateCall.add newCall(bindSym"expectNimNode", symName)
|
||||||
|
for expr in extraCommentGenExpr:
|
||||||
|
templateCall.add expr
|
||||||
|
let getAstCall = newCall(bindSym"getAst", templateCall)
|
||||||
|
result = newStmtList(templateDef, getAstCall)
|
||||||
|
|
||||||
|
|
||||||
macro testAddrAst(arg: typed): bool =
|
macro testAddrAst(arg: typed): bool =
|
||||||
arg.expectKind nnkStmtListExpr
|
arg.expectKind nnkStmtListExpr
|
||||||
arg[0].expectKind(nnkVarSection)
|
arg[0].expectKind(nnkVarSection)
|
||||||
|
|
@ -49,34 +117,35 @@ static:
|
||||||
echo "OK"
|
echo "OK"
|
||||||
|
|
||||||
|
|
||||||
testPattern nnkIntLit(intVal = 42) , 42
|
testPattern nnkIntLit(intVal = 42), 42
|
||||||
testPattern nnkInt8Lit(intVal = 42) , 42'i8
|
testPattern nnkInt8Lit(intVal = 42), 42'i8
|
||||||
testPattern nnkInt16Lit(intVal = 42) , 42'i16
|
testPattern nnkInt16Lit(intVal = 42), 42'i16
|
||||||
testPattern nnkInt32Lit(intVal = 42) , 42'i32
|
testPattern nnkInt32Lit(intVal = 42), 42'i32
|
||||||
testPattern nnkInt64Lit(intVal = 42) , 42'i64
|
testPattern nnkInt64Lit(intVal = 42), 42'i64
|
||||||
testPattern nnkUInt8Lit(intVal = 42) , 42'u8
|
testPattern nnkUInt8Lit(intVal = 42), 42'u8
|
||||||
testPattern nnkUInt16Lit(intVal = 42) , 42'u16
|
testPattern nnkUInt16Lit(intVal = 42), 42'u16
|
||||||
testPattern nnkUInt32Lit(intVal = 42) , 42'u32
|
testPattern nnkUInt32Lit(intVal = 42), 42'u32
|
||||||
testPattern nnkUInt64Lit(intVal = 42) , 42'u64
|
testPattern nnkUInt64Lit(intVal = 42), 42'u64
|
||||||
#testPattern nnkFloat64Lit(floatVal = 42.0) , 42.0
|
#testPattern nnkFloat64Lit(floatVal = 42.0), 42.0
|
||||||
testPattern nnkFloat32Lit(floatVal = 42.0) , 42.0'f32
|
testPattern nnkFloat32Lit(floatVal = 42.0), 42.0'f32
|
||||||
#testPattern nnkFloat64Lit(floatVal = 42.0) , 42.0'f64
|
#testPattern nnkFloat64Lit(floatVal = 42.0), 42.0'f64
|
||||||
testPattern nnkStrLit(strVal = "abc") , "abc"
|
testPattern nnkStrLit(strVal = "abc"), "abc"
|
||||||
testPattern nnkRStrLit(strVal = "abc") , r"abc"
|
testPattern nnkRStrLit(strVal = "abc"), r"abc"
|
||||||
testPattern nnkTripleStrLit(strVal = "abc") , """abc"""
|
testPattern nnkTripleStrLit(strVal = "abc"), """abc"""
|
||||||
testPattern nnkCharLit(intVal = 32) , ' '
|
testPattern nnkCharLit(intVal = 32), ' '
|
||||||
testPattern nnkNilLit() , nil
|
testPattern nnkNilLit(), nil
|
||||||
testPattern nnkIdent(strVal = "myIdentifier") , myIdentifier
|
testPattern nnkIdent(strVal = "myIdentifier"), myIdentifier
|
||||||
|
|
||||||
|
testPatternFail nnkInt8Lit(intVal = 42), 42'i16
|
||||||
|
testPatternFail nnkInt16Lit(intVal = 42), 42'i8
|
||||||
|
|
||||||
testPatternFail nnkInt8Lit(intVal = 42) , 42'i16
|
|
||||||
testPatternFail nnkInt16Lit(intVal = 42) , 42'i8
|
|
||||||
|
|
||||||
|
|
||||||
# this should be just `block` but it doesn't work that way anymore because of VM.
|
# this should be just `block` but it doesn't work that way anymore because of VM.
|
||||||
macro scope(arg: untyped): untyped =
|
macro scope(arg: untyped): untyped =
|
||||||
let procSym = genSym(nskProc)
|
let procSym = genSym(nskProc)
|
||||||
result = quote do:
|
result = quote do:
|
||||||
proc `procSym`(): void {.compileTime.} =
|
proc `procSym`() {.compileTime.} =
|
||||||
`arg`
|
`arg`
|
||||||
|
|
||||||
`procSym`()
|
`procSym`()
|
||||||
|
|
@ -85,7 +154,7 @@ static:
|
||||||
## Command call
|
## Command call
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
echo "abc", "xyz"
|
echo "abc", "xyz"
|
||||||
|
|
||||||
ast.matchAst:
|
ast.matchAst:
|
||||||
|
|
@ -95,7 +164,7 @@ static:
|
||||||
## Call with ``()``
|
## Call with ``()``
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
echo("abc", "xyz")
|
echo("abc", "xyz")
|
||||||
|
|
||||||
ast.matchAst:
|
ast.matchAst:
|
||||||
|
|
@ -140,7 +209,7 @@ static:
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
? "xyz"
|
? "xyz"
|
||||||
|
|
||||||
ast.matchAst(err):
|
ast.matchAst(err):
|
||||||
|
|
@ -155,7 +224,7 @@ static:
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
proc identifier*
|
proc identifier*
|
||||||
|
|
||||||
ast[0].matchAst(err):
|
ast[0].matchAst(err):
|
||||||
|
|
@ -185,7 +254,7 @@ static:
|
||||||
|
|
||||||
## Call with raw string literal
|
## Call with raw string literal
|
||||||
scope:
|
scope:
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
echo"abc"
|
echo"abc"
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -230,7 +299,7 @@ static:
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
cast[T](x)
|
cast[T](x)
|
||||||
|
|
||||||
ast.matchAst:
|
ast.matchAst:
|
||||||
|
|
@ -242,7 +311,7 @@ static:
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
x.y
|
x.y
|
||||||
|
|
||||||
ast.matchAst:
|
ast.matchAst:
|
||||||
|
|
@ -264,7 +333,7 @@ static:
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
(1, 2, (3))
|
(1, 2, (3))
|
||||||
|
|
||||||
ast.matchAst:
|
ast.matchAst:
|
||||||
|
|
@ -276,7 +345,7 @@ static:
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
{1, 2, 3}
|
{1, 2, 3}
|
||||||
|
|
||||||
ast.matchAst:
|
ast.matchAst:
|
||||||
|
|
@ -285,7 +354,7 @@ static:
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
{a: 3, b: 5}
|
{a: 3, b: 5}
|
||||||
|
|
||||||
ast.matchAst:
|
ast.matchAst:
|
||||||
|
|
@ -300,7 +369,7 @@ static:
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
[1, 2, 3]
|
[1, 2, 3]
|
||||||
|
|
||||||
ast.matchAst:
|
ast.matchAst:
|
||||||
|
|
@ -312,7 +381,7 @@ static:
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
1..3
|
1..3
|
||||||
|
|
||||||
ast.matchAst:
|
ast.matchAst:
|
||||||
|
|
@ -328,7 +397,7 @@ static:
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
if cond1: expr1 elif cond2: expr2 else: expr3
|
if cond1: expr1 elif cond2: expr2 else: expr3
|
||||||
|
|
||||||
ast.matchAst:
|
ast.matchAst:
|
||||||
|
|
@ -343,7 +412,7 @@ static:
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
## This is a comment
|
## This is a comment
|
||||||
## This is part of the first comment
|
## This is part of the first comment
|
||||||
stmt1
|
stmt1
|
||||||
|
|
@ -357,12 +426,12 @@ static:
|
||||||
):
|
):
|
||||||
echo "ok"
|
echo "ok"
|
||||||
else:
|
else:
|
||||||
echo "NOT OK!!!"
|
echo "warning!"
|
||||||
echo ast.treeRepr
|
echo ast.treeRepr
|
||||||
echo "TEST causes no fail, because of a regression in Nim."
|
echo "TEST causes no fail, because of a regression in Nim."
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
{.emit: "#include <stdio.h>".}
|
{.emit: "#include <stdio.h>".}
|
||||||
|
|
||||||
ast.matchAst:
|
ast.matchAst:
|
||||||
|
|
@ -375,7 +444,7 @@ static:
|
||||||
echo "ok"
|
echo "ok"
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
{.pragma: cdeclRename, cdecl.}
|
{.pragma: cdeclRename, cdecl.}
|
||||||
|
|
||||||
ast.matchAst:
|
ast.matchAst:
|
||||||
|
|
@ -391,7 +460,7 @@ static:
|
||||||
|
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
if cond1:
|
if cond1:
|
||||||
stmt1
|
stmt1
|
||||||
elif cond2:
|
elif cond2:
|
||||||
|
|
@ -413,7 +482,7 @@ static:
|
||||||
|
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
x = 42
|
x = 42
|
||||||
|
|
||||||
ast.matchAst:
|
ast.matchAst:
|
||||||
|
|
@ -423,7 +492,7 @@ static:
|
||||||
|
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
stmt1
|
stmt1
|
||||||
stmt2
|
stmt2
|
||||||
stmt3
|
stmt3
|
||||||
|
|
@ -439,7 +508,7 @@ static:
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
case expr1
|
case expr1
|
||||||
of expr2, expr3..expr4:
|
of expr2, expr3..expr4:
|
||||||
stmt1
|
stmt1
|
||||||
|
|
@ -464,7 +533,7 @@ static:
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
while expr1:
|
while expr1:
|
||||||
stmt1
|
stmt1
|
||||||
|
|
||||||
|
|
@ -477,7 +546,7 @@ static:
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
for ident1, ident2 in expr1:
|
for ident1, ident2 in expr1:
|
||||||
stmt1
|
stmt1
|
||||||
|
|
||||||
|
|
@ -490,7 +559,7 @@ static:
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
try:
|
try:
|
||||||
stmt1
|
stmt1
|
||||||
except e1, e2:
|
except e1, e2:
|
||||||
|
|
@ -517,7 +586,7 @@ static:
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
return expr1
|
return expr1
|
||||||
|
|
||||||
ast.matchAst:
|
ast.matchAst:
|
||||||
|
|
@ -528,7 +597,7 @@ static:
|
||||||
## Continue statement
|
## Continue statement
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
ast.matchAst:
|
ast.matchAst:
|
||||||
|
|
@ -539,7 +608,7 @@ static:
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
break otherLocation
|
break otherLocation
|
||||||
|
|
||||||
ast.matchAst:
|
ast.matchAst:
|
||||||
|
|
@ -550,10 +619,12 @@ static:
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let ast = quote do:
|
template blockStatement {.dirty.} =
|
||||||
block name:
|
block name:
|
||||||
discard
|
discard
|
||||||
|
|
||||||
|
let ast = getAst(blockStatement())
|
||||||
|
|
||||||
ast.matchAst:
|
ast.matchAst:
|
||||||
of nnkBlockStmt(ident"name", nnkStmtList):
|
of nnkBlockStmt(ident"name", nnkStmtList):
|
||||||
echo "ok"
|
echo "ok"
|
||||||
|
|
@ -562,7 +633,7 @@ static:
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
asm """some asm"""
|
asm """some asm"""
|
||||||
|
|
||||||
ast.matchAst:
|
ast.matchAst:
|
||||||
|
|
@ -576,7 +647,7 @@ static:
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
import math
|
import math
|
||||||
|
|
||||||
ast.matchAst:
|
ast.matchAst:
|
||||||
|
|
@ -585,7 +656,7 @@ static:
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
import math except pow
|
import math except pow
|
||||||
|
|
||||||
ast.matchAst:
|
ast.matchAst:
|
||||||
|
|
@ -594,7 +665,7 @@ static:
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
import strutils as su
|
import strutils as su
|
||||||
|
|
||||||
ast.matchAst:
|
ast.matchAst:
|
||||||
|
|
@ -611,7 +682,7 @@ static:
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
from math import pow
|
from math import pow
|
||||||
|
|
||||||
ast.matchAst:
|
ast.matchAst:
|
||||||
|
|
@ -622,7 +693,7 @@ static:
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
export unsigned
|
export unsigned
|
||||||
|
|
||||||
ast.matchAst:
|
ast.matchAst:
|
||||||
|
|
@ -631,7 +702,7 @@ static:
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
export math except pow # we're going to implement our own exponentiation
|
export math except pow # we're going to implement our own exponentiation
|
||||||
|
|
||||||
ast.matchAst:
|
ast.matchAst:
|
||||||
|
|
@ -642,7 +713,7 @@ static:
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
include blocks
|
include blocks
|
||||||
|
|
||||||
ast.matchAst:
|
ast.matchAst:
|
||||||
|
|
@ -653,7 +724,7 @@ static:
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
var a = 3
|
var a = 3
|
||||||
|
|
||||||
ast.matchAst:
|
ast.matchAst:
|
||||||
|
|
@ -670,7 +741,7 @@ static:
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
let a = 3
|
let a = 3
|
||||||
|
|
||||||
ast.matchAst:
|
ast.matchAst:
|
||||||
|
|
@ -687,7 +758,7 @@ static:
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
const a = 3
|
const a = 3
|
||||||
|
|
||||||
ast.matchAst:
|
ast.matchAst:
|
||||||
|
|
@ -704,7 +775,7 @@ static:
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
type A = int
|
type A = int
|
||||||
|
|
||||||
ast.matchAst:
|
ast.matchAst:
|
||||||
|
|
@ -719,7 +790,7 @@ static:
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
type MyInt = distinct int
|
type MyInt = distinct int
|
||||||
|
|
||||||
ast.peelOff({nnkTypeSection}).matchAst:
|
ast.peelOff({nnkTypeSection}).matchAst:
|
||||||
|
|
@ -735,7 +806,7 @@ static:
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
type A[T] = expr1
|
type A[T] = expr1
|
||||||
|
|
||||||
ast.matchAst:
|
ast.matchAst:
|
||||||
|
|
@ -757,7 +828,7 @@ static:
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
type IO = object of RootObj
|
type IO = object of RootObj
|
||||||
|
|
||||||
ast.peelOff(nnkTypeSection).matchAst:
|
ast.peelOff(nnkTypeSection).matchAst:
|
||||||
|
|
@ -840,7 +911,7 @@ static:
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
type X = enum
|
type X = enum
|
||||||
First
|
First
|
||||||
|
|
||||||
|
|
@ -853,7 +924,7 @@ static:
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
type Con = concept x,y,z
|
type Con = concept x,y,z
|
||||||
(x & y & z) is string
|
(x & y & z) is string
|
||||||
|
|
||||||
|
|
@ -865,7 +936,7 @@ static:
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let astX = quote do:
|
let astX = myquote:
|
||||||
type
|
type
|
||||||
A[T: static[int]] = object
|
A[T: static[int]] = object
|
||||||
|
|
||||||
|
|
@ -880,7 +951,7 @@ static:
|
||||||
|
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
type MyProc[T] = proc(x: T)
|
type MyProc[T] = proc(x: T)
|
||||||
|
|
||||||
ast.peelOff({nnkStmtList, nnkTypeSection}).matchAst(err):
|
ast.peelOff({nnkStmtList, nnkTypeSection}).matchAst(err):
|
||||||
|
|
@ -952,7 +1023,7 @@ static:
|
||||||
proc hello*[T: SomeInteger](x: int = 3, y: float32): int {.inline.} = discard
|
proc hello*[T: SomeInteger](x: int = 3, y: float32): int {.inline.} = discard
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
var ast = quote do:
|
var ast = myquote:
|
||||||
proc foobar(a, b: int): void
|
proc foobar(a, b: int): void
|
||||||
|
|
||||||
ast = ast[3]
|
ast = ast[3]
|
||||||
|
|
@ -971,7 +1042,7 @@ static:
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
proc hello(): var int
|
proc hello(): var int
|
||||||
|
|
||||||
ast[3].matchAst: # subAst
|
ast[3].matchAst: # subAst
|
||||||
|
|
@ -986,7 +1057,7 @@ static:
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
iterator nonsense[T](x: seq[T]): float {.closure.} =
|
iterator nonsense[T](x: seq[T]): float {.closure.} =
|
||||||
discard
|
discard
|
||||||
|
|
||||||
|
|
@ -998,7 +1069,7 @@ static:
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
converter toBool(x: float): bool
|
converter toBool(x: float): bool
|
||||||
|
|
||||||
ast.matchAst:
|
ast.matchAst:
|
||||||
|
|
@ -1008,7 +1079,7 @@ static:
|
||||||
## Template declaration
|
## Template declaration
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
let ast = quote do:
|
let ast = myquote:
|
||||||
template optOpt{expr1}(a: int): int
|
template optOpt{expr1}(a: int): int
|
||||||
|
|
||||||
ast.matchAst:
|
ast.matchAst:
|
||||||
|
|
|
||||||
44
tests/template/tmore_regressions.nim
Normal file
44
tests/template/tmore_regressions.nim
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
discard """
|
||||||
|
output: '''0
|
||||||
|
|
||||||
|
0.0'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
# bug #11494
|
||||||
|
import macros
|
||||||
|
|
||||||
|
macro staticForEach(arr: untyped, body: untyped): untyped =
|
||||||
|
result = newNimNode(nnkStmtList)
|
||||||
|
|
||||||
|
arr.expectKind(nnkBracket)
|
||||||
|
for n in arr:
|
||||||
|
let b = copyNimTree(body)
|
||||||
|
result.add quote do:
|
||||||
|
block:
|
||||||
|
type it {.inject.} = `n`
|
||||||
|
`b`
|
||||||
|
|
||||||
|
template forEveryMatchingEntity*() =
|
||||||
|
staticForEach([int, string, float]):
|
||||||
|
var a: it
|
||||||
|
echo a
|
||||||
|
|
||||||
|
forEveryMatchingEntity()
|
||||||
|
|
||||||
|
|
||||||
|
# bug #11483
|
||||||
|
proc main =
|
||||||
|
template first(body) =
|
||||||
|
template second: var int =
|
||||||
|
var o: int
|
||||||
|
var i = addr(o)
|
||||||
|
i[]
|
||||||
|
|
||||||
|
body
|
||||||
|
|
||||||
|
first:
|
||||||
|
second = 5
|
||||||
|
second = 6
|
||||||
|
|
||||||
|
main()
|
||||||
|
|
||||||
|
|
@ -8,6 +8,7 @@ output: '''
|
||||||
1
|
1
|
||||||
2
|
2
|
||||||
3
|
3
|
||||||
|
wth
|
||||||
'''
|
'''
|
||||||
"""
|
"""
|
||||||
# bug #1915
|
# bug #1915
|
||||||
|
|
@ -130,3 +131,17 @@ template test() =
|
||||||
doAssert(foo.len == 3)
|
doAssert(foo.len == 3)
|
||||||
|
|
||||||
test()
|
test()
|
||||||
|
|
||||||
|
# regression found in PMunch's parser generator
|
||||||
|
|
||||||
|
proc namedcall(arg: string) =
|
||||||
|
discard
|
||||||
|
|
||||||
|
macro m(): untyped =
|
||||||
|
result = quote do:
|
||||||
|
(proc (arg: string) =
|
||||||
|
namedcall(arg = arg)
|
||||||
|
echo arg)
|
||||||
|
|
||||||
|
let meh = m()
|
||||||
|
meh("wth")
|
||||||
|
|
|
||||||
13
tests/template/tredefinition.nim
Normal file
13
tests/template/tredefinition.nim
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
discard """
|
||||||
|
errormsg: "redefinition of 'a`gensym"
|
||||||
|
line: 9
|
||||||
|
"""
|
||||||
|
# bug #10180
|
||||||
|
proc f() =
|
||||||
|
template t() =
|
||||||
|
var a = 1
|
||||||
|
var a = 2
|
||||||
|
echo a
|
||||||
|
t()
|
||||||
|
|
||||||
|
f()
|
||||||
Loading…
Add table
Add a link
Reference in a new issue