importing of C++ nested generics like std::vector<T>::iterator, using the apostrophe operator

This commit is contained in:
Zahary Karadjov 2015-04-13 23:49:41 +03:00
commit 1ebf1aaa80
6 changed files with 101 additions and 16 deletions

View file

@ -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

View file

@ -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:

View file

@ -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)

View file

@ -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)

View file

@ -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

View 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]