Author: Matti Picus <mtti.pi...@gmail.com>
Branch: unicode-utf8
Changeset: r94754:daeb185c5482
Date: 2018-06-10 22:26 -0700
http://bitbucket.org/pypy/pypy/changeset/daeb185c5482/

Log:    merge default into branch

diff too long, truncating to 2000 out of 5932 lines

diff --git a/lib_pypy/grp.py b/lib_pypy/grp.py
--- a/lib_pypy/grp.py
+++ b/lib_pypy/grp.py
@@ -4,6 +4,8 @@
 
 from _pwdgrp_cffi import ffi, lib
 import _structseq
+import thread
+_lock = thread.allocate_lock()
 
 try: from __pypy__ import builtinify
 except ImportError: builtinify = lambda f: f
@@ -33,32 +35,35 @@
 
 @builtinify
 def getgrgid(gid):
-    res = lib.getgrgid(gid)
-    if not res:
-        # XXX maybe check error eventually
-        raise KeyError(gid)
-    return _group_from_gstruct(res)
+    with _lock:
+        res = lib.getgrgid(gid)
+        if not res:
+            # XXX maybe check error eventually
+            raise KeyError(gid)
+        return _group_from_gstruct(res)
 
 @builtinify
 def getgrnam(name):
     if not isinstance(name, basestring):
         raise TypeError("expected string")
     name = str(name)
-    res = lib.getgrnam(name)
-    if not res:
-        raise KeyError("'getgrnam(): name not found: %s'" % name)
-    return _group_from_gstruct(res)
+    with _lock:
+        res = lib.getgrnam(name)
+        if not res:
+            raise KeyError("'getgrnam(): name not found: %s'" % name)
+        return _group_from_gstruct(res)
 
 @builtinify
 def getgrall():
-    lib.setgrent()
     lst = []
-    while 1:
-        p = lib.getgrent()
-        if not p:
-            break
-        lst.append(_group_from_gstruct(p))
-    lib.endgrent()
+    with _lock:
+        lib.setgrent()
+        while 1:
+            p = lib.getgrent()
+            if not p:
+                break
+            lst.append(_group_from_gstruct(p))
+        lib.endgrent()
     return lst
 
 __all__ = ('struct_group', 'getgrgid', 'getgrnam', 'getgrall')
diff --git a/lib_pypy/pwd.py b/lib_pypy/pwd.py
--- a/lib_pypy/pwd.py
+++ b/lib_pypy/pwd.py
@@ -12,6 +12,8 @@
 
 from _pwdgrp_cffi import ffi, lib
 import _structseq
+import thread
+_lock = thread.allocate_lock()
 
 try: from __pypy__ import builtinify
 except ImportError: builtinify = lambda f: f
@@ -55,10 +57,11 @@
     Return the password database entry for the given numeric user ID.
     See pwd.__doc__ for more on password database entries.
     """
-    pw = lib.getpwuid(uid)
-    if not pw:
-        raise KeyError("getpwuid(): uid not found: %s" % uid)
-    return _mkpwent(pw)
+    with _lock:
+        pw = lib.getpwuid(uid)
+        if not pw:
+            raise KeyError("getpwuid(): uid not found: %s" % uid)
+        return _mkpwent(pw)
 
 @builtinify
 def getpwnam(name):
@@ -71,10 +74,11 @@
     if not isinstance(name, basestring):
         raise TypeError("expected string")
     name = str(name)
-    pw = lib.getpwnam(name)
-    if not pw:
-        raise KeyError("getpwname(): name not found: %s" % name)
-    return _mkpwent(pw)
+    with _lock:
+        pw = lib.getpwnam(name)
+        if not pw:
+            raise KeyError("getpwname(): name not found: %s" % name)
+        return _mkpwent(pw)
 
 @builtinify
 def getpwall():
@@ -84,13 +88,14 @@
     See pwd.__doc__ for more on password database entries.
     """
     users = []
-    lib.setpwent()
-    while True:
-        pw = lib.getpwent()
-        if not pw:
-            break
-        users.append(_mkpwent(pw))
-    lib.endpwent()
+    with _lock:
+        lib.setpwent()
+        while True:
+            pw = lib.getpwent()
+            if not pw:
+                break
+            users.append(_mkpwent(pw))
+        lib.endpwent()
     return users
 
 __all__ = ('struct_passwd', 'getpwuid', 'getpwnam', 'getpwall')
diff --git a/pypy/doc/install.rst b/pypy/doc/install.rst
--- a/pypy/doc/install.rst
+++ b/pypy/doc/install.rst
@@ -20,7 +20,7 @@
 OS and architecture.  You may be able to use either use the
 `most recent release`_ or one of our `development nightly build`_. These
 builds depend on dynamically linked libraries that may not be available on your
-OS. See the section about `Linux binaries` for more info and alternatives that
+OS. See the section about `Linux binaries`_ for more info and alternatives that
 may work on your system.
 
 Please note that the nightly builds are not
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -7,9 +7,9 @@
 
 .. branch: cppyy-packaging
 
-Upgrade to backend 0.6.0, support exception handling from wrapped functions,
-update enum handling, const correctness for data members and associated tests,
-support anonymous enums, support for function pointer arguments
+Upgrade to backend 1.1.0, improved handling of templated methods and
+functions (in particular automatic deduction of types), improved pythonization
+interface, and a range of compatibility fixes for Python3
 
 .. branch: socket_default_timeout_blockingness
 
@@ -28,9 +28,11 @@
 The reverse-debugger branch has been merged.  For more information, see
 https://bitbucket.org/pypy/revdb
 
+.. branch: pyparser-improvements-3
+
+Small refactorings in the Python parser.
+
 .. branch: unicode-utf8-re
 .. branch: utf8-io
 
 Utf8 handling for unicode
-
-
diff --git a/pypy/doc/windows.rst b/pypy/doc/windows.rst
--- a/pypy/doc/windows.rst
+++ b/pypy/doc/windows.rst
@@ -29,29 +29,28 @@
 ``C:\Users\<user name>\AppData\Local\Programs\Common\Microsoft\Visual C++ for 
Python``
 or in
 ``C:\Program Files (x86)\Common Files\Microsoft\Visual C++ for Python``.
-A current version of ``setuptools`` will be able to find it there. For
-Windows 10, you must right-click the download, and under ``Properties`` ->
-``Compatibility`` mark it as ``Run run this program in comatibility mode for``
-``Previous version...``. Also, you must download and install the ``.Net 
Framework 3.5``,
+A current version of ``setuptools`` will be able to find it there.
+Also, you must download and install the ``.Net Framework 3.5``,
 otherwise ``mt.exe`` will silently fail. Installation will begin automatically
 by running the mt.exe command by hand from a DOS window (that is how the author
 discovered the problem).
 
 .. _Microsoft Visual C++ Compiler for Python 2.7: 
https://www.microsoft.com/EN-US/DOWNLOAD/DETAILS.ASPX?ID=44266
 
-Installing "Build Tools for Visual Studio 2017" (for Python 3)
+Installing "Build Tools for Visual Studio 2015" (for Python 3)
 --------------------------------------------------------------
 
-As documented in the CPython Wiki_, CPython now recommends Visual C++ version
-14.0. A compact version of the compiler suite can be obtained from Microsoft_
-downloads, search the page for "Build Tools for Visual Studio 2017".
+As documented in the CPython Wiki_, CPython recommends Visual C++ version
+14.0 for python version 3.5. A compact version of the compiler suite can be 
+obtained from Microsoft_ downloads, search the page for "Microsoft Build Tools 
2015".
 
-You will also need to install the the `Windows SDK`_ in order to use the 
-`mt.exe` mainfest compiler.
+You will need to reboot the computer for the installation to successfully 
install and
+run the `mt.exe` mainfest compiler. The installation will set the
+`VS140COMNTOOLS` environment variable, this is key to distutils/setuptools
+finding the compiler
 
 .. _Wiki: https://wiki.python.org/moin/WindowsCompilers
-.. _Microsoft: https://www.visualstudio.com/downloads
-.. _`Windows SDK`: 
https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk
+.. _Microsoft: https://www.visualstudio.com/vs/older-downloads/
 
 Translating PyPy with Visual Studio
 -----------------------------------
@@ -99,6 +98,9 @@
 Setting Up Visual Studio 9.0 for building SSL in Python3
 --------------------------------------------------------
 
+**Note: this is old information, left for historical reference. We recommend
+using Visual Studio 2015, which now seems to properly set this all up.**
+
 On Python3, the ``ssl`` module is based on ``cffi``, and requires a build step 
after
 translation. However ``distutils`` does not support the Micorosft-provided 
Visual C
 compiler, and ``cffi`` depends on ``distutils`` to find the compiler. The
@@ -146,14 +148,14 @@
 Installing external packages
 ----------------------------
 
-We uses a `repository` parallel to pypy to hold binary compiled versions of the
+We uses a subrepository_ inside pypy to hold binary compiled versions of the
 build dependencies for windows. As part of the `rpython` setup stage, 
environment
 variables will be set to use these dependencies. The repository has a README
 file on how to replicate, and a branch for each supported platform. You may run
 the `get_externals.py` utility to checkout the proper branch for your platform
 and PyPy version.
 
-.. _repository:  https://bitbucket.org/pypy/external
+.. _subrepository:  https://bitbucket.org/pypy/external
 
 Using the mingw compiler
 ------------------------
diff --git a/pypy/interpreter/astcompiler/test/test_astbuilder.py 
b/pypy/interpreter/astcompiler/test/test_astbuilder.py
--- a/pypy/interpreter/astcompiler/test/test_astbuilder.py
+++ b/pypy/interpreter/astcompiler/test/test_astbuilder.py
@@ -1096,7 +1096,7 @@
         s = self.get_first_expr("'hi' ' implicitly' ' extra'")
         assert isinstance(s, ast.Str)
         assert space.eq_w(s.s, space.wrap("hi implicitly extra"))
-        sentence = u"Die M&#228;nner &#228;rgen sich!"
+        sentence = u"Die M&#228;nner &#228;rgern sich!"
         source = u"# coding: utf-7\nstuff = u'%s'" % (sentence,)
         info = pyparse.CompileInfo("<test>", "exec")
         tree = self.parser.parse_source(source.encode("utf-7"), info)
diff --git a/pypy/interpreter/astcompiler/test/test_compiler.py 
b/pypy/interpreter/astcompiler/test/test_compiler.py
--- a/pypy/interpreter/astcompiler/test/test_compiler.py
+++ b/pypy/interpreter/astcompiler/test/test_compiler.py
@@ -27,7 +27,7 @@
     generator._resolve_block_targets(blocks)
     return generator, blocks
 
-class TestCompiler:
+class BaseTestCompiler:
     """These tests compile snippets of code and check them by
     running them with our own interpreter.  These are thus not
     completely *unit* tests, but given that our interpreter is
@@ -74,6 +74,9 @@
     def error_test(self, source, exc_type):
         py.test.raises(exc_type, self.simple_test, source, None, None)
 
+
+class TestCompiler(BaseTestCompiler):
+
     def test_issue_713(self):
         func = "def f(_=2): return (_ if _ else _) if False else _"
         yield self.st, func, "f()", 2
@@ -953,9 +956,11 @@
         yield (self.st, "x=(lambda: (-0.0, 0.0), lambda: (0.0, -0.0))[1]()",
                         'repr(x)', '(0.0, -0.0)')
 
+class TestCompilerRevDB(BaseTestCompiler):
+    spaceconfig = {"translation.reverse_debugger": True}
+
     def test_revdb_metavar(self):
         from pypy.interpreter.reverse_debugging import dbstate, setup_revdb
-        self.space.config.translation.reverse_debugger = True
         self.space.reverse_debugging = True
         try:
             setup_revdb(self.space)
diff --git a/pypy/interpreter/pyparser/future.py 
b/pypy/interpreter/pyparser/future.py
--- a/pypy/interpreter/pyparser/future.py
+++ b/pypy/interpreter/pyparser/future.py
@@ -43,7 +43,7 @@
         self.tok = self.tokens[index]
 
     def skip(self, n):
-        if self.tok[0] == n:
+        if self.tok.token_type == n:
             self.next()
             return True
         else:
@@ -51,7 +51,7 @@
 
     def skip_name(self, name):
         from pypy.interpreter.pyparser import pygram
-        if self.tok[0] == pygram.tokens.NAME and self.tok[1] == name:
+        if self.tok.token_type == pygram.tokens.NAME and self.tok.value == 
name:
             self.next()
             return True
         else:
@@ -59,8 +59,8 @@
 
     def next_feature_name(self):
         from pypy.interpreter.pyparser import pygram
-        if self.tok[0] == pygram.tokens.NAME:
-            name = self.tok[1]
+        if self.tok.token_type == pygram.tokens.NAME:
+            name = self.tok.value
             self.next()
             if self.skip_name("as"):
                 self.skip(pygram.tokens.NAME)
@@ -101,7 +101,7 @@
         # somewhere inside the last __future__ import statement
         # (at the start would be fine too, but it's easier to grab a
         # random position inside)
-        last_position = (it.tok[2], it.tok[3])
+        last_position = (it.tok.lineno, it.tok.column)
         result |= future_flags.get_compiler_feature(it.next_feature_name())
         while it.skip(pygram.tokens.COMMA):
             result |= future_flags.get_compiler_feature(it.next_feature_name())
diff --git a/pypy/interpreter/pyparser/parser.py 
b/pypy/interpreter/pyparser/parser.py
--- a/pypy/interpreter/pyparser/parser.py
+++ b/pypy/interpreter/pyparser/parser.py
@@ -28,11 +28,24 @@
         new.symbol_ids = self.symbol_ids
         new.symbols_names = self.symbol_names
         new.keyword_ids = self.keyword_ids
+        new.token_to_error_string = self.token_to_error_string
         new.dfas = self.dfas
         new.labels = self.labels
         new.token_ids = self.token_ids
         return new
 
+
+    def classify(self, token):
+        """Find the label for a token."""
+        if token.token_type == self.KEYWORD_TOKEN:
+            label_index = self.keyword_ids.get(token.value, -1)
+            if label_index != -1:
+                return label_index
+        label_index = self.token_ids.get(token.token_type, -1)
+        if label_index == -1:
+            raise ParseError("invalid token", token)
+        return label_index
+
     def _freeze_(self):
         # Remove some attributes not used in parsing.
         try:
@@ -65,6 +78,33 @@
             b[pos] |= bit
         return str(b)
 
+
+class Token(object):
+    def __init__(self, token_type, value, lineno, column, line):
+        self.token_type = token_type
+        self.value = value
+        self.lineno = lineno
+        # 0-based offset
+        self.column = column
+        self.line = line
+
+    def __repr__(self):
+        return "Token(%s, %s)" % (self.token_type, self.value)
+
+    def __eq__(self, other):
+        # for tests
+        return (
+            self.token_type == other.token_type and
+            self.value == other.value and
+            self.lineno == other.lineno and
+            self.column == other.column and
+            self.line == other.line
+        )
+
+    def __ne__(self, other):
+        return not self == other
+
+
 class Node(object):
 
     __slots__ = ("type", )
@@ -105,6 +145,11 @@
         self.lineno = lineno
         self.column = column
 
+    @staticmethod
+    def fromtoken(token):
+        return Terminal(
+            token.token_type, token.value, token.lineno, token.column)
+
     def __repr__(self):
         return "Terminal(type=%s, value=%r)" % (self.type, self.value)
 
@@ -193,20 +238,14 @@
 
 class ParseError(Exception):
 
-    def __init__(self, msg, token_type, value, lineno, column, line,
-                 expected=-1, expected_str=None):
+    def __init__(self, msg, token, expected=-1, expected_str=None):
         self.msg = msg
-        self.token_type = token_type
-        self.value = value
-        self.lineno = lineno
-        # this is a 0-based index
-        self.column = column
-        self.line = line
+        self.token = token
         self.expected = expected
         self.expected_str = expected_str
 
     def __str__(self):
-        return "ParserError(%s, %r)" % (self.token_type, self.value)
+        return "ParserError(%s)" % (self.token, )
 
 
 class StackEntry(object):
@@ -249,8 +288,8 @@
         self.root = None
         self.stack = StackEntry(None, self.grammar.dfas[start - 256], 0)
 
-    def add_token(self, token_type, value, lineno, column, line):
-        label_index = self.classify(token_type, value, lineno, column, line)
+    def add_token(self, token):
+        label_index = self.grammar.classify(token)
         sym_id = 0 # for the annotator
         while True:
             dfa = self.stack.dfa
@@ -261,7 +300,7 @@
                 sym_id = self.grammar.labels[i]
                 if label_index == i:
                     # We matched a non-terminal.
-                    self.shift(next_state, token_type, value, lineno, column)
+                    self.shift(next_state, token)
                     state = states[next_state]
                     # While the only possible action is to accept, pop nodes 
off
                     # the stack.
@@ -278,8 +317,7 @@
                     sub_node_dfa = self.grammar.dfas[sym_id - 256]
                     # Check if this token can start a child node.
                     if sub_node_dfa.could_match_token(label_index):
-                        self.push(sub_node_dfa, next_state, sym_id, lineno,
-                                  column)
+                        self.push(sub_node_dfa, next_state, sym_id)
                         break
             else:
                 # We failed to find any arcs to another state, so unless this
@@ -287,8 +325,7 @@
                 if is_accepting:
                     self.pop()
                     if self.stack is None:
-                        raise ParseError("too much input", token_type, value,
-                                         lineno, column, line)
+                        raise ParseError("too much input", token)
                 else:
                     # If only one possible input would satisfy, attach it to 
the
                     # error.
@@ -299,28 +336,16 @@
                     else:
                         expected = -1
                         expected_str = None
-                    raise ParseError("bad input", token_type, value, lineno,
-                                     column, line, expected, expected_str)
+                    raise ParseError("bad input", token, expected, 
expected_str)
 
-    def classify(self, token_type, value, lineno, column, line):
-        """Find the label for a token."""
-        if token_type == self.grammar.KEYWORD_TOKEN:
-            label_index = self.grammar.keyword_ids.get(value, -1)
-            if label_index != -1:
-                return label_index
-        label_index = self.grammar.token_ids.get(token_type, -1)
-        if label_index == -1:
-            raise ParseError("invalid token", token_type, value, lineno, 
column,
-                             line)
-        return label_index
 
-    def shift(self, next_state, token_type, value, lineno, column):
+    def shift(self, next_state, token):
         """Shift a non-terminal and prepare for the next state."""
-        new_node = Terminal(token_type, value, lineno, column)
+        new_node = Terminal.fromtoken(token)
         self.stack.node_append_child(new_node)
         self.stack.state = next_state
 
-    def push(self, next_dfa, next_state, node_type, lineno, column):
+    def push(self, next_dfa, next_state, node_type):
         """Push a terminal and adjust the current state."""
         self.stack.state = next_state
         self.stack = self.stack.push(next_dfa, 0)
diff --git a/pypy/interpreter/pyparser/pygram.py 
b/pypy/interpreter/pyparser/pygram.py
--- a/pypy/interpreter/pyparser/pygram.py
+++ b/pypy/interpreter/pyparser/pygram.py
@@ -23,6 +23,17 @@
 python_grammar_no_print.keyword_ids = 
python_grammar_no_print.keyword_ids.copy()
 del python_grammar_no_print.keyword_ids["print"]
 
+python_grammar_revdb = python_grammar.shared_copy()
+python_grammar_no_print_revdb = python_grammar_no_print.shared_copy()
+copied_token_ids = python_grammar.token_ids.copy()
+python_grammar_revdb.token_ids = copied_token_ids
+python_grammar_no_print_revdb.token_ids = copied_token_ids
+
+metavar_token_id = pytoken.python_tokens['REVDBMETAVAR']
+# the following line affects python_grammar_no_print too, since they share the
+# dict
+del python_grammar.token_ids[metavar_token_id]
+
 class _Tokens(object):
     pass
 for tok_name, idx in pytoken.python_tokens.iteritems():
@@ -39,3 +50,16 @@
 syms._rev_lookup = rev_lookup # for debugging
 
 del _get_python_grammar, _Tokens, tok_name, sym_name, idx
+
+def choose_grammar(print_function, revdb):
+    if print_function:
+        if revdb:
+            return python_grammar_no_print_revdb
+        else:
+            return python_grammar_no_print
+    else:
+        if revdb:
+            return python_grammar_revdb
+        else:
+            return python_grammar
+
diff --git a/pypy/interpreter/pyparser/pyparse.py 
b/pypy/interpreter/pyparser/pyparse.py
--- a/pypy/interpreter/pyparser/pyparse.py
+++ b/pypy/interpreter/pyparser/pyparse.py
@@ -147,38 +147,37 @@
             flags &= ~consts.PyCF_DONT_IMPLY_DEDENT
 
         self.prepare(_targets[compile_info.mode])
-        tp = 0
         try:
             try:
                 # Note: we no longer pass the CO_FUTURE_* to the tokenizer,
                 # which is expected to work independently of them.  It's
                 # certainly the case for all futures in Python <= 2.7.
                 tokens = pytokenizer.generate_tokens(source_lines, flags)
-
-                newflags, last_future_import = (
-                    future.add_future_flags(self.future_flags, tokens))
-                compile_info.last_future_import = last_future_import
-                compile_info.flags |= newflags
-
-                if compile_info.flags & consts.CO_FUTURE_PRINT_FUNCTION:
-                    self.grammar = pygram.python_grammar_no_print
-                else:
-                    self.grammar = pygram.python_grammar
-
-                for tp, value, lineno, column, line in tokens:
-                    if self.add_token(tp, value, lineno, column, line):
-                        break
             except error.TokenError as e:
                 e.filename = compile_info.filename
                 raise
             except error.TokenIndentationError as e:
                 e.filename = compile_info.filename
                 raise
+
+            newflags, last_future_import = (
+                future.add_future_flags(self.future_flags, tokens))
+            compile_info.last_future_import = last_future_import
+            compile_info.flags |= newflags
+
+            self.grammar = pygram.choose_grammar(
+                print_function=compile_info.flags & 
consts.CO_FUTURE_PRINT_FUNCTION,
+                revdb=self.space.config.translation.reverse_debugger)
+
+            try:
+                for token in tokens:
+                    if self.add_token(token):
+                        break
             except parser.ParseError as e:
                 # Catch parse errors, pretty them up and reraise them as a
                 # SyntaxError.
                 new_err = error.IndentationError
-                if tp == pygram.tokens.INDENT:
+                if token.token_type == pygram.tokens.INDENT:
                     msg = "unexpected indent"
                 elif e.expected == pygram.tokens.INDENT:
                     msg = "expected an indented block"
@@ -190,7 +189,7 @@
 
                 # parser.ParseError(...).column is 0-based, but the offsets in 
the
                 # exceptions in the error module are 1-based, hence the '+ 1'
-                raise new_err(msg, e.lineno, e.column + 1, e.line,
+                raise new_err(msg, e.token.lineno, e.token.column + 1, 
e.token.line,
                               compile_info.filename)
             else:
                 tree = self.root
diff --git a/pypy/interpreter/pyparser/pytokenize.py 
b/pypy/interpreter/pyparser/pytokenize.py
--- a/pypy/interpreter/pyparser/pytokenize.py
+++ b/pypy/interpreter/pyparser/pytokenize.py
@@ -1,9 +1,6 @@
 # ______________________________________________________________________
 """Module pytokenize
 
-THIS FILE WAS COPIED FROM pypy/module/parser/pytokenize.py AND ADAPTED
-TO BE ANNOTABLE (Mainly made lists homogeneous)
-
 This is a modified version of Ka-Ping Yee's tokenize module found in the
 Python standard library.
 
@@ -12,7 +9,6 @@
 expressions have been replaced with hand built DFA's using the
 basil.util.automata module.
 
-$Id: pytokenize.py,v 1.3 2003/10/03 16:31:53 jriehl Exp $
 """
 # ______________________________________________________________________
 
@@ -65,22 +61,3 @@
     single_quoted[t] = t
 
 tabsize = 8
-
-# PYPY MODIFICATION: removed TokenError class as it's not needed here
-
-# PYPY MODIFICATION: removed StopTokenizing class as it's not needed here
-
-# PYPY MODIFICATION: removed printtoken() as it's not needed here
-
-# PYPY MODIFICATION: removed tokenize() as it's not needed here
-
-# PYPY MODIFICATION: removed tokenize_loop() as it's not needed here
-
-# PYPY MODIFICATION: removed generate_tokens() as it was copied / modified
-#                    in pythonlexer.py
-
-# PYPY MODIFICATION: removed main() as it's not needed here
-
-# ______________________________________________________________________
-# End of pytokenize.py
-
diff --git a/pypy/interpreter/pyparser/pytokenizer.py 
b/pypy/interpreter/pyparser/pytokenizer.py
--- a/pypy/interpreter/pyparser/pytokenizer.py
+++ b/pypy/interpreter/pyparser/pytokenizer.py
@@ -1,4 +1,5 @@
 from pypy.interpreter.pyparser import automata
+from pypy.interpreter.pyparser.parser import Token
 from pypy.interpreter.pyparser.pygram import tokens
 from pypy.interpreter.pyparser.pytoken import python_opmap
 from pypy.interpreter.pyparser.error import TokenError, TokenIndentationError
@@ -103,7 +104,7 @@
             endmatch = endDFA.recognize(line)
             if endmatch >= 0:
                 pos = end = endmatch
-                tok = (tokens.STRING, contstr + line[:end], strstart[0],
+                tok = Token(tokens.STRING, contstr + line[:end], strstart[0],
                        strstart[1], line)
                 token_list.append(tok)
                 last_comment = ''
@@ -111,7 +112,7 @@
                 contline = None
             elif (needcont and not line.endswith('\\\n') and
                                not line.endswith('\\\r\n')):
-                tok = (tokens.ERRORTOKEN, contstr + line, strstart[0],
+                tok = Token(tokens.ERRORTOKEN, contstr + line, strstart[0],
                        strstart[1], line)
                 token_list.append(tok)
                 last_comment = ''
@@ -140,11 +141,11 @@
 
             if column > indents[-1]:           # count indents or dedents
                 indents.append(column)
-                token_list.append((tokens.INDENT, line[:pos], lnum, 0, line))
+                token_list.append(Token(tokens.INDENT, line[:pos], lnum, 0, 
line))
                 last_comment = ''
             while column < indents[-1]:
                 indents.pop()
-                token_list.append((tokens.DEDENT, '', lnum, pos, line))
+                token_list.append(Token(tokens.DEDENT, '', lnum, pos, line))
                 last_comment = ''
             if column != indents[-1]:
                 err = "unindent does not match any outer indentation level"
@@ -177,11 +178,11 @@
                 token, initial = line[start:end], line[start]
                 if initial in numchars or \
                    (initial == '.' and token != '.'):      # ordinary number
-                    token_list.append((tokens.NUMBER, token, lnum, start, 
line))
+                    token_list.append(Token(tokens.NUMBER, token, lnum, start, 
line))
                     last_comment = ''
                 elif initial in '\r\n':
                     if not parenstack:
-                        tok = (tokens.NEWLINE, last_comment, lnum, start, line)
+                        tok = Token(tokens.NEWLINE, last_comment, lnum, start, 
line)
                         token_list.append(tok)
                     last_comment = ''
                 elif initial == '#':
@@ -193,7 +194,7 @@
                     if endmatch >= 0:                     # all on one line
                         pos = endmatch
                         token = line[start:pos]
-                        tok = (tokens.STRING, token, lnum, start, line)
+                        tok = Token(tokens.STRING, token, lnum, start, line)
                         token_list.append(tok)
                         last_comment = ''
                     else:
@@ -212,16 +213,16 @@
                         contline = line
                         break
                     else:                                  # ordinary string
-                        tok = (tokens.STRING, token, lnum, start, line)
+                        tok = Token(tokens.STRING, token, lnum, start, line)
                         token_list.append(tok)
                         last_comment = ''
                 elif initial in namechars:                 # ordinary name
-                    token_list.append((tokens.NAME, token, lnum, start, line))
+                    token_list.append(Token(tokens.NAME, token, lnum, start, 
line))
                     last_comment = ''
                 elif initial == '\\':                      # continued stmt
                     continued = 1
                 elif initial == '$':
-                    token_list.append((tokens.REVDBMETAVAR, token,
+                    token_list.append(Token(tokens.REVDBMETAVAR, token,
                                        lnum, start, line))
                     last_comment = ''
                 else:
@@ -246,7 +247,7 @@
                         punct = python_opmap[token]
                     else:
                         punct = tokens.OP
-                    token_list.append((punct, token, lnum, start, line))
+                    token_list.append(Token(punct, token, lnum, start, line))
                     last_comment = ''
             else:
                 start = whiteSpaceDFA.recognize(line, pos)
@@ -255,22 +256,22 @@
                 if start<max and line[start] in single_quoted:
                     raise TokenError("end of line (EOL) while scanning string 
literal",
                              line, lnum, start+1, token_list)
-                tok = (tokens.ERRORTOKEN, line[pos], lnum, pos, line)
+                tok = Token(tokens.ERRORTOKEN, line[pos], lnum, pos, line)
                 token_list.append(tok)
                 last_comment = ''
                 pos = pos + 1
 
     lnum -= 1
     if not (flags & consts.PyCF_DONT_IMPLY_DEDENT):
-        if token_list and token_list[-1][0] != tokens.NEWLINE:
-            tok = (tokens.NEWLINE, '', lnum, 0, '\n')
+        if token_list and token_list[-1].token_type != tokens.NEWLINE:
+            tok = Token(tokens.NEWLINE, '', lnum, 0, '\n')
             token_list.append(tok)
         for indent in indents[1:]:                # pop remaining indent levels
-            token_list.append((tokens.DEDENT, '', lnum, pos, line))
-    tok = (tokens.NEWLINE, '', lnum, 0, '\n')
+            token_list.append(Token(tokens.DEDENT, '', lnum, pos, line))
+    tok = Token(tokens.NEWLINE, '', lnum, 0, '\n')
     token_list.append(tok)
 
-    token_list.append((tokens.ENDMARKER, '', lnum, pos, line))
+    token_list.append(Token(tokens.ENDMARKER, '', lnum, pos, line))
     return token_list
 
 
diff --git a/pypy/interpreter/pyparser/test/test_automata.py 
b/pypy/interpreter/pyparser/test/test_automata.py
--- a/pypy/interpreter/pyparser/test/test_automata.py
+++ b/pypy/interpreter/pyparser/test/test_automata.py
@@ -1,4 +1,4 @@
-from pypy.interpreter.pyparser.automata import DFA, DEFAULT
+from pypy.interpreter.pyparser.automata import DFA, NonGreedyDFA, DEFAULT
 
 def test_states():
     d = DFA([{"\x00": 1}, {"\x01": 0}], [False, True])
@@ -10,3 +10,20 @@
     assert d.states == "\x01\x00"
     assert d.defaults == "\xff\x00"
     assert d.max_char == 1
+
+def test_recognize():
+    d = DFA([{"a": 1}, {"b": 0}], [False, True])
+    assert d.recognize("ababab") == 5
+    assert d.recognize("c") == -1
+
+    d = DFA([{"a": 1}, {DEFAULT: 0}], [False, True])
+    assert d.recognize("a,a?ab") == 5
+    assert d.recognize("c") == -1
+
+    d = NonGreedyDFA([{"a": 1}, {"b": 0}], [False, True])
+    assert d.recognize("ababab") == 1
+    assert d.recognize("c") == -1
+
+    d = NonGreedyDFA([{"a": 1}, {DEFAULT: 0}], [False, True])
+    assert d.recognize("a,a?ab") == 1
+    assert d.recognize("c") == -1
diff --git a/pypy/interpreter/pyparser/test/test_parser.py 
b/pypy/interpreter/pyparser/test/test_parser.py
--- a/pypy/interpreter/pyparser/test/test_parser.py
+++ b/pypy/interpreter/pyparser/test/test_parser.py
@@ -20,7 +20,7 @@
         rl = StringIO.StringIO(input + "\n").readline
         gen = tokenize.generate_tokens(rl)
         for tp, value, begin, end, line in gen:
-            if self.add_token(tp, value, begin[0], begin[1], line):
+            if self.add_token(parser.Token(tp, value, begin[0], begin[1], 
line)):
                 py.test.raises(StopIteration, gen.next)
         return self.root
 
diff --git a/pypy/interpreter/pyparser/test/test_pyparse.py 
b/pypy/interpreter/pyparser/test/test_pyparse.py
--- a/pypy/interpreter/pyparser/test/test_pyparse.py
+++ b/pypy/interpreter/pyparser/test/test_pyparse.py
@@ -38,7 +38,7 @@
 """, info=info)
         assert tree.type == syms.file_input
         assert info.encoding == "iso-8859-1"
-        sentence = u"u'Die M&#228;nner &#228;rgen sich!'"
+        sentence = u"u'Die M&#228;nner &#228;rgern sich!'"
         input = (u"# coding: utf-7\nstuff = %s" % (sentence,)).encode("utf-7")
         tree = self.parse(input, info=info)
         assert info.encoding == "utf-7"
@@ -168,13 +168,11 @@
             assert expected_tree == tree
 
     def test_revdb_dollar_num(self):
-        self.parse('$0')
-        self.parse('$5')
-        self.parse('$42')
-        self.parse('2+$42.attrname')
-        py.test.raises(SyntaxError, self.parse, '$')
-        py.test.raises(SyntaxError, self.parse, '$a')
-        py.test.raises(SyntaxError, self.parse, '$.5')
+        assert not self.space.config.translation.reverse_debugger
+        py.test.raises(SyntaxError, self.parse, '$0')
+        py.test.raises(SyntaxError, self.parse, '$0 + 5')
+        py.test.raises(SyntaxError, self.parse,
+                "from __future__ import print_function\nx = ($0, print)")
 
     def test_error_forgotten_chars(self):
         info = py.test.raises(SyntaxError, self.parse, "if 1\n    print 4")
@@ -183,3 +181,18 @@
         assert "(expected ':')" in info.value.msg
         info = py.test.raises(SyntaxError, self.parse, "def f:\n print 1")
         assert "(expected '(')" in info.value.msg
+
+class TestPythonParserRevDB(TestPythonParser):
+    spaceconfig = {"translation.reverse_debugger": True}
+
+    def test_revdb_dollar_num(self):
+        self.parse('$0')
+        self.parse('$5')
+        self.parse('$42')
+        self.parse('2+$42.attrname')
+        self.parse("from __future__ import print_function\nx = ($0, print)")
+        py.test.raises(SyntaxError, self.parse, '$')
+        py.test.raises(SyntaxError, self.parse, '$a')
+        py.test.raises(SyntaxError, self.parse, '$.5')
+
+
diff --git a/pypy/interpreter/pyparser/test/test_pytokenizer.py 
b/pypy/interpreter/pyparser/test/test_pytokenizer.py
--- a/pypy/interpreter/pyparser/test/test_pytokenizer.py
+++ b/pypy/interpreter/pyparser/test/test_pytokenizer.py
@@ -1,5 +1,6 @@
 import pytest
 from pypy.interpreter.pyparser import pytokenizer
+from pypy.interpreter.pyparser.parser import Token
 from pypy.interpreter.pyparser.pygram import tokens
 from pypy.interpreter.pyparser.error import TokenError
 
@@ -22,12 +23,12 @@
         line = "a+1"
         tks = tokenize(line)
         assert tks == [
-            (tokens.NAME, 'a', 1, 0, line),
-            (tokens.PLUS, '+', 1, 1, line),
-            (tokens.NUMBER, '1', 1, 2, line),
-            (tokens.NEWLINE, '', 2, 0, '\n'),
-            (tokens.NEWLINE, '', 2, 0, '\n'),
-            (tokens.ENDMARKER, '', 2, 0, ''),
+            Token(tokens.NAME, 'a', 1, 0, line),
+            Token(tokens.PLUS, '+', 1, 1, line),
+            Token(tokens.NUMBER, '1', 1, 2, line),
+            Token(tokens.NEWLINE, '', 2, 0, '\n'),
+            Token(tokens.NEWLINE, '', 2, 0, '\n'),
+            Token(tokens.ENDMARKER, '', 2, 0, ''),
             ]
 
     def test_error_parenthesis(self):
diff --git a/pypy/interpreter/test/test_reverse_debugging.py 
b/pypy/interpreter/test/test_reverse_debugging.py
--- a/pypy/interpreter/test/test_reverse_debugging.py
+++ b/pypy/interpreter/test/test_reverse_debugging.py
@@ -86,6 +86,9 @@
         if msg[0] == revdb.ANSWER_TEXT:
             assert got_output is None
             got_output = msg[-1]
+            assert msg[1] in (0, 1)
+            if msg[1]:
+                got_output += "\n"
         elif msg[0] == revdb.ANSWER_CHBKPT:
             assert got_chbkpt is None
             assert msg[1] == 5
diff --git a/pypy/module/_cppyy/__init__.py b/pypy/module/_cppyy/__init__.py
--- a/pypy/module/_cppyy/__init__.py
+++ b/pypy/module/_cppyy/__init__.py
@@ -1,7 +1,7 @@
 from pypy.interpreter.mixedmodule import MixedModule
 
 class Module(MixedModule):
-    "This module brigdes the cppyy frontend with its backend, through PyPy.\n\
+    "This module bridges the cppyy frontend with its backend, through PyPy.\n\
     See http://cppyy.readthedocs.io/en/latest for full details."
 
     interpleveldefs = {
@@ -14,17 +14,19 @@
         '_set_function_generator': 'interp_cppyy.set_function_generator',
         '_register_class'        : 'interp_cppyy.register_class',
         '_get_nullptr'           : 'interp_cppyy.get_nullptr',
-        'CPPInstanceBase'        : 'interp_cppyy.W_CPPInstance',
+        'CPPInstance'            : 'interp_cppyy.W_CPPInstance',
         'addressof'              : 'interp_cppyy.addressof',
         '_bind_object'           : 'interp_cppyy._bind_object',
         'bind_object'            : 'interp_cppyy.bind_object',
         'move'                   : 'interp_cppyy.move',
+        '_pin_type'              : 'interp_cppyy._pin_type',
     }
 
     appleveldefs = {
         '_post_import_startup'   : 'pythonify._post_import_startup',
+        'Template'               : 'pythonify.CPPTemplate',
         'add_pythonization'      : 'pythonify.add_pythonization',
-        'Template'               : 'pythonify.CPPTemplate',
+        'remove_pythonization'   : 'pythonify.remove_pythonization',
     }
 
     def __init__(self, space, *args):
diff --git a/pypy/module/_cppyy/capi/__init__.py 
b/pypy/module/_cppyy/capi/__init__.py
--- a/pypy/module/_cppyy/capi/__init__.py
+++ b/pypy/module/_cppyy/capi/__init__.py
@@ -11,6 +11,3 @@
     assert lltype.typeOf(ptr) == C_OBJECT
     address = rffi.cast(rffi.CCHARP, ptr)
     return rffi.cast(C_OBJECT, lltype.direct_ptradd(address, offset))
-
-def exchange_address(ptr, cif_descr, index):
-    return rffi.ptradd(ptr, cif_descr.exchange_args[index])
diff --git a/pypy/module/_cppyy/capi/loadable_capi.py 
b/pypy/module/_cppyy/capi/loadable_capi.py
--- a/pypy/module/_cppyy/capi/loadable_capi.py
+++ b/pypy/module/_cppyy/capi/loadable_capi.py
@@ -69,7 +69,8 @@
         space = self.space
         cif_descr = self.cif_descr
         size = cif_descr.exchange_size
-        raw_string = rffi.cast(rffi.CCHARP, 0)    # only ever have one in the 
CAPI
+        raw_string1 = rffi.cast(rffi.CCHARP, 0)
+        raw_string2 = rffi.cast(rffi.CCHARP, 0)   # have max two in any CAPI
         buffer = lltype.malloc(rffi.CCHARP.TO, size, flavor='raw')
         try:
             for i in range(len(args)):
@@ -88,14 +89,18 @@
                     assert obj._voidp != rffi.cast(rffi.VOIDP, 0)
                     data = rffi.cast(rffi.VOIDPP, data)
                     data[0] = obj._voidp
-                else:    # only other use is sring
+                else:    # only other use is string
                     assert obj.tc == 's'
                     n = len(obj._string)
-                    assert raw_string == rffi.cast(rffi.CCHARP, 0)
-                    # XXX could use rffi.get_nonmovingbuffer_final_null()
-                    raw_string = rffi.str2charp(obj._string)
                     data = rffi.cast(rffi.CCHARPP, data)
-                    data[0] = raw_string
+                    if raw_string1 == rffi.cast(rffi.CCHARP, 0):
+                        # XXX could use rffi.get_nonmovingbuffer_final_null()
+                        raw_string1 = rffi.str2charp(obj._string)
+                        data[0] = raw_string1
+                    else:
+                        assert raw_string2 == rffi.cast(rffi.CCHARP, 0)
+                        raw_string2 = rffi.str2charp(obj._string)
+                        data[0] = raw_string2
 
             jit_libffi.jit_ffi_call(cif_descr,
                                     rffi.cast(rffi.VOIDP, funcaddr),
@@ -106,8 +111,10 @@
             # immediate unwrapping, the round-trip is removed
             w_res = self.ctitem.copy_and_convert_to_object(resultdata)
         finally:
-            if raw_string != rffi.cast(rffi.CCHARP, 0):
-                rffi.free_charp(raw_string)
+            if raw_string1 != rffi.cast(rffi.CCHARP, 0):
+                rffi.free_charp(raw_string1)
+            if raw_string2 != rffi.cast(rffi.CCHARP, 0):
+                rffi.free_charp(raw_string2)
             lltype.free(buffer, flavor='raw')
         return w_res
 
@@ -183,8 +190,7 @@
             'constructor'  : ([c_method, c_object, c_int, c_voidp],   
c_object),
             'call_o'       : ([c_method, c_object, c_int, c_voidp, c_type],    
 c_object),
 
-            'function_address_from_index'  : ([c_scope, c_index],     
c_voidp), # TODO: verify
-            'function_address_from_method' : ([c_method],             
c_voidp), # id.
+            'function_address' : ([c_method],                         
c_voidp), # TODO: verify
 
             # handling of function argument buffer
             'allocate_function_args'   : ([c_int],                    c_voidp),
@@ -207,6 +213,8 @@
             'num_bases'                : ([c_type],                   c_int),
             'base_name'                : ([c_type, c_int],            
c_ccharp),
             'is_subtype'               : ([c_type, c_type],           c_int),
+            'smartptr_info'            : ([c_ccharp, c_voidp, c_voidp],        
 c_int),
+            'add_smartptr_type'        : ([c_ccharp],                 c_void),
 
             'base_offset'              : ([c_type, c_type, c_object, c_int],   
 c_ptrdiff_t),
 
@@ -214,30 +222,31 @@
             'num_methods'              : ([c_scope],                  c_int),
             'method_indices_from_name' : ([c_scope, c_ccharp],        
c_index_array),
 
-            'method_name'              : ([c_scope, c_index],         
c_ccharp),
-            'method_mangled_name'      : ([c_scope, c_index],         
c_ccharp),
-            'method_result_type'       : ([c_scope, c_index],         
c_ccharp),
-            'method_num_args'          : ([c_scope, c_index],         c_int),
-            'method_req_args'          : ([c_scope, c_index],         c_int),
-            'method_arg_type'          : ([c_scope, c_index, c_int],  
c_ccharp),
-            'method_arg_default'       : ([c_scope, c_index, c_int],  
c_ccharp),
-            'method_signature'         : ([c_scope, c_index, c_int],  
c_ccharp),
-            'method_prototype'         : ([c_scope, c_index, c_int],  
c_ccharp),
+            'get_method'               : ([c_scope, c_index],         
c_method),
+
+            'method_name'              : ([c_method],                 
c_ccharp),
+            'method_full_name'         : ([c_method],                 
c_ccharp),
+            'method_mangled_name'      : ([c_method],                 
c_ccharp),
+            'method_result_type'       : ([c_method],                 
c_ccharp),
+            'method_num_args'          : ([c_method],                 c_int),
+            'method_req_args'          : ([c_method],                 c_int),
+            'method_arg_type'          : ([c_method, c_int],          
c_ccharp),
+            'method_arg_default'       : ([c_method, c_int],          
c_ccharp),
+            'method_signature'         : ([c_method, c_int],          
c_ccharp),
+            'method_prototype'         : ([c_scope, c_method, c_int], 
c_ccharp),
             'is_const_method'          : ([c_method],                 c_int),
 
             'exists_method_template'   : ([c_scope, c_ccharp],        c_int),
             'method_is_template'       : ([c_scope, c_index],         c_int),
-            'method_num_template_args' : ([c_scope, c_index],         c_int),
-            'method_template_arg_name' : ([c_scope, c_index, c_index],         
 c_ccharp),
+            'get_method_template'      : ([c_scope, c_ccharp, c_ccharp],       
 c_method),
 
-            'get_method'               : ([c_scope, c_index],         
c_method),
             'get_global_operator'      : ([c_scope, c_scope, c_scope, 
c_ccharp],   c_index),
 
             # method properties
-            'is_public_method'         : ([c_type, c_index],          c_int),
-            'is_constructor'           : ([c_type, c_index],          c_int),
-            'is_destructor'            : ([c_type, c_index],          c_int),
-            'is_staticmethod'          : ([c_type, c_index],          c_int),
+            'is_public_method'         : ([c_method],                 c_int),
+            'is_constructor'           : ([c_method],                 c_int),
+            'is_destructor'            : ([c_method],                 c_int),
+            'is_staticmethod'          : ([c_method],                 c_int),
 
             # data member reflection information
             'num_datamembers'          : ([c_scope],                  c_int),
@@ -415,13 +424,9 @@
     args = [_ArgH(cppmethod), _ArgH(cppobject), _ArgL(nargs), _ArgP(cargs), 
_ArgH(cppclass.handle)]
     return _cdata_to_cobject(space, call_capi(space, 'call_o', args))
 
-def c_function_address_from_index(space, cppscope, index):
-    args = [_ArgH(cppscope.handle), _ArgL(index)]
+def c_function_address(space, cppmethod):
     return rffi.cast(C_FUNC_PTR,
-        _cdata_to_ptr(space, call_capi(space, 'function_address_from_index', 
args)))
-def c_function_address_from_method(space, cppmethod):
-    return rffi.cast(C_FUNC_PTR,
-        _cdata_to_ptr(space, call_capi(space, 'function_address_from_method', 
[_ArgH(cppmethod)])))
+        _cdata_to_ptr(space, call_capi(space, 'function_address', 
[_ArgH(cppmethod)])))
 
 # handling of function argument buffer ---------------------------------------
 def c_allocate_function_args(space, size):
@@ -479,6 +484,21 @@
     if derived == base:
         return bool(1)
     return space.bool_w(call_capi(space, 'is_subtype', [_ArgH(derived.handle), 
_ArgH(base.handle)]))
+def c_smartptr_info(space, name):
+    out_raw   = lltype.malloc(rffi.ULONGP.TO, 1, flavor='raw', zero=True)
+    out_deref = lltype.malloc(rffi.ULONGP.TO, 1, flavor='raw', zero=True)
+    try:
+        args = [_ArgS(name),
+           _ArgP(rffi.cast(rffi.VOIDP, out_raw)), _ArgP(rffi.cast(rffi.VOIDP, 
out_deref))]
+        result = space.bool_w(call_capi(space, 'smartptr_info', args))
+        raw   = rffi.cast(C_TYPE, out_raw[0])
+        deref = rffi.cast(C_METHOD, out_deref[0])
+    finally:
+        lltype.free(out_deref, flavor='raw')
+        lltype.free(out_raw, flavor='raw')
+    return (result, raw, deref)
+def c_add_smartptr_type(space, name):
+    return space.bool_w(call_capi(space, 'add_smartptr_type', [_ArgS(name)]))
 
 def _c_base_offset(space, derived_h, base_h, address, direction):
     args = [_ArgH(derived_h), _ArgH(base_h), _ArgH(address), _ArgL(direction)]
@@ -510,30 +530,36 @@
     c_free(space, rffi.cast(rffi.VOIDP, indices))   # c_free defined below
     return py_indices
 
-def c_method_name(space, cppscope, index):
+def c_get_method(space, cppscope, index):
     args = [_ArgH(cppscope.handle), _ArgL(index)]
-    return charp2str_free(space, call_capi(space, 'method_name', args))
-def c_method_result_type(space, cppscope, index):
-    args = [_ArgH(cppscope.handle), _ArgL(index)]
-    return charp2str_free(space, call_capi(space, 'method_result_type', args))
-def c_method_num_args(space, cppscope, index):
-    args = [_ArgH(cppscope.handle), _ArgL(index)]
-    return space.int_w(call_capi(space, 'method_num_args', args))
-def c_method_req_args(space, cppscope, index):
-    args = [_ArgH(cppscope.handle), _ArgL(index)]
-    return space.int_w(call_capi(space, 'method_req_args', args))
-def c_method_arg_type(space, cppscope, index, arg_index):
-    args = [_ArgH(cppscope.handle), _ArgL(index), _ArgL(arg_index)]
+    return rffi.cast(C_METHOD, space.uint_w(call_capi(space, 'get_method', 
args)))
+
+def c_method_name(space, cppmeth):
+    return charp2str_free(space, call_capi(space, 'method_name', 
[_ArgH(cppmeth)]))
+def c_method_full_name(space, cppmeth):
+    return charp2str_free(space, call_capi(space, 'method_full_name', 
[_ArgH(cppmeth)]))
+def c_method_mangled_name(space, cppmeth):
+    return charp2str_free(space, call_capi(space, 'method_mangled_name', 
[_ArgH(cppmeth)]))
+def c_method_result_type(space, cppmeth):
+    return charp2str_free(space, call_capi(space, 'method_result_type', 
[_ArgH(cppmeth)]))
+def c_method_num_args(space, cppmeth):
+    return space.int_w(call_capi(space, 'method_num_args', [_ArgH(cppmeth)]))
+def c_method_req_args(space, cppmeth):
+    return space.int_w(call_capi(space, 'method_req_args', [_ArgH(cppmeth)]))
+def c_method_arg_type(space, cppmeth, arg_index):
+    args = [_ArgH(cppmeth), _ArgL(arg_index)]
     return charp2str_free(space, call_capi(space, 'method_arg_type', args))
-def c_method_arg_default(space, cppscope, index, arg_index):
-    args = [_ArgH(cppscope.handle), _ArgL(index), _ArgL(arg_index)]
+def c_method_arg_default(space, cppmeth, arg_index):
+    args = [_ArgH(cppmeth), _ArgL(arg_index)]
     return charp2str_free(space, call_capi(space, 'method_arg_default', args))
-def c_method_signature(space, cppscope, index, show_formalargs=True):
-    args = [_ArgH(cppscope.handle), _ArgL(index), _ArgL(show_formalargs)]
+def c_method_signature(space, cppmeth, show_formalargs=True):
+    args = [_ArgH(cppmeth), _ArgL(show_formalargs)]
     return charp2str_free(space, call_capi(space, 'method_signature', args))
-def c_method_prototype(space, cppscope, index, show_formalargs=True):
-    args = [_ArgH(cppscope.handle), _ArgL(index), _ArgL(show_formalargs)]
+def c_method_prototype(space, cppscope, cppmeth, show_formalargs=True):
+    args = [_ArgH(cppscope.handle), _ArgH(cppmeth), _ArgL(show_formalargs)]
     return charp2str_free(space, call_capi(space, 'method_prototype', args))
+def c_is_const_method(space, cppmeth):
+    return space.bool_w(call_capi(space, 'is_const_method', [_ArgH(cppmeth)]))
 
 def c_exists_method_template(space, cppscope, name):
     args = [_ArgH(cppscope.handle), _ArgS(name)]
@@ -541,21 +567,10 @@
 def c_method_is_template(space, cppscope, index):
     args = [_ArgH(cppscope.handle), _ArgL(index)]
     return space.bool_w(call_capi(space, 'method_is_template', args))
-def _c_method_num_template_args(space, cppscope, index):
-    args = [_ArgH(cppscope.handle), _ArgL(index)]
-    return space.int_w(call_capi(space, 'method_num_template_args', args)) 
-def c_template_args(space, cppscope, index):
-    nargs = _c_method_num_template_args(space, cppscope, index)
-    arg1 = _ArgH(cppscope.handle)
-    arg2 = _ArgL(index)
-    args = [c_resolve_name(space, charp2str_free(space,
-                call_capi(space, 'method_template_arg_name', [arg1, arg2, 
_ArgL(iarg)]))
-            ) for iarg in range(nargs)]
-    return args
 
-def c_get_method(space, cppscope, index):
-    args = [_ArgH(cppscope.handle), _ArgL(index)]
-    return rffi.cast(C_METHOD, space.uint_w(call_capi(space, 'get_method', 
args)))
+def c_get_method_template(space, cppscope, name, proto):
+    args = [_ArgH(cppscope.handle), _ArgS(name), _ArgS(proto)]
+    return rffi.cast(C_METHOD, space.uint_w(call_capi(space, 
'get_method_template', args)))
 def c_get_global_operator(space, nss, lc, rc, op):
     if nss is not None:
         args = [_ArgH(nss.handle), _ArgH(lc.handle), _ArgH(rc.handle), 
_ArgS(op)]
@@ -563,18 +578,14 @@
     return rffi.cast(WLAVC_INDEX, -1)
 
 # method properties ----------------------------------------------------------
-def c_is_public_method(space, cppclass, index):
-    args = [_ArgH(cppclass.handle), _ArgL(index)]
-    return space.bool_w(call_capi(space, 'is_public_method', args))
-def c_is_constructor(space, cppclass, index):
-    args = [_ArgH(cppclass.handle), _ArgL(index)]
-    return space.bool_w(call_capi(space, 'is_constructor', args))
-def c_is_destructor(space, cppclass, index):
-    args = [_ArgH(cppclass.handle), _ArgL(index)]
-    return space.bool_w(call_capi(space, 'is_destructor', args))
-def c_is_staticmethod(space, cppclass, index):
-    args = [_ArgH(cppclass.handle), _ArgL(index)]
-    return space.bool_w(call_capi(space, 'is_staticmethod', args))
+def c_is_public_method(space, cppmeth):
+    return space.bool_w(call_capi(space, 'is_public_method', [_ArgH(cppmeth)]))
+def c_is_constructor(space, cppmeth):
+    return space.bool_w(call_capi(space, 'is_constructor', [_ArgH(cppmeth)]))
+def c_is_destructor(space, cppmeth):
+    return space.bool_w(call_capi(space, 'is_destructor', [_ArgH(cppmeth)]))
+def c_is_staticmethod(space, cppmeth):
+    return space.bool_w(call_capi(space, 'is_staticmethod', [_ArgH(cppmeth)]))
 
 # data member reflection information -----------------------------------------
 def c_num_datamembers(space, cppscope):
@@ -676,7 +687,7 @@
     space.setattr(w_pycppclass, space.newtext(m1),
                   space.getattr(w_pycppclass, space.newtext(m2)))
 
-def pythonize(space, name, w_pycppclass):
+def pythonize(space, w_pycppclass, name):
     if name == "string":
         space.setattr(w_pycppclass, space.newtext("c_str"), 
_pythonizations["stdstring_c_str"])
         _method_alias(space, w_pycppclass, "_cppyy_as_builtin", "c_str")
diff --git a/pypy/module/_cppyy/converter.py b/pypy/module/_cppyy/converter.py
--- a/pypy/module/_cppyy/converter.py
+++ b/pypy/module/_cppyy/converter.py
@@ -7,7 +7,7 @@
 from rpython.rlib import rfloat, rawrefcount
 
 from pypy.module._rawffi.interp_rawffi import letter2tp
-from pypy.module._rawffi.array import W_Array, W_ArrayInstance
+from pypy.module._rawffi.array import W_ArrayInstance
 
 from pypy.module._cppyy import helper, capi, ffitypes
 
@@ -68,6 +68,8 @@
         pass
     # array type
     try:
+        if hasattr(space, "fake"):
+            raise NotImplementedError
         arr = space.interp_w(W_ArrayInstance, w_obj, can_be_None=True)
         if arr:
             return rffi.cast(rffi.VOIDP, space.uint_w(arr.getbuffer(space)))
@@ -130,20 +132,6 @@
         pass
 
 
-class ArrayCache(object):
-    def __init__(self, space):
-        self.space = space
-    def __getattr__(self, name):
-        if name.startswith('array_'):
-            typecode = name[len('array_'):]
-            arr = self.space.interp_w(W_Array, letter2tp(self.space, typecode))
-            setattr(self, name, arr)
-            return arr
-        raise AttributeError(name)
-
-    def _freeze_(self):
-        return True
-
 class ArrayTypeConverterMixin(object):
     _mixin_ = True
     _immutable_fields_ = ['size']
@@ -162,9 +150,7 @@
         # read access, so no copy needed
         address_value = self._get_raw_address(space, w_obj, offset)
         address = rffi.cast(rffi.ULONG, address_value)
-        cache = space.fromcache(ArrayCache)
-        arr = getattr(cache, 'array_' + self.typecode)
-        return arr.fromaddress(space, address, self.size)
+        return W_ArrayInstance(space, letter2tp(space, self.typecode), 
self.size, address)
 
     def to_memory(self, space, w_obj, w_value, offset):
         # copy the full array (uses byte copy for now)
