Merge branch 'master' of github.com:Araq/Nimrod

This commit is contained in:
Araq 2012-10-05 12:10:01 +02:00
commit 350e178d83
22 changed files with 146 additions and 175 deletions

View file

@ -145,7 +145,6 @@ type
nkElifBranch, # used in if statements
nkExceptBranch, # an except section
nkElse, # an else part
nkMacroStmt, # a macro statement
nkAsmStmt, # an assembler block
nkPragma, # a pragma statement
nkPragmaBlock, # a pragma with a block
@ -911,6 +910,18 @@ proc newMetaNodeIT*(tree: PNode, info: TLineInfo, typ: PType): PNode =
result = newNodeIT(nkMetaNode, info, typ)
result.add(tree)
var emptyParams = newNode(nkFormalParams)
emptyParams.addSon(emptyNode)
proc newProcNode*(kind: TNodeKind, info: TLineInfo, body: PNode,
params = emptyParams,
name, pattern, genericParams,
pragmas, exceptions = ast.emptyNode): PNode =
result = newNodeI(kind, info)
result.sons = @[name, pattern, genericParams, params,
pragmas, exceptions, body]
proc NewType(kind: TTypeKind, owner: PSym): PType =
new(result)
result.kind = kind

View file

@ -1382,7 +1382,7 @@ proc nestedStatement(p: var TParser): PNode =
# Nimrod requires complex statements to be nested in whitespace!
const
complexStmt = {nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef,
nkTemplateDef, nkIteratorDef, nkMacroStmt, nkIfStmt,
nkTemplateDef, nkIteratorDef, nkIfStmt,
nkWhenStmt, nkForStmt, nkWhileStmt, nkCaseStmt, nkVarSection,
nkConstSection, nkTypeSection, nkTryStmt, nkBlockStmt, nkStmtList,
nkCommentStmt, nkStmtListExpr, nkBlockExpr, nkStmtListType, nkBlockType}

View file

@ -1296,7 +1296,7 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
of nkEmpty: result = n
of nkSym: result = evalSym(c, n, flags)
of nkType..nkNilLit: result = copyNode(n) # end of atoms
of nkCall, nkHiddenCallConv, nkMacroStmt, nkCommand, nkCallStrLit, nkInfix,
of nkCall, nkHiddenCallConv, nkCommand, nkCallStrLit, nkInfix,
nkPrefix, nkPostfix:
result = evalMagicOrCall(c, n)
of nkCurly, nkBracket, nkRange:

View file

@ -101,4 +101,6 @@ proc getIdent*(identifier: string, h: THash): PIdent =
proc IdentEq*(id: PIdent, name: string): bool =
result = id.id == getIdent(name).id
let idAnon* = getIdent":anonymous"

View file

@ -585,22 +585,25 @@ proc inCheckpoint*(current: TLineInfo): TCheckPointResult =
type
TErrorHandling = enum doNothing, doAbort, doRaise
proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) =
if msg == errInternal:
assert(false) # we want a stack trace here
proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) =
template maybeTrace =
if defined(debug) or gVerbosity >= 3:
writeStackTrace()
if msg == errInternal:
writeStackTrace() # we always want a stack trace here
if msg >= fatalMin and msg <= fatalMax:
if gVerbosity >= 3: assert(false)
maybeTrace()
quit(1)
if msg >= errMin and msg <= errMax:
if gVerbosity >= 3: assert(false)
maybeTrace()
inc(gErrorCounter)
options.gExitcode = 1'i8
if gErrorCounter >= gErrorMax or eh == doAbort:
if gVerbosity >= 3: assert(false)
quit(1) # one error stops the compiler
quit(1) # one error stops the compiler
elif eh == doRaise:
raiseRecoverableError(s)
proc `==`*(a, b: TLineInfo): bool =
result = a.line == b.line and a.fileIndex == b.fileIndex

View file

@ -227,5 +227,7 @@ proc binaryStrSearch*(x: openarray[string], y: string): int =
result = - 1
# Can we keep this? I'm using it all the time
template nimdbg*: expr = c.filename.endsWith"nimdbg.nim"
template cnimdbg*: expr = p.module.filename.endsWith"nimdbg.nim"
template nimdbg*: expr = c.filename.endsWith"hallo.nim"
template cnimdbg*: expr = p.module.filename.endsWith"hallo.nim"
template enimdbg*: expr = c.module.name.s == "hallo"
template pnimdbg*: expr = p.lex.fileIdx.ToFilename.endsWith"hallo.nim"

View file

@ -693,20 +693,15 @@ proc optPragmas(p: var TParser): PNode =
else: result = ast.emptyNode
proc parseDoBlock(p: var TParser): PNode =
var info = parLineInfo(p)
let info = parLineInfo(p)
getTok(p)
var params = parseParamList(p, retColon=false)
var pragmas = optPragmas(p)
let params = parseParamList(p, retColon=false)
let pragmas = optPragmas(p)
eat(p, tkColon)
result = newNodeI(nkDo, info)
addSon(result, ast.emptyNode) # no name part
addSon(result, ast.emptyNode) # no pattern part
addSon(result, ast.emptyNode) # no generic parameters
addSon(result, params)
addSon(result, pragmas)
skipComment(p, result)
addSon(result, ast.emptyNode) # no exception list
addSon(result, parseStmt(p))
result = newProcNode(nkDo, info, parseStmt(p),
params = params,
pragmas = pragmas)
proc parseDoBlocks(p: var TParser, call: PNode) =
while p.tok.tokType == tkDo:
@ -723,16 +718,11 @@ proc parseProcExpr(p: var TParser, isExpr: bool): PNode =
params = parseParamList(p)
pragmas = optPragmas(p)
if p.tok.tokType == tkEquals and isExpr:
result = newNodeI(nkLambda, info)
addSon(result, ast.emptyNode) # no name part
addSon(result, ast.emptyNode) # no pattern
addSon(result, ast.emptyNode) # no generic parameters
addSon(result, params)
addSon(result, pragmas)
getTok(p)
skipComment(p, result)
addSon(result, ast.emptyNode) # no exception list
addSon(result, parseStmt(p))
result = newProcNode(nkLambda, info, parseStmt(p),
params = params,
pragmas = pragmas)
else:
result = newNodeI(nkProcTy, info)
if hasSignature:
@ -822,7 +812,7 @@ proc primary(p: var TParser, skipSuffix = false): PNode =
proc parseTypeDesc(p: var TParser): PNode =
if p.tok.toktype == tkProc: result = parseProcExpr(p, false)
else: result = parseExpr(p)
proc parseExprStmt(p: var TParser): PNode =
var a = lowestExpr(p)
if p.tok.tokType == tkEquals:
@ -832,32 +822,29 @@ proc parseExprStmt(p: var TParser): PNode =
result = newNodeI(nkAsgn, a.info)
addSon(result, a)
addSon(result, b)
else:
result = newNodeP(nkCommand, p)
result.info = a.info
addSon(result, a)
while true:
else:
var call = if a.kind == nkCall: a
else: newNode(nkCommand, a.info, @[a])
while true:
if not isExprStart(p): break
var e = parseExpr(p)
addSon(result, e)
addSon(call, e)
if p.tok.tokType != tkComma: break
getTok(p)
optInd(p, a)
if p.tok.tokType == tkDo:
parseDoBlocks(p, result)
parseDoBlocks(p, call)
return
if sonsLen(result) <= 1: result = a
else: a = result
result = if call.sonsLen <= 1: a
else: call
if p.tok.tokType == tkColon:
# macro statement
result = newNodeP(nkMacroStmt, p)
result.info = a.info
addSon(result, a)
result = call
getTok(p)
skipComment(p, result)
if p.tok.tokType == tkSad: getTok(p)
if not (p.tok.TokType in {tkOf, tkElif, tkElse, tkExcept}):
addSon(result, parseStmt(p))
if not (p.tok.TokType in {tkOf, tkElif, tkElse, tkExcept}):
let body = parseStmt(p)
addSon(result, newProcNode(nkDo, body.info, body))
while true:
if p.tok.tokType == tkSad: getTok(p)
var b: PNode
@ -882,7 +869,7 @@ proc parseExprStmt(p: var TParser): PNode =
else: break
addSon(b, parseStmt(p))
addSon(result, b)
if b.kind == nkElse: break
if b.kind == nkElse: break
proc parseImportOrIncludeStmt(p: var TParser, kind: TNodeKind): PNode =
var a: PNode

View file

@ -1051,7 +1051,6 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
of nkWhileStmt: gwhile(g, n)
of nkPragmaBlock: gpragmaBlock(g, n)
of nkCaseStmt, nkRecCase: gcase(g, n)
of nkMacroStmt: gmacro(g, n)
of nkTryStmt: gtry(g, n)
of nkForStmt, nkParForStmt: gfor(g, n)
of nkBlockStmt, nkBlockExpr: gblock(g, n)

View file

@ -22,8 +22,7 @@ proc semPass*(): TPass
type
TExprFlag = enum
efLValue, efWantIterator, efInTypeof, efWantStmt,
efMacroStmt # expr to semcheck is a macro statement
efLValue, efWantIterator, efInTypeof, efWantStmt, efDetermineType
TExprFlags = set[TExprFlag]
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
@ -35,7 +34,7 @@ proc semProcBody(c: PContext, n: PNode): PNode
proc fitNode(c: PContext, formal: PType, arg: PNode): PNode
proc changeType(n: PNode, newType: PType)
proc semLambda(c: PContext, n: PNode): PNode
proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType
proc semStmt(c: PContext, n: PNode): PNode
proc semParamList(c: PContext, n, genericParams: PNode, s: PSym)
@ -44,6 +43,8 @@ proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind)
proc addResultNode(c: PContext, n: PNode)
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType
proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
proc fixImmediateParams(n: PNode): PNode
proc activate(c: PContext, n: PNode)
proc typeMismatch(n: PNode, formal, actual: PType) =
if formal.kind != tyError and actual.kind != tyError:
@ -91,8 +92,6 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
semCheck: bool = true): PNode
proc semMacroStmt(c: PContext, n: PNode, flags: TExprFlags,
semCheck = true): PNode
proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode
proc semWhen(c: PContext, n: PNode, semCheck: bool = true): PNode

View file

@ -304,16 +304,17 @@ proc semIs(c: PContext, n: PNode): PNode =
# BUGFIX: don't evaluate this too early: ``T is void``
if not containsGenericType(t1): result = evalIsOp(n)
proc semOpAux(c: PContext, n: PNode, tailToExclude = 1) =
for i in countup(1, sonsLen(n) - tailToExclude):
proc semOpAux(c: PContext, n: PNode) =
let flags = {efDetermineType}
for i in countup(1, n.sonsLen- 1):
var a = n.sons[i]
if a.kind == nkExprEqExpr and sonsLen(a) == 2:
var info = a.sons[0].info
a.sons[0] = newIdentNode(considerAcc(a.sons[0]), info)
a.sons[1] = semExprWithType(c, a.sons[1])
a.sons[1] = semExprWithType(c, a.sons[1], flags)
a.typ = a.sons[1].typ
else:
n.sons[i] = semExprWithType(c, a)
n.sons[i] = semExprWithType(c, a, flags)
proc overloadedCallOpr(c: PContext, n: PNode): PNode =
# quick check if there is *any* () operator overloaded:
@ -668,8 +669,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
# this seems to be a hotspot in the compiler!
let nOrig = n.copyTree
semOpAux(c, n, 1 + ord(efMacroStmt in flags))
let flags = flags - {efMacroStmt}
semOpAux(c, n)
result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
if result == nil:
result = overloadedCallOpr(c, n)
@ -679,8 +679,9 @@ proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
let callee = result.sons[0].sym
case callee.kind
of skMacro: result = semMacroExpr(c, result, nOrig, callee)
of skTemplate: result = semTemplateExpr(c, nOrig, callee)
of skTemplate: result = semTemplateExpr(c, result, callee)
else:
activate(c, n)
fixAbstractType(c, result)
analyseIfAddressTakenInCall(c, result)
if callee.magic != mNone:
@ -1281,7 +1282,7 @@ proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode =
# we replace this node by a 'true' or 'false' node:
if sonsLen(n) != 2: return semDirectOp(c, n, flags)
result = newIntNode(nkIntLit, ord(tryExpr(c, n, flags) != nil))
result = newIntNode(nkIntLit, ord(tryExpr(c, n[1], flags) != nil))
result.info = n.info
result.typ = getSysType(tyBool)
@ -1496,52 +1497,6 @@ proc buildCall(n: PNode): PNode =
else:
result = n
proc semMacroStmt(c: PContext, n: PNode, flags: TExprFlags,
semCheck = true): PNode =
checkMinSonsLen(n, 2)
var a: PNode
if isCallExpr(n.sons[0]): a = n.sons[0].sons[0]
else: a = n.sons[0]
var s = qualifiedLookup(c, a, {checkUndeclared})
if s != nil:
# transform
# nkMacroStmt(nkCall(a...), stmt, b...)
# to
# nkCall(a..., stmt, b...)
result = newNodeI(nkCall, n.info)
addSon(result, a)
if isCallExpr(n.sons[0]):
for i in countup(1, sonsLen(n.sons[0]) - 1):
addSon(result, n.sons[0].sons[i])
# for sigmatch this need to have a type; we use 'void':
for i in countup(1, sonsLen(n) - 1):
n.sons[i].typ = newTypeS(tyEmpty, c)
addSon(result, n.sons[i])
case s.kind
of skMacro:
if sfImmediate notin s.flags:
result = semDirectOp(c, result, flags+{efMacroStmt})
else:
result = semMacroExpr(c, result, n, s, semCheck)
of skTemplate:
if sfImmediate notin s.flags:
result = semDirectOp(c, result, flags+{efMacroStmt})
else:
result = semTemplateExpr(c, result, s, semCheck)
else:
LocalError(n.info, errXisNoMacroOrTemplate, s.name.s)
result = errorNode(c, n)
elif a.kind == nkDotExpr:
# 'x.m(y): stmt' == nkMacroStmt(nkCall(nkDotExpr(x, m), y), stmt)
# --> nkMacroStmt(nkCall(m, x, y), stmt)
n.sons[0] = buildCall(n.sons[0])
result = semMacroStmt(c, n, flags, semCheck)
else:
LocalError(n.info, errInvalidExpressionX,
renderTree(a, {renderNoComments}))
result = errorNode(c, n)
proc semCaseExpr(c: PContext, caseStmt: PNode): PNode =
# The case expression is simply rewritten to a StmtListExpr:
# var res {.noInit, genSym.}: type(values)
@ -1553,7 +1508,7 @@ proc semCaseExpr(c: PContext, caseStmt: PNode): PNode =
# res
var
info = caseStmt.info
resVar = newSym(skVar, getIdent":res", getCurrOwner(), info)
resVar = newSym(skVar, idAnon, getCurrOwner(), info)
resNode = newSymNode(resVar, info)
resType: PType
@ -1592,7 +1547,15 @@ proc semCaseExpr(c: PContext, caseStmt: PNode): PNode =
resNode])
result = semStmtListExpr(c, result)
proc fixImmediateParams(n: PNode): PNode =
# XXX: Temporary work-around until we carry out
# the planned overload resolution reforms
for i in 1 .. <n.len:
if n[i].kind == nkDo: n.sons[i] = n[i][bodyPos]
result = n
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
result = n
if gCmd == cmdIdeTools: suggestExpr(c, n)
@ -1670,12 +1633,14 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
if sfImmediate notin s.flags:
result = semDirectOp(c, n, flags)
else:
result = semMacroExpr(c, n, n, s)
var p = fixImmediateParams(n)
result = semMacroExpr(c, p, p, s)
of skTemplate:
if sfImmediate notin s.flags:
result = semDirectOp(c, n, flags)
else:
result = semTemplateExpr(c, n, s)
var p = fixImmediateParams(n)
result = semTemplateExpr(c, p, s)
of skType:
# XXX think about this more (``set`` procs)
if n.len == 2:
@ -1695,8 +1660,6 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
result = semDirectOp(c, n, flags)
else:
result = semIndirectOp(c, n, flags)
of nkMacroStmt:
result = semMacroStmt(c, n, flags)
of nkWhen:
if efWantStmt in flags:
result = semWhen(c, n, true)
@ -1725,7 +1688,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
of paSingle: result = semExpr(c, n.sons[0], flags)
of nkCurly: result = semSetConstr(c, n)
of nkBracket: result = semArrayConstr(c, n)
of nkLambdaKinds: result = semLambda(c, n)
of nkLambdaKinds: result = semLambda(c, n, flags)
of nkDerefExpr: result = semDeref(c, n)
of nkAddr:
result = n

View file

@ -53,6 +53,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym): PNode =
result = symChoice(c, n, s, scOpen)
of skTemplate:
if macroToExpand(s):
let n = fixImmediateParams(n)
result = semTemplateExpr(c, n, s, false)
else:
result = symChoice(c, n, s, scOpen)
@ -123,6 +124,7 @@ proc semGenericStmt(c: PContext, n: PNode,
result = n
of skTemplate:
if macroToExpand(s):
let n = fixImmediateParams(n)
result = semTemplateExpr(c, n, s, false)
else:
n.sons[0] = symChoice(c, n.sons[0], s, scOpen)
@ -151,17 +153,6 @@ proc semGenericStmt(c: PContext, n: PNode,
let flags = if isDefinedMagic: flags+{withinMixin} else: flags
for i in countup(first, sonsLen(result) - 1):
result.sons[i] = semGenericStmt(c, result.sons[i], flags, toBind)
of nkMacroStmt:
checkMinSonsLen(n, 2)
var a: PNode
if isCallExpr(n.sons[0]): a = n.sons[0].sons[0]
else: a = n.sons[0]
let luf = if withinMixin notin flags: {checkUndeclared} else: {}
var s = qualifiedLookup(c, a, luf)
if s != nil and macroToExpand(s):
result = semMacroStmt(c, n, {}, false)
for i in countup(0, sonsLen(result)-1):
result.sons[i] = semGenericStmt(c, result.sons[i], flags, toBind)
of nkIfStmt:
for i in countup(0, sonsLen(n)-1):
n.sons[i] = semGenericStmtScope(c, n.sons[i], flags, toBind)

View file

@ -623,9 +623,9 @@ proc semProcAnnotation(c: PContext, prc: PNode): PNode =
var key = if it.kind == nkExprColonExpr: it.sons[0] else: it
let m = lookupMacro(c, key)
if m == nil: continue
# we transform ``proc p {.m, rest.}`` into ``m: proc p {.rest.}`` and
# we transform ``proc p {.m, rest.}`` into ``m(proc p {.rest.})`` and
# let the semantic checker deal with it:
var x = newNodeI(nkMacroStmt, n.info)
var x = newNodeI(nkCall, n.info)
x.add(newSymNode(m))
prc.sons[pragmasPos] = copyExcept(n, i)
if it.kind == nkExprColonExpr:
@ -634,15 +634,19 @@ proc semProcAnnotation(c: PContext, prc: PNode): PNode =
x.add(prc)
# recursion assures that this works for multiple macro annotations too:
return semStmt(c, x)
proc semLambda(c: PContext, n: PNode): PNode =
proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
result = semProcAnnotation(c, n)
if result != nil: return result
result = n
checkSonsLen(n, bodyPos + 1)
var s = newSym(skProc, getIdent":anonymous", getCurrOwner(), n.info)
s.ast = n
n.sons[namePos] = newSymNode(s)
var s: PSym
if n[namePos].kind != nkSym:
s = newSym(skProc, idAnon, getCurrOwner(), n.info)
s.ast = n
n.sons[namePos] = newSymNode(s)
else:
s = n[namePos].sym
pushOwner(s)
openScope(c.tab)
if n.sons[genericParamsPos].kind != nkEmpty:
@ -659,19 +663,31 @@ proc semLambda(c: PContext, n: PNode): PNode =
if n.sons[bodyPos].kind != nkEmpty:
if sfImportc in s.flags:
LocalError(n.sons[bodyPos].info, errImplOfXNotAllowed, s.name.s)
pushProcCon(c, s)
addResult(c, s.typ.sons[0], n.info, skProc)
let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
n.sons[bodyPos] = transformBody(c.module, semBody, s)
addResultNode(c, n)
popProcCon(c)
if efDetermineType notin flags:
pushProcCon(c, s)
addResult(c, s.typ.sons[0], n.info, skProc)
let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
n.sons[bodyPos] = transformBody(c.module, semBody, s)
addResultNode(c, n)
popProcCon(c)
sideEffectsCheck(c, s)
else:
LocalError(n.info, errImplOfXexpected, s.name.s)
sideEffectsCheck(c, s)
closeScope(c.tab) # close scope for parameters
popOwner()
result.typ = s.typ
proc activate(c: PContext, n: PNode) =
# XXX: This proc is part of my plan for getting rid of
# forward declarations. stay tuned.
case n.kind
of nkLambdaKinds:
discard semLambda(c, n, {})
of nkCallKinds:
for i in 1 .. <n.len: activate(c, n[i])
else:
nil
proc instantiateDestructor*(c: PContext, typ: PType): bool
proc doDestructorStuff(c: PContext, s: PSym, n: PNode) =

View file

@ -64,10 +64,11 @@ proc ReplaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode
proc prepareNode(cl: var TReplTypeVars, n: PNode): PNode =
result = copyNode(n)
result.typ = ReplaceTypeVarsT(cl, n.typ)
if result.kind == nkSym: result.sym = ReplaceTypeVarsS(cl, n.sym)
for i in 0 .. safeLen(n)-1:
# XXX HACK: ``f(a, b)``, avoid to instantiate `f`
if i == 0: result.add(n[i])
else: result.add(ReplaceTypeVarsN(cl, n[i]))
else: result.add(prepareNode(cl, n[i]))
proc ReplaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode =
if n == nil: return

View file

@ -637,8 +637,12 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
of isGeneric:
inc(m.genericMatches)
if m.calleeSym != nil and m.calleeSym.kind in {skMacro, skTemplate}:
if f.kind == tyTypeDesc: result = arg
else: result = argOrig
if f.kind == tyStmt and argOrig.kind == nkDo:
result = argOrig[bodyPos]
elif f.kind == tyTypeDesc:
result = arg
else:
result = argOrig
else:
result = copyTree(arg)
result.typ = getInstantiatedType(c, arg, m, f)

View file

@ -175,8 +175,7 @@ proc findClosestDot(n: PNode): PNode =
if result != nil: return
const
CallNodes = {nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit,
nkMacroStmt}
CallNodes = {nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit}
proc findClosestCall(n: PNode): PNode =
if n.kind in callNodes and msgs.inCheckpoint(n.info) == cpExact: