importing of C++ nested generics like std::vector<T>::iterator, using the apostrophe operator
This commit is contained in:
parent
6c78f1a43d
commit
1ebf1aaa80
6 changed files with 101 additions and 16 deletions
|
|
@ -795,8 +795,8 @@ type
|
||||||
# for enum types a list of symbols
|
# for enum types a list of symbols
|
||||||
# for tyInt it can be the int literal
|
# for tyInt it can be the int literal
|
||||||
# for procs and tyGenericBody, it's the
|
# for procs and tyGenericBody, it's the
|
||||||
# the body of the user-defined type class
|
|
||||||
# formal param list
|
# formal param list
|
||||||
|
# for concepts, the concept body
|
||||||
# else: unused
|
# else: unused
|
||||||
owner*: PSym # the 'owner' of the type
|
owner*: PSym # the 'owner' of the type
|
||||||
sym*: PSym # types have the sym associated with them
|
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 j
|
||||||
inc i
|
inc i
|
||||||
of '\'':
|
of '\'':
|
||||||
inc i
|
var idx, stars: int
|
||||||
let stars = i
|
if scanCppGenericSlot(pat, i, idx, stars):
|
||||||
while pat[i] == '*': inc i
|
var t = resolveStarsInCppType(typ, idx, stars)
|
||||||
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
|
|
||||||
if t == nil: result.add(~"void")
|
if t == nil: result.add(~"void")
|
||||||
else: result.add(getTypeDesc(p.module, t))
|
else: result.add(getTypeDesc(p.module, t))
|
||||||
inc i
|
|
||||||
else:
|
else:
|
||||||
let start = i
|
let start = i
|
||||||
while i < pat.len:
|
while i < pat.len:
|
||||||
|
|
|
||||||
|
|
@ -495,6 +495,33 @@ proc getTupleDesc(m: BModule, typ: PType, name: Rope,
|
||||||
else: add(result, desc)
|
else: add(result, desc)
|
||||||
add(result, "};" & tnl)
|
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 =
|
proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope =
|
||||||
# returns only the type's name
|
# returns only the type's name
|
||||||
var t = getUniqueType(typ)
|
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:
|
if isImportedCppType(t) and typ.kind == tyGenericInst:
|
||||||
# for instantiated templates we do not go through the type cache as the
|
# for instantiated templates we do not go through the type cache as the
|
||||||
# the type cache is not aware of 'tyGenericInst'.
|
# the type cache is not aware of 'tyGenericInst'.
|
||||||
result = getTypeName(t) & "<"
|
let cppName = getTypeName(t)
|
||||||
for i in 1 .. typ.len-2:
|
var i = 0
|
||||||
if i > 1: result.add(", ")
|
var chunkStart = 0
|
||||||
result.add(getTypeDescAux(m, typ.sons[i], check))
|
while i < cppName.data.len:
|
||||||
result.add("> ")
|
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:
|
# always call for sideeffects:
|
||||||
assert t.kind != tyTuple
|
assert t.kind != tyTuple
|
||||||
discard getRecordDesc(m, t, result, check)
|
discard getRecordDesc(m, t, result, check)
|
||||||
|
|
|
||||||
|
|
@ -827,6 +827,9 @@ proc localError*(info: TLineInfo, msg: TMsgKind, arg = "") =
|
||||||
proc localError*(info: TLineInfo, arg: string) =
|
proc localError*(info: TLineInfo, arg: string) =
|
||||||
liMessage(info, errGenerated, arg, doNothing)
|
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 = "") =
|
proc message*(info: TLineInfo, msg: TMsgKind, arg = "") =
|
||||||
liMessage(info, msg, arg, doNothing)
|
liMessage(info, msg, arg, doNothing)
|
||||||
|
|
||||||
|
|
|
||||||
19
doc/nimc.txt
19
doc/nimc.txt
|
|
@ -596,6 +596,25 @@ Produces:
|
||||||
x[6] = 91.4;
|
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
|
ImportObjC pragma
|
||||||
-----------------
|
-----------------
|
||||||
Similar to the `importc pragma for C <manual.html#importc-pragma>`_, the
|
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]
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue