From b38eb2e2a84537c315f28e9f823c10363be8cdb1 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 31 Mar 2015 00:39:23 +0100 Subject: [PATCH] Implements #2154. When unpacking tuples in var/let declarations a part of the tuple can now be discarded using a single underscore. --- compiler/ast.nim | 1 + compiler/docgen.nim | 3 ++- compiler/lexer.nim | 6 +++++- compiler/lookups.nim | 1 + compiler/parser.nim | 10 ++++++++-- compiler/renderer.nim | 3 ++- compiler/semstmts.nim | 3 ++- tests/parser/ttupleunpack.nim | 18 ++++++++++++++++++ 8 files changed, 39 insertions(+), 6 deletions(-) create mode 100644 tests/parser/ttupleunpack.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index 10f2a71da2..8ff38a12fb 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -221,6 +221,7 @@ type nkGotoState, # used for the state machine (for iterators) nkState, # give a label to a code section (for iterators) nkBreakState, # special break statement for easier code generation + nkUnderscore, # underscore inside a tuple unpack ``(_, x) = foo()`` TNodeKinds* = set[TNodeKind] type diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 4af69745be..4145883d6d 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -384,7 +384,8 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) = tkBracketDotLe, tkBracketDotRi, tkCurlyDotLe, tkCurlyDotRi, tkParDotLe, tkParDotRi, tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot, tkAccent, tkColonColon, - tkGStrLit, tkGTripleStrLit, tkInfixOpr, tkPrefixOpr, tkPostfixOpr: + tkGStrLit, tkGTripleStrLit, tkInfixOpr, tkPrefixOpr, tkPostfixOpr, + tkUnderscore: dispA(result, "$1", "\\spanOther{$1}", [toRope(esc(d.target, literal))]) inc(d.id) diff --git a/compiler/lexer.nim b/compiler/lexer.nim index 78266ef4d3..5d98b872b2 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -62,6 +62,7 @@ type tkColon, tkColonColon, tkEquals, tkDot, tkDotDot, tkOpr, tkComment, tkAccent, tkSpaces, tkInfixOpr, tkPrefixOpr, tkPostfixOpr, + tkUnderscore TTokTypes* = set[TTokType] @@ -96,7 +97,7 @@ const ":", "::", "=", ".", "..", "tkOpr", "tkComment", "`", "tkSpaces", "tkInfixOpr", - "tkPrefixOpr", "tkPostfixOpr"] + "tkPrefixOpr", "tkPostfixOpr", "_"] type TNumericalBase* = enum @@ -874,6 +875,9 @@ proc rawGetTok(L: var TLexer, tok: var TToken) = of '`': tok.tokType = tkAccent inc(L.bufpos) + of '_': + tok.tokType = tkUnderscore + inc(L.bufpos) of '\"': # check for extended raw string literal: var rawMode = L.bufpos > 0 and L.buf[L.bufpos-1] in SymChars diff --git a/compiler/lookups.nim b/compiler/lookups.nim index 88e32404af..8cfb5ed250 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -20,6 +20,7 @@ proc considerQuotedIdent*(n: PNode): PIdent = case n.kind of nkIdent: result = n.ident of nkSym: result = n.sym.name + of nkUnderscore: result = getIdent"_" of nkAccQuoted: case n.len of 0: diff --git a/compiler/parser.nim b/compiler/parser.nim index dcd5401e8a..0b2619b01d 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -296,12 +296,15 @@ proc colcom(p: var TParser, n: PNode) = skipComment(p, n) proc parseSymbol(p: var TParser, allowNil = false): PNode = - #| symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`' + #| symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'='|'_')+)+ '`' #| | IDENT | 'addr' | 'type' case p.tok.tokType of tkSymbol, tkAddr, tkType: result = newIdentNodeP(p.tok.ident, p) getTok(p) + of tkUnderscore: + result = newNodeP(nkUnderscore, p) + getTok(p) of tkAccent: result = newNodeP(nkAccQuoted, p) getTok(p) @@ -643,6 +646,9 @@ proc identOrLiteral(p: var TParser, mode: TPrimaryMode): PNode = of tkNil: result = newNodeP(nkNilLit, p) getTok(p) + of tkUnderscore: + result = newNodeP(nkUnderscore, p) + getTok(p) of tkParLe: # () constructor if mode in {pmTypeDesc, pmTypeDef}: @@ -1814,7 +1820,7 @@ proc parseVarTuple(p: var TParser): PNode = result = newNodeP(nkVarTuple, p) getTok(p) # skip '(' optInd(p, result) - while p.tok.tokType in {tkSymbol, tkAccent}: + while p.tok.tokType in {tkSymbol, tkAccent, tkUnderscore}: var a = identWithPragma(p) addSon(result, a) if p.tok.tokType != tkComma: break diff --git a/compiler/renderer.nim b/compiler/renderer.nim index ce818e3cd6..2e614dde08 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -349,6 +349,7 @@ proc atom(n: PNode): string = else: result = litAux(n, (cast[PInt64](addr(n.floatVal)))[], 8) & "\'f64" of nkNilLit: result = "nil" + of nkUnderscore: result = "_" of nkType: if (n.typ != nil) and (n.typ.sym != nil): result = n.typ.sym.name.s else: result = "[type node]" @@ -805,7 +806,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = of nkTripleStrLit: putRawStr(g, tkTripleStrLit, n.strVal) of nkEmpty: discard of nkType: put(g, tkInvalid, atom(n)) - of nkSym, nkIdent: gident(g, n) + of nkSym, nkIdent, nkUnderscore: gident(g, n) of nkIntLit: put(g, tkIntLit, atom(n)) of nkInt8Lit: put(g, tkInt8Lit, atom(n)) of nkInt16Lit: put(g, tkInt16Lit, atom(n)) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 7263b21b9a..5b7cca338f 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -403,7 +403,8 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = for j in countup(0, length-3): var v = semIdentDef(c, a.sons[j], symkind) - if sfGenSym notin v.flags: addInterfaceDecl(c, v) + if sfGenSym notin v.flags and + a.sons[j].kind != nkUnderscore: addInterfaceDecl(c, v) when oKeepVariableNames: if c.inUnrolledContext > 0: v.flags.incl(sfShadowed) else: diff --git a/tests/parser/ttupleunpack.nim b/tests/parser/ttupleunpack.nim new file mode 100644 index 0000000000..0479871e8b --- /dev/null +++ b/tests/parser/ttupleunpack.nim @@ -0,0 +1,18 @@ +discard """ + file: "ttupleunpack.nim" + output: "" + exitcode: 0 +""" +proc foo(): tuple[x, y, z: int] = + return (4, 2, 3) + +var (x, _, y) = foo() +doAssert x == 4 +doAssert y == 3 + +iterator bar(): tuple[x, y, z: int] = + yield (1,2,3) + +for x, y, _ in bar(): + doAssert x == 1 + doAssert y == 2