added the 'x.p[:T]' notation for explicit generic instantiations in combination with the ddot calling syntax
This commit is contained in:
parent
651c0e45da
commit
212fdc5946
9 changed files with 81 additions and 53 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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))])
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 ']':
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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'
|
||||||
|
|
|
||||||
|
|
@ -335,8 +335,8 @@ The concept types can be parametric just like the regular generic types:
|
||||||
AnyTransform3D* = AnyMatrix[4, 4, float]
|
AnyTransform3D* = AnyMatrix[4, 4, float]
|
||||||
|
|
||||||
proc transposed*(m: AnyMatrix): m.TransposedType =
|
proc transposed*(m: AnyMatrix): m.TransposedType =
|
||||||
for r in 0 .. <m.R:
|
for r in 0 ..< m.R:
|
||||||
for c in 0 .. <m.C:
|
for c in 0 ..< m.C:
|
||||||
result[r, c] = m[c, r]
|
result[r, c] = m[c, r]
|
||||||
|
|
||||||
proc determinant*(m: AnySquareMatrix): int =
|
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
|
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
|
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
|
.. code-block:: nim
|
||||||
a small set of simpler types. This is achieved with a `return` statement within
|
type
|
||||||
the concept body:
|
Stringable = concept x
|
||||||
|
$x is string
|
||||||
|
return $x
|
||||||
|
|
||||||
.. code-block:: nim
|
StringRefValue[CharType] = object
|
||||||
type
|
base: ptr CharType
|
||||||
Stringable = concept x
|
len: int
|
||||||
$x is string
|
|
||||||
return $x
|
|
||||||
|
|
||||||
StringRefValue[CharType] = object
|
StringRef = concept x
|
||||||
base: ptr CharType
|
# the following would be an overloaded proc for cstring, string, seq and
|
||||||
len: int
|
# other user-defined types, returning either a StringRefValue[char] or
|
||||||
|
# StringRefValue[wchar]
|
||||||
|
return makeStringRefValue(x)
|
||||||
|
|
||||||
StringRef = concept x
|
# the varargs param will here be converted to an array of StringRefValues
|
||||||
# the following would be an overloaded proc for cstring, string, seq and
|
# the proc will have only two instantiations for the two character types
|
||||||
# other user-defined types, returning either a StringRefValue[char] or
|
proc log(format: static[string], varargs[StringRef])
|
||||||
# StringRefValue[wchar]
|
|
||||||
return makeStringRefValue(x)
|
|
||||||
|
|
||||||
# the varargs param will here be converted to an array of StringRefValues
|
# this proc will allow char and wchar values to be mixed in
|
||||||
# the proc will have only two instantiations for the two character types
|
# the same call at the cost of additional instantiations
|
||||||
proc log(format: static[string], varargs[StringRef])
|
# 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 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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
----------
|
----------
|
||||||
|
|
|
||||||
|
|
@ -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]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue