From 1ebf1aaa80664bfb19ca09845d4258fe6dff25df Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Mon, 13 Apr 2015 23:49:41 +0300 Subject: [PATCH] importing of C++ nested generics like std::vector::iterator, using the apostrophe operator --- compiler/ast.nim | 2 +- compiler/ccgcalls.nim | 13 ++------ compiler/ccgtypes.nim | 59 ++++++++++++++++++++++++++++++++--- compiler/msgs.nim | 3 ++ doc/nimc.txt | 19 +++++++++++ tests/cpp/vector_iterator.nim | 21 +++++++++++++ 6 files changed, 101 insertions(+), 16 deletions(-) create mode 100644 tests/cpp/vector_iterator.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index 6bfaad527d..b0e9577fc3 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -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 diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 8f354d4573..2dacc25e9f 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -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: diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 8fdabd6cc6..60ebf591be 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -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 = 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) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 3f5c4763ed..778b839f37 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -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) diff --git a/doc/nimc.txt b/doc/nimc.txt index 831fce5670..1af35d694c 100644 --- a/doc/nimc.txt +++ b/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::iterator x; + + ImportObjC pragma ----------------- Similar to the `importc pragma for C `_, the diff --git a/tests/cpp/vector_iterator.nim b/tests/cpp/vector_iterator.nim new file mode 100644 index 0000000000..bd26db3511 --- /dev/null +++ b/tests/cpp/vector_iterator.nim @@ -0,0 +1,21 @@ +discard """ + cmd: "nim cpp $file" +""" + +{.emit: """ + +template +struct Vector { + struct Iterator { + + }; +}; + +""".} + +type + Vector {.importcpp: "Vector".} [T] = object + VectorIterator {.importcpp: "Vector<'2>::Iterator".} [T] = object + +var x: VectorIterator[void] +