Const tuple unpacking (#9964)

* tuple unpacking is now supported for consts

* Move nkConstTuple to the end of TNodeKind

* Add nnkConstTuple in macros.nim

* Fix Formatting
This commit is contained in:
Neelesh Chandola 2018-12-19 15:22:41 +05:30 • committed by Andreas Rumpf
commit 8e90ed0618
4 changed files with 77 additions and 31 deletions

View file

@ -222,7 +222,8 @@ type
nkState, # give a label to a code section (for iterators) nkState, # give a label to a code section (for iterators)
nkBreakState, # special break statement for easier code generation nkBreakState, # special break statement for easier code generation
nkFuncDef, # a func nkFuncDef, # a func
nkTupleConstr # a tuple constructor nkTupleConstr, # a tuple constructor
nkConstTuple # a ``const (a, b) = expr`` construct
TNodeKinds* = set[TNodeKind] TNodeKinds* = set[TNodeKind]

View file

@ -1764,8 +1764,30 @@ proc parseSection(p: var TParser, kind: TNodeKind,
else: else:
parMessage(p, errIdentifierExpected, p.tok) parMessage(p, errIdentifierExpected, p.tok)
proc parseConstTuple(p: var TParser): PNode =
result = newNodeP(nkConstTuple, p)
getTok(p) # skip '('
optInd(p, result)
while p.tok.tokType in {tkSymbol, tkAccent}:
addSon(result, identWithPragma(p))
if p.tok.tokType == tkColon:
getTok(p)
optInd(p, result)
addSon(result, parseTypeDesc(p))
if p.tok.tokType != tkComma: break
getTok(p)
addSon(result, p.emptyNode)
eat(p, tkParRi)
eat(p, tkEquals)
optInd(p, result)
addSon(result, parseExpr(p))
indAndComment(p, result)
proc parseConstant(p: var TParser): PNode = proc parseConstant(p: var TParser): PNode =
#| constant = identWithPragma (colon typeDesc)? '=' optInd expr indAndComment #| constant = identWithPragma (colon typeDesc)? '=' optInd expr indAndComment
if p.tok.tokType == tkParLe: result = parseConstTuple(p)
else:
result = newNodeP(nkConstDef, p) result = newNodeP(nkConstDef, p)
addSon(result, identWithPragma(p)) addSon(result, identWithPragma(p))
if p.tok.tokType == tkColon: if p.tok.tokType == tkColon:

View file

@ -542,17 +542,17 @@ proc semConst(c: PContext, n: PNode): PNode =
var a = n.sons[i] var a = n.sons[i]
if c.config.cmd == cmdIdeTools: suggestStmt(c, a) if c.config.cmd == cmdIdeTools: suggestStmt(c, a)
if a.kind == nkCommentStmt: continue if a.kind == nkCommentStmt: continue
if a.kind != nkConstDef: illFormedAst(a, c.config) if a.kind notin {nkConstDef, nkConstTuple}: illFormedAst(a, c.config)
checkSonsLen(a, 3, c.config) checkMinSonsLen(a, 3, c.config)
var v = semIdentDef(c, a.sons[0], skConst) var length = sonsLen(a)
styleCheckDef(c.config, v)
onDef(a[0].info, v)
var typ: PType = nil
if a.sons[1].kind != nkEmpty: typ = semTypeNode(c, a.sons[1], nil)
var def = semConstExpr(c, a.sons[2]) var typ: PType = nil
if a.sons[length-2].kind != nkEmpty:
typ = semTypeNode(c, a.sons[length-2], nil)
var def = semConstExpr(c, a.sons[length-1])
if def == nil: if def == nil:
localError(c.config, a.sons[2].info, errConstExprExpected) localError(c.config, a.sons[length-1].info, errConstExprExpected)
continue continue
# check type compatibility between def.typ and typ: # check type compatibility between def.typ and typ:
if typ != nil: if typ != nil:
@ -560,20 +560,42 @@ proc semConst(c: PContext, n: PNode): PNode =
else: else:
typ = def.typ typ = def.typ
if typ == nil: if typ == nil:
localError(c.config, a.sons[2].info, errConstExprExpected) localError(c.config, a.sons[length-1].info, errConstExprExpected)
continue continue
if typeAllowed(typ, skConst) != nil and def.kind != nkNilLit: if typeAllowed(typ, skConst) != nil and def.kind != nkNilLit:
localError(c.config, a.info, "invalid type for const: " & typeToString(typ)) localError(c.config, a.info, "invalid type for const: " & typeToString(typ))
continue continue
setVarType(c, v, typ)
v.ast = def # no need to copy var b: PNode
if a.kind == nkConstTuple:
if typ.kind != tyTuple:
localError(c.config, a.info, errXExpected, "tuple")
elif int(length/2) != sonsLen(typ):
localError(c.config, a.info, errWrongNumberOfVariables)
b = newNodeI(nkConstTuple, a.info)
newSons(b, length)
b.sons[length-2] = a.sons[length-2]
b.sons[length-1] = def
for j in countup(0, length-3):
var v = semIdentDef(c, a.sons[j], skConst)
if sfGenSym notin v.flags: addInterfaceDecl(c, v) if sfGenSym notin v.flags: addInterfaceDecl(c, v)
elif v.owner == nil: v.owner = getCurrOwner(c) elif v.owner == nil: v.owner = getCurrOwner(c)
var b = newNodeI(nkConstDef, a.info) styleCheckDef(c.config, v)
onDef(a[j].info, v)
if a.kind != nkConstTuple:
setVarType(c, v, typ)
v.ast = def # no need to copy
b = newNodeI(nkConstDef, a.info)
if importantComments(c.config): b.comment = a.comment if importantComments(c.config): b.comment = a.comment
addSon(b, newSymNode(v)) addSon(b, newSymNode(v))
addSon(b, a.sons[1]) addSon(b, a.sons[1])
addSon(b, copyTree(def)) addSon(b, copyTree(def))
else:
setVarType(c, v, typ.sons[j])
v.ast = def[j]
b.sons[j] = newSymNode(v)
addSon(result,b) addSon(result,b)
include semfields include semfields

View file

@ -81,7 +81,8 @@ type
nnkState, nnkState,
nnkBreakState, nnkBreakState,
nnkFuncDef, nnkFuncDef,
nnkTupleConstr nnkTupleConstr,
nnkConstTuple
NimNodeKinds* = set[NimNodeKind] NimNodeKinds* = set[NimNodeKind]
NimTypeKind* = enum # some types are no longer used, see ast.nim NimTypeKind* = enum # some types are no longer used, see ast.nim