mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-20 06:20:38 +00:00
added the 'x.p[:T]' notation for explicit generic instantiations in combination with the ddot calling syntax
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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, "<span class=\"Other\">$1</span>", "\\spanOther{$1}",
|
||||
[rope(esc(d.target, literal))])
|
||||
|
||||
|
||||
@@ -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 ']':
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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 .. <m.R:
|
||||
for c in 0 .. <m.C:
|
||||
for r in 0 ..< m.R:
|
||||
for c in 0 ..< m.C:
|
||||
result[r, c] = m[c, r]
|
||||
|
||||
proc determinant*(m: AnySquareMatrix): int =
|
||||
@@ -550,38 +550,38 @@ object inheritance syntax involving the ``of`` keyword:
|
||||
proc f(g: BidirectionalGraph) # this one will be preferred if we pass a type
|
||||
# matching the BidirectionalGraph concept
|
||||
|
||||
..
|
||||
Converter type classes
|
||||
----------------------
|
||||
|
||||
Converter type classes
|
||||
----------------------
|
||||
Concepts can also be used to convert a whole range of types to a single type or
|
||||
a small set of simpler types. This is achieved with a `return` statement within
|
||||
the concept body:
|
||||
|
||||
Concepts can also be used to convert a whole range of types to a single type or
|
||||
a small set of simpler types. This is achieved with a `return` statement within
|
||||
the concept body:
|
||||
.. code-block:: nim
|
||||
type
|
||||
Stringable = concept x
|
||||
$x is string
|
||||
return $x
|
||||
|
||||
.. code-block:: nim
|
||||
type
|
||||
Stringable = concept x
|
||||
$x is string
|
||||
return $x
|
||||
StringRefValue[CharType] = object
|
||||
base: ptr CharType
|
||||
len: int
|
||||
|
||||
StringRefValue[CharType] = object
|
||||
base: ptr CharType
|
||||
len: int
|
||||
StringRef = concept x
|
||||
# the following would be an overloaded proc for cstring, string, seq and
|
||||
# other user-defined types, returning either a StringRefValue[char] or
|
||||
# StringRefValue[wchar]
|
||||
return makeStringRefValue(x)
|
||||
|
||||
StringRef = concept x
|
||||
# the following would be an overloaded proc for cstring, string, seq and
|
||||
# other user-defined types, returning either a StringRefValue[char] or
|
||||
# StringRefValue[wchar]
|
||||
return makeStringRefValue(x)
|
||||
# the varargs param will here be converted to an array of StringRefValues
|
||||
# the proc will have only two instantiations for the two character types
|
||||
proc log(format: static[string], varargs[StringRef])
|
||||
|
||||
# the varargs param will here be converted to an array of StringRefValues
|
||||
# the proc will have only two instantiations for the two character types
|
||||
proc log(format: static[string], varargs[StringRef])
|
||||
|
||||
# this proc will allow char and wchar values to be mixed in
|
||||
# the same call at the cost of additional instantiations
|
||||
# the varargs param will be converted to a tuple
|
||||
proc log(format: static[string], varargs[distinct StringRef])
|
||||
# this proc will allow char and wchar values to be mixed in
|
||||
# the same call at the cost of additional instantiations
|
||||
# the varargs param will be converted to a tuple
|
||||
proc log(format: static[string], varargs[distinct StringRef])
|
||||
|
||||
|
||||
..
|
||||
|
||||
@@ -411,7 +411,7 @@ Other tokens
|
||||
|
||||
The following strings denote other tokens::
|
||||
|
||||
` ( ) { } [ ] , ; [. .] {. .} (. .)
|
||||
` ( ) { } [ ] , ; [. .] {. .} (. .) [:
|
||||
|
||||
|
||||
The `slice`:idx: operator `..`:tok: takes precedence over other tokens that
|
||||
|
||||
@@ -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
|
||||
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
|
||||
<#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
|
||||
----------
|
||||
|
||||
@@ -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]
|
||||
|
||||
Reference in New Issue
Block a user