mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 17:04:41 +00:00
importing of C++ nested generics like std::vector<T>::iterator, using the apostrophe operator
This commit is contained in:
@@ -795,8 +795,8 @@ type
|
||||
# for enum types a list of symbols
|
||||
# for tyInt it can be the int literal
|
||||
# for procs and tyGenericBody, it's the
|
||||
# the body of the user-defined type class
|
||||
# formal param list
|
||||
# for concepts, the concept body
|
||||
# else: unused
|
||||
owner*: PSym # the 'owner' of the type
|
||||
sym*: PSym # types have the sym associated with them
|
||||
|
||||
@@ -385,18 +385,11 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): Rope =
|
||||
inc j
|
||||
inc i
|
||||
of '\'':
|
||||
inc i
|
||||
let stars = i
|
||||
while pat[i] == '*': inc i
|
||||
if pat[i] in Digits:
|
||||
let j = pat[i].ord - '0'.ord
|
||||
var t = typ.sons[j]
|
||||
for k in 1..i-stars:
|
||||
if t != nil and t.len > 0:
|
||||
t = if t.kind == tyGenericInst: t.sons[1] else: t.elemType
|
||||
var idx, stars: int
|
||||
if scanCppGenericSlot(pat, i, idx, stars):
|
||||
var t = resolveStarsInCppType(typ, idx, stars)
|
||||
if t == nil: result.add(~"void")
|
||||
else: result.add(getTypeDesc(p.module, t))
|
||||
inc i
|
||||
else:
|
||||
let start = i
|
||||
while i < pat.len:
|
||||
|
||||
@@ -495,6 +495,33 @@ proc getTupleDesc(m: BModule, typ: PType, name: Rope,
|
||||
else: add(result, desc)
|
||||
add(result, "};" & tnl)
|
||||
|
||||
proc scanCppGenericSlot(pat: string, cursor, outIdx, outStars: var int): bool =
|
||||
# A helper proc for handling cppimport patterns, involving numeric
|
||||
# placeholders for generic types (e.g. '0, '**2, etc).
|
||||
# pre: the cursor must be placed at the ' symbol
|
||||
# post: the cursor will be placed after the final digit
|
||||
# false will returned if the input is not recognized as a placeholder
|
||||
inc cursor
|
||||
let begin = cursor
|
||||
while pat[cursor] == '*': inc cursor
|
||||
if pat[cursor] in Digits:
|
||||
outIdx = pat[cursor].ord - '0'.ord
|
||||
outStars = cursor - begin
|
||||
inc cursor
|
||||
return true
|
||||
else:
|
||||
return false
|
||||
|
||||
proc resolveStarsInCppType(typ: PType, idx, stars: int): PType =
|
||||
# XXX: we should catch this earlier and report it as a semantic error
|
||||
if idx >= typ.len: internalError "invalid apostrophe type parameter index"
|
||||
|
||||
result = typ.sons[idx]
|
||||
for i in 1..stars:
|
||||
if result != nil and result.len > 0:
|
||||
result = if result.kind == tyGenericInst: result.sons[1]
|
||||
else: result.elemType
|
||||
|
||||
proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope =
|
||||
# returns only the type's name
|
||||
var t = getUniqueType(typ)
|
||||
@@ -597,11 +624,33 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope =
|
||||
if isImportedCppType(t) and typ.kind == tyGenericInst:
|
||||
# for instantiated templates we do not go through the type cache as the
|
||||
# the type cache is not aware of 'tyGenericInst'.
|
||||
result = getTypeName(t) & "<"
|
||||
for i in 1 .. typ.len-2:
|
||||
if i > 1: result.add(", ")
|
||||
result.add(getTypeDescAux(m, typ.sons[i], check))
|
||||
result.add("> ")
|
||||
let cppName = getTypeName(t)
|
||||
var i = 0
|
||||
var chunkStart = 0
|
||||
while i < cppName.data.len:
|
||||
if cppName.data[i] == '\'':
|
||||
var chunkEnd = <i
|
||||
var idx, stars: int
|
||||
if scanCppGenericSlot(cppName.data, i, idx, stars):
|
||||
result.add cppName.data.substr(chunkStart, chunkEnd)
|
||||
chunkStart = i
|
||||
|
||||
let typeInSlot = resolveStarsInCppType(typ, idx + 1, stars)
|
||||
if typeInSlot == nil or typeInSlot.kind == tyEmpty:
|
||||
result.add(~"void")
|
||||
else:
|
||||
result.add getTypeDescAux(m, typeInSlot, check)
|
||||
else:
|
||||
inc i
|
||||
|
||||
if chunkStart != 0:
|
||||
result.add cppName.data.substr(chunkStart)
|
||||
else:
|
||||
result = cppName & "<"
|
||||
for i in 1 .. typ.len-2:
|
||||
if i > 1: result.add(", ")
|
||||
result.add(getTypeDescAux(m, typ.sons[i], check))
|
||||
result.add("> ")
|
||||
# always call for sideeffects:
|
||||
assert t.kind != tyTuple
|
||||
discard getRecordDesc(m, t, result, check)
|
||||
|
||||
@@ -827,6 +827,9 @@ proc localError*(info: TLineInfo, msg: TMsgKind, arg = "") =
|
||||
proc localError*(info: TLineInfo, arg: string) =
|
||||
liMessage(info, errGenerated, arg, doNothing)
|
||||
|
||||
proc localError*(info: TLineInfo, format: string, params: openarray[string]) =
|
||||
localError(info, format % params)
|
||||
|
||||
proc message*(info: TLineInfo, msg: TMsgKind, arg = "") =
|
||||
liMessage(info, msg, arg, doNothing)
|
||||
|
||||
|
||||
19
doc/nimc.txt
19
doc/nimc.txt
@@ -596,6 +596,25 @@ Produces:
|
||||
x[6] = 91.4;
|
||||
|
||||
|
||||
- If more precise control is needed, the apostrophe ``'`` can be used in the
|
||||
supplied pattern to denote the concrete type parameters of the generic type.
|
||||
See the usage of the apostrophe operator in proc patterns for more details.
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
type
|
||||
VectorIterator {.importcpp: "std::vector<'0>::iterator".} [T] = object
|
||||
|
||||
var x: VectorIterator[cint]
|
||||
|
||||
|
||||
Produces:
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
std::vector<int>::iterator x;
|
||||
|
||||
|
||||
ImportObjC pragma
|
||||
-----------------
|
||||
Similar to the `importc pragma for C <manual.html#importc-pragma>`_, the
|
||||
|
||||
21
tests/cpp/vector_iterator.nim
Normal file
21
tests/cpp/vector_iterator.nim
Normal file
@@ -0,0 +1,21 @@
|
||||
discard """
|
||||
cmd: "nim cpp $file"
|
||||
"""
|
||||
|
||||
{.emit: """
|
||||
|
||||
template <class T>
|
||||
struct Vector {
|
||||
struct Iterator {
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
""".}
|
||||
|
||||
type
|
||||
Vector {.importcpp: "Vector".} [T] = object
|
||||
VectorIterator {.importcpp: "Vector<'2>::Iterator".} [T] = object
|
||||
|
||||
var x: VectorIterator[void]
|
||||
|
||||
Reference in New Issue
Block a user