unify tuple expressions (#13793)
* unify tuple expressions * fix test * fix test * apply feedback * Handle empty tuples * Fix rendering named unary tuple * Protect static NimNode against stripping * Slightly less hacky * Revert "Slightly less hacky" This reverts commit 170c5aec0addc029f637afbc948700ca006b7942. * Slightly less hacky * Cleanup * Fix test * Fix another test * Add condsym * Rebase fallout * changelog: Move from compiler changes to language changes * Add stricter tests * Add empty tuple example to doc/astspec * Fix test Co-authored-by: Clyybber <darkmine956@gmail.com>
This commit is contained in:
parent
35655cd189
commit
159c06e045
13 changed files with 136 additions and 32 deletions
|
|
@ -274,6 +274,9 @@
|
||||||
|
|
||||||
- Custom numeric literals (e.g. `-128'bignum`) are now supported.
|
- Custom numeric literals (e.g. `-128'bignum`) are now supported.
|
||||||
|
|
||||||
|
- Tuple expressions are now parsed consistently as
|
||||||
|
`nnkTupleConstr` node. Will affect macros expecting nodes to be of `nnkPar`.
|
||||||
|
|
||||||
|
|
||||||
## Compiler changes
|
## Compiler changes
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -131,3 +131,4 @@ proc initDefines*(symbols: StringTableRef) =
|
||||||
defineSymbol("nimHasHintAsError")
|
defineSymbol("nimHasHintAsError")
|
||||||
defineSymbol("nimHasSpellSuggest")
|
defineSymbol("nimHasSpellSuggest")
|
||||||
defineSymbol("nimHasCustomLiterals")
|
defineSymbol("nimHasCustomLiterals")
|
||||||
|
defineSymbol("nimHasUnifiedTuple")
|
||||||
|
|
|
||||||
|
|
@ -421,10 +421,9 @@ proc exprColonEqExprListAux(p: var Parser, endTok: TokType, result: PNode) =
|
||||||
var a = exprColonEqExpr(p)
|
var a = exprColonEqExpr(p)
|
||||||
result.add(a)
|
result.add(a)
|
||||||
if p.tok.tokType != tkComma: break
|
if p.tok.tokType != tkComma: break
|
||||||
getTok(p)
|
elif result.kind == nkPar:
|
||||||
# (1,) produces a tuple expression
|
|
||||||
if endTok == tkParRi and p.tok.tokType == tkParRi and result.kind == nkPar:
|
|
||||||
result.transitionSonsKind(nkTupleConstr)
|
result.transitionSonsKind(nkTupleConstr)
|
||||||
|
getTok(p)
|
||||||
skipComment(p, a)
|
skipComment(p, a)
|
||||||
optPar(p)
|
optPar(p)
|
||||||
eat(p, endTok)
|
eat(p, endTok)
|
||||||
|
|
@ -584,7 +583,10 @@ proc parsePar(p: var Parser): PNode =
|
||||||
semiStmtList(p, result)
|
semiStmtList(p, result)
|
||||||
elif p.tok.tokType == tkCurlyDotLe:
|
elif p.tok.tokType == tkCurlyDotLe:
|
||||||
result.add(parseStmtPragma(p))
|
result.add(parseStmtPragma(p))
|
||||||
elif p.tok.tokType != tkParRi:
|
elif p.tok.tokType == tkParRi:
|
||||||
|
# Empty tuple '()'
|
||||||
|
result.transitionSonsKind(nkTupleConstr)
|
||||||
|
else:
|
||||||
var a = simpleExpr(p)
|
var a = simpleExpr(p)
|
||||||
if p.tok.tokType == tkDo:
|
if p.tok.tokType == tkDo:
|
||||||
result = postExprBlocks(p, a)
|
result = postExprBlocks(p, a)
|
||||||
|
|
@ -605,13 +607,14 @@ proc parsePar(p: var Parser): PNode =
|
||||||
semiStmtList(p, result)
|
semiStmtList(p, result)
|
||||||
else:
|
else:
|
||||||
a = colonOrEquals(p, a)
|
a = colonOrEquals(p, a)
|
||||||
|
if a.kind == nkExprColonExpr:
|
||||||
|
result.transitionSonsKind(nkTupleConstr)
|
||||||
result.add(a)
|
result.add(a)
|
||||||
if p.tok.tokType == tkComma:
|
if p.tok.tokType == tkComma:
|
||||||
getTok(p)
|
getTok(p)
|
||||||
skipComment(p, a)
|
skipComment(p, a)
|
||||||
# (1,) produces a tuple expression:
|
# (1,) produces a tuple expression:
|
||||||
if p.tok.tokType == tkParRi:
|
result.transitionSonsKind(nkTupleConstr)
|
||||||
result.transitionSonsKind(nkTupleConstr)
|
|
||||||
# progress guaranteed
|
# progress guaranteed
|
||||||
while p.tok.tokType != tkParRi and p.tok.tokType != tkEof:
|
while p.tok.tokType != tkParRi and p.tok.tokType != tkEof:
|
||||||
var a = exprColonEqExpr(p)
|
var a = exprColonEqExpr(p)
|
||||||
|
|
|
||||||
|
|
@ -1182,7 +1182,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||||
of nkTupleConstr:
|
of nkTupleConstr:
|
||||||
put(g, tkParLe, "(")
|
put(g, tkParLe, "(")
|
||||||
gcomma(g, n, c)
|
gcomma(g, n, c)
|
||||||
if n.len == 1: put(g, tkComma, ",")
|
if n.len == 1 and n[0].kind != nkExprColonExpr: put(g, tkComma, ",")
|
||||||
put(g, tkParRi, ")")
|
put(g, tkParRi, ")")
|
||||||
of nkCurly:
|
of nkCurly:
|
||||||
put(g, tkCurlyLe, "{")
|
put(g, tkCurlyLe, "{")
|
||||||
|
|
|
||||||
|
|
@ -2228,6 +2228,12 @@ proc prepareVMValue(arg: PNode): PNode =
|
||||||
if arg.kind in nkLiterals:
|
if arg.kind in nkLiterals:
|
||||||
return arg
|
return arg
|
||||||
|
|
||||||
|
if arg.kind == nkExprColonExpr and arg[0].typ != nil and
|
||||||
|
arg[0].typ.sym != nil and arg[0].typ.sym.magic == mPNimrodNode:
|
||||||
|
# Poor mans way of protecting static NimNodes
|
||||||
|
# XXX: Maybe we need a nkNimNode?
|
||||||
|
return arg
|
||||||
|
|
||||||
result = copyNode(arg)
|
result = copyNode(arg)
|
||||||
if arg.kind == nkTupleConstr:
|
if arg.kind == nkTupleConstr:
|
||||||
for child in arg:
|
for child in arg:
|
||||||
|
|
|
||||||
|
|
@ -329,19 +329,56 @@ AST:
|
||||||
Parentheses
|
Parentheses
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
Parentheses for affecting operator precedence or tuple construction
|
Parentheses for affecting operator precedence use the ``nnkPar`` node.
|
||||||
are built with the ``nnkPar`` node.
|
|
||||||
|
|
||||||
Concrete syntax:
|
Concrete syntax:
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
(1, 2, (3))
|
(a + b) * c
|
||||||
|
|
||||||
AST:
|
AST:
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
nnkPar(nnkIntLit(1), nnkIntLit(2), nnkPar(nnkIntLit(3)))
|
nnkInfix(nnkIdent("*"),
|
||||||
|
nnkPar(
|
||||||
|
nnkInfix(nnkIdent("+"), nnkIdent("a"), nnkIdent("b"))),
|
||||||
|
nnkIdent("c"))
|
||||||
|
|
||||||
|
Tuple Constructors
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Nodes for tuple construction are built with the ``nnkTupleConstr`` node.
|
||||||
|
|
||||||
|
Concrete syntax:
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
(1, 2, 3)
|
||||||
|
(a: 1, b: 2, c: 3)
|
||||||
|
()
|
||||||
|
|
||||||
|
AST:
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
nnkTupleConstr(nnkIntLit(1), nnkIntLit(2), nnkIntLit(3))
|
||||||
|
nnkTupleConstr(
|
||||||
|
nnkExprColonExpr(nnkIdent("a"), nnkIntLit(1)),
|
||||||
|
nnkExprColonExpr(nnkIdent("b"), nnkIntLit(2)),
|
||||||
|
nnkExprColonExpr(nnkIdent("c"), nnkIntLit(3)))
|
||||||
|
|
||||||
|
Since the one tuple would be syntactically identical to parentheses
|
||||||
|
with an expression in them, the parser expects a trailing comma for
|
||||||
|
them. For tuple constructors with field names, this is not necessary.
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
(1,)
|
||||||
|
(a: 1)
|
||||||
|
|
||||||
|
AST:
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
nnkTupleConstr(nnkIntLit(1))
|
||||||
|
nnkTupleConstr(
|
||||||
|
nnkExprColonExpr(nnkIdent("a"), nnkIntLit(1)))
|
||||||
|
|
||||||
Curly braces
|
Curly braces
|
||||||
------------
|
------------
|
||||||
|
|
|
||||||
|
|
@ -133,8 +133,8 @@ proc matchLengthKind*(arg: NimNode; kind: NimNodeKind; length: int): MatchingErr
|
||||||
matchLengthKind(arg, {kind}, length)
|
matchLengthKind(arg, {kind}, length)
|
||||||
|
|
||||||
proc matchValue(arg: NimNode; kind: set[NimNodeKind]; value: SomeInteger): MatchingError {.compileTime.} =
|
proc matchValue(arg: NimNode; kind: set[NimNodeKind]; value: SomeInteger): MatchingError {.compileTime.} =
|
||||||
let kindFail = not(kind.card == 0 or arg.kind in kind)
|
template kindFail: bool = not(kind.card == 0 or arg.kind in kind)
|
||||||
let valueFail = arg.intVal != int(value)
|
template valueFail: bool = arg.intVal != int(value)
|
||||||
if kindFail or valueFail:
|
if kindFail or valueFail:
|
||||||
result.node = arg
|
result.node = arg
|
||||||
result.kind = WrongKindValue
|
result.kind = WrongKindValue
|
||||||
|
|
|
||||||
|
|
@ -327,19 +327,43 @@ static:
|
||||||
|
|
||||||
testArrayAccessOperator(x[y])
|
testArrayAccessOperator(x[y])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Parentheses
|
## Parentheses
|
||||||
|
|
||||||
scope:
|
scope:
|
||||||
|
|
||||||
let ast = myquote:
|
let ast = myquote:
|
||||||
(1, 2, (3))
|
(a + b) * c
|
||||||
|
|
||||||
ast.matchAst:
|
ast.matchAst:
|
||||||
of nnkPar(nnkIntLit(intVal = 1), nnkIntLit(intVal = 2), nnkPar(nnkIntLit(intVal = 3))):
|
of nnkInfix(ident"*", nnkPar(nnkInfix(ident"+", ident"a", ident"b")), ident"c"):
|
||||||
echo "ok"
|
echo "parentheses ok"
|
||||||
|
|
||||||
|
## Tuple Constructors
|
||||||
|
|
||||||
|
scope:
|
||||||
|
let ast = myquote:
|
||||||
|
(1, 2, 3)
|
||||||
|
(a: 1, b: 2, c: 3)
|
||||||
|
(1,)
|
||||||
|
(a: 1)
|
||||||
|
()
|
||||||
|
|
||||||
|
for it in ast:
|
||||||
|
echo it.lispRepr
|
||||||
|
it.matchAst:
|
||||||
|
of nnkTupleConstr(nnkIntLit(intVal = 1), nnkIntLit(intVal = 2), nnkIntLit(intVal = 3)):
|
||||||
|
echo "simple tuple ok"
|
||||||
|
of nnkTupleConstr(
|
||||||
|
nnkExprColonExpr(ident"a", nnkIntLit(intVal = 1)),
|
||||||
|
nnkExprColonExpr(ident"b", nnkIntLit(intVal = 2)),
|
||||||
|
nnkExprColonExpr(ident"c", nnkIntLit(intVal = 3))
|
||||||
|
):
|
||||||
|
echo "named tuple ok"
|
||||||
|
of nnkTupleConstr(nnkIntLit(intVal = 1)):
|
||||||
|
echo "one tuple ok"
|
||||||
|
of nnkTupleConstr(nnkExprColonExpr(ident"a", nnkIntLit(intVal = 1))):
|
||||||
|
echo "named one tuple ok"
|
||||||
|
of nnkTupleConstr():
|
||||||
|
echo "empty tuple ok"
|
||||||
|
|
||||||
## Curly braces
|
## Curly braces
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ macro check(val, body: untyped): untyped =
|
||||||
result = newStmtList()
|
result = newStmtList()
|
||||||
expectKind body, nnkStmtList
|
expectKind body, nnkStmtList
|
||||||
for b in body:
|
for b in body:
|
||||||
expectKind b, nnkPar
|
expectKind b, nnkTupleConstr
|
||||||
expectLen b, 2
|
expectLen b, 2
|
||||||
let p = b[0]
|
let p = b[0]
|
||||||
let s = b[1]
|
let s = b[1]
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ template main =
|
||||||
doAssert lispReprStr([-1]) == """(Bracket (IntLit -1))"""
|
doAssert lispReprStr([-1]) == """(Bracket (IntLit -1))"""
|
||||||
doAssert (-1, 2)[0] == minusOne:
|
doAssert (-1, 2)[0] == minusOne:
|
||||||
"unable to handle negatives after parenthesis"
|
"unable to handle negatives after parenthesis"
|
||||||
doAssert lispReprStr((-1, 2)) == """(Par (IntLit -1) (IntLit 2))"""
|
doAssert lispReprStr((-1, 2)) == """(TupleConstr (IntLit -1) (IntLit 2))"""
|
||||||
proc x(): int =
|
proc x(): int =
|
||||||
var a = 1;-1 # the -1 should act as the return value
|
var a = 1;-1 # the -1 should act as the return value
|
||||||
doAssert x() == minusOne:
|
doAssert x() == minusOne:
|
||||||
|
|
|
||||||
|
|
@ -48,3 +48,34 @@ macro fun3(): untyped =
|
||||||
int | float | array | seq | object | ptr | pointer | float32
|
int | float | array | seq | object | ptr | pointer | float32
|
||||||
doAssert n.repr == "int | float | array | seq | object | ptr | pointer | float32", n.repr
|
doAssert n.repr == "int | float | array | seq | object | ptr | pointer | float32", n.repr
|
||||||
fun3()
|
fun3()
|
||||||
|
|
||||||
|
macro fun4() =
|
||||||
|
let n = quote do:
|
||||||
|
(a: 1)
|
||||||
|
doAssert n.repr == "(a: 1)", n.repr
|
||||||
|
fun4()
|
||||||
|
|
||||||
|
# nkTupleConstr vs nkPar tests:
|
||||||
|
block: # lispRepr
|
||||||
|
macro lispRepr2(a: untyped): string = newLit a.lispRepr
|
||||||
|
|
||||||
|
doAssert lispRepr2(()) == """(TupleConstr)"""
|
||||||
|
doAssert lispRepr2((a: 1)) == """(TupleConstr (ExprColonExpr (Ident "a") (IntLit 1)))"""
|
||||||
|
doAssert lispRepr2((a: 1, b: 2)) == """(TupleConstr (ExprColonExpr (Ident "a") (IntLit 1)) (ExprColonExpr (Ident "b") (IntLit 2)))"""
|
||||||
|
doAssert lispRepr2((1,)) == """(TupleConstr (IntLit 1))"""
|
||||||
|
doAssert lispRepr2((1, 2)) == """(TupleConstr (IntLit 1) (IntLit 2))"""
|
||||||
|
doAssert lispRepr2((1, 2, 3.0)) == """(TupleConstr (IntLit 1) (IntLit 2) (FloatLit 3.0))"""
|
||||||
|
doAssert lispRepr2((1)) == """(Par (IntLit 1))"""
|
||||||
|
doAssert lispRepr2((1+2)) == """(Par (Infix (Ident "+") (IntLit 1) (IntLit 2)))"""
|
||||||
|
|
||||||
|
block: # repr
|
||||||
|
macro repr2(a: untyped): string = newLit a.repr
|
||||||
|
|
||||||
|
doAssert repr2(()) == "()"
|
||||||
|
doAssert repr2((a: 1)) == "(a: 1)"
|
||||||
|
doAssert repr2((a: 1, b: 2)) == "(a: 1, b: 2)"
|
||||||
|
doAssert repr2((1,)) == "(1,)"
|
||||||
|
doAssert repr2((1, 2)) == "(1, 2)"
|
||||||
|
doAssert repr2((1, 2, 3.0)) == "(1, 2, 3.0)"
|
||||||
|
doAssert repr2((1)) == "(1)"
|
||||||
|
doAssert repr2((1+2)) == "(1 + 2)"
|
||||||
|
|
|
||||||
|
|
@ -464,7 +464,7 @@ StmtList
|
||||||
DiscardStmt
|
DiscardStmt
|
||||||
Empty
|
Empty
|
||||||
OfBranch
|
OfBranch
|
||||||
Par
|
TupleConstr
|
||||||
Ident "a"
|
Ident "a"
|
||||||
Ident "b"
|
Ident "b"
|
||||||
StmtList
|
StmtList
|
||||||
|
|
@ -476,7 +476,7 @@ StmtList
|
||||||
DiscardStmt
|
DiscardStmt
|
||||||
Empty
|
Empty
|
||||||
ElifBranch
|
ElifBranch
|
||||||
Par
|
TupleConstr
|
||||||
Ident "a"
|
Ident "a"
|
||||||
Ident "b"
|
Ident "b"
|
||||||
StmtList
|
StmtList
|
||||||
|
|
@ -488,7 +488,7 @@ StmtList
|
||||||
DiscardStmt
|
DiscardStmt
|
||||||
Empty
|
Empty
|
||||||
ExceptBranch
|
ExceptBranch
|
||||||
Par
|
TupleConstr
|
||||||
Ident "a"
|
Ident "a"
|
||||||
Ident "b"
|
Ident "b"
|
||||||
StmtList
|
StmtList
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ StmtList
|
||||||
Ident "PtrTuple"
|
Ident "PtrTuple"
|
||||||
Empty
|
Empty
|
||||||
PtrTy
|
PtrTy
|
||||||
Par
|
TupleConstr
|
||||||
Ident "int"
|
Ident "int"
|
||||||
Ident "string"
|
Ident "string"
|
||||||
TypeDef
|
TypeDef
|
||||||
|
|
@ -43,14 +43,14 @@ StmtList
|
||||||
Ident "RefTupleType"
|
Ident "RefTupleType"
|
||||||
Empty
|
Empty
|
||||||
RefTy
|
RefTy
|
||||||
Par
|
TupleConstr
|
||||||
Ident "int"
|
Ident "int"
|
||||||
Ident "string"
|
Ident "string"
|
||||||
TypeDef
|
TypeDef
|
||||||
Ident "RefTupleVars"
|
Ident "RefTupleVars"
|
||||||
Empty
|
Empty
|
||||||
RefTy
|
RefTy
|
||||||
Par
|
TupleConstr
|
||||||
Ident "a"
|
Ident "a"
|
||||||
Ident "b"
|
Ident "b"
|
||||||
TypeDef
|
TypeDef
|
||||||
|
|
@ -80,7 +80,7 @@ StmtList
|
||||||
Empty
|
Empty
|
||||||
Command
|
Command
|
||||||
Ident "static"
|
Ident "static"
|
||||||
Par
|
TupleConstr
|
||||||
Ident "int"
|
Ident "int"
|
||||||
Ident "string"
|
Ident "string"
|
||||||
TypeDef
|
TypeDef
|
||||||
|
|
@ -155,7 +155,7 @@ StmtList
|
||||||
Empty
|
Empty
|
||||||
Command
|
Command
|
||||||
Ident "type"
|
Ident "type"
|
||||||
Par
|
TupleConstr
|
||||||
Ident "a"
|
Ident "a"
|
||||||
Ident "b"
|
Ident "b"
|
||||||
TypeDef
|
TypeDef
|
||||||
|
|
@ -163,7 +163,7 @@ StmtList
|
||||||
Empty
|
Empty
|
||||||
Command
|
Command
|
||||||
Ident "type"
|
Ident "type"
|
||||||
Par
|
TupleConstr
|
||||||
Ident "int"
|
Ident "int"
|
||||||
Ident "string"
|
Ident "string"
|
||||||
TypeDef
|
TypeDef
|
||||||
|
|
@ -287,7 +287,7 @@ StmtList
|
||||||
IdentDefs
|
IdentDefs
|
||||||
Ident "refTuple2"
|
Ident "refTuple2"
|
||||||
RefTy
|
RefTy
|
||||||
Par
|
TupleConstr
|
||||||
Ident "int"
|
Ident "int"
|
||||||
Ident "string"
|
Ident "string"
|
||||||
Empty
|
Empty
|
||||||
|
|
@ -524,4 +524,3 @@ dumpTree:
|
||||||
static:
|
static:
|
||||||
staticStmtList1
|
staticStmtList1
|
||||||
staticStmtList2
|
staticStmtList2
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue