added the 'x.p[:T]' notation for explicit generic instantiations in combination with the ddot calling syntax

This commit is contained in:
Araq 2018-04-06 22:05:47 +02:00
commit 212fdc5946
9 changed files with 81 additions and 53 deletions

View file

@ -27,6 +27,9 @@
### Language additions ### 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 ### Language changes
- The `importcpp` pragma now allows importing the listed fields of generic - The `importcpp` pragma now allows importing the listed fields of generic

View file

@ -257,7 +257,8 @@ proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var Rope; renderFlags: TRe
tkBracketDotLe, tkBracketDotRi, tkParDotLe, tkBracketDotLe, tkBracketDotRi, tkParDotLe,
tkParDotRi, tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot, tkParDotRi, tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot,
tkAccent, tkColonColon, tkAccent, tkColonColon,
tkGStrLit, tkGTripleStrLit, tkInfixOpr, tkPrefixOpr, tkPostfixOpr: tkGStrLit, tkGTripleStrLit, tkInfixOpr, tkPrefixOpr, tkPostfixOpr,
tkBracketLeColon:
dispA(result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}", dispA(result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}",
[rope(esc(d.target, literal))]) [rope(esc(d.target, literal))])

View file

@ -60,7 +60,7 @@ type
tkCurlyDotLe, tkCurlyDotRi, # {. and .} tkCurlyDotLe, tkCurlyDotRi, # {. and .}
tkParDotLe, tkParDotRi, # (. and .) tkParDotLe, tkParDotRi, # (. and .)
tkComma, tkSemiColon, tkComma, tkSemiColon,
tkColon, tkColonColon, tkEquals, tkDot, tkDotDot, tkColon, tkColonColon, tkEquals, tkDot, tkDotDot, tkBracketLeColon,
tkOpr, tkComment, tkAccent, tkOpr, tkComment, tkAccent,
tkSpaces, tkInfixOpr, tkPrefixOpr, tkPostfixOpr tkSpaces, tkInfixOpr, tkPrefixOpr, tkPostfixOpr
@ -98,7 +98,7 @@ const
"tkTripleStrLit", "tkGStrLit", "tkGTripleStrLit", "tkCharLit", "(", "tkTripleStrLit", "tkGStrLit", "tkGTripleStrLit", "tkCharLit", "(",
")", "[", "]", "{", "}", "[.", ".]", "{.", ".}", "(.", ".)", ")", "[", "]", "{", "}", "[.", ".]", "{.", ".}", "(.", ".)",
",", ";", ",", ";",
":", "::", "=", ".", "..", ":", "::", "=", ".", "..", "[:",
"tkOpr", "tkComment", "`", "tkOpr", "tkComment", "`",
"tkSpaces", "tkInfixOpr", "tkSpaces", "tkInfixOpr",
"tkPrefixOpr", "tkPostfixOpr"] "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] != '.': if L.buf[L.bufpos] == '.' and L.buf[L.bufpos+1] != '.':
tok.tokType = tkBracketDotLe tok.tokType = tkBracketDotLe
inc(L.bufpos) inc(L.bufpos)
elif L.buf[L.bufpos] == ':':
tok.tokType = tkBracketLeColon
inc(L.bufpos)
else: else:
tok.tokType = tkBracketLe tok.tokType = tkBracketLe
of ']': of ']':

View file

@ -389,20 +389,6 @@ proc exprList(p: var TParser, endTok: TTokType, result: PNode) =
getTok(p) getTok(p)
optInd(p, a) 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) = proc exprColonEqExprListAux(p: var TParser, endTok: TTokType, result: PNode) =
assert(endTok in {tkCurlyRi, tkCurlyDotRi, tkBracketRi, tkParRi}) assert(endTok in {tkCurlyRi, tkCurlyDotRi, tkBracketRi, tkParRi})
getTok(p) getTok(p)
@ -423,6 +409,33 @@ proc exprColonEqExprList(p: var TParser, kind: TNodeKind,
result = newNodeP(kind, p) result = newNodeP(kind, p)
exprColonEqExprListAux(p, endTok, result) 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 = proc setOrTableConstr(p: var TParser): PNode =
#| setOrTableConstr = '{' ((exprColonEqExpr comma)* | ':' ) '}' #| setOrTableConstr = '{' ((exprColonEqExpr comma)* | ':' ) '}'
result = newNodeP(nkCurly, p) result = newNodeP(nkCurly, p)

View file

@ -26,9 +26,10 @@ symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`'
| IDENT | KEYW | IDENT | KEYW
exprColonEqExpr = expr (':'|'=' expr)? exprColonEqExpr = expr (':'|'=' expr)?
exprList = expr ^+ comma exprList = expr ^+ comma
dotExpr = expr '.' optInd symbol
qualifiedIdent = symbol ('.' optInd symbol)?
exprColonEqExprList = exprColonEqExpr (comma exprColonEqExpr)* (comma)? exprColonEqExprList = exprColonEqExpr (comma exprColonEqExpr)* (comma)?
dotExpr = expr '.' optInd (symbol | '[:' exprList ']')
explicitGenericInstantiation = '[:' exprList ']' ( '(' exprColonEqExpr ')' )?
qualifiedIdent = symbol ('.' optInd symbol)?
setOrTableConstr = '{' ((exprColonEqExpr comma)* | ':' ) '}' setOrTableConstr = '{' ((exprColonEqExpr comma)* | ':' ) '}'
castExpr = 'cast' '[' optInd typeDesc optPar ']' '(' optInd expr optPar ')' castExpr = 'cast' '[' optInd typeDesc optPar ']' '(' optInd expr optPar ')'
parKeyw = 'discard' | 'include' | 'if' | 'while' | 'case' | 'try' parKeyw = 'discard' | 'include' | 'if' | 'while' | 'case' | 'try'

View file

@ -550,7 +550,7 @@ object inheritance syntax involving the ``of`` keyword:
proc f(g: BidirectionalGraph) # this one will be preferred if we pass a type proc f(g: BidirectionalGraph) # this one will be preferred if we pass a type
# matching the BidirectionalGraph concept # matching the BidirectionalGraph concept
..
Converter type classes Converter type classes
---------------------- ----------------------

View file

@ -411,7 +411,7 @@ Other tokens
The following strings denote other tokens:: The following strings denote other tokens::
` ( ) { } [ ] , ; [. .] {. .} (. .) ` ( ) { } [ ] , ; [. .] {. .} (. .) [:
The `slice`:idx: operator `..`:tok: takes precedence over other tokens that The `slice`:idx: operator `..`:tok: takes precedence over other tokens that

View file

@ -141,13 +141,14 @@ The method call syntax conflicts with explicit generic instantiations:
``p[T](x)`` cannot be written as ``x.p[T]`` because ``x.p[T]`` is always ``p[T](x)`` cannot be written as ``x.p[T]`` because ``x.p[T]`` is always
parsed as ``(x.p)[T]``. parsed as ``(x.p)[T]``.
**Future directions**: ``p[.T.]`` might be introduced as an alternative syntax
to pass explicit types to a generic and then ``x.p[.T.]`` can be parsed as
``x.(p[.T.])``.
See also: `Limitations of the method call syntax See also: `Limitations of the method call syntax
<#templates-limitations-of-the-method-call-syntax>`_. <#templates-limitations-of-the-method-call-syntax>`_.
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 Properties
---------- ----------

View file

@ -1,6 +1,7 @@
discard """ discard """
output: '''holla output: '''holla
true''' true
defabc 4'''
""" """
# Test top level semicolon works properly: # Test top level semicolon works properly:
@ -13,3 +14,8 @@ proc `\*` (x, y: int): int = result = x * y
echo 5 \+ 1 \* 9 == 6*9 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]