@@ -205,17 +191,15 @@
         # read access, so no copy needed
         address_value = self._get_raw_address(space, w_obj, offset)
         address = rffi.cast(rffi.ULONGP, address_value)
-        cache = space.fromcache(ArrayCache)
-        arr = getattr(cache, 'array_' + self.typecode)
-        return arr.fromaddress(space, address[0], self.size)
+        return W_ArrayInstance(space, letter2tp(space, self.typecode), 
self.size, address[0])
 
     def to_memory(self, space, w_obj, w_value, offset):
         # copy only the pointer value
         rawobject = get_rawobject_nonnull(space, w_obj)
-        byteptr = rffi.cast(rffi.CCHARPP, capi.direct_ptradd(rawobject, 
offset))
+        byteptr = rffi.cast(rffi.VOIDPP, capi.direct_ptradd(rawobject, offset))
         buf = space.getarg_w('s*', w_value)
         try:
-            byteptr[0] = buf.get_raw_address()
+            byteptr[0] = rffi.cast(rffi.VOIDP, buf.get_raw_address())
         except ValueError:
             raise oefmt(space.w_TypeError,
                         "raw buffer interface not supported")
@@ -337,6 +321,10 @@
         address = rffi.cast(rffi.CCHARP, self._get_raw_address(space, w_obj, 
offset))
         address[0] = self._unwrap_object(space, w_value)
 
+
+class UCharConverter(ffitypes.typeid(rffi.UCHAR), CharConverter):
+    pass
+
 class FloatConverter(ffitypes.typeid(rffi.FLOAT), FloatTypeConverterMixin, 
TypeConverter):
     _immutable_fields_ = ['default']
 
@@ -398,12 +386,12 @@
         arg = space.text_w(w_obj)
         x[0] = rffi.cast(rffi.LONG, rffi.str2charp(arg))
         ba = rffi.cast(rffi.CCHARP, address)
-        ba[capi.c_function_arg_typeoffset(space)] = 'o'
+        ba[capi.c_function_arg_typeoffset(space)] = 'p'
 
     def from_memory(self, space, w_obj, w_pycppclass, offset):
         address = self._get_raw_address(space, w_obj, offset)
         charpptr = rffi.cast(rffi.CCHARPP, address)
-        return space.newbytes(rffi.charp2str(charpptr[0]))
+        return space.newtext(rffi.charp2str(charpptr[0]))
 
     def free_argument(self, space, arg, call_local):
         lltype.free(rffi.cast(rffi.CCHARPP, arg)[0], flavor='raw')
@@ -420,7 +408,7 @@
         strsize = self.size
         if charpptr[self.size-1] == '\0':
             strsize = self.size-1  # rffi will add \0 back
-        return space.newbytes(rffi.charpsize2str(charpptr, strsize))
+        return space.newtext(rffi.charpsize2str(charpptr, strsize))
 
 
 class VoidPtrConverter(TypeConverter):
@@ -449,12 +437,12 @@
         # returned as a long value for the address (INTPTR_T is not proper
         # per se, but rffi does not come with a PTRDIFF_T)
         address = self._get_raw_address(space, w_obj, offset)
-        ptrval = rffi.cast(rffi.ULONG, rffi.cast(rffi.VOIDPP, address)[0])
-        if ptrval == 0:
+        ptrval = rffi.cast(rffi.ULONGP, address)[0]
+        if ptrval == rffi.cast(rffi.ULONG, 0):
             from pypy.module._cppyy import interp_cppyy
             return interp_cppyy.get_nullptr(space)
-        arr = space.interp_w(W_Array, letter2tp(space, 'P'))
-        return arr.fromaddress(space, ptrval, sys.maxint)
+        shape = letter2tp(space, 'P')
+        return W_ArrayInstance(space, shape, sys.maxint/shape.size, ptrval)
 
     def to_memory(self, space, w_obj, w_value, offset):
         address = rffi.cast(rffi.VOIDPP, self._get_raw_address(space, w_obj, 
offset))
@@ -504,8 +492,8 @@
     def _unwrap_object(self, space, w_obj):
         from pypy.module._cppyy.interp_cppyy import W_CPPInstance
         if isinstance(w_obj, W_CPPInstance):
-            from pypy.module._cppyy.interp_cppyy import 
INSTANCE_FLAGS_IS_R_VALUE
-            if w_obj.flags & INSTANCE_FLAGS_IS_R_VALUE:
+            from pypy.module._cppyy.interp_cppyy import 
INSTANCE_FLAGS_IS_RVALUE
+            if w_obj.flags & INSTANCE_FLAGS_IS_RVALUE:
                 # reject moves as all are explicit
                 raise ValueError("lvalue expected")
             if capi.c_is_subtype(space, w_obj.clsdecl, self.clsdecl):
@@ -514,7 +502,7 @@
                 obj_address = capi.direct_ptradd(rawobject, offset)
                 return rffi.cast(capi.C_OBJECT, obj_address)
         raise oefmt(space.w_TypeError,
-                    "cannot pass %T as %s", w_obj, self.clsdecl.name)
+                    "cannot pass %T instance as %s", w_obj, self.clsdecl.name)
 
     def cffi_type(self, space):
         state = space.fromcache(ffitypes.State)
@@ -534,11 +522,18 @@
 class InstanceMoveConverter(InstanceRefConverter):
     def _unwrap_object(self, space, w_obj):
         # moving is same as by-ref, but have to check that move is allowed
-        from pypy.module._cppyy.interp_cppyy import W_CPPInstance, 
INSTANCE_FLAGS_IS_R_VALUE
-        if isinstance(w_obj, W_CPPInstance):
-            if w_obj.flags & INSTANCE_FLAGS_IS_R_VALUE:
-                w_obj.flags &= ~INSTANCE_FLAGS_IS_R_VALUE
-                return InstanceRefConverter._unwrap_object(self, space, w_obj)
+        from pypy.module._cppyy.interp_cppyy import W_CPPInstance, 
INSTANCE_FLAGS_IS_RVALUE
+        obj = space.interp_w(W_CPPInstance, w_obj)
+        if obj:
+            if obj.flags & INSTANCE_FLAGS_IS_RVALUE:
+                obj.flags &= ~INSTANCE_FLAGS_IS_RVALUE
+                try:
+                    return InstanceRefConverter._unwrap_object(self, space, 
w_obj)
+                except Exception:
+                    # TODO: if the method fails on some other converter, then 
the next
+                    # overload can not be an rvalue anymore
+                    obj.flags |= INSTANCE_FLAGS_IS_RVALUE
+                    raise
         raise oefmt(space.w_ValueError, "object is not an rvalue")
 
 
@@ -629,8 +624,7 @@
             address = rffi.cast(capi.C_OBJECT, self._get_raw_address(space, 
w_obj, offset))
             assign = self.clsdecl.get_overload("__assign__")
             from pypy.module._cppyy import interp_cppyy
-            assign.call(
-                interp_cppyy.wrap_cppinstance(space, address, self.clsdecl, 
do_cast=False), [w_value])
+            assign.call_impl(address, [w_value])
         except Exception:
             InstanceConverter.to_memory(self, space, w_obj, w_value, offset)
 
@@ -639,7 +633,6 @@
 
 class StdStringRefConverter(InstancePtrConverter):
     _immutable_fields_ = ['cppclass', 'typecode']
-
     typecode    = 'V'
 
     def __init__(self, space, extra):
@@ -702,8 +695,7 @@
             m = cppol.functions[i]
             if m.signature(False) == self.signature:
                 x = rffi.cast(rffi.VOIDPP, address)
-                x[0] = rffi.cast(rffi.VOIDP,
-                    capi.c_function_address_from_method(space, m.cppmethod))
+                x[0] = rffi.cast(rffi.VOIDP, capi.c_function_address(space, 
m.cppmethod))
                 address = rffi.cast(capi.C_OBJECT, address)
                 ba = rffi.cast(rffi.CCHARP, address)
                 ba[capi.c_function_arg_typeoffset(space)] = 'p'
@@ -714,6 +706,67 @@
                     "no overload found matching %s", self.signature)
 
 
+class SmartPointerConverter(TypeConverter):
+    _immutable_fields = ['typecode', 'smartdecl', 'rawdecl', 'deref']
+    typecode    = 'V'
+
+    def __init__(self, space, smartdecl, raw, deref):
+        from pypy.module._cppyy.interp_cppyy import W_CPPClassDecl, 
get_pythonized_cppclass
+        self.smartdecl = smartdecl
+        w_raw   = get_pythonized_cppclass(space, raw)
+        self.rawdecl   = space.interp_w(W_CPPClassDecl,
+            space.findattr(w_raw, space.newtext("__cppdecl__")))
+        self.deref     = deref
+
+    def _unwrap_object(self, space, w_obj):
+        from pypy.module._cppyy.interp_cppyy import W_CPPInstance
+        if isinstance(w_obj, W_CPPInstance):
+            # w_obj could carry a 'hidden' smart ptr or be one, cover both 
cases
+            have_match = False
+            if w_obj.smartdecl and capi.c_is_subtype(space, w_obj.smartdecl, 
self.smartdecl):
+                # hidden case, do not derefence when getting obj address
+                have_match = True
+                rawobject = w_obj._rawobject      # TODO: this direct access 
if fugly
+                offset = capi.c_base_offset(space, w_obj.smartdecl, 
self.smartdecl, rawobject, 1)
+            elif capi.c_is_subtype(space, w_obj.clsdecl, self.smartdecl):
+                # exposed smart pointer
+                have_match = True
+                rawobject = w_obj.get_rawobject()
+                offset = capi.c_base_offset(space, w_obj.clsdecl, 
self.smartdecl, rawobject, 1)
+            if have_match:
+                obj_address = capi.direct_ptradd(rawobject, offset)
+                return rffi.cast(capi.C_OBJECT, obj_address)
+
+        raise oefmt(space.w_TypeError,
+                    "cannot pass %T instance as %s", w_obj, self.rawdecl.name)
+
+    def convert_argument(self, space, w_obj, address, call_local):
+        x = rffi.cast(rffi.VOIDPP, address)
+        x[0] = rffi.cast(rffi.VOIDP, self._unwrap_object(space, w_obj))
+        address = rffi.cast(capi.C_OBJECT, address)
+        ba = rffi.cast(rffi.CCHARP, address)
+        ba[capi.c_function_arg_typeoffset(space)] = self.typecode
+
+    def from_memory(self, space, w_obj, w_pycppclass, offset):
+        address = rffi.cast(capi.C_OBJECT, self._get_raw_address(space, w_obj, 
offset))
+        from pypy.module._cppyy import interp_cppyy
+        return interp_cppyy.wrap_cppinstance(space, address,
+            self.rawdecl, smartdecl=self.smartdecl, deref=self.deref, 
do_cast=False)
+
+class SmartPointerPtrConverter(SmartPointerConverter):
+    typecode    = 'o'
+
+    def from_memory(self, space, w_obj, w_pycppclass, offset):
+        self._is_abstract(space)
+
+    def to_memory(self, space, w_obj, w_value, offset):
+        self._is_abstract(space)
+
+
+class SmartPointerRefConverter(SmartPointerPtrConverter):
+    typecode    = 'V'
+
+
 class MacroConverter(TypeConverter):
     def from_memory(self, space, w_obj, w_pycppclass, offset):
         # TODO: get the actual type info from somewhere ...
@@ -729,44 +782,55 @@
     #   1) full, exact match
     #       1a) const-removed match
     #   2) match of decorated, unqualified type
-    #   3) accept ref as pointer (for the stubs, const& can be
-    #       by value, but that does not work for the ffi path)
-    #   4) generalized cases (covers basically all user classes)
-    #   5) void* or void converter (which fails on use)
+    #   3) generalized cases (covers basically all user classes)
+    #       3a) smart pointers
+    #   4) void* or void converter (which fails on use)
 
     name = capi.c_resolve_name(space, _name)
 
-    #   1) full, exact match
+    # full, exact match
     try:
         return _converters[name](space, default)
     except KeyError:
         pass
 
-    #   1a) const-removed match
+    # const-removed match
     try:
         return _converters[helper.remove_const(name)](space, default)
     except KeyError:
         pass
 
-    #   2) match of decorated, unqualified type
+    # match of decorated, unqualified type
     compound = helper.compound(name)
     clean_name = capi.c_resolve_name(space, helper.clean_type(name))
     try:
         # array_index may be negative to indicate no size or no size found
         array_size = helper.array_size(_name)     # uses original arg
+        # TODO: using clean_name here drops const (e.g. const char[] will
+        # never be seen this way)
         return _a_converters[clean_name+compound](space, array_size)
     except KeyError:
         pass
 
-    #   3) TODO: accept ref as pointer
-
-    #   4) generalized cases (covers basically all user classes)
+    # generalized cases (covers basically all user classes)
     from pypy.module._cppyy import interp_cppyy
     scope_decl = interp_cppyy.scope_byname(space, clean_name)
     if scope_decl:
-        # type check for the benefit of the annotator
         from pypy.module._cppyy.interp_cppyy import W_CPPClassDecl
         clsdecl = space.interp_w(W_CPPClassDecl, scope_decl, can_be_None=False)
+
+        # check smart pointer type
+        check_smart = capi.c_smartptr_info(space, clean_name)
+        if check_smart[0]:
+            if compound == '':
+                return SmartPointerConverter(space, clsdecl, check_smart[1], 
check_smart[2])
+            elif compound == '*':
+                return SmartPointerPtrConverter(space, clsdecl, 
check_smart[1], check_smart[2])
+            elif compound == '&':
+                return SmartPointerRefConverter(space, clsdecl, 
check_smart[1], check_smart[2])
+            # fall through: can still return smart pointer in non-smart way
+
+        # type check for the benefit of the annotator
         if compound == "*":
             return InstancePtrConverter(space, clsdecl)
         elif compound == "&":
@@ -786,7 +850,7 @@
         if pos > 0:
             return FunctionPointerConverter(space, name[pos+2:])
 
-    #   5) void* or void converter (which fails on use)
+    # void* or void converter (which fails on use)
     if 0 <= compound.find('*'):
         return VoidPtrConverter(space, default)  # "user knows best"
 
@@ -797,6 +861,7 @@
 
 _converters["bool"]                     = BoolConverter
 _converters["char"]                     = CharConverter
+_converters["unsigned char"]            = UCharConverter
 _converters["float"]                    = FloatConverter
 _converters["const float&"]             = ConstFloatRefConverter
 _converters["double"]                   = DoubleConverter
