This commit is contained in:
Andreas Rumpf 2019-09-05 08:21:01 +02:00 • committed by GitHub
commit 58bcf6cd46
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 62 additions and 15 deletions

View file

@ -228,7 +228,7 @@ type
TNodeKinds* = set[TNodeKind] TNodeKinds* = set[TNodeKind]
type type
TSymFlag* = enum # already 36 flags! TSymFlag* = enum # already 38 flags!
sfUsed, # read access of sym (for warnings) or simply used sfUsed, # read access of sym (for warnings) or simply used
sfExported, # symbol is exported from module sfExported, # symbol is exported from module
sfFromGeneric, # symbol is instantiation of a generic; this is needed sfFromGeneric, # symbol is instantiation of a generic; this is needed
@ -282,6 +282,7 @@ type
sfGeneratedOp # proc is a generated '='; do not inject destructors in it sfGeneratedOp # proc is a generated '='; do not inject destructors in it
# variable is generated closure environment; requires early # variable is generated closure environment; requires early
# destruction for --newruntime. # destruction for --newruntime.
sfTemplateParam # symbol is a template parameter
TSymFlags* = set[TSymFlag] TSymFlags* = set[TSymFlag]

View file

@ -38,7 +38,7 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
of nkSym: of nkSym:
var s = templ.sym var s = templ.sym
if (s.owner == nil and s.kind == skParam) or s.owner == c.owner: if (s.owner == nil and s.kind == skParam) or s.owner == c.owner:
if s.kind == skParam and sfGenSym notin s.flags: if s.kind == skParam and {sfGenSym, sfTemplateParam} * s.flags == {sfTemplateParam}:
handleParam actual.sons[s.position] handleParam actual.sons[s.position]
elif (s.owner != nil) and (s.kind == skGenericParam or elif (s.owner != nil) and (s.kind == skGenericParam or
s.kind == skType and s.typ != nil and s.typ.kind == tyGenericParam): s.kind == skType and s.typ != nil and s.typ.kind == tyGenericParam):

View file

@ -1896,7 +1896,6 @@ proc expectString(c: PContext, n: PNode): string =
proc newAnonSym(c: PContext; kind: TSymKind, info: TLineInfo): PSym = proc newAnonSym(c: PContext; kind: TSymKind, info: TLineInfo): PSym =
result = newSym(kind, c.cache.idAnon, getCurrOwner(c), info) result = newSym(kind, c.cache.idAnon, getCurrOwner(c), info)
result.flags = {sfGenSym}
proc semExpandToAst(c: PContext, n: PNode): PNode = proc semExpandToAst(c: PContext, n: PNode): PNode =
let macroCall = n[1] let macroCall = n[1]

View file

@ -125,6 +125,7 @@ type
cursorInBody: bool # only for nimsuggest cursorInBody: bool # only for nimsuggest
scopeN: int scopeN: int
noGenSym: int noGenSym: int
inTemplateHeader: int
template withBracketExpr(ctx, x, body: untyped) = template withBracketExpr(ctx, x, body: untyped) =
body body
@ -144,9 +145,12 @@ proc getIdentNode(c: var TemplCtx, n: PNode): PNode =
illFormedAst(n, c.c.config) illFormedAst(n, c.c.config)
result = n result = n
template oldCheck(cx: TemplCtx; cond: bool): bool =
(optNimV019 notin cx.c.config.globalOptions or cond)
proc isTemplParam(c: TemplCtx, n: PNode): bool {.inline.} = proc isTemplParam(c: TemplCtx, n: PNode): bool {.inline.} =
result = n.kind == nkSym and n.sym.kind == skParam and result = n.kind == nkSym and n.sym.kind == skParam and
n.sym.owner == c.owner and sfGenSym notin n.sym.flags n.sym.owner == c.owner and sfTemplateParam in n.sym.flags
proc semTemplBody(c: var TemplCtx, n: PNode): PNode proc semTemplBody(c: var TemplCtx, n: PNode): PNode
@ -231,6 +235,8 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
styleCheckDef(c.c.config, n.info, local) styleCheckDef(c.c.config, n.info, local)
onDef(n.info, local) onDef(n.info, local)
replaceIdentBySym(c.c, n, newSymNode(local, n.info)) replaceIdentBySym(c.c, n, newSymNode(local, n.info))
if k == skParam and c.inTemplateHeader > 0:
local.flags.incl sfTemplateParam
else: else:
replaceIdentBySym(c.c, n, ident) replaceIdentBySym(c.c, n, ident)
@ -288,7 +294,14 @@ proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode =
n.sons[namePos] = semRoutineInTemplName(c, n.sons[namePos]) n.sons[namePos] = semRoutineInTemplName(c, n.sons[namePos])
# open scope for parameters # open scope for parameters
openScope(c) openScope(c)
for i in patternPos..miscPos: for i in patternPos..paramsPos-1:
n.sons[i] = semTemplBody(c, n.sons[i])
if k == skTemplate: inc(c.inTemplateHeader)
n.sons[paramsPos] = semTemplBody(c, n.sons[paramsPos])
if k == skTemplate: dec(c.inTemplateHeader)
for i in paramsPos+1..miscPos:
n.sons[i] = semTemplBody(c, n.sons[i]) n.sons[i] = semTemplBody(c, n.sons[i])
# open scope for locals # open scope for locals
inc c.scopeN inc c.scopeN
@ -331,8 +344,8 @@ 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 and if s.owner == c.owner and s.kind == skParam and sfTemplateParam in s.flags:
(sfGenSym notin s.flags or c.noGenSym == 0): # oldCheck(c, 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)
@ -542,16 +555,16 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
if n.kind == nkDotExpr: if n.kind == nkDotExpr:
result = n result = n
result.sons[0] = semTemplBody(c, n.sons[0]) result.sons[0] = semTemplBody(c, n.sons[0])
inc c.noGenSym if optNimV019 notin c.c.config.globalOptions: inc c.noGenSym
result.sons[1] = semTemplBody(c, n.sons[1]) result.sons[1] = semTemplBody(c, n.sons[1])
dec c.noGenSym if optNimV019 notin c.c.config.globalOptions: dec c.noGenSym
else: else:
result = semTemplBodySons(c, n) result = semTemplBodySons(c, n)
of nkExprColonExpr, nkExprEqExpr: of nkExprColonExpr, nkExprEqExpr:
if n.len == 2: if n.len == 2:
inc c.noGenSym if optNimV019 notin c.c.config.globalOptions: inc c.noGenSym
result.sons[0] = semTemplBody(c, n.sons[0]) result.sons[0] = semTemplBody(c, n.sons[0])
dec c.noGenSym if optNimV019 notin c.c.config.globalOptions: dec c.noGenSym
result.sons[1] = semTemplBody(c, n.sons[1]) result.sons[1] = semTemplBody(c, n.sons[1])
else: else:
result = semTemplBodySons(c, n) result = semTemplBodySons(c, n)
@ -625,7 +638,9 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
# body by the absence of the sfGenSym flag: # body by the absence of the sfGenSym flag:
for i in 1 .. s.typ.n.len-1: for i in 1 .. s.typ.n.len-1:
let param = s.typ.n.sons[i].sym let param = s.typ.n.sons[i].sym
param.flags.excl sfGenSym param.flags.incl sfTemplateParam
if optNimV019 in c.config.globalOptions:
param.flags.excl sfGenSym
if param.typ.kind != tyUntyped: allUntyped = false if param.typ.kind != tyUntyped: allUntyped = false
if sonsLen(gp) > 0: if sonsLen(gp) > 0:
if n.sons[genericParamsPos].kind == nkEmpty: if n.sons[genericParamsPos].kind == nkEmpty:

View file

@ -890,12 +890,13 @@ macro mkHandlerTplts(handlers: untyped): untyped =
# <handler code block> # <handler code block>
# ... # ...
proc mkEnter(hdName, body: NimNode): NimNode = proc mkEnter(hdName, body: NimNode): NimNode =
quote do: template helper(hdName, body) {.dirty.} =
template `hdName`(s, p, start) = template hdName(s, p, start) =
let s {.inject.} = s let s {.inject.} = s
let p {.inject.} = p let p {.inject.} = p
let start {.inject.} = start let start {.inject.} = start
`body` body
result = getAst(helper(hdName, body))
template mkLeave(hdPostf, body) {.dirty.} = template mkLeave(hdPostf, body) {.dirty.} =
# this has to be dirty to be able to capture *result* as *length* in # this has to be dirty to be able to capture *result* as *length* in

View file

@ -14,6 +14,7 @@ wth
1 1
0 0
(total: 6) (total: 6)
S1
''' '''
""" """
# bug #1915 # bug #1915
@ -164,3 +165,33 @@ template baz(): untyped =
echo (total: bar2(3)) echo (total: bar2(3))
baz() baz()
# bug #12121
macro state_machine_enum(states: varargs[untyped]) =
result = nnkTypeSection.newTree(
nnkTypeDef.newTree(
nnkPragmaExpr.newTree(ident("State"), nnkPragma.newTree(ident("pure"))),
newEmptyNode(),
nnkEnumTy.newTree(newEmptyNode())
)
)
for s in states:
expectKind(s, nnkIdent)
result[0][2].add s
template mystate_machine(body: untyped) =
state_machine_enum(S1, S2, S3)
var state_stack: seq[State]
template state_current(): State {.inject, used.} =
state_stack[^1]
template state_push(state_name) {.inject, used.} =
state_stack.add State.state_name
template state_pop(n = 1) {.inject, used.} =
state_stack.setLen(state_stack.len - n)
body
mystate_machine:
state_push(S1)
echo state_current()
state_pop()