Merge pull request #8949 from nim-lang/araq-for-loop-expressions
For loop expressions
This commit is contained in:
commit
132eb31e32
9 changed files with 163 additions and 81 deletions
|
|
@ -16,7 +16,7 @@ import
|
||||||
wordrecg, syntaxes, renderer, lexer, packages/docutils/rstast,
|
wordrecg, syntaxes, renderer, lexer, packages/docutils/rstast,
|
||||||
packages/docutils/rst, packages/docutils/rstgen,
|
packages/docutils/rst, packages/docutils/rstgen,
|
||||||
packages/docutils/highlite, sempass2, json, xmltree, cgi,
|
packages/docutils/highlite, sempass2, json, xmltree, cgi,
|
||||||
typesrenderer, astalgo, modulepaths, lineinfos, sequtils
|
typesrenderer, astalgo, modulepaths, lineinfos, sequtils, intsets
|
||||||
|
|
||||||
type
|
type
|
||||||
TSections = array[TSymKind, Rope]
|
TSections = array[TSymKind, Rope]
|
||||||
|
|
@ -32,6 +32,8 @@ type
|
||||||
conf*: ConfigRef
|
conf*: ConfigRef
|
||||||
cache*: IdentCache
|
cache*: IdentCache
|
||||||
exampleCounter: int
|
exampleCounter: int
|
||||||
|
emitted: IntSet # we need to track which symbols have been emitted
|
||||||
|
# already. See bug #3655
|
||||||
|
|
||||||
PDoc* = ref TDocumentor ## Alias to type less.
|
PDoc* = ref TDocumentor ## Alias to type less.
|
||||||
|
|
||||||
|
|
@ -119,6 +121,7 @@ proc newDocumentor*(filename: string; cache: IdentCache; conf: ConfigRef): PDoc
|
||||||
initStrTable result.types
|
initStrTable result.types
|
||||||
result.onTestSnippet = proc (d: var RstGenerator; filename, cmd: string; status: int; content: string) =
|
result.onTestSnippet = proc (d: var RstGenerator; filename, cmd: string; status: int; content: string) =
|
||||||
localError(conf, newLineInfo(conf, d.filename, -1, -1), warnUser, "only 'rst2html' supports the ':test:' attribute")
|
localError(conf, newLineInfo(conf, d.filename, -1, -1), warnUser, "only 'rst2html' supports the ':test:' attribute")
|
||||||
|
result.emitted = initIntSet()
|
||||||
|
|
||||||
proc dispA(conf: ConfigRef; dest: var Rope, xml, tex: string, args: openArray[Rope]) =
|
proc dispA(conf: ConfigRef; dest: var Rope, xml, tex: string, args: openArray[Rope]) =
|
||||||
if conf.cmd != cmdRst2tex: addf(dest, xml, args)
|
if conf.cmd != cmdRst2tex: addf(dest, xml, args)
|
||||||
|
|
@ -377,7 +380,7 @@ when false:
|
||||||
else:
|
else:
|
||||||
result = n.comment.substr(2).replace("\n##", "\n").strip
|
result = n.comment.substr(2).replace("\n##", "\n").strip
|
||||||
|
|
||||||
proc isVisible(n: PNode): bool =
|
proc isVisible(d: PDoc; n: PNode): bool =
|
||||||
result = false
|
result = false
|
||||||
if n.kind == nkPostfix:
|
if n.kind == nkPostfix:
|
||||||
if n.len == 2 and n.sons[0].kind == nkIdent:
|
if n.len == 2 and n.sons[0].kind == nkIdent:
|
||||||
|
|
@ -388,8 +391,10 @@ proc isVisible(n: PNode): bool =
|
||||||
# exception tracking information here. Instead we copy over the comment
|
# exception tracking information here. Instead we copy over the comment
|
||||||
# from the proc header.
|
# from the proc header.
|
||||||
result = {sfExported, sfFromGeneric, sfForward}*n.sym.flags == {sfExported}
|
result = {sfExported, sfFromGeneric, sfForward}*n.sym.flags == {sfExported}
|
||||||
|
if result and containsOrIncl(d.emitted, n.sym.id):
|
||||||
|
result = false
|
||||||
elif n.kind == nkPragmaExpr:
|
elif n.kind == nkPragmaExpr:
|
||||||
result = isVisible(n.sons[0])
|
result = isVisible(d, n.sons[0])
|
||||||
|
|
||||||
proc getName(d: PDoc, n: PNode, splitAfter = -1): string =
|
proc getName(d: PDoc, n: PNode, splitAfter = -1): string =
|
||||||
case n.kind
|
case n.kind
|
||||||
|
|
@ -520,7 +525,7 @@ proc docstringSummary(rstText: string): string =
|
||||||
|
|
||||||
|
|
||||||
proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
|
proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
|
||||||
if not isVisible(nameNode): return
|
if not isVisible(d, nameNode): return
|
||||||
let
|
let
|
||||||
name = getName(d, nameNode)
|
name = getName(d, nameNode)
|
||||||
nameRope = name.rope
|
nameRope = name.rope
|
||||||
|
|
@ -601,7 +606,7 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
|
||||||
d.types.strTableAdd nameNode.sym
|
d.types.strTableAdd nameNode.sym
|
||||||
|
|
||||||
proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode =
|
proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode =
|
||||||
if not isVisible(nameNode): return
|
if not isVisible(d, nameNode): return
|
||||||
var
|
var
|
||||||
name = getName(d, nameNode)
|
name = getName(d, nameNode)
|
||||||
comm = $genRecComment(d, n)
|
comm = $genRecComment(d, n)
|
||||||
|
|
|
||||||
|
|
@ -537,7 +537,7 @@ proc parsePar(p: var TParser): PNode =
|
||||||
flexComment(p, result)
|
flexComment(p, result)
|
||||||
if p.tok.tokType in {tkDiscard, tkInclude, tkIf, tkWhile, tkCase,
|
if p.tok.tokType in {tkDiscard, tkInclude, tkIf, tkWhile, tkCase,
|
||||||
tkTry, tkDefer, tkFinally, tkExcept, tkFor, tkBlock,
|
tkTry, tkDefer, tkFinally, tkExcept, tkFor, tkBlock,
|
||||||
tkConst, tkLet, tkWhen, tkVar,
|
tkConst, tkLet, tkWhen, tkVar, tkFor,
|
||||||
tkMixin}:
|
tkMixin}:
|
||||||
# XXX 'bind' used to be an expression, so we exclude it here;
|
# XXX 'bind' used to be an expression, so we exclude it here;
|
||||||
# tests/reject/tbind2 fails otherwise.
|
# tests/reject/tbind2 fails otherwise.
|
||||||
|
|
@ -1112,7 +1112,7 @@ proc parseProcExpr(p: var TParser; isExpr: bool; kind: TNodeKind): PNode =
|
||||||
|
|
||||||
proc isExprStart(p: TParser): bool =
|
proc isExprStart(p: TParser): bool =
|
||||||
case p.tok.tokType
|
case p.tok.tokType
|
||||||
of tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf,
|
of tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf, tkFor,
|
||||||
tkProc, tkFunc, tkIterator, tkBind, tkBuiltInMagics,
|
tkProc, tkFunc, tkIterator, tkBind, tkBuiltInMagics,
|
||||||
tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit, tkVar, tkRef, tkPtr,
|
tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit, tkVar, tkRef, tkPtr,
|
||||||
tkTuple, tkObject, tkWhen, tkCase, tkOut:
|
tkTuple, tkObject, tkWhen, tkCase, tkOut:
|
||||||
|
|
@ -1152,16 +1152,35 @@ proc parseTypeDescKAux(p: var TParser, kind: TNodeKind,
|
||||||
result.addSon list
|
result.addSon list
|
||||||
parseSymbolList(p, list)
|
parseSymbolList(p, list)
|
||||||
|
|
||||||
|
proc parseFor(p: var TParser): PNode =
|
||||||
|
#| forStmt = 'for' (identWithPragma ^+ comma) 'in' expr colcom stmt
|
||||||
|
#| forExpr = forStmt
|
||||||
|
result = newNodeP(nkForStmt, p)
|
||||||
|
getTokNoInd(p)
|
||||||
|
var a = identWithPragma(p)
|
||||||
|
addSon(result, a)
|
||||||
|
while p.tok.tokType == tkComma:
|
||||||
|
getTok(p)
|
||||||
|
optInd(p, a)
|
||||||
|
a = identWithPragma(p)
|
||||||
|
addSon(result, a)
|
||||||
|
eat(p, tkIn)
|
||||||
|
addSon(result, parseExpr(p))
|
||||||
|
colcom(p, result)
|
||||||
|
addSon(result, parseStmt(p))
|
||||||
|
|
||||||
proc parseExpr(p: var TParser): PNode =
|
proc parseExpr(p: var TParser): PNode =
|
||||||
#| expr = (blockExpr
|
#| expr = (blockExpr
|
||||||
#| | ifExpr
|
#| | ifExpr
|
||||||
#| | whenExpr
|
#| | whenExpr
|
||||||
#| | caseExpr
|
#| | caseExpr
|
||||||
|
#| | forExpr
|
||||||
#| | tryExpr)
|
#| | tryExpr)
|
||||||
#| / simpleExpr
|
#| / simpleExpr
|
||||||
case p.tok.tokType:
|
case p.tok.tokType:
|
||||||
of tkBlock: result = parseBlock(p)
|
of tkBlock: result = parseBlock(p)
|
||||||
of tkIf: result = parseIfExpr(p, nkIfExpr)
|
of tkIf: result = parseIfExpr(p, nkIfExpr)
|
||||||
|
of tkFor: result = parseFor(p)
|
||||||
of tkWhen: result = parseIfExpr(p, nkWhenExpr)
|
of tkWhen: result = parseIfExpr(p, nkWhenExpr)
|
||||||
of tkCase: result = parseCase(p)
|
of tkCase: result = parseCase(p)
|
||||||
of tkTry: result = parseTry(p, isExpr=true)
|
of tkTry: result = parseTry(p, isExpr=true)
|
||||||
|
|
@ -1568,22 +1587,6 @@ proc parseExceptBlock(p: var TParser, kind: TNodeKind): PNode =
|
||||||
colcom(p, result)
|
colcom(p, result)
|
||||||
addSon(result, parseStmt(p))
|
addSon(result, parseStmt(p))
|
||||||
|
|
||||||
proc parseFor(p: var TParser): PNode =
|
|
||||||
#| forStmt = 'for' (identWithPragma ^+ comma) 'in' expr colcom stmt
|
|
||||||
result = newNodeP(nkForStmt, p)
|
|
||||||
getTokNoInd(p)
|
|
||||||
var a = identWithPragma(p)
|
|
||||||
addSon(result, a)
|
|
||||||
while p.tok.tokType == tkComma:
|
|
||||||
getTok(p)
|
|
||||||
optInd(p, a)
|
|
||||||
a = identWithPragma(p)
|
|
||||||
addSon(result, a)
|
|
||||||
eat(p, tkIn)
|
|
||||||
addSon(result, parseExpr(p))
|
|
||||||
colcom(p, result)
|
|
||||||
addSon(result, parseStmt(p))
|
|
||||||
|
|
||||||
proc parseBlock(p: var TParser): PNode =
|
proc parseBlock(p: var TParser): PNode =
|
||||||
#| blockStmt = 'block' symbol? colcom stmt
|
#| blockStmt = 'block' symbol? colcom stmt
|
||||||
#| blockExpr = 'block' symbol? colcom stmt
|
#| blockExpr = 'block' symbol? colcom stmt
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ proc changeType(c: PContext; n: PNode, newType: PType, check: bool)
|
||||||
|
|
||||||
proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode
|
proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode
|
||||||
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType
|
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType
|
||||||
proc semStmt(c: PContext, n: PNode): PNode
|
proc semStmt(c: PContext, n: PNode; flags: TExprFlags): PNode
|
||||||
proc semOpAux(c: PContext, n: PNode)
|
proc semOpAux(c: PContext, n: PNode)
|
||||||
proc semParamList(c: PContext, n, genericParams: PNode, s: PSym)
|
proc semParamList(c: PContext, n, genericParams: PNode, s: PSym)
|
||||||
proc addParams(c: PContext, n: PNode, kind: TSymKind)
|
proc addParams(c: PContext, n: PNode, kind: TSymKind)
|
||||||
|
|
@ -399,7 +399,7 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
|
||||||
excl(result.flags, nfSem)
|
excl(result.flags, nfSem)
|
||||||
#resetSemFlag n
|
#resetSemFlag n
|
||||||
if s.typ.sons[0] == nil:
|
if s.typ.sons[0] == nil:
|
||||||
result = semStmt(c, result)
|
result = semStmt(c, result, flags)
|
||||||
else:
|
else:
|
||||||
case s.typ.sons[0].kind
|
case s.typ.sons[0].kind
|
||||||
of tyExpr:
|
of tyExpr:
|
||||||
|
|
@ -408,7 +408,7 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
|
||||||
# semExprWithType(c, result)
|
# semExprWithType(c, result)
|
||||||
result = semExpr(c, result, flags)
|
result = semExpr(c, result, flags)
|
||||||
of tyStmt:
|
of tyStmt:
|
||||||
result = semStmt(c, result)
|
result = semStmt(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)
|
||||||
|
|
@ -557,7 +557,7 @@ proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
|
||||||
result = semAllTypeSections(c, n)
|
result = semAllTypeSections(c, n)
|
||||||
else:
|
else:
|
||||||
result = n
|
result = n
|
||||||
result = semStmt(c, result)
|
result = semStmt(c, result, {})
|
||||||
when false:
|
when false:
|
||||||
# Code generators are lazy now and can deal with undeclared procs, so these
|
# Code generators are lazy now and can deal with undeclared procs, so these
|
||||||
# steps are not required anymore and actually harmful for the upcoming
|
# steps are not required anymore and actually harmful for the upcoming
|
||||||
|
|
|
||||||
|
|
@ -918,7 +918,7 @@ proc semExprNoType(c: PContext, n: PNode): PNode =
|
||||||
let isPush = hintExtendedContext in c.config.notes
|
let isPush = hintExtendedContext in c.config.notes
|
||||||
if isPush: pushInfoContext(c.config, n.info)
|
if isPush: pushInfoContext(c.config, n.info)
|
||||||
result = semExpr(c, n, {efWantStmt})
|
result = semExpr(c, n, {efWantStmt})
|
||||||
discardCheck(c, result)
|
discardCheck(c, result, {})
|
||||||
if isPush: popInfoContext(c.config)
|
if isPush: popInfoContext(c.config)
|
||||||
|
|
||||||
proc isTypeExpr(n: PNode): bool =
|
proc isTypeExpr(n: PNode): bool =
|
||||||
|
|
@ -1530,7 +1530,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
|
||||||
# unfortunately we need to rewrite ``(x, y) = foo()`` already here so
|
# unfortunately we need to rewrite ``(x, y) = foo()`` already here so
|
||||||
# that overloading of the assignment operator still works. Usually we
|
# that overloading of the assignment operator still works. Usually we
|
||||||
# prefer to do these rewritings in transf.nim:
|
# prefer to do these rewritings in transf.nim:
|
||||||
return semStmt(c, lowerTupleUnpackingForAsgn(c.graph, n, c.p.owner))
|
return semStmt(c, lowerTupleUnpackingForAsgn(c.graph, n, c.p.owner), {})
|
||||||
else:
|
else:
|
||||||
a = semExprWithType(c, a, {efLValue})
|
a = semExprWithType(c, a, {efLValue})
|
||||||
else:
|
else:
|
||||||
|
|
@ -1614,7 +1614,7 @@ proc semProcBody(c: PContext, n: PNode): PNode =
|
||||||
a.sons[1] = result
|
a.sons[1] = result
|
||||||
result = semAsgn(c, a)
|
result = semAsgn(c, a)
|
||||||
else:
|
else:
|
||||||
discardCheck(c, result)
|
discardCheck(c, result, {})
|
||||||
|
|
||||||
if c.p.owner.kind notin {skMacro, skTemplate} and
|
if c.p.owner.kind notin {skMacro, skTemplate} and
|
||||||
c.p.resultSym != nil and c.p.resultSym.typ.isMetaType:
|
c.p.resultSym != nil and c.p.resultSym.typ.isMetaType:
|
||||||
|
|
@ -1990,7 +1990,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||||
var x = n.lastSon
|
var x = n.lastSon
|
||||||
if x.kind == nkDo: x = x.sons[bodyPos]
|
if x.kind == nkDo: x = x.sons[bodyPos]
|
||||||
inc c.inParallelStmt
|
inc c.inParallelStmt
|
||||||
result.sons[1] = semStmt(c, x)
|
result.sons[1] = semStmt(c, x, {})
|
||||||
dec c.inParallelStmt
|
dec c.inParallelStmt
|
||||||
of mSpawn:
|
of mSpawn:
|
||||||
result = setMs(n, s)
|
result = setMs(n, s)
|
||||||
|
|
@ -2241,7 +2241,7 @@ proc isTupleType(n: PNode): bool =
|
||||||
|
|
||||||
include semobjconstr
|
include semobjconstr
|
||||||
|
|
||||||
proc semBlock(c: PContext, n: PNode): PNode =
|
proc semBlock(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
||||||
result = n
|
result = n
|
||||||
inc(c.p.nestedBlockCounter)
|
inc(c.p.nestedBlockCounter)
|
||||||
checkSonsLen(n, 2, c.config)
|
checkSonsLen(n, 2, c.config)
|
||||||
|
|
@ -2253,7 +2253,7 @@ proc semBlock(c: PContext, n: PNode): PNode =
|
||||||
n.sons[0] = newSymNode(labl, n.sons[0].info)
|
n.sons[0] = newSymNode(labl, n.sons[0].info)
|
||||||
suggestSym(c.config, n.sons[0].info, labl, c.graph.usageSym)
|
suggestSym(c.config, n.sons[0].info, labl, c.graph.usageSym)
|
||||||
styleCheckDef(c.config, labl)
|
styleCheckDef(c.config, labl)
|
||||||
n.sons[1] = semExpr(c, n.sons[1])
|
n.sons[1] = semExpr(c, n.sons[1], flags)
|
||||||
n.typ = n.sons[1].typ
|
n.typ = n.sons[1].typ
|
||||||
if isEmptyType(n.typ): n.kind = nkBlockStmt
|
if isEmptyType(n.typ): n.kind = nkBlockStmt
|
||||||
else: n.kind = nkBlockExpr
|
else: n.kind = nkBlockExpr
|
||||||
|
|
@ -2498,7 +2498,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
checkSonsLen(n, 1, c.config)
|
checkSonsLen(n, 1, c.config)
|
||||||
n.sons[0] = semExpr(c, n.sons[0], flags)
|
n.sons[0] = semExpr(c, n.sons[0], flags)
|
||||||
of nkCast: result = semCast(c, n)
|
of nkCast: result = semCast(c, n)
|
||||||
of nkIfExpr, nkIfStmt: result = semIf(c, n)
|
of nkIfExpr, nkIfStmt: result = semIf(c, n, flags)
|
||||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkHiddenCallConv:
|
of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkHiddenCallConv:
|
||||||
checkSonsLen(n, 2, c.config)
|
checkSonsLen(n, 2, c.config)
|
||||||
considerGenSyms(c, n)
|
considerGenSyms(c, n)
|
||||||
|
|
@ -2519,7 +2519,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
discard
|
discard
|
||||||
of nkStaticExpr: result = semStaticExpr(c, n[0])
|
of nkStaticExpr: result = semStaticExpr(c, n[0])
|
||||||
of nkAsgn: result = semAsgn(c, n)
|
of nkAsgn: result = semAsgn(c, n)
|
||||||
of nkBlockStmt, nkBlockExpr: result = semBlock(c, n)
|
of nkBlockStmt, nkBlockExpr: result = semBlock(c, n, flags)
|
||||||
of nkStmtList, nkStmtListExpr: result = semStmtList(c, n, flags)
|
of nkStmtList, nkStmtListExpr: result = semStmtList(c, n, flags)
|
||||||
of nkRaiseStmt: result = semRaise(c, n)
|
of nkRaiseStmt: result = semRaise(c, n)
|
||||||
of nkVarSection: result = semVarOrLet(c, n, skVar)
|
of nkVarSection: result = semVarOrLet(c, n, skVar)
|
||||||
|
|
@ -2527,11 +2527,11 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
of nkConstSection: result = semConst(c, n)
|
of nkConstSection: result = semConst(c, n)
|
||||||
of nkTypeSection: result = semTypeSection(c, n)
|
of nkTypeSection: result = semTypeSection(c, n)
|
||||||
of nkDiscardStmt: result = semDiscard(c, n)
|
of nkDiscardStmt: result = semDiscard(c, n)
|
||||||
of nkWhileStmt: result = semWhile(c, n)
|
of nkWhileStmt: result = semWhile(c, n, flags)
|
||||||
of nkTryStmt: result = semTry(c, n)
|
of nkTryStmt: result = semTry(c, n, flags)
|
||||||
of nkBreakStmt, nkContinueStmt: result = semBreakOrContinue(c, n)
|
of nkBreakStmt, nkContinueStmt: result = semBreakOrContinue(c, n)
|
||||||
of nkForStmt, nkParForStmt: result = semFor(c, n)
|
of nkForStmt, nkParForStmt: result = semFor(c, n, flags)
|
||||||
of nkCaseStmt: result = semCase(c, n)
|
of nkCaseStmt: result = semCase(c, n, flags)
|
||||||
of nkReturnStmt: result = semReturn(c, n)
|
of nkReturnStmt: result = semReturn(c, n)
|
||||||
of nkUsingStmt: result = semUsing(c, n)
|
of nkUsingStmt: result = semUsing(c, n)
|
||||||
of nkAsmStmt: result = semAsm(c, n)
|
of nkAsmStmt: result = semAsm(c, n)
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ proc semForObjectFields(c: TFieldsCtx, typ, forLoop, father: PNode) =
|
||||||
openScope(c.c)
|
openScope(c.c)
|
||||||
inc c.c.inUnrolledContext
|
inc c.c.inUnrolledContext
|
||||||
let body = instFieldLoopBody(fc, lastSon(forLoop), forLoop)
|
let body = instFieldLoopBody(fc, lastSon(forLoop), forLoop)
|
||||||
father.add(semStmt(c.c, body))
|
father.add(semStmt(c.c, body, {}))
|
||||||
dec c.c.inUnrolledContext
|
dec c.c.inUnrolledContext
|
||||||
closeScope(c.c)
|
closeScope(c.c)
|
||||||
of nkNilLit: discard
|
of nkNilLit: discard
|
||||||
|
|
@ -145,7 +145,7 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
|
||||||
fc.replaceByFieldName = m == mFieldPairs
|
fc.replaceByFieldName = m == mFieldPairs
|
||||||
var body = instFieldLoopBody(fc, loopBody, n)
|
var body = instFieldLoopBody(fc, loopBody, n)
|
||||||
inc c.inUnrolledContext
|
inc c.inUnrolledContext
|
||||||
stmts.add(semStmt(c, body))
|
stmts.add(semStmt(c, body, {}))
|
||||||
dec c.inUnrolledContext
|
dec c.inUnrolledContext
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -76,17 +76,19 @@ proc semAsm(c: PContext, n: PNode): PNode =
|
||||||
if marker == '\0': marker = '`' # default marker
|
if marker == '\0': marker = '`' # default marker
|
||||||
result = semAsmOrEmit(c, n, marker)
|
result = semAsmOrEmit(c, n, marker)
|
||||||
|
|
||||||
proc semWhile(c: PContext, n: PNode): PNode =
|
proc semWhile(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
||||||
result = n
|
result = n
|
||||||
checkSonsLen(n, 2, c.config)
|
checkSonsLen(n, 2, c.config)
|
||||||
openScope(c)
|
openScope(c)
|
||||||
n.sons[0] = forceBool(c, semExprWithType(c, n.sons[0]))
|
n.sons[0] = forceBool(c, semExprWithType(c, n.sons[0]))
|
||||||
inc(c.p.nestedLoopCounter)
|
inc(c.p.nestedLoopCounter)
|
||||||
n.sons[1] = semStmt(c, n.sons[1])
|
n.sons[1] = semStmt(c, n.sons[1], flags)
|
||||||
dec(c.p.nestedLoopCounter)
|
dec(c.p.nestedLoopCounter)
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
if n.sons[1].typ == c.enforceVoidContext:
|
if n.sons[1].typ == c.enforceVoidContext:
|
||||||
result.typ = c.enforceVoidContext
|
result.typ = c.enforceVoidContext
|
||||||
|
elif efInTypeof in flags:
|
||||||
|
result.typ = n[1].typ
|
||||||
|
|
||||||
proc toCover(c: PContext, t: PType): BiggestInt =
|
proc toCover(c: PContext, t: PType): BiggestInt =
|
||||||
let t2 = skipTypes(t, abstractVarRange-{tyTypeDesc})
|
let t2 = skipTypes(t, abstractVarRange-{tyTypeDesc})
|
||||||
|
|
@ -97,8 +99,8 @@ proc toCover(c: PContext, t: PType): BiggestInt =
|
||||||
|
|
||||||
proc semProc(c: PContext, n: PNode): PNode
|
proc semProc(c: PContext, n: PNode): PNode
|
||||||
|
|
||||||
proc semExprBranch(c: PContext, n: PNode): PNode =
|
proc semExprBranch(c: PContext, n: PNode; flags: TExprFlags = {}): PNode =
|
||||||
result = semExpr(c, n)
|
result = semExpr(c, n, flags)
|
||||||
if result.typ != nil:
|
if result.typ != nil:
|
||||||
# XXX tyGenericInst here?
|
# XXX tyGenericInst here?
|
||||||
if result.typ.kind in {tyVar, tyLent}: result = newDeref(result)
|
if result.typ.kind in {tyVar, tyLent}: result = newDeref(result)
|
||||||
|
|
@ -130,8 +132,9 @@ proc fixNilType(c: PContext; n: PNode) =
|
||||||
for it in n: fixNilType(c, it)
|
for it in n: fixNilType(c, it)
|
||||||
n.typ = nil
|
n.typ = nil
|
||||||
|
|
||||||
proc discardCheck(c: PContext, result: PNode) =
|
proc discardCheck(c: PContext, result: PNode, flags: TExprFlags) =
|
||||||
if c.matchedConcept != nil: return
|
if c.matchedConcept != nil or efInTypeof in flags: return
|
||||||
|
|
||||||
if result.typ != nil and result.typ.kind notin {tyStmt, tyVoid}:
|
if result.typ != nil and result.typ.kind notin {tyStmt, tyVoid}:
|
||||||
if implicitlyDiscardable(result):
|
if implicitlyDiscardable(result):
|
||||||
var n = newNodeI(nkDiscardStmt, result.info, 1)
|
var n = newNodeI(nkDiscardStmt, result.info, 1)
|
||||||
|
|
@ -148,7 +151,7 @@ proc discardCheck(c: PContext, result: PNode) =
|
||||||
s.add "; for a function call use ()"
|
s.add "; for a function call use ()"
|
||||||
localError(c.config, n.info, s)
|
localError(c.config, n.info, s)
|
||||||
|
|
||||||
proc semIf(c: PContext, n: PNode): PNode =
|
proc semIf(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
||||||
result = n
|
result = n
|
||||||
var typ = commonTypeBegin
|
var typ = commonTypeBegin
|
||||||
var hasElse = false
|
var hasElse = false
|
||||||
|
|
@ -165,8 +168,9 @@ proc semIf(c: PContext, n: PNode): PNode =
|
||||||
it.sons[0] = semExprBranchScope(c, it.sons[0])
|
it.sons[0] = semExprBranchScope(c, it.sons[0])
|
||||||
typ = commonType(typ, it.sons[0])
|
typ = commonType(typ, it.sons[0])
|
||||||
else: illFormedAst(it, c.config)
|
else: illFormedAst(it, c.config)
|
||||||
if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or not hasElse:
|
if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or
|
||||||
for it in n: discardCheck(c, it.lastSon)
|
(not hasElse and efInTypeof notin flags):
|
||||||
|
for it in n: discardCheck(c, it.lastSon, flags)
|
||||||
result.kind = nkIfStmt
|
result.kind = nkIfStmt
|
||||||
# propagate any enforced VoidContext:
|
# propagate any enforced VoidContext:
|
||||||
if typ == c.enforceVoidContext: result.typ = c.enforceVoidContext
|
if typ == c.enforceVoidContext: result.typ = c.enforceVoidContext
|
||||||
|
|
@ -178,8 +182,7 @@ proc semIf(c: PContext, n: PNode): PNode =
|
||||||
result.kind = nkIfExpr
|
result.kind = nkIfExpr
|
||||||
result.typ = typ
|
result.typ = typ
|
||||||
|
|
||||||
proc semTry(c: PContext, n: PNode): PNode =
|
proc semTry(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
||||||
|
|
||||||
var check = initIntSet()
|
var check = initIntSet()
|
||||||
template semExceptBranchType(typeNode: PNode): bool =
|
template semExceptBranchType(typeNode: PNode): bool =
|
||||||
# returns true if exception type is imported type
|
# returns true if exception type is imported type
|
||||||
|
|
@ -246,12 +249,12 @@ proc semTry(c: PContext, n: PNode): PNode =
|
||||||
|
|
||||||
dec c.p.inTryStmt
|
dec c.p.inTryStmt
|
||||||
if isEmptyType(typ) or typ.kind in {tyNil, tyExpr}:
|
if isEmptyType(typ) or typ.kind in {tyNil, tyExpr}:
|
||||||
discardCheck(c, n.sons[0])
|
discardCheck(c, n.sons[0], flags)
|
||||||
for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon)
|
for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon, flags)
|
||||||
if typ == c.enforceVoidContext:
|
if typ == c.enforceVoidContext:
|
||||||
result.typ = c.enforceVoidContext
|
result.typ = c.enforceVoidContext
|
||||||
else:
|
else:
|
||||||
if n.lastSon.kind == nkFinally: discardCheck(c, n.lastSon.lastSon)
|
if n.lastSon.kind == nkFinally: discardCheck(c, n.lastSon.lastSon, flags)
|
||||||
n.sons[0] = fitNode(c, typ, n.sons[0], n.sons[0].info)
|
n.sons[0] = fitNode(c, typ, n.sons[0], n.sons[0].info)
|
||||||
for i in 1..last:
|
for i in 1..last:
|
||||||
var it = n.sons[i]
|
var it = n.sons[i]
|
||||||
|
|
@ -570,7 +573,7 @@ proc symForVar(c: PContext, n: PNode): PSym =
|
||||||
if n.kind == nkPragmaExpr:
|
if n.kind == nkPragmaExpr:
|
||||||
pragma(c, result, n.sons[1], forVarPragmas)
|
pragma(c, result, n.sons[1], forVarPragmas)
|
||||||
|
|
||||||
proc semForVars(c: PContext, n: PNode): PNode =
|
proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
||||||
result = n
|
result = n
|
||||||
var length = sonsLen(n)
|
var length = sonsLen(n)
|
||||||
let iterBase = n.sons[length-2].typ
|
let iterBase = n.sons[length-2].typ
|
||||||
|
|
@ -601,7 +604,7 @@ proc semForVars(c: PContext, n: PNode): PNode =
|
||||||
addForVarDecl(c, v)
|
addForVarDecl(c, v)
|
||||||
inc(c.p.nestedLoopCounter)
|
inc(c.p.nestedLoopCounter)
|
||||||
openScope(c)
|
openScope(c)
|
||||||
n.sons[length-1] = semStmt(c, n.sons[length-1])
|
n.sons[length-1] = semExprBranch(c, n.sons[length-1], flags)
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
dec(c.p.nestedLoopCounter)
|
dec(c.p.nestedLoopCounter)
|
||||||
|
|
||||||
|
|
@ -685,7 +688,7 @@ proc handleCaseStmtMacro(c: PContext; n: PNode): PNode =
|
||||||
when false:
|
when false:
|
||||||
result = handleStmtMacro(c, n, n[0], "CaseStmt")
|
result = handleStmtMacro(c, n, n[0], "CaseStmt")
|
||||||
|
|
||||||
proc semFor(c: PContext, n: PNode): PNode =
|
proc semFor(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
||||||
checkMinSonsLen(n, 3, c.config)
|
checkMinSonsLen(n, 3, c.config)
|
||||||
var length = sonsLen(n)
|
var length = sonsLen(n)
|
||||||
if forLoopMacros in c.features:
|
if forLoopMacros in c.features:
|
||||||
|
|
@ -702,14 +705,14 @@ proc semFor(c: PContext, n: PNode): PNode =
|
||||||
if isCallExpr and call[0].kind == nkSym and
|
if isCallExpr and call[0].kind == nkSym and
|
||||||
call[0].sym.magic in {mFields, mFieldPairs, mOmpParFor}:
|
call[0].sym.magic in {mFields, mFieldPairs, mOmpParFor}:
|
||||||
if call.sons[0].sym.magic == mOmpParFor:
|
if call.sons[0].sym.magic == mOmpParFor:
|
||||||
result = semForVars(c, n)
|
result = semForVars(c, n, flags)
|
||||||
result.kind = nkParForStmt
|
result.kind = nkParForStmt
|
||||||
else:
|
else:
|
||||||
result = semForFields(c, n, call.sons[0].sym.magic)
|
result = semForFields(c, n, call.sons[0].sym.magic)
|
||||||
elif isCallExpr and call.sons[0].typ.callConv == ccClosure and
|
elif isCallExpr and call.sons[0].typ.callConv == ccClosure and
|
||||||
tfIterator in call.sons[0].typ.flags:
|
tfIterator in call.sons[0].typ.flags:
|
||||||
# first class iterator:
|
# first class iterator:
|
||||||
result = semForVars(c, n)
|
result = semForVars(c, n, flags)
|
||||||
elif not isCallExpr or call.sons[0].kind != nkSym or
|
elif not isCallExpr or call.sons[0].kind != nkSym or
|
||||||
call.sons[0].sym.kind != skIterator:
|
call.sons[0].sym.kind != skIterator:
|
||||||
if length == 3:
|
if length == 3:
|
||||||
|
|
@ -718,15 +721,17 @@ proc semFor(c: PContext, n: PNode): PNode =
|
||||||
n.sons[length-2] = implicitIterator(c, "pairs", n.sons[length-2])
|
n.sons[length-2] = implicitIterator(c, "pairs", n.sons[length-2])
|
||||||
else:
|
else:
|
||||||
localError(c.config, n.sons[length-2].info, "iterator within for loop context expected")
|
localError(c.config, n.sons[length-2].info, "iterator within for loop context expected")
|
||||||
result = semForVars(c, n)
|
result = semForVars(c, n, flags)
|
||||||
else:
|
else:
|
||||||
result = semForVars(c, n)
|
result = semForVars(c, n, flags)
|
||||||
# propagate any enforced VoidContext:
|
# propagate any enforced VoidContext:
|
||||||
if n.sons[length-1].typ == c.enforceVoidContext:
|
if n.sons[length-1].typ == c.enforceVoidContext:
|
||||||
result.typ = c.enforceVoidContext
|
result.typ = c.enforceVoidContext
|
||||||
|
elif efInTypeof in flags:
|
||||||
|
result.typ = result.lastSon.typ
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
|
|
||||||
proc semCase(c: PContext, n: PNode): PNode =
|
proc semCase(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
||||||
result = n
|
result = n
|
||||||
checkMinSonsLen(n, 2, c.config)
|
checkMinSonsLen(n, 2, c.config)
|
||||||
openScope(c)
|
openScope(c)
|
||||||
|
|
@ -782,8 +787,9 @@ proc semCase(c: PContext, n: PNode): PNode =
|
||||||
else:
|
else:
|
||||||
localError(c.config, n.info, "not all cases are covered")
|
localError(c.config, n.info, "not all cases are covered")
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or not hasElse:
|
if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or
|
||||||
for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon)
|
(not hasElse and efInTypeof notin flags):
|
||||||
|
for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon, flags)
|
||||||
# propagate any enforced VoidContext:
|
# propagate any enforced VoidContext:
|
||||||
if typ == c.enforceVoidContext:
|
if typ == c.enforceVoidContext:
|
||||||
result.typ = c.enforceVoidContext
|
result.typ = c.enforceVoidContext
|
||||||
|
|
@ -1795,7 +1801,7 @@ proc evalInclude(c: PContext, n: PNode): PNode =
|
||||||
if containsOrIncl(c.includedFiles, f.int):
|
if containsOrIncl(c.includedFiles, f.int):
|
||||||
localError(c.config, n.info, errRecursiveDependencyX % toFilename(c.config, f))
|
localError(c.config, n.info, errRecursiveDependencyX % toFilename(c.config, f))
|
||||||
else:
|
else:
|
||||||
addSon(result, semStmt(c, c.graph.includeFileCallback(c.graph, c.module, f)))
|
addSon(result, semStmt(c, c.graph.includeFileCallback(c.graph, c.module, f), {}))
|
||||||
excl(c.includedFiles, f.int)
|
excl(c.includedFiles, f.int)
|
||||||
|
|
||||||
proc setLine(n: PNode, info: TLineInfo) =
|
proc setLine(n: PNode, info: TLineInfo) =
|
||||||
|
|
@ -1822,7 +1828,7 @@ proc semStaticStmt(c: PContext, n: PNode): PNode =
|
||||||
#writeStackTrace()
|
#writeStackTrace()
|
||||||
inc c.inStaticContext
|
inc c.inStaticContext
|
||||||
openScope(c)
|
openScope(c)
|
||||||
let a = semStmt(c, n.sons[0])
|
let a = semStmt(c, n.sons[0], {})
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
dec c.inStaticContext
|
dec c.inStaticContext
|
||||||
n.sons[0] = a
|
n.sons[0] = a
|
||||||
|
|
@ -1898,11 +1904,11 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
if n.sons[i].typ == c.enforceVoidContext: #or usesResult(n.sons[i]):
|
if n.sons[i].typ == c.enforceVoidContext: #or usesResult(n.sons[i]):
|
||||||
voidContext = true
|
voidContext = true
|
||||||
n.typ = c.enforceVoidContext
|
n.typ = c.enforceVoidContext
|
||||||
if i == last and (length == 1 or efWantValue in flags):
|
if i == last and (length == 1 or ({efWantValue, efInTypeof} * flags != {})):
|
||||||
n.typ = n.sons[i].typ
|
n.typ = n.sons[i].typ
|
||||||
if not isEmptyType(n.typ): n.kind = nkStmtListExpr
|
if not isEmptyType(n.typ): n.kind = nkStmtListExpr
|
||||||
elif i != last or voidContext:
|
elif i != last or voidContext:
|
||||||
discardCheck(c, n.sons[i])
|
discardCheck(c, n.sons[i], flags)
|
||||||
else:
|
else:
|
||||||
n.typ = n.sons[i].typ
|
n.typ = n.sons[i].typ
|
||||||
if not isEmptyType(n.typ): n.kind = nkStmtListExpr
|
if not isEmptyType(n.typ): n.kind = nkStmtListExpr
|
||||||
|
|
@ -1931,6 +1937,8 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
# it is an old-style comment statement: we replace it with 'discard ""':
|
# it is an old-style comment statement: we replace it with 'discard ""':
|
||||||
prettybase.replaceComment(result.info)
|
prettybase.replaceComment(result.info)
|
||||||
|
|
||||||
proc semStmt(c: PContext, n: PNode): PNode =
|
proc semStmt(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
||||||
# now: simply an alias:
|
if efInTypeof notin flags:
|
||||||
result = semExprNoType(c, n)
|
result = semExprNoType(c, n)
|
||||||
|
else:
|
||||||
|
result = semExpr(c, n, flags)
|
||||||
|
|
|
||||||
|
|
@ -1161,7 +1161,7 @@ proc semStmtListType(c: PContext, n: PNode, prev: PType): PType =
|
||||||
checkMinSonsLen(n, 1, c.config)
|
checkMinSonsLen(n, 1, c.config)
|
||||||
var length = sonsLen(n)
|
var length = sonsLen(n)
|
||||||
for i in countup(0, length - 2):
|
for i in countup(0, length - 2):
|
||||||
n.sons[i] = semStmt(c, n.sons[i])
|
n.sons[i] = semStmt(c, n.sons[i], {})
|
||||||
if length > 0:
|
if length > 0:
|
||||||
result = semTypeNode(c, n.sons[length - 1], prev)
|
result = semTypeNode(c, n.sons[length - 1], prev)
|
||||||
n.typ = result
|
n.typ = result
|
||||||
|
|
@ -1406,6 +1406,13 @@ proc semStaticType(c: PContext, childNode: PNode, prev: PType): PType =
|
||||||
result.rawAddSon(base)
|
result.rawAddSon(base)
|
||||||
result.flags.incl tfHasStatic
|
result.flags.incl tfHasStatic
|
||||||
|
|
||||||
|
proc semTypeof(c: PContext; n: PNode; prev: PType): PType =
|
||||||
|
openScope(c)
|
||||||
|
let t = semExprWithType(c, n, {efInTypeof})
|
||||||
|
closeScope(c)
|
||||||
|
fixupTypeOf(c, prev, t)
|
||||||
|
result = t.typ
|
||||||
|
|
||||||
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
result = nil
|
result = nil
|
||||||
inc c.inTypeContext
|
inc c.inTypeContext
|
||||||
|
|
@ -1416,9 +1423,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
of nkTypeOfExpr:
|
of nkTypeOfExpr:
|
||||||
# for ``type(countup(1,3))``, see ``tests/ttoseq``.
|
# for ``type(countup(1,3))``, see ``tests/ttoseq``.
|
||||||
checkSonsLen(n, 1, c.config)
|
checkSonsLen(n, 1, c.config)
|
||||||
let typExpr = semExprWithType(c, n.sons[0], {efInTypeof})
|
result = semTypeof(c, n.sons[0], prev)
|
||||||
fixupTypeOf(c, prev, typExpr)
|
|
||||||
result = typExpr.typ
|
|
||||||
if result.kind == tyTypeDesc: result.flags.incl tfExplicit
|
if result.kind == tyTypeDesc: result.flags.incl tfExplicit
|
||||||
of nkPar:
|
of nkPar:
|
||||||
if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
|
if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
|
||||||
|
|
@ -1487,9 +1492,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
result = semAnyRef(c, n, tyRef, prev)
|
result = semAnyRef(c, n, tyRef, prev)
|
||||||
elif op.id == ord(wType):
|
elif op.id == ord(wType):
|
||||||
checkSonsLen(n, 2, c.config)
|
checkSonsLen(n, 2, c.config)
|
||||||
let typExpr = semExprWithType(c, n.sons[1], {efInTypeof})
|
result = semTypeof(c, n[1], prev)
|
||||||
fixupTypeOf(c, prev, typExpr)
|
|
||||||
result = typExpr.typ
|
|
||||||
else:
|
else:
|
||||||
if c.inGenericContext > 0 and n.kind == nkCall:
|
if c.inGenericContext > 0 and n.kind == nkCall:
|
||||||
result = makeTypeFromExpr(c, n.copyTree)
|
result = makeTypeFromExpr(c, n.copyTree)
|
||||||
|
|
|
||||||
|
|
@ -240,7 +240,7 @@ else: # bootstrapping substitute
|
||||||
when defined(nimHasSymOwnerInMacro):
|
when defined(nimHasSymOwnerInMacro):
|
||||||
proc owner*(sym: NimNode): NimNode {.magic: "SymOwner", noSideEffect.}
|
proc owner*(sym: NimNode): NimNode {.magic: "SymOwner", noSideEffect.}
|
||||||
## accepts node of kind nnkSym and returns its owner's symbol.
|
## accepts node of kind nnkSym and returns its owner's symbol.
|
||||||
## result is also mnde of kind nnkSym if owner exists otherwise
|
## result is also mnde of kind nnkSym if owner exists otherwise
|
||||||
## nnkNilLit is returned
|
## nnkNilLit is returned
|
||||||
|
|
||||||
proc getType*(n: NimNode): NimNode {.magic: "NGetType", noSideEffect.}
|
proc getType*(n: NimNode): NimNode {.magic: "NGetType", noSideEffect.}
|
||||||
|
|
@ -977,7 +977,7 @@ proc newIfStmt*(branches: varargs[tuple[cond, body: NimNode]]):
|
||||||
##
|
##
|
||||||
result = newNimNode(nnkIfStmt)
|
result = newNimNode(nnkIfStmt)
|
||||||
for i in branches:
|
for i in branches:
|
||||||
result.add(newNimNode(nnkElifBranch).add(i.cond, i.body))
|
result.add(newTree(nnkElifBranch, i.cond, i.body))
|
||||||
|
|
||||||
proc newEnum*(name: NimNode, fields: openArray[NimNode],
|
proc newEnum*(name: NimNode, fields: openArray[NimNode],
|
||||||
public, pure: bool): NimNode {.compileTime.} =
|
public, pure: bool): NimNode {.compileTime.} =
|
||||||
|
|
|
||||||
63
tests/macros/tcollect.nim
Normal file
63
tests/macros/tcollect.nim
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
discard """
|
||||||
|
output: '''@[2, 3, 4, 2, 3, 4, 2, 3, 4, 2, 3, 4, 2, 3, 4]
|
||||||
|
@[0, 1, 2, 3]'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
const data = [1,2,3,4,5,6]
|
||||||
|
|
||||||
|
import macros
|
||||||
|
|
||||||
|
macro collect(body): untyped =
|
||||||
|
# analyse the body, find the deepest expression 'it' and replace it via
|
||||||
|
# 'result.add it'
|
||||||
|
let res = genSym(nskVar, "collectResult")
|
||||||
|
|
||||||
|
when false:
|
||||||
|
proc detectForLoopVar(n: NimNode): NimNode =
|
||||||
|
if n.kind == nnkForStmt:
|
||||||
|
result = n[0]
|
||||||
|
else:
|
||||||
|
for x in n:
|
||||||
|
result = detectForLoopVar(x)
|
||||||
|
if result != nil: return result
|
||||||
|
return nil
|
||||||
|
|
||||||
|
proc t(n, res: NimNode): NimNode =
|
||||||
|
case n.kind
|
||||||
|
of nnkStmtList, nnkStmtListExpr, nnkBlockStmt, nnkBlockExpr,
|
||||||
|
nnkWhileStmt,
|
||||||
|
nnkForStmt, nnkIfExpr, nnkIfStmt, nnkTryStmt, nnkCaseStmt,
|
||||||
|
nnkElifBranch, nnkElse, nnkElifExpr:
|
||||||
|
result = copyNimTree(n)
|
||||||
|
if n.len >= 1:
|
||||||
|
result[^1] = t(n[^1], res)
|
||||||
|
else:
|
||||||
|
if true: #n == it:
|
||||||
|
template adder(res, it) =
|
||||||
|
res.add it
|
||||||
|
result = getAst adder(res, n)
|
||||||
|
else:
|
||||||
|
result = n
|
||||||
|
|
||||||
|
when false:
|
||||||
|
let it = detectForLoopVar(body)
|
||||||
|
if it == nil: error("no for loop in body", body)
|
||||||
|
|
||||||
|
let v = newTree(nnkVarSection,
|
||||||
|
newTree(nnkIdentDefs, res, newTree(nnkBracketExpr, bindSym"seq",
|
||||||
|
newCall(bindSym"type", body)), newEmptyNode()))
|
||||||
|
|
||||||
|
result = newTree(nnkStmtListExpr, v, t(body, res), res)
|
||||||
|
#echo repr result
|
||||||
|
|
||||||
|
let stuff = collect:
|
||||||
|
var i = -1
|
||||||
|
while i < 4:
|
||||||
|
inc i
|
||||||
|
for it in data:
|
||||||
|
if it < 5 and it > 1:
|
||||||
|
it
|
||||||
|
|
||||||
|
echo stuff
|
||||||
|
|
||||||
|
echo collect(for i in 0..3: i)
|
||||||
Loading…
Add table
Add a link
Reference in a new issue