@@ -886,6 +951,7 @@
     "NOT_RPYTHON"
     array_info = (
         ('b', rffi.sizeof(rffi.UCHAR),      ("bool",)),    # is debatable, but 
works ...
+        ('B', rffi.sizeof(rffi.UCHAR),      ("unsigned char",)),
         ('h', rffi.sizeof(rffi.SHORT),      ("short int", "short")),
         ('H', rffi.sizeof(rffi.USHORT),     ("unsigned short int", "unsigned 
short")),
         ('i', rffi.sizeof(rffi.INT),        ("int",)),
@@ -901,9 +967,11 @@
 
     for tcode, tsize, names in array_info:
         class ArrayConverter(ArrayTypeConverterMixin, TypeConverter):
+            _immutable_fields_ = ['typecode', 'typesize']
             typecode = tcode
             typesize = tsize
         class PtrConverter(PtrTypeConverterMixin, TypeConverter):
+            _immutable_fields_ = ['typecode', 'typesize']
             typecode = tcode
             typesize = tsize
         for name in names:
@@ -912,6 +980,7 @@
 
     # special case, const char* w/ size and w/o '\0'
     _a_converters["const char[]"] = CStringConverterWithSize
+    _a_converters["char[]"]       = _a_converters["const char[]"]     # 
debatable
 
 _build_array_converters()
 
@@ -919,7 +988,6 @@
 def _add_aliased_converters():
     "NOT_RPYTHON"
     aliases = (
-        ("char",                            "unsigned char"), # TODO: check
         ("char",                            "signed char"),   # TODO: check
         ("const char*",                     "char*"),
 
diff --git a/pypy/module/_cppyy/executor.py b/pypy/module/_cppyy/executor.py
--- a/pypy/module/_cppyy/executor.py
+++ b/pypy/module/_cppyy/executor.py
@@ -5,7 +5,7 @@
 from rpython.rtyper.lltypesystem import rffi, lltype
 from rpython.rlib import jit_libffi
 
-from pypy.module._rawffi.interp_rawffi import unpack_simple_shape
+from pypy.module._rawffi.interp_rawffi import letter2tp
 from pypy.module._rawffi.array import W_Array, W_ArrayInstance
 
 from pypy.module._cppyy import helper, capi, ffitypes
@@ -56,11 +56,11 @@
             raise NotImplementedError
         lresult = capi.c_call_l(space, cppmethod, cppthis, num_args, args)
         ptrval = rffi.cast(rffi.ULONG, lresult)
-        arr = space.interp_w(W_Array, unpack_simple_shape(space, 
space.newtext(self.typecode)))
-        if ptrval == 0:
+        if ptrval == rffi.cast(rffi.ULONG, 0):
             from pypy.module._cppyy import interp_cppyy
             return interp_cppyy.get_nullptr(space)
-        return arr.fromaddress(space, ptrval, sys.maxint)
+        shape = letter2tp(space, self.typecode)
+        return W_ArrayInstance(space, shape, sys.maxint/shape.size, ptrval)
 
 
 class VoidExecutor(FunctionExecutor):
@@ -125,7 +125,6 @@
 
 
 class CStringExecutor(FunctionExecutor):
-
     def execute(self, space, cppmethod, cppthis, num_args, args):
         lresult = capi.c_call_l(space, cppmethod, cppthis, num_args, args)
         ccpresult = rffi.cast(rffi.CCHARP, lresult)
@@ -136,7 +135,6 @@
 
 
 class ConstructorExecutor(FunctionExecutor):
-
     def execute(self, space, cppmethod, cpptype, num_args, args):
         from pypy.module._cppyy import interp_cppyy
         newthis = capi.c_constructor(space, cppmethod, cpptype, num_args, args)
@@ -144,80 +142,77 @@
         return space.newlong(rffi.cast(rffi.LONG, newthis))   # really want 
ptrdiff_t here
 
 
-class InstancePtrExecutor(FunctionExecutor):
-    _immutable_fields_ = ['cppclass']
+class InstanceExecutor(FunctionExecutor):
+    # For return of a C++ instance by pointer: MyClass* func()
+    _immutable_fields_ = ['clsdecl']
 
-    def __init__(self, space, cppclass):
-        FunctionExecutor.__init__(self, space, cppclass)
-        self.cppclass = cppclass
+    def __init__(self, space, clsdecl):
+        FunctionExecutor.__init__(self, space, clsdecl)
+        self.clsdecl = clsdecl
+
+    def _wrap_result(self, space, obj):
+        from pypy.module._cppyy import interp_cppyy
+        return interp_cppyy.wrap_cppinstance(space,
+            obj, self.clsdecl, do_cast=False, python_owns=True, fresh=True)
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        oresult = capi.c_call_o(space, cppmethod, cppthis, num_args, args, 
self.clsdecl)
+        return self._wrap_result(space, rffi.cast(capi.C_OBJECT, oresult))
+
+
+class InstancePtrExecutor(InstanceExecutor):
+    # For return of a C++ instance by pointer: MyClass* func()
 
     def cffi_type(self, space):
         state = space.fromcache(ffitypes.State)
         return state.c_voidp
 
+    def _wrap_result(self, space, obj):
+        from pypy.module._cppyy import interp_cppyy
+        return interp_cppyy.wrap_cppinstance(space, obj, self.clsdecl)
+
     def execute(self, space, cppmethod, cppthis, num_args, args):
-        from pypy.module._cppyy import interp_cppyy
-        long_result = capi.c_call_l(space, cppmethod, cppthis, num_args, args)
-        ptr_result = rffi.cast(capi.C_OBJECT, long_result)
-        pyres = interp_cppyy.wrap_cppinstance(space, ptr_result, self.cppclass)
-        return pyres
+        lresult = capi.c_call_l(space, cppmethod, cppthis, num_args, args)
+        return self._wrap_result(space, rffi.cast(capi.C_OBJECT, lresult))
 
     def execute_libffi(self, space, cif_descr, funcaddr, buffer):
         jit_libffi.jit_ffi_call(cif_descr, funcaddr, buffer)
-        result = rffi.ptradd(buffer, cif_descr.exchange_result)
-        from pypy.module._cppyy import interp_cppyy
-        ptr_result = rffi.cast(capi.C_OBJECT, rffi.cast(rffi.VOIDPP, 
result)[0])
-        return interp_cppyy.wrap_cppinstance(space, ptr_result, self.cppclass)
+        presult = rffi.ptradd(buffer, cif_descr.exchange_result)
+        obj = rffi.cast(capi.C_OBJECT, rffi.cast(rffi.VOIDPP, presult)[0])
+        return self._wrap_result(space, obj)
 
 class InstancePtrPtrExecutor(InstancePtrExecutor):
+    # For return of a C++ instance by ptr-to-ptr or ptr-to-ref: MyClass*& 
func()
 
     def execute(self, space, cppmethod, cppthis, num_args, args):
-        from pypy.module._cppyy import interp_cppyy
-        voidp_result = capi.c_call_r(space, cppmethod, cppthis, num_args, args)
-        ref_address = rffi.cast(rffi.VOIDPP, voidp_result)
-        ptr_result = rffi.cast(capi.C_OBJECT, ref_address[0])
-        return interp_cppyy.wrap_cppinstance(space, ptr_result, self.cppclass)
+        presult = capi.c_call_r(space, cppmethod, cppthis, num_args, args)
+        ref = rffi.cast(rffi.VOIDPP, presult)
+        return self._wrap_result(space, rffi.cast(capi.C_OBJECT, ref[0]))
 
     def execute_libffi(self, space, cif_descr, funcaddr, buffer):
         from pypy.module._cppyy.interp_cppyy import FastCallNotPossible
         raise FastCallNotPossible
 
-class InstanceExecutor(InstancePtrExecutor):
-
-    def execute(self, space, cppmethod, cppthis, num_args, args):
-        from pypy.module._cppyy import interp_cppyy
-        long_result = capi.c_call_o(space, cppmethod, cppthis, num_args, args, 
self.cppclass)
-        ptr_result = rffi.cast(capi.C_OBJECT, long_result)
-        return interp_cppyy.wrap_cppinstance(space, ptr_result, self.cppclass,
-                                             do_cast=False, python_owns=True, 
fresh=True)
-
-    def execute_libffi(self, space, cif_descr, funcaddr, buffer):
-        from pypy.module._cppyy.interp_cppyy import FastCallNotPossible
-        raise FastCallNotPossible
-
 
 class StdStringExecutor(InstancePtrExecutor):
-
     def execute(self, space, cppmethod, cppthis, num_args, args):
         cstr, cstr_len = capi.c_call_s(space, cppmethod, cppthis, num_args, 
args)
         pystr = rffi.charpsize2str(cstr, cstr_len)
         capi.c_free(space, rffi.cast(rffi.VOIDP, cstr))
-        return space.newbytes(pystr)
+        return space.newbytes(pystr) 
 
     def execute_libffi(self, space, cif_descr, funcaddr, buffer):
         from pypy.module._cppyy.interp_cppyy import FastCallNotPossible
         raise FastCallNotPossible
 
 class StdStringRefExecutor(InstancePtrExecutor):
-
-    def __init__(self, space, cppclass):
+    def __init__(self, space, clsdecl):
         from pypy.module._cppyy import interp_cppyy
-        cppclass = interp_cppyy.scope_byname(space, capi.std_string_name)
-        InstancePtrExecutor.__init__(self, space, cppclass)
+        clsdecl = interp_cppyy.scope_byname(space, capi.std_string_name)
+        InstancePtrExecutor.__init__(self, space, clsdecl)
 
 
 class PyObjectExecutor(PtrTypeExecutor):
-
     def wrap_result(self, space, lresult):
         space.getbuiltinmodule("cpyext")
         from pypy.module.cpyext.pyobject import PyObject, from_ref, make_ref, 
decref
@@ -241,6 +236,41 @@
         return self.wrap_result(space, rffi.cast(rffi.LONGP, result)[0])
 
 
+class SmartPointerExecutor(InstanceExecutor):
+    _immutable_fields_ = ['smartdecl', 'deref']
+
+    def __init__(self, space, smartdecl, raw, deref):
+        from pypy.module._cppyy.interp_cppyy import W_CPPClassDecl, 
get_pythonized_cppclass
+        w_raw   = get_pythonized_cppclass(space, raw)
+        rawdecl = space.interp_w(W_CPPClassDecl, space.findattr(w_raw, 
space.newtext("__cppdecl__")))
+        InstanceExecutor.__init__(self, space, rawdecl)
+        self.smartdecl = smartdecl
+        self.deref     = deref
+
+    def _wrap_result(self, space, obj):
+        from pypy.module._cppyy import interp_cppyy
+        return interp_cppyy.wrap_cppinstance(space, obj, self.clsdecl,
+            self.smartdecl, self.deref, do_cast=False, python_owns=True, 
fresh=True)
+
+class SmartPointerPtrExecutor(InstancePtrExecutor):
+    _immutable_fields_ = ['smartdecl', 'deref']
+
+    def __init__(self, space, smartdecl, raw, deref):
+        # TODO: share this with SmartPointerExecutor through in mixin
+        from pypy.module._cppyy.interp_cppyy import W_CPPClassDecl, 
get_pythonized_cppclass
+        w_raw   = get_pythonized_cppclass(space, raw)
+        rawdecl = space.interp_w(W_CPPClassDecl, space.findattr(w_raw, 
space.newtext("__cppdecl__")))
+        InstancePtrExecutor.__init__(self, space, rawdecl)
+        self.smartdecl = smartdecl
+        self.deref     = deref
+
+    def _wrap_result(self, space, obj):
+        from pypy.module._cppyy import interp_cppyy
+        # TODO: this is a pointer to a smart pointer, take ownership on the 
smart one?
+        return interp_cppyy.wrap_cppinstance(space, obj, self.clsdecl,
+            self.smartdecl, self.deref, do_cast=False)
+
+
 _executors = {}
 def get_executor(space, name):
     # Matching of 'name' to an executor factory goes through up to four levels:
@@ -253,7 +283,7 @@
 
     name = capi.c_resolve_name(space, name)
 
-    #   1) full, qualified match
+    # full, qualified match
     try:
         return _executors[name](space, None)
     except KeyError:
@@ -262,13 +292,13 @@
     compound = helper.compound(name)
     clean_name = capi.c_resolve_name(space, helper.clean_type(name))
 
-    #   1a) clean lookup
+    # clean lookup
     try:
         return _executors[clean_name+compound](space, None)
     except KeyError:
         pass
 
-    #   2) drop '&': by-ref is pretty much the same as by-value, python-wise
+    # drop '&': by-ref is pretty much the same as by-value, python-wise
     if compound and compound[len(compound)-1] == '&':
         # TODO: this does not actually work with Reflex (?)
         try:
@@ -276,19 +306,29 @@
         except KeyError:
             pass
 
-    #   3) types/classes, either by ref/ptr or by value
+    # types/classes, either by ref/ptr or by value
     from pypy.module._cppyy import interp_cppyy
     cppclass = interp_cppyy.scope_byname(space, clean_name)
     if cppclass:
         # type check for the benefit of the annotator
         from pypy.module._cppyy.interp_cppyy import W_CPPClassDecl
-        cppclass = space.interp_w(W_CPPClassDecl, cppclass, can_be_None=False)
+        clsdecl = space.interp_w(W_CPPClassDecl, cppclass, can_be_None=False)
+
+        # check smart pointer type
+        check_smart = capi.c_smartptr_info(space, clean_name)
+        if check_smart[0]:
+            if compound == '':
+                return SmartPointerExecutor(space, clsdecl, check_smart[1], 
check_smart[2])
+            elif compound == '*' or compound == '&':
+                return SmartPointerPtrExecutor(space, clsdecl, check_smart[1], 
check_smart[2])
+            # fall through: can still return smart pointer in non-smart way
+
         if compound == '':
-            return InstanceExecutor(space, cppclass)
+            return InstanceExecutor(space, clsdecl)
         elif compound == '*' or compound == '&':
-            return InstancePtrExecutor(space, cppclass)
+            return InstancePtrExecutor(space, clsdecl)
         elif compound == '**' or compound == '*&':
-            return InstancePtrPtrExecutor(space, cppclass)
+            return InstancePtrPtrExecutor(space, clsdecl)
     elif "(anonymous)" in name:
         # special case: enum w/o a type name
         return _executors["internal_enum_type_t"](space, None)
diff --git a/pypy/module/_cppyy/ffitypes.py b/pypy/module/_cppyy/ffitypes.py
--- a/pypy/module/_cppyy/ffitypes.py
+++ b/pypy/module/_cppyy/ffitypes.py
@@ -74,15 +74,52 @@
         # allow int to pass to char and make sure that str is of length 1
         if space.isinstance_w(w_value, space.w_int):
             ival = space.c_int_w(w_value)
+            if ival < -128 or 127 < ival:
+                raise oefmt(space.w_ValueError, "char arg not in 
range(-128,128)")
+
+            value = rffi.cast(rffi.CHAR, space.c_int_w(w_value))
+        else:
+            if space.isinstance_w(w_value, space.w_text):
+                value = space.text_w(w_value)
+            else:
+                value = space.bytes_w(w_value)
+            if len(value) != 1:
+                raise oefmt(space.w_ValueError,
+                            "char expected, got string of size %d", len(value))
+
+        value = rffi.cast(rffi.CHAR, value[0])
+        return value     # turn it into a "char" to the annotator
+
+    def cffi_type(self, space):
+        state = space.fromcache(State)
+        return state.c_char
+
+class UCharTypeMixin(object):
+    _mixin_     = True
+    _immutable_fields_ = ['c_type', 'c_ptrtype']
+
+    c_type      = rffi.UCHAR
+    c_ptrtype   = rffi.CCHARP           # there's no such thing as rffi.UCHARP
+
+    def _wrap_object(self, space, obj):
+        return space.newbytes(obj)
+
+    def _unwrap_object(self, space, w_value):
+        # allow int to pass to char and make sure that str is of length 1
+        if space.isinstance_w(w_value, space.w_int):
+            ival = space.c_int_w(w_value)
             if ival < 0 or 256 <= ival:
                 raise oefmt(space.w_ValueError, "char arg not in range(256)")
 
             value = rffi.cast(rffi.CHAR, space.c_int_w(w_value))
         else:
-            value = space.text_w(w_value)
+            if space.isinstance_w(w_value, space.w_text):
+                value = space.text_w(w_value)
+            else:
+                value = space.bytes_w(w_value)
             if len(value) != 1:
                 raise oefmt(space.w_ValueError,
-                        "char expected, got string of size %d", len(value))
+                            "usigned char expected, got string of size %d", 
len(value))
 
         value = rffi.cast(rffi.CHAR, value[0])
         return value     # turn it into a "char" to the annotator
@@ -277,6 +314,7 @@
     "NOT_RPYTHON"
     if c_type == bool:            return BoolTypeMixin
     if c_type == rffi.CHAR:       return CharTypeMixin
+    if c_type == rffi.UCHAR:      return UCharTypeMixin
     if c_type == rffi.SHORT:      return ShortTypeMixin
     if c_type == rffi.USHORT:     return UShortTypeMixin
     if c_type == rffi.INT:        return IntTypeMixin
diff --git a/pypy/module/_cppyy/helper.py b/pypy/module/_cppyy/helper.py
--- a/pypy/module/_cppyy/helper.py
+++ b/pypy/module/_cppyy/helper.py
@@ -1,3 +1,4 @@
+import sys
 from rpython.rlib import rstring
 
 
@@ -116,6 +117,17 @@
     # TODO: perhaps absorb or "pythonify" these operators?
     return cppname
 
+if sys.hexversion < 0x3000000:
+    CPPYY__div__  = "__div__"
+    CPPYY__idiv__ = "__idiv__"
+    CPPYY__long__ = "__long__"
+    CPPYY__bool__ = "__nonzero__"
+else:
+    CPPYY__div__  = "__truediv__"
+    CPPYY__idiv__ = "__itruediv__"
+    CPPYY__long__ = "__int__"
+    CPPYY__bool__ = "__bool__"
+
 # _operator_mappings["[]"]  = "__setitem__"      # depends on return type
 # _operator_mappings["+"]   = "__add__"          # depends on # of args (see 
__pos__)
 # _operator_mappings["-"]   = "__sub__"          # id. (eq. __neg__)
@@ -123,7 +135,7 @@
 
 # _operator_mappings["[]"]  = "__getitem__"      # depends on return type
 _operator_mappings["()"]  = "__call__"
-_operator_mappings["/"]   = "__div__"            # __truediv__ in p3
+_operator_mappings["/"]   = CPPYY__div__
 _operator_mappings["%"]   = "__mod__"
 _operator_mappings["**"]  = "__pow__"            # not C++
 _operator_mappings["<<"]  = "__lshift__"
@@ -136,7 +148,7 @@
 _operator_mappings["+="]  = "__iadd__"
 _operator_mappings["-="]  = "__isub__"
 _operator_mappings["*="]  = "__imul__"
-_operator_mappings["/="]  = "__idiv__"           # __itruediv__ in p3
+_operator_mappings["/="]  = CPPYY__idiv__
 _operator_mappings["%="]  = "__imod__"
 _operator_mappings["**="] = "__ipow__"
 _operator_mappings["<<="] = "__ilshift__"
@@ -154,7 +166,7 @@
 # the following type mappings are "exact"
 _operator_mappings["const char*"] = "__str__"
 _operator_mappings["int"]         = "__int__"
-_operator_mappings["long"]        = "__long__"   # __int__ in p3
+_operator_mappings["long"]        = CPPYY__long__
 _operator_mappings["double"]      = "__float__"
 
 # the following type mappings are "okay"; the assumption is that they
@@ -163,13 +175,13 @@
 _operator_mappings["char*"]              = "__str__"
 _operator_mappings["short"]              = "__int__"
 _operator_mappings["unsigned short"]     = "__int__"
-_operator_mappings["unsigned int"]       = "__long__"      # __int__ in p3
-_operator_mappings["unsigned long"]      = "__long__"      # id.
-_operator_mappings["long long"]          = "__long__"      # id.
-_operator_mappings["unsigned long long"] = "__long__"      # id.
+_operator_mappings["unsigned int"]       = CPPYY__long__
+_operator_mappings["unsigned long"]      = CPPYY__long__
+_operator_mappings["long long"]          = CPPYY__long__
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to