From 212fdc5946a5ba8f72c83b427987d17bd67218a1 Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 6 Apr 2018 22:05:47 +0200 Subject: [PATCH] added the 'x.p[:T]' notation for explicit generic instantiations in combination with the ddot calling syntax --- changelog.md | 3 ++ compiler/docgen.nim | 3 +- compiler/lexer.nim | 7 +++-- compiler/parser.nim | 41 +++++++++++++++++--------- doc/grammar.txt | 5 ++-- doc/manual/generics.txt | 56 ++++++++++++++++++------------------ doc/manual/lexing.txt | 2 +- doc/manual/procs.txt | 9 +++--- tests/parser/tprecedence.nim | 8 +++++- 9 files changed, 81 insertions(+), 53 deletions(-) diff --git a/changelog.md b/changelog.md index 3ede1ceea..7a817fd81 100644 --- a/changelog.md +++ b/changelog.md @@ -27,6 +27,9 @@ ### Language additions +- Dot calls combined with explicit generic instantiations can now be written + as ``x.y[:z]``. ``x.y[:z]`` that is transformed into ``y[z](x)`` in the parser. + ### Language changes - The `importcpp` pragma now allows importing the listed fields of generic diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 65dcb73c9..67ff9edf1 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -257,7 +257,8 @@ proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var Rope; renderFlags: TRe tkBracketDotLe, tkBracketDotRi, tkParDotLe, tkParDotRi, tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot, tkAccent, tkColonColon, - tkGStrLit, tkGTripleStrLit, tkInfixOpr, tkPrefixOpr, tkPostfixOpr: + tkGStrLit, tkGTripleStrLit, tkInfixOpr, tkPrefixOpr, tkPostfixOpr, + tkBracketLeColon: dispA(result, "$1", "\\spanOther{$1}", [rope(esc(d.target, literal))]) diff --git a/compiler/lexer.nim b/compiler/lexer.nim index afa7642dc..e55da2f35 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -60,7 +60,7 @@ type tkCurlyDotLe, tkCurlyDotRi, # {. and .} tkParDotLe, tkParDotRi, # (. and .) tkComma, tkSemiColon, - tkColon, tkColonColon, tkEquals, tkDot, tkDotDot, + tkColon, tkColonColon, tkEquals, tkDot, tkDotDot, tkBracketLeColon, tkOpr, tkComment, tkAccent, tkSpaces, tkInfixOpr, tkPrefixOpr, tkPostfixOpr @@ -98,7 +98,7 @@ const "tkTripleStrLit", "tkGStrLit", "tkGTripleStrLit", "tkCharLit", "(", ")", "[", "]", "{", "}", "[.", ".]", "{.", ".}", "(.", ".)", ",", ";", - ":", "::", "=", ".", "..", + ":", "::", "=", ".", "..", "[:", "tkOpr", "tkComment", "`", "tkSpaces", "tkInfixOpr", "tkPrefixOpr", "tkPostfixOpr"] @@ -1119,6 +1119,9 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) = if L.buf[L.bufpos] == '.' and L.buf[L.bufpos+1] != '.': tok.tokType = tkBracketDotLe inc(L.bufpos) + elif L.buf[L.bufpos] == ':': + tok.tokType = tkBracketLeColon + inc(L.bufpos) else: tok.tokType = tkBracketLe of ']': diff --git a/compiler/parser.nim b/compiler/parser.nim index debb0b34d..78a89f6c6 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -389,20 +389,6 @@ proc exprList(p: var TParser, endTok: TTokType, result: PNode) = getTok(p) optInd(p, a) -proc dotExpr(p: var TParser, a: PNode): PNode = - #| dotExpr = expr '.' optInd symbol - var info = p.parLineInfo - getTok(p) - result = newNodeI(nkDotExpr, info) - optInd(p, result) - addSon(result, a) - addSon(result, parseSymbol(p, smAfterDot)) - -proc qualifiedIdent(p: var TParser): PNode = - #| qualifiedIdent = symbol ('.' optInd symbol)? - result = parseSymbol(p) - if p.tok.tokType == tkDot: result = dotExpr(p, result) - proc exprColonEqExprListAux(p: var TParser, endTok: TTokType, result: PNode) = assert(endTok in {tkCurlyRi, tkCurlyDotRi, tkBracketRi, tkParRi}) getTok(p) @@ -423,6 +409,33 @@ proc exprColonEqExprList(p: var TParser, kind: TNodeKind, result = newNodeP(kind, p) exprColonEqExprListAux(p, endTok, result) +proc dotExpr(p: var TParser, a: PNode): PNode = + #| dotExpr = expr '.' optInd (symbol | '[:' exprList ']') + #| explicitGenericInstantiation = '[:' exprList ']' ( '(' exprColonEqExpr ')' )? + var info = p.parLineInfo + getTok(p) + result = newNodeI(nkDotExpr, info) + optInd(p, result) + addSon(result, a) + addSon(result, parseSymbol(p, smAfterDot)) + if p.tok.tokType == tkBracketLeColon and p.tok.strongSpaceA <= 0: + var x = newNodeI(nkBracketExpr, p.parLineInfo) + # rewrite 'x.y[:z]()' to 'y[z](x)' + x.add result[1] + exprList(p, tkBracketRi, x) + eat(p, tkBracketRi) + var y = newNodeI(nkCall, p.parLineInfo) + y.add x + y.add result[0] + if p.tok.tokType == tkParLe and p.tok.strongSpaceA <= 0: + exprColonEqExprListAux(p, tkParRi, y) + result = y + +proc qualifiedIdent(p: var TParser): PNode = + #| qualifiedIdent = symbol ('.' optInd symbol)? + result = parseSymbol(p) + if p.tok.tokType == tkDot: result = dotExpr(p, result) + proc setOrTableConstr(p: var TParser): PNode = #| setOrTableConstr = '{' ((exprColonEqExpr comma)* | ':' ) '}' result = newNodeP(nkCurly, p) diff --git a/doc/grammar.txt b/doc/grammar.txt index f25b079f4..e06ebd5d9 100644 --- a/doc/grammar.txt +++ b/doc/grammar.txt @@ -26,9 +26,10 @@ symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`' | IDENT | KEYW exprColonEqExpr = expr (':'|'=' expr)? exprList = expr ^+ comma -dotExpr = expr '.' optInd symbol -qualifiedIdent = symbol ('.' optInd symbol)? exprColonEqExprList = exprColonEqExpr (comma exprColonEqExpr)* (comma)? +dotExpr = expr '.' optInd (symbol | '[:' exprList ']') +explicitGenericInstantiation = '[:' exprList ']' ( '(' exprColonEqExpr ')' )? +qualifiedIdent = symbol ('.' optInd symbol)? setOrTableConstr = '{' ((exprColonEqExpr comma)* | ':' ) '}' castExpr = 'cast' '[' optInd typeDesc optPar ']' '(' optInd expr optPar ')' parKeyw = 'discard' | 'include' | 'if' | 'while' | 'case' | 'try' diff --git a/doc/manual/generics.txt b/doc/manual/generics.txt index 4c908fefe..01f76b591 100644 --- a/doc/manual/generics.txt +++ b/doc/manual/generics.txt @@ -335,8 +335,8 @@ The concept types can be parametric just like the regular generic types: AnyTransform3D* = AnyMatrix[4, 4, float] proc transposed*(m: AnyMatrix): m.TransposedType = - for r in 0 .. `_. +The ``[: ]`` notation has been designed to mitigate this issue: ``x.p[:T]`` +is rewritten by the parser to ``p[T](x)``, ``x.p[:T](y)`` is rewritten to +``p[T](x, y)``. Note that ``[: ]`` has no AST representation, the rewrite +is performed directly in the parsing step. + Properties ---------- diff --git a/tests/parser/tprecedence.nim b/tests/parser/tprecedence.nim index d2c6d0b30..d586f14a3 100644 --- a/tests/parser/tprecedence.nim +++ b/tests/parser/tprecedence.nim @@ -1,6 +1,7 @@ discard """ output: '''holla -true''' +true +defabc 4''' """ # Test top level semicolon works properly: @@ -13,3 +14,8 @@ proc `\*` (x, y: int): int = result = x * y echo 5 \+ 1 \* 9 == 6*9 +proc foo[S, T](x: S, y: T): T = x & y + +proc bar[T](x: T): T = x + +echo "def".foo[:string, string]("abc"), " ", 4.bar[:int]