[pypy-commit] pypy cffi-1.0: Add some files

arigo noreply at buildbot.pypy.org
Sat May 2 16:42:59 CEST 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: cffi-1.0
Changeset: r76977:ec7541ae9244
Date: 2015-05-02 16:43 +0200
http://bitbucket.org/pypy/pypy/changeset/ec7541ae9244/

Log:	Add some files

diff --git a/pypy/module/_cffi_backend/cffi_opcode.py b/pypy/module/_cffi_backend/cffi_opcode.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cffi_backend/cffi_opcode.py
@@ -0,0 +1,144 @@
+
+class CffiOp(object):
+    def __init__(self, op, arg):
+        self.op = op
+        self.arg = arg
+    def as_c_expr(self):
+        if self.op is None:
+            assert isinstance(self.arg, str)
+            return '(_cffi_opcode_t)(%s)' % (self.arg,)
+        classname = CLASS_NAME[self.op]
+        return '_CFFI_OP(_CFFI_OP_%s, %d)' % (classname, self.arg)
+    def __str__(self):
+        classname = CLASS_NAME.get(self.op, self.op)
+        return '(%s %s)' % (classname, self.arg)
+
+OP_PRIMITIVE       = 1
+OP_POINTER         = 3
+OP_ARRAY           = 5
+OP_OPEN_ARRAY      = 7
+OP_STRUCT_UNION    = 9
+OP_ENUM            = 11
+OP_FUNCTION        = 13
+OP_FUNCTION_END    = 15
+OP_NOOP            = 17
+OP_BITFIELD        = 19
+OP_TYPENAME        = 21
+OP_CPYTHON_BLTN_V  = 23   # varargs
+OP_CPYTHON_BLTN_N  = 25   # noargs
+OP_CPYTHON_BLTN_O  = 27   # O  (i.e. a single arg)
+OP_CONSTANT        = 29
+OP_CONSTANT_INT    = 31
+OP_GLOBAL_VAR      = 33
+
+PRIM_VOID          = 0
+PRIM_BOOL          = 1
+PRIM_CHAR          = 2
+PRIM_SCHAR         = 3
+PRIM_UCHAR         = 4
+PRIM_SHORT         = 5
+PRIM_USHORT        = 6
+PRIM_INT           = 7
+PRIM_UINT          = 8
+PRIM_LONG          = 9
+PRIM_ULONG         = 10
+PRIM_LONGLONG      = 11
+PRIM_ULONGLONG     = 12
+PRIM_FLOAT         = 13
+PRIM_DOUBLE        = 14
+PRIM_LONGDOUBLE    = 15
+
+PRIM_WCHAR         = 16
+PRIM_INT8          = 17
+PRIM_UINT8         = 18
+PRIM_INT16         = 19
+PRIM_UINT16        = 20
+PRIM_INT32         = 21
+PRIM_UINT32        = 22
+PRIM_INT64         = 23
+PRIM_UINT64        = 24
+PRIM_INTPTR        = 25
+PRIM_UINTPTR       = 26
+PRIM_PTRDIFF       = 27
+PRIM_SIZE          = 28
+PRIM_SSIZE         = 29
+PRIM_INT_LEAST8    = 30
+PRIM_UINT_LEAST8   = 31
+PRIM_INT_LEAST16   = 32
+PRIM_UINT_LEAST16  = 33
+PRIM_INT_LEAST32   = 34
+PRIM_UINT_LEAST32  = 35
+PRIM_INT_LEAST64   = 36
+PRIM_UINT_LEAST64  = 37
+PRIM_INT_FAST8     = 38
+PRIM_UINT_FAST8    = 39
+PRIM_INT_FAST16    = 40
+PRIM_UINT_FAST16   = 41
+PRIM_INT_FAST32    = 42
+PRIM_UINT_FAST32   = 43
+PRIM_INT_FAST64    = 44
+PRIM_UINT_FAST64   = 45
+PRIM_INTMAX        = 46
+PRIM_UINTMAX       = 47
+
+_NUM_PRIM          = 48
+
+PRIMITIVE_TO_INDEX = {
+    'char':               PRIM_CHAR,
+    'short':              PRIM_SHORT,
+    'int':                PRIM_INT,
+    'long':               PRIM_LONG,
+    'long long':          PRIM_LONGLONG,
+    'signed char':        PRIM_SCHAR,
+    'unsigned char':      PRIM_UCHAR,
+    'unsigned short':     PRIM_USHORT,
+    'unsigned int':       PRIM_UINT,
+    'unsigned long':      PRIM_ULONG,
+    'unsigned long long': PRIM_ULONGLONG,
+    'float':              PRIM_FLOAT,
+    'double':             PRIM_DOUBLE,
+    'long double':        PRIM_LONGDOUBLE,
+    '_Bool':              PRIM_BOOL,
+    'wchar_t':            PRIM_WCHAR,
+    'int8_t':             PRIM_INT8,
+    'uint8_t':            PRIM_UINT8,
+    'int16_t':            PRIM_INT16,
+    'uint16_t':           PRIM_UINT16,
+    'int32_t':            PRIM_INT32,
+    'uint32_t':           PRIM_UINT32,
+    'int64_t':            PRIM_INT64,
+    'uint64_t':           PRIM_UINT64,
+    'intptr_t':           PRIM_INTPTR,
+    'uintptr_t':          PRIM_UINTPTR,
+    'ptrdiff_t':          PRIM_PTRDIFF,
+    'size_t':             PRIM_SIZE,
+    'ssize_t':            PRIM_SSIZE,
+    'int_least8_t':       PRIM_INT_LEAST8,
+    'uint_least8_t':      PRIM_UINT_LEAST8,
+    'int_least16_t':      PRIM_INT_LEAST16,
+    'uint_least16_t':     PRIM_UINT_LEAST16,
+    'int_least32_t':      PRIM_INT_LEAST32,
+    'uint_least32_t':     PRIM_UINT_LEAST32,
+    'int_least64_t':      PRIM_INT_LEAST64,
+    'uint_least64_t':     PRIM_UINT_LEAST64,
+    'int_fast8_t':        PRIM_INT_FAST8,
+    'uint_fast8_t':       PRIM_UINT_FAST8,
+    'int_fast16_t':       PRIM_INT_FAST16,
+    'uint_fast16_t':      PRIM_UINT_FAST16,
+    'int_fast32_t':       PRIM_INT_FAST32,
+    'uint_fast32_t':      PRIM_UINT_FAST32,
+    'int_fast64_t':       PRIM_INT_FAST64,
+    'uint_fast64_t':      PRIM_UINT_FAST64,
+    'intmax_t':           PRIM_INTMAX,
+    'uintmax_t':          PRIM_UINTMAX,
+    }
+
+F_UNION         = 0x01
+F_CHECK_FIELDS  = 0x02
+F_PACKED        = 0x04
+F_EXTERNAL      = 0x08
+
+CLASS_NAME = {}
+for _name, _value in list(globals().items()):
+    if _name.startswith('OP_') and isinstance(_value, int):
+        CLASS_NAME[_value] = _name[3:]
diff --git a/pypy/module/_cffi_backend/parse_c_type.py b/pypy/module/_cffi_backend/parse_c_type.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cffi_backend/parse_c_type.py
@@ -0,0 +1,28 @@
+import py, os
+from rpython.rtyper.lltypesystem import lltype, rffi
+from rpython.translator import cdir
+from rpython.translator.tool.cbuild import ExternalCompilationInfo
+
+
+src_dir = py.path.local(os.path.dirname(__file__)) / 'src'
+
+eci = ExternalCompilationInfo(
+    includes = ['parse_c_type.h'],
+    separate_module_files = [src_dir / 'parse_c_type.c'],
+    include_dirs = [src_dir, cdir],
+    pre_include_bits = ['#define _CFFI_INTERNAL'],
+)
+
+def llexternal(name, args, result, **kwds):
+    return rffi.llexternal(name, args, result, compilation_info=eci, **kwds)
+
+
+PCTX = rffi.CStructPtr('struct _cffi_type_context_s')
+PINFO = rffi.CStructPtr('struct _cffi_parse_info_s',
+                        ('ctx', PCTX),
+                        ('output', rffi.VOIDPP),
+                        ('output_size', rffi.UINT),
+                        ('error_location', rffi.SIZE_T),
+                        ('error_message', rffi.CCHARP))
+
+parse_c_type = llexternal('parse_c_type', [PINFO, rffi.CCHARP], rffi.INT)
diff --git a/pypy/module/_cffi_backend/src/parse_c_type.c b/pypy/module/_cffi_backend/src/parse_c_type.c
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cffi_backend/src/parse_c_type.c
@@ -0,0 +1,756 @@
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdint.h>
+
+#define _CFFI_INTERNAL
+#include "src/precommondefs.h"
+#include "parse_c_type.h"
+
+
+enum token_e {
+    TOK_STAR='*',
+    TOK_OPEN_PAREN='(',
+    TOK_CLOSE_PAREN=')',
+    TOK_OPEN_BRACKET='[',
+    TOK_CLOSE_BRACKET=']',
+    TOK_COMMA=',',
+
+    TOK_START=256,
+    TOK_END,
+    TOK_ERROR,
+    TOK_IDENTIFIER,
+    TOK_INTEGER,
+    TOK_DOTDOTDOT,
+
+    /* keywords */
+    TOK__BOOL,
+    TOK_CHAR,
+    //TOK__COMPLEX,
+    TOK_CONST,
+    TOK_DOUBLE,
+    TOK_ENUM,
+    TOK_FLOAT,
+    //TOK__IMAGINARY,
+    TOK_INT,
+    TOK_LONG,
+    TOK_SHORT,
+    TOK_SIGNED,
+    TOK_STRUCT,
+    TOK_UNION,
+    TOK_UNSIGNED,
+    TOK_VOID,
+    TOK_VOLATILE,
+};
+
+typedef struct {
+    struct _cffi_parse_info_s *info;
+    const char *input, *p;
+    size_t size;              // the next token is at 'p' and of length 'size'
+    enum token_e kind;
+    _cffi_opcode_t *output;
+    size_t output_index;
+} token_t;
+
+static int is_space(char x)
+{
+    return (x == ' ' || x == '\f' || x == '\n' || x == '\r' ||
+            x == '\t' || x == '\v');
+}
+
+static int is_ident_first(char x)
+{
+    return (('A' <= x && x <= 'Z') || ('a' <= x && x <= 'z') || x == '_' ||
+            x == '$');   /* '$' in names is supported here, for the struct
+                            names invented by cparser */
+}
+
+static int is_digit(char x)
+{
+    return ('0' <= x && x <= '9');
+}
+
+static int is_hex_digit(char x)
+{
+    return (('0' <= x && x <= '9') ||
+            ('A' <= x && x <= 'F') ||
+            ('a' <= x && x <= 'f'));
+}
+
+static int is_ident_next(char x)
+{
+    return (is_ident_first(x) || is_digit(x));
+}
+
+static char get_following_char(token_t *tok)
+{
+    const char *p = tok->p + tok->size;
+    if (tok->kind == TOK_ERROR)
+        return 0;
+    while (is_space(*p))
+        p++;
+    return *p;
+}
+
+static int number_of_commas(token_t *tok)
+{
+    const char *p = tok->p;
+    int result = 0;
+    int nesting = 0;
+    while (1) {
+        switch (*p++) {
+        case ',': result += !nesting; break;
+        case '(': nesting++; break;
+        case ')': if ((--nesting) < 0) return result; break;
+        case 0:   return result;
+        default:  break;
+        }
+    }
+}
+
+static void next_token(token_t *tok)
+{
+    const char *p = tok->p + tok->size;
+    if (tok->kind == TOK_ERROR)
+        return;
+    while (!is_ident_first(*p)) {
+        if (is_space(*p)) {
+            p++;
+        }
+        else if (is_digit(*p)) {
+            tok->kind = TOK_INTEGER;
+            tok->p = p;
+            tok->size = 1;
+            if (p[1] == 'x' || p[1] == 'X')
+                tok->size = 2;
+            while (is_hex_digit(p[tok->size]))
+                tok->size++;
+            return;
+        }
+        else if (p[0] == '.' && p[1] == '.' && p[2] == '.') {
+            tok->kind = TOK_DOTDOTDOT;
+            tok->p = p;
+            tok->size = 3;
+            return;
+        }
+        else if (*p) {
+            tok->kind = *p;
+            tok->p = p;
+            tok->size = 1;
+            return;
+        }
+        else {
+            tok->kind = TOK_END;
+            tok->p = p;
+            tok->size = 0;
+            return;
+        }
+    }
+    tok->kind = TOK_IDENTIFIER;
+    tok->p = p;
+    tok->size = 1;
+    while (is_ident_next(p[tok->size]))
+        tok->size++;
+
+    switch (*p) {
+    case '_':
+        if (tok->size == 5 && !memcmp(p, "_Bool", 5))  tok->kind = TOK__BOOL;
+        break;
+    case 'c':
+        if (tok->size == 4 && !memcmp(p, "char", 4))   tok->kind = TOK_CHAR;
+        if (tok->size == 5 && !memcmp(p, "const", 5))  tok->kind = TOK_CONST;
+        break;
+    case 'd':
+        if (tok->size == 6 && !memcmp(p, "double", 6)) tok->kind = TOK_DOUBLE;
+        break;
+    case 'e':
+        if (tok->size == 4 && !memcmp(p, "enum", 4))   tok->kind = TOK_ENUM;
+        break;
+    case 'f':
+        if (tok->size == 5 && !memcmp(p, "float", 5))  tok->kind = TOK_FLOAT;
+        break;
+    case 'i':
+        if (tok->size == 3 && !memcmp(p, "int", 3))    tok->kind = TOK_INT;
+        break;
+    case 'l':
+        if (tok->size == 4 && !memcmp(p, "long", 4))   tok->kind = TOK_LONG;
+        break;
+    case 's':
+        if (tok->size == 5 && !memcmp(p, "short", 5))  tok->kind = TOK_SHORT;
+        if (tok->size == 6 && !memcmp(p, "signed", 6)) tok->kind = TOK_SIGNED;
+        if (tok->size == 6 && !memcmp(p, "struct", 6)) tok->kind = TOK_STRUCT;
+        break;
+    case 'u':
+        if (tok->size == 5 && !memcmp(p, "union", 5))  tok->kind = TOK_UNION;
+        if (tok->size == 8 && !memcmp(p,"unsigned",8)) tok->kind = TOK_UNSIGNED;
+        break;
+    case 'v':
+        if (tok->size == 4 && !memcmp(p, "void", 4))   tok->kind = TOK_VOID;
+        if (tok->size == 8 && !memcmp(p,"volatile",8)) tok->kind = TOK_VOLATILE;
+        break;
+    }
+}
+
+static int parse_error(token_t *tok, const char *msg)
+{
+    if (tok->kind != TOK_ERROR) {
+        tok->kind = TOK_ERROR;
+        tok->info->error_location = tok->p - tok->input;
+        tok->info->error_message = msg;
+    }
+    return -1;
+}
+
+static int write_ds(token_t *tok, _cffi_opcode_t ds)
+{
+    size_t index = tok->output_index;
+    if (index >= tok->info->output_size) {
+        parse_error(tok, "internal type complexity limit reached");
+        return -1;
+    }
+    tok->output[index] = ds;
+    tok->output_index = index + 1;
+    return index;
+}
+
+#define MAX_SSIZE_T  (((size_t)-1) >> 1)
+
+static int parse_complete(token_t *tok);
+
+static int parse_sequel(token_t *tok, int outer)
+{
+    /* Emit opcodes for the "sequel", which is the optional part of a
+       type declaration that follows the type name, i.e. everything
+       with '*', '[ ]', '( )'.  Returns the entry point index pointing
+       the innermost opcode (the one that corresponds to the complete
+       type).  The 'outer' argument is the index of the opcode outside
+       this "sequel".
+     */
+    int check_for_grouping;
+    _cffi_opcode_t result, *p_current;
+
+ header:
+    switch (tok->kind) {
+    case TOK_STAR:
+        outer = write_ds(tok, _CFFI_OP(_CFFI_OP_POINTER, outer));
+        next_token(tok);
+        goto header;
+    case TOK_CONST:
+        /* ignored for now */
+        next_token(tok);
+        goto header;
+    case TOK_VOLATILE:
+        /* ignored for now */
+        next_token(tok);
+        goto header;
+    default:
+        break;
+    }
+
+    check_for_grouping = 1;
+    if (tok->kind == TOK_IDENTIFIER) {
+        next_token(tok);    /* skip a potential variable name */
+        check_for_grouping = 0;
+    }
+
+    result = 0;
+    p_current = &result;
+
+    while (tok->kind == TOK_OPEN_PAREN) {
+        next_token(tok);
+
+        if ((check_for_grouping--) == 1 && (tok->kind == TOK_STAR ||
+                                            tok->kind == TOK_CONST ||
+                                            tok->kind == TOK_VOLATILE ||
+                                            tok->kind == TOK_OPEN_BRACKET)) {
+            /* just parentheses for grouping.  Use a OP_NOOP to simplify */
+            int x;
+            assert(p_current == &result);
+            x = tok->output_index;
+            p_current = tok->output + x;
+
+            write_ds(tok, _CFFI_OP(_CFFI_OP_NOOP, 0));
+
+            x = parse_sequel(tok, x);
+            result = _CFFI_OP(_CFFI_GETOP(0), x);
+        }
+        else {
+            /* function type */
+            int arg_total, base_index, arg_next, has_ellipsis=0;
+
+            if (tok->kind == TOK_VOID && get_following_char(tok) == ')') {
+                next_token(tok);
+            }
+
+            /* (over-)estimate 'arg_total'.  May return 1 when it is really 0 */
+            arg_total = number_of_commas(tok) + 1;
+
+            *p_current = _CFFI_OP(_CFFI_GETOP(*p_current), tok->output_index);
+            p_current = tok->output + tok->output_index;
+
+            base_index = write_ds(tok, _CFFI_OP(_CFFI_OP_FUNCTION, 0));
+            if (base_index < 0)
+                return -1;
+            /* reserve (arg_total + 1) slots for the arguments and the
+               final FUNCTION_END */
+            for (arg_next = 0; arg_next <= arg_total; arg_next++)
+                if (write_ds(tok, _CFFI_OP(0, 0)) < 0)
+                    return -1;
+
+            arg_next = base_index + 1;
+
+            if (tok->kind != TOK_CLOSE_PAREN) {
+                while (1) {
+                    int arg;
+                    _cffi_opcode_t oarg;
+
+                    if (tok->kind == TOK_DOTDOTDOT) {
+                        has_ellipsis = 1;
+                        next_token(tok);
+                        break;
+                    }
+                    arg = parse_complete(tok);
+                    switch (_CFFI_GETOP(tok->output[arg])) {
+                    case _CFFI_OP_ARRAY:
+                    case _CFFI_OP_OPEN_ARRAY:
+                        arg = _CFFI_GETARG(tok->output[arg]);
+                        /* fall-through */
+                    case _CFFI_OP_FUNCTION:
+                        oarg = _CFFI_OP(_CFFI_OP_POINTER, arg);
+                        break;
+                    default:
+                        oarg = _CFFI_OP(_CFFI_OP_NOOP, arg);
+                        break;
+                    }
+                    assert(arg_next - base_index <= arg_total);
+                    tok->output[arg_next++] = oarg;
+                    if (tok->kind != TOK_COMMA)
+                        break;
+                    next_token(tok);
+                }
+            }
+            tok->output[arg_next] = _CFFI_OP(_CFFI_OP_FUNCTION_END,
+                                             has_ellipsis);
+        }
+
+        if (tok->kind != TOK_CLOSE_PAREN)
+            return parse_error(tok, "expected ')'");
+        next_token(tok);
+    }
+
+    while (tok->kind == TOK_OPEN_BRACKET) {
+        *p_current = _CFFI_OP(_CFFI_GETOP(*p_current), tok->output_index);
+        p_current = tok->output + tok->output_index;
+
+        next_token(tok);
+        if (tok->kind != TOK_CLOSE_BRACKET) {
+            size_t length;
+            int gindex;
+            char *endptr;
+
+            switch (tok->kind) {
+
+            case TOK_INTEGER:
+                errno = 0;
+#ifndef MS_WIN32
+                if (sizeof(length) > sizeof(unsigned long))
+                    length = strtoull(tok->p, &endptr, 0);
+                else
+#endif
+                    length = strtoul(tok->p, &endptr, 0);
+                if (endptr != tok->p + tok->size)
+                    return parse_error(tok, "invalid number");
+                if (errno == ERANGE || length > MAX_SSIZE_T)
+                    return parse_error(tok, "number too large");
+                break;
+
+            case TOK_IDENTIFIER:
+                gindex = search_in_globals(tok->info->ctx, tok->p, tok->size);
+                if (gindex >= 0) {
+                    const struct _cffi_global_s *g;
+                    g = &tok->info->ctx->globals[gindex];
+                    if (_CFFI_GETOP(g->type_op) == _CFFI_OP_CONSTANT_INT ||
+                        _CFFI_GETOP(g->type_op) == _CFFI_OP_ENUM) {
+                        unsigned long long value;
+                        int neg = ((int(*)(unsigned long long*))g->address)
+                            (&value);
+                        if (!neg && value > MAX_SSIZE_T)
+                            return parse_error(tok,
+                                               "integer constant too large");
+                        if (!neg || value == 0) {
+                            length = (size_t)value;
+                            break;
+                        }
+                    }
+                }
+                /* fall-through to the default case */
+            default:
+                return parse_error(tok, "expected a positive integer constant");
+            }
+
+            next_token(tok);
+
+            write_ds(tok, _CFFI_OP(_CFFI_OP_ARRAY, 0));
+            write_ds(tok, (_cffi_opcode_t)length);
+        }
+        else
+            write_ds(tok, _CFFI_OP(_CFFI_OP_OPEN_ARRAY, 0));
+
+        if (tok->kind != TOK_CLOSE_BRACKET)
+            return parse_error(tok, "expected ']'");
+        next_token(tok);
+    }
+
+    *p_current = _CFFI_OP(_CFFI_GETOP(*p_current), outer);
+    return _CFFI_GETARG(result);
+}
+
+
+#define MAKE_SEARCH_FUNC(FIELD)                                 \
+  static                                                        \
+  int search_in_##FIELD(const struct _cffi_type_context_s *ctx, \
+                        const char *search, size_t search_len)  \
+  {                                                             \
+      int left = 0, right = ctx->num_##FIELD;                   \
+                                                                \
+      while (left < right) {                                    \
+          int middle = (left + right) / 2;                      \
+          const char *src = ctx->FIELD[middle].name;            \
+          int diff = strncmp(src, search, search_len);          \
+          if (diff == 0 && src[search_len] == '\0')             \
+              return middle;                                    \
+          else if (diff >= 0)                                   \
+              right = middle;                                   \
+          else                                                  \
+              left = middle + 1;                                \
+      }                                                         \
+      return -1;                                                \
+  }
+
+MAKE_SEARCH_FUNC(globals)
+MAKE_SEARCH_FUNC(struct_unions)
+MAKE_SEARCH_FUNC(typenames)
+MAKE_SEARCH_FUNC(enums)
+
+#undef MAKE_SEARCH_FUNC
+
+
+static
+int search_standard_typename(const char *p, size_t size)
+{
+    if (size < 6 || p[size-2] != '_' || p[size-1] != 't')
+        return -1;
+
+    switch (p[4]) {
+
+    case '1':
+        if (size == 8 && !memcmp(p, "uint16", 6)) return _CFFI_PRIM_UINT16;
+        break;
+
+    case '2':
+        if (size == 7 && !memcmp(p, "int32", 5)) return _CFFI_PRIM_INT32;
+        break;
+
+    case '3':
+        if (size == 8 && !memcmp(p, "uint32", 6)) return _CFFI_PRIM_UINT32;
+        break;
+
+    case '4':
+        if (size == 7 && !memcmp(p, "int64", 5)) return _CFFI_PRIM_INT64;
+        break;
+
+    case '6':
+        if (size == 8 && !memcmp(p, "uint64", 6)) return _CFFI_PRIM_UINT64;
+        if (size == 7 && !memcmp(p, "int16", 5)) return _CFFI_PRIM_INT16;
+        break;
+
+    case '8':
+        if (size == 7 && !memcmp(p, "uint8", 5)) return _CFFI_PRIM_UINT8;
+        break;
+
+    case 'a':
+        if (size == 8 && !memcmp(p, "intmax", 6)) return _CFFI_PRIM_INTMAX;
+        break;
+
+    case 'e':
+        if (size == 7 && !memcmp(p, "ssize", 5)) return _CFFI_PRIM_SSIZE;
+        break;
+
+    case 'f':
+        if (size == 11 && !memcmp(p, "int_fast8",   9)) return _CFFI_PRIM_INT_FAST8;
+        if (size == 12 && !memcmp(p, "int_fast16", 10)) return _CFFI_PRIM_INT_FAST16;
+        if (size == 12 && !memcmp(p, "int_fast32", 10)) return _CFFI_PRIM_INT_FAST32;
+        if (size == 12 && !memcmp(p, "int_fast64", 10)) return _CFFI_PRIM_INT_FAST64;
+        break;
+
+    case 'i':
+        if (size == 9 && !memcmp(p, "ptrdiff", 7)) return _CFFI_PRIM_PTRDIFF;
+        break;
+
+    case 'l':
+        if (size == 12 && !memcmp(p, "int_least8",  10)) return _CFFI_PRIM_INT_LEAST8;
+        if (size == 13 && !memcmp(p, "int_least16", 11)) return _CFFI_PRIM_INT_LEAST16;
+        if (size == 13 && !memcmp(p, "int_least32", 11)) return _CFFI_PRIM_INT_LEAST32;
+        if (size == 13 && !memcmp(p, "int_least64", 11)) return _CFFI_PRIM_INT_LEAST64;
+        break;
+
+    case 'm':
+        if (size == 9 && !memcmp(p, "uintmax", 7)) return _CFFI_PRIM_UINTMAX;
+        break;
+
+    case 'p':
+        if (size == 9 && !memcmp(p, "uintptr", 7)) return _CFFI_PRIM_UINTPTR;
+        break;
+
+    case 'r':
+        if (size == 7 && !memcmp(p, "wchar", 5)) return _CFFI_PRIM_WCHAR;
+        break;
+
+    case 't':
+        if (size == 8 && !memcmp(p, "intptr", 6)) return _CFFI_PRIM_INTPTR;
+        break;
+
+    case '_':
+        if (size == 6 && !memcmp(p, "size", 4)) return _CFFI_PRIM_SIZE;
+        if (size == 6 && !memcmp(p, "int8", 4)) return _CFFI_PRIM_INT8;
+        if (size >= 12) {
+            switch (p[10]) {
+            case '1':
+                if (size == 14 && !memcmp(p, "uint_least16", 12)) return _CFFI_PRIM_UINT_LEAST16;
+                break;
+            case '2':
+                if (size == 13 && !memcmp(p, "uint_fast32", 11)) return _CFFI_PRIM_UINT_FAST32;
+                break;
+            case '3':
+                if (size == 14 && !memcmp(p, "uint_least32", 12)) return _CFFI_PRIM_UINT_LEAST32;
+                break;
+            case '4':
+                if (size == 13 && !memcmp(p, "uint_fast64", 11)) return _CFFI_PRIM_UINT_FAST64;
+                break;
+            case '6':
+                if (size == 14 && !memcmp(p, "uint_least64", 12)) return _CFFI_PRIM_UINT_LEAST64;
+                if (size == 13 && !memcmp(p, "uint_fast16", 11)) return _CFFI_PRIM_UINT_FAST16;
+                break;
+            case '8':
+                if (size == 13 && !memcmp(p, "uint_least8", 11)) return _CFFI_PRIM_UINT_LEAST8;
+                break;
+            case '_':
+                if (size == 12 && !memcmp(p, "uint_fast8", 10)) return _CFFI_PRIM_UINT_FAST8;
+                break;
+            default:
+                break;
+            }
+        }
+        break;
+
+    default:
+        break;
+    }
+    return -1;
+}
+
+
+static int parse_complete(token_t *tok)
+{
+    unsigned int t0;
+    _cffi_opcode_t t1;
+    int modifiers_length, modifiers_sign;
+
+ qualifiers:
+    switch (tok->kind) {
+    case TOK_CONST:
+        /* ignored for now */
+        next_token(tok);
+        goto qualifiers;
+    case TOK_VOLATILE:
+        /* ignored for now */
+        next_token(tok);
+        goto qualifiers;
+    default:
+        ;
+    }
+
+    modifiers_length = 0;
+    modifiers_sign = 0;
+ modifiers:
+    switch (tok->kind) {
+
+    case TOK_SHORT:
+        if (modifiers_length != 0)
+            return parse_error(tok, "'short' after another 'short' or 'long'");
+        modifiers_length--;
+        next_token(tok);
+        goto modifiers;
+
+    case TOK_LONG:
+        if (modifiers_length < 0)
+            return parse_error(tok, "'long' after 'short'");
+        if (modifiers_length >= 2)
+            return parse_error(tok, "'long long long' is too long");
+        modifiers_length++;
+        next_token(tok);
+        goto modifiers;
+
+    case TOK_SIGNED:
+        if (modifiers_sign)
+            return parse_error(tok, "multiple 'signed' or 'unsigned'");
+        modifiers_sign++;
+        next_token(tok);
+        goto modifiers;
+
+    case TOK_UNSIGNED:
+        if (modifiers_sign)
+            return parse_error(tok, "multiple 'signed' or 'unsigned'");
+        modifiers_sign--;
+        next_token(tok);
+        goto modifiers;
+
+    default:
+        break;
+    }
+
+    if (modifiers_length || modifiers_sign) {
+
+        switch (tok->kind) {
+
+        case TOK_VOID:
+        case TOK__BOOL:
+        case TOK_FLOAT:
+        case TOK_STRUCT:
+        case TOK_UNION:
+        case TOK_ENUM:
+            return parse_error(tok, "invalid combination of types");
+
+        case TOK_DOUBLE:
+            if (modifiers_sign != 0 || modifiers_length != 1)
+                return parse_error(tok, "invalid combination of types");
+            next_token(tok);
+            t0 = _CFFI_PRIM_LONGDOUBLE;
+            break;
+
+        case TOK_CHAR:
+            if (modifiers_length != 0)
+                return parse_error(tok, "invalid combination of types");
+            modifiers_length = -2;
+            /* fall-through */
+        case TOK_INT:
+            next_token(tok);
+            /* fall-through */
+        default:
+            if (modifiers_sign >= 0)
+                switch (modifiers_length) {
+                case -2: t0 = _CFFI_PRIM_SCHAR; break;
+                case -1: t0 = _CFFI_PRIM_SHORT; break;
+                case 1:  t0 = _CFFI_PRIM_LONG; break;
+                case 2:  t0 = _CFFI_PRIM_LONGLONG; break;
+                default: t0 = _CFFI_PRIM_INT; break;
+                }
+            else
+                switch (modifiers_length) {
+                case -2: t0 = _CFFI_PRIM_UCHAR; break;
+                case -1: t0 = _CFFI_PRIM_USHORT; break;
+                case 1:  t0 = _CFFI_PRIM_ULONG; break;
+                case 2:  t0 = _CFFI_PRIM_ULONGLONG; break;
+                default: t0 = _CFFI_PRIM_UINT; break;
+                }
+        }
+        t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, t0);
+    }
+    else {
+        switch (tok->kind) {
+        case TOK_INT:
+            t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_INT);
+            break;
+        case TOK_CHAR:
+            t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_CHAR);
+            break;
+        case TOK_VOID:
+            t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_VOID);
+            break;
+        case TOK__BOOL:
+            t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_BOOL);
+            break;
+        case TOK_FLOAT:
+            t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_FLOAT);
+            break;
+        case TOK_DOUBLE:
+            t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_DOUBLE);
+            break;
+        case TOK_IDENTIFIER:
+        {
+            int n = search_in_typenames(tok->info->ctx, tok->p, tok->size);
+            if (n >= 0) {
+                t1 = _CFFI_OP(_CFFI_OP_TYPENAME, n);
+                break;
+            }
+            n = search_standard_typename(tok->p, tok->size);
+            if (n >= 0) {
+                t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, n);
+                break;
+            }
+            return parse_error(tok, "undefined type name");
+        }
+        case TOK_STRUCT:
+        case TOK_UNION:
+        {
+            int n, kind = tok->kind;
+            next_token(tok);
+            if (tok->kind != TOK_IDENTIFIER)
+                return parse_error(tok, "struct or union name expected");
+
+            n = search_in_struct_unions(tok->info->ctx, tok->p, tok->size);
+            if (n < 0)
+                return parse_error(tok, "undefined struct/union name");
+            if (((tok->info->ctx->struct_unions[n].flags & _CFFI_F_UNION) != 0)
+                ^ (kind == TOK_UNION))
+                return parse_error(tok, "wrong kind of tag: struct vs union");
+
+            t1 = _CFFI_OP(_CFFI_OP_STRUCT_UNION, n);
+            break;
+        }
+        case TOK_ENUM:
+        {
+            int n;
+            next_token(tok);
+            if (tok->kind != TOK_IDENTIFIER)
+                return parse_error(tok, "enum name expected");
+
+            n = search_in_enums(tok->info->ctx, tok->p, tok->size);
+            if (n < 0)
+                return parse_error(tok, "undefined enum name");
+
+            t1 = _CFFI_OP(_CFFI_OP_ENUM, n);
+            break;
+        }
+        default:
+            return parse_error(tok, "identifier expected");
+        }
+        next_token(tok);
+    }
+
+    return parse_sequel(tok, write_ds(tok, t1));
+}
+
+
+RPY_EXTERN
+int parse_c_type(struct _cffi_parse_info_s *info, const char *input)
+{
+    int result;
+    token_t token;
+
+    token.info = info;
+    token.kind = TOK_START;
+    token.input = input;
+    token.p = input;
+    token.size = 0;
+    token.output = info->output;
+    token.output_index = 0;
+
+    next_token(&token);
+    result = parse_complete(&token);
+
+    if (token.kind != TOK_END)
+        return parse_error(&token, "unexpected symbol");
+    return result;
+}
diff --git a/pypy/module/_cffi_backend/src/parse_c_type.h b/pypy/module/_cffi_backend/src/parse_c_type.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cffi_backend/src/parse_c_type.h
@@ -0,0 +1,149 @@
+
+typedef void *_cffi_opcode_t;
+
+#define _CFFI_OP(opcode, arg)   (_cffi_opcode_t)(opcode | (((uintptr_t)(arg)) << 8))
+#define _CFFI_GETOP(cffi_opcode)    ((unsigned char)(uintptr_t)cffi_opcode)
+#define _CFFI_GETARG(cffi_opcode)   (((uintptr_t)cffi_opcode) >> 8)
+
+#define _CFFI_OP_PRIMITIVE       1
+#define _CFFI_OP_POINTER         3
+#define _CFFI_OP_ARRAY           5
+#define _CFFI_OP_OPEN_ARRAY      7
+#define _CFFI_OP_STRUCT_UNION    9
+#define _CFFI_OP_ENUM           11
+#define _CFFI_OP_FUNCTION       13
+#define _CFFI_OP_FUNCTION_END   15
+#define _CFFI_OP_NOOP           17
+#define _CFFI_OP_BITFIELD       19
+#define _CFFI_OP_TYPENAME       21
+#define _CFFI_OP_CPYTHON_BLTN_V 23   // varargs
+#define _CFFI_OP_CPYTHON_BLTN_N 25   // noargs
+#define _CFFI_OP_CPYTHON_BLTN_O 27   // O  (i.e. a single arg)
+#define _CFFI_OP_CONSTANT       29
+#define _CFFI_OP_CONSTANT_INT   31
+#define _CFFI_OP_GLOBAL_VAR     33
+
+#define _CFFI_PRIM_VOID          0
+#define _CFFI_PRIM_BOOL          1
+#define _CFFI_PRIM_CHAR          2
+#define _CFFI_PRIM_SCHAR         3
+#define _CFFI_PRIM_UCHAR         4
+#define _CFFI_PRIM_SHORT         5
+#define _CFFI_PRIM_USHORT        6
+#define _CFFI_PRIM_INT           7
+#define _CFFI_PRIM_UINT          8
+#define _CFFI_PRIM_LONG          9
+#define _CFFI_PRIM_ULONG        10
+#define _CFFI_PRIM_LONGLONG     11
+#define _CFFI_PRIM_ULONGLONG    12
+#define _CFFI_PRIM_FLOAT        13
+#define _CFFI_PRIM_DOUBLE       14
+#define _CFFI_PRIM_LONGDOUBLE   15
+
+#define _CFFI_PRIM_WCHAR        16
+#define _CFFI_PRIM_INT8         17
+#define _CFFI_PRIM_UINT8        18
+#define _CFFI_PRIM_INT16        19
+#define _CFFI_PRIM_UINT16       20
+#define _CFFI_PRIM_INT32        21
+#define _CFFI_PRIM_UINT32       22
+#define _CFFI_PRIM_INT64        23
+#define _CFFI_PRIM_UINT64       24
+#define _CFFI_PRIM_INTPTR       25
+#define _CFFI_PRIM_UINTPTR      26
+#define _CFFI_PRIM_PTRDIFF      27
+#define _CFFI_PRIM_SIZE         28
+#define _CFFI_PRIM_SSIZE        29
+#define _CFFI_PRIM_INT_LEAST8   30
+#define _CFFI_PRIM_UINT_LEAST8  31
+#define _CFFI_PRIM_INT_LEAST16  32
+#define _CFFI_PRIM_UINT_LEAST16 33
+#define _CFFI_PRIM_INT_LEAST32  34
+#define _CFFI_PRIM_UINT_LEAST32 35
+#define _CFFI_PRIM_INT_LEAST64  36
+#define _CFFI_PRIM_UINT_LEAST64 37
+#define _CFFI_PRIM_INT_FAST8    38
+#define _CFFI_PRIM_UINT_FAST8   39
+#define _CFFI_PRIM_INT_FAST16   40
+#define _CFFI_PRIM_UINT_FAST16  41
+#define _CFFI_PRIM_INT_FAST32   42
+#define _CFFI_PRIM_UINT_FAST32  43
+#define _CFFI_PRIM_INT_FAST64   44
+#define _CFFI_PRIM_UINT_FAST64  45
+#define _CFFI_PRIM_INTMAX       46
+#define _CFFI_PRIM_UINTMAX      47
+
+#define _CFFI__NUM_PRIM         48
+
+
+struct _cffi_global_s {
+    const char *name;
+    void *address;
+    _cffi_opcode_t type_op;
+    size_t size;             // 0 if unknown
+};
+
+struct _cffi_struct_union_s {
+    const char *name;
+    int type_index;          // -> _cffi_types, on a OP_STRUCT_UNION
+    int flags;               // _CFFI_F_* flags below
+    size_t size;
+    int alignment;
+    int first_field_index;   // -> _cffi_fields array
+    int num_fields;
+};
+#define _CFFI_F_UNION         0x01   // is a union, not a struct
+#define _CFFI_F_CHECK_FIELDS  0x02   // complain if fields are not in the
+                                     // "standard layout" or if some are missing
+#define _CFFI_F_PACKED        0x04   // for CHECK_FIELDS, assume a packed struct
+#define _CFFI_F_EXTERNAL      0x08   // in some other ffi.include()
+
+struct _cffi_field_s {
+    const char *name;
+    size_t field_offset;
+    size_t field_size;
+    _cffi_opcode_t field_type_op;
+};
+
+struct _cffi_enum_s {
+    const char *name;
+    int type_index;          // -> _cffi_types, on a OP_ENUM
+    int type_prim;           // _CFFI_PRIM_xxx
+    const char *enumerators; // comma-delimited string
+};
+
+struct _cffi_typename_s {
+    const char *name;
+    int type_index;   /* if opaque, points to a possibly artificial
+                         OP_STRUCT which is itself opaque */
+};
+
+struct _cffi_type_context_s {
+    _cffi_opcode_t *types;
+    const struct _cffi_global_s *globals;
+    const struct _cffi_field_s *fields;
+    const struct _cffi_struct_union_s *struct_unions;
+    const struct _cffi_enum_s *enums;
+    const struct _cffi_typename_s *typenames;
+    int num_globals;
+    int num_struct_unions;
+    int num_enums;
+    int num_typenames;
+    const char *const *includes;
+};
+
+struct _cffi_parse_info_s {
+    const struct _cffi_type_context_s *ctx;
+    _cffi_opcode_t *output;
+    unsigned int output_size;
+    size_t error_location;
+    const char *error_message;
+};
+
+#ifdef _CFFI_INTERNAL
+RPY_EXTERN int parse_c_type(struct _cffi_parse_info_s *info, const char *input);
+static int search_in_globals(const struct _cffi_type_context_s *ctx,
+                             const char *search, size_t search_len);
+static int search_in_struct_unions(const struct _cffi_type_context_s *ctx,
+                                   const char *search, size_t search_len);
+#endif
diff --git a/pypy/module/_cffi_backend/test/test_parse_c_type.py b/pypy/module/_cffi_backend/test/test_parse_c_type.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cffi_backend/test/test_parse_c_type.py
@@ -0,0 +1,330 @@
+import sys, re, os, py
+from rpython.rtyper.lltypesystem import lltype, rffi
+from pypy.module._cffi_backend import parse_c_type, cffi_opcode
+
+
+class ParseError(Exception):
+    pass
+
+## struct_names = ["bar_s", "foo", "foo_", "foo_s", "foo_s1", "foo_s12"]
+## assert struct_names == sorted(struct_names)
+
+## enum_names = ["ebar_s", "efoo", "efoo_", "efoo_s", "efoo_s1", "efoo_s12"]
+## assert enum_names == sorted(enum_names)
+
+## identifier_names = ["id", "id0", "id05", "id05b", "tail"]
+## assert identifier_names == sorted(identifier_names)
+
+## global_names = ["FIVE", "NEG", "ZERO"]
+## assert global_names == sorted(global_names)
+
+## ctx = ffi.new("struct _cffi_type_context_s *")
+## c_struct_names = [ffi.new("char[]", _n.encode('ascii')) for _n in struct_names]
+## ctx_structs = ffi.new("struct _cffi_struct_union_s[]", len(struct_names))
+## for _i in range(len(struct_names)):
+##     ctx_structs[_i].name = c_struct_names[_i]
+## ctx_structs[3].flags = lib._CFFI_F_UNION
+## ctx.struct_unions = ctx_structs
+## ctx.num_struct_unions = len(struct_names)
+
+## c_enum_names = [ffi.new("char[]", _n.encode('ascii')) for _n in enum_names]
+## ctx_enums = ffi.new("struct _cffi_enum_s[]", len(enum_names))
+## for _i in range(len(enum_names)):
+##     ctx_enums[_i].name = c_enum_names[_i]
+## ctx.enums = ctx_enums
+## ctx.num_enums = len(enum_names)
+
+## c_identifier_names = [ffi.new("char[]", _n.encode('ascii'))
+##                       for _n in identifier_names]
+## ctx_identifiers = ffi.new("struct _cffi_typename_s[]", len(identifier_names))
+## for _i in range(len(identifier_names)):
+##     ctx_identifiers[_i].name = c_identifier_names[_i]
+##     ctx_identifiers[_i].type_index = 100 + _i
+## ctx.typenames = ctx_identifiers
+## ctx.num_typenames = len(identifier_names)
+
+## @ffi.callback("int(unsigned long long *)")
+## def fetch_constant_five(p):
+##     p[0] = 5
+##     return 0
+## @ffi.callback("int(unsigned long long *)")
+## def fetch_constant_zero(p):
+##     p[0] = 0
+##     return 1
+## @ffi.callback("int(unsigned long long *)")
+## def fetch_constant_neg(p):
+##     p[0] = 123321
+##     return 1
+
+## ctx_globals = ffi.new("struct _cffi_global_s[]", len(global_names))
+## c_glob_names = [ffi.new("char[]", _n.encode('ascii')) for _n in global_names]
+## for _i, _fn in enumerate([fetch_constant_five,
+##                           fetch_constant_neg,
+##                           fetch_constant_zero]):
+##     ctx_globals[_i].name = c_glob_names[_i]
+##     ctx_globals[_i].address = _fn
+##     ctx_globals[_i].type_op = ffi.cast("_cffi_opcode_t",
+##                                        cffi_opcode.OP_CONSTANT_INT if _i != 1
+##                                        else cffi_opcode.OP_ENUM)
+## ctx.globals = ctx_globals
+## ctx.num_globals = len(global_names)
+
+ctx = lltype.malloc(parse_c_type.PCTX.TO, flavor='raw', zero=True,
+                    track_allocation=False)
+
+
+def parse(input):
+    OUTPUT_SIZE = 100
+    out = lltype.malloc(rffi.VOIDPP.TO, OUTPUT_SIZE, flavor='raw',
+                        track_allocation=False)
+    info = lltype.malloc(parse_c_type.PINFO.TO, flavor='raw',
+                        track_allocation=False)
+    info.c_ctx = ctx
+    info.c_output = out
+    rffi.setintfield(info, 'c_output_size', OUTPUT_SIZE)
+    for j in range(OUTPUT_SIZE):
+        out[j] = rffi.cast(rffi.VOIDP, -424242)
+    res = parse_c_type.parse_c_type(info, input.encode('ascii'))
+    if res < 0:
+        raise ParseError(rffi.charp2str(info.c_error_message).decode('ascii'),
+                         rffi.getintfield(info, 'c_error_location'))
+    assert 0 <= res < OUTPUT_SIZE
+    result = []
+    for j in range(OUTPUT_SIZE):
+        if out[j] == rffi.cast(rffi.VOIDP, -424242):
+            assert res < j
+            break
+        i = rffi.cast(rffi.SIGNED, out[j])
+        if j == res:
+            result.append('->')
+        result.append(i)
+    return result
+
+def parsex(input):
+    result = parse(input)
+    def str_if_int(x):
+        if isinstance(x, str):
+            return x
+        return '%d,%d' % (x & 255, x >> 8)
+    return '  '.join(map(str_if_int, result))
+
+def parse_error(input, expected_msg, expected_location):
+    e = py.test.raises(ParseError, parse, input)
+    assert e.value.args[0] == expected_msg
+    assert e.value.args[1] == expected_location
+
+def make_getter(name):
+    opcode = getattr(cffi_opcode, 'OP_' + name)
+    def getter(value):
+        return opcode | (value << 8)
+    return getter
+
+Prim = make_getter('PRIMITIVE')
+Pointer = make_getter('POINTER')
+Array = make_getter('ARRAY')
+OpenArray = make_getter('OPEN_ARRAY')
+NoOp = make_getter('NOOP')
+Func = make_getter('FUNCTION')
+FuncEnd = make_getter('FUNCTION_END')
+Struct = make_getter('STRUCT_UNION')
+Enum = make_getter('ENUM')
+Typename = make_getter('TYPENAME')
+
+
+def test_simple():
+    for simple_type, expected in [
+            ("int", cffi_opcode.PRIM_INT),
+            ("signed int", cffi_opcode.PRIM_INT),
+            ("  long  ", cffi_opcode.PRIM_LONG),
+            ("long int", cffi_opcode.PRIM_LONG),
+            ("unsigned short", cffi_opcode.PRIM_USHORT),
+            ("long double", cffi_opcode.PRIM_LONGDOUBLE),
+            ]:
+        assert parse(simple_type) == ['->', Prim(expected)]
+
+def test_array():
+    assert parse("int[5]") == [Prim(cffi_opcode.PRIM_INT), '->', Array(0), 5]
+    assert parse("int[]") == [Prim(cffi_opcode.PRIM_INT), '->', OpenArray(0)]
+    assert parse("int[5][8]") == [Prim(cffi_opcode.PRIM_INT),
+                                  '->', Array(3),
+                                  5,
+                                  Array(0),
+                                  8]
+    assert parse("int[][8]") == [Prim(cffi_opcode.PRIM_INT),
+                                 '->', OpenArray(2),
+                                 Array(0),
+                                 8]
+
+def test_pointer():
+    assert parse("int*") == [Prim(cffi_opcode.PRIM_INT), '->', Pointer(0)]
+    assert parse("int***") == [Prim(cffi_opcode.PRIM_INT),
+                               Pointer(0), Pointer(1), '->', Pointer(2)]
+
+def test_grouping():
+    assert parse("int*[]") == [Prim(cffi_opcode.PRIM_INT),
+                               Pointer(0), '->', OpenArray(1)]
+    assert parse("int**[][8]") == [Prim(cffi_opcode.PRIM_INT),
+                                   Pointer(0), Pointer(1),
+                                   '->', OpenArray(4), Array(2), 8]
+    assert parse("int(*)[]") == [Prim(cffi_opcode.PRIM_INT),
+                                 NoOp(3), '->', Pointer(1), OpenArray(0)]
+    assert parse("int(*)[][8]") == [Prim(cffi_opcode.PRIM_INT),
+                                    NoOp(3), '->', Pointer(1),
+                                    OpenArray(4), Array(0), 8]
+    assert parse("int**(**)") == [Prim(cffi_opcode.PRIM_INT),
+                                  Pointer(0), Pointer(1),
+                                  NoOp(2), Pointer(3), '->', Pointer(4)]
+    assert parse("int**(**)[]") == [Prim(cffi_opcode.PRIM_INT),
+                                    Pointer(0), Pointer(1),
+                                    NoOp(6), Pointer(3), '->', Pointer(4),
+                                    OpenArray(2)]
+
+def test_simple_function():
+    assert parse("int()") == [Prim(cffi_opcode.PRIM_INT),
+                              '->', Func(0), FuncEnd(0), 0]
+    assert parse("int(int)") == [Prim(cffi_opcode.PRIM_INT),
+                                 '->', Func(0), NoOp(4), FuncEnd(0),
+                                 Prim(cffi_opcode.PRIM_INT)]
+    assert parse("int(long, char)") == [
+                                 Prim(cffi_opcode.PRIM_INT),
+                                 '->', Func(0), NoOp(5), NoOp(6), FuncEnd(0),
+                                 Prim(cffi_opcode.PRIM_LONG),
+                                 Prim(cffi_opcode.PRIM_CHAR)]
+    assert parse("int(int*)") == [Prim(cffi_opcode.PRIM_INT),
+                                  '->', Func(0), NoOp(5), FuncEnd(0),
+                                  Prim(cffi_opcode.PRIM_INT),
+                                  Pointer(4)]
+    assert parse("int*(void)") == [Prim(cffi_opcode.PRIM_INT),
+                                   Pointer(0),
+                                   '->', Func(1), FuncEnd(0), 0]
+    assert parse("int(int, ...)") == [Prim(cffi_opcode.PRIM_INT),
+                                      '->', Func(0), NoOp(5), FuncEnd(1), 0,
+                                      Prim(cffi_opcode.PRIM_INT)]
+
+def test_internal_function():
+    assert parse("int(*)()") == [Prim(cffi_opcode.PRIM_INT),
+                                 NoOp(3), '->', Pointer(1),
+                                 Func(0), FuncEnd(0), 0]
+    assert parse("int(*())[]") == [Prim(cffi_opcode.PRIM_INT),
+                                   NoOp(6), Pointer(1),
+                                   '->', Func(2), FuncEnd(0), 0,
+                                   OpenArray(0)]
+    assert parse("int(char(*)(long, short))") == [
+        Prim(cffi_opcode.PRIM_INT),
+        '->', Func(0), NoOp(6), FuncEnd(0),
+        Prim(cffi_opcode.PRIM_CHAR),
+        NoOp(7), Pointer(5),
+        Func(4), NoOp(11), NoOp(12), FuncEnd(0),
+        Prim(cffi_opcode.PRIM_LONG),
+        Prim(cffi_opcode.PRIM_SHORT)]
+
+def test_fix_arg_types():
+    assert parse("int(char(long, short))") == [
+        Prim(cffi_opcode.PRIM_INT),
+        '->', Func(0), Pointer(5), FuncEnd(0),
+        Prim(cffi_opcode.PRIM_CHAR),
+        Func(4), NoOp(9), NoOp(10), FuncEnd(0),
+        Prim(cffi_opcode.PRIM_LONG),
+        Prim(cffi_opcode.PRIM_SHORT)]
+    assert parse("int(char[])") == [
+        Prim(cffi_opcode.PRIM_INT),
+        '->', Func(0), Pointer(4), FuncEnd(0),
+        Prim(cffi_opcode.PRIM_CHAR),
+        OpenArray(4)]
+
+def test_enum():
+    for i in range(len(enum_names)):
+        assert parse("enum %s" % (enum_names[i],)) == ['->', Enum(i)]
+        assert parse("enum %s*" % (enum_names[i],)) == [Enum(i),
+                                                        '->', Pointer(0)]
+
+def test_error():
+    parse_error("short short int", "'short' after another 'short' or 'long'", 6)
+    parse_error("long long long", "'long long long' is too long", 10)
+    parse_error("short long", "'long' after 'short'", 6)
+    parse_error("signed unsigned int", "multiple 'signed' or 'unsigned'", 7)
+    parse_error("unsigned signed int", "multiple 'signed' or 'unsigned'", 9)
+    parse_error("long char", "invalid combination of types", 5)
+    parse_error("short char", "invalid combination of types", 6)
+    parse_error("signed void", "invalid combination of types", 7)
+    parse_error("unsigned struct", "invalid combination of types", 9)
+    #
+    parse_error("", "identifier expected", 0)
+    parse_error("]", "identifier expected", 0)
+    parse_error("*", "identifier expected", 0)
+    parse_error("int ]**", "unexpected symbol", 4)
+    parse_error("char char", "unexpected symbol", 5)
+    parse_error("int(int]", "expected ')'", 7)
+    parse_error("int(*]", "expected ')'", 5)
+    parse_error("int(]", "identifier expected", 4)
+    parse_error("int[?]", "expected a positive integer constant", 4)
+    parse_error("int[24)", "expected ']'", 6)
+    parse_error("struct", "struct or union name expected", 6)
+    parse_error("struct 24", "struct or union name expected", 7)
+    parse_error("int[5](*)", "unexpected symbol", 6)
+    parse_error("int a(*)", "identifier expected", 6)
+    parse_error("int[123456789012345678901234567890]", "number too large", 4)
+
+def test_number_too_large():
+    num_max = sys.maxsize
+    assert parse("char[%d]" % num_max) == [Prim(cffi_opcode.PRIM_CHAR),
+                                          '->', Array(0), num_max]
+    parse_error("char[%d]" % (num_max + 1), "number too large", 5)
+
+def test_complexity_limit():
+    parse_error("int" + "[]" * 2500, "internal type complexity limit reached",
+                202)
+
+def test_struct():
+    for i in range(len(struct_names)):
+        if i == 3:
+            tag = "union"
+        else:
+            tag = "struct"
+        assert parse("%s %s" % (tag, struct_names[i])) == ['->', Struct(i)]
+        assert parse("%s %s*" % (tag, struct_names[i])) == [Struct(i),
+                                                            '->', Pointer(0)]
+
+def test_exchanging_struct_union():
+    parse_error("union %s" % (struct_names[0],),
+                "wrong kind of tag: struct vs union", 6)
+    parse_error("struct %s" % (struct_names[3],),
+                "wrong kind of tag: struct vs union", 7)
+
+def test_identifier():
+    for i in range(len(identifier_names)):
+        assert parse("%s" % (identifier_names[i])) == ['->', Typename(i)]
+        assert parse("%s*" % (identifier_names[i])) == [Typename(i),
+                                                        '->', Pointer(0)]
+
+def test_cffi_opcode_sync():
+    import cffi.model
+    for name in dir(lib):
+        if name.startswith('_CFFI_'):
+            assert getattr(cffi_opcode, name[6:]) == getattr(lib, name)
+    assert sorted(cffi_opcode.PRIMITIVE_TO_INDEX.keys()) == (
+        sorted(cffi.model.PrimitiveType.ALL_PRIMITIVE_TYPES.keys()))
+
+def test_array_length_from_constant():
+    parse_error("int[UNKNOWN]", "expected a positive integer constant", 4)
+    assert parse("int[FIVE]") == [Prim(cffi_opcode.PRIM_INT), '->', Array(0), 5]
+    assert parse("int[ZERO]") == [Prim(cffi_opcode.PRIM_INT), '->', Array(0), 0]
+    parse_error("int[NEG]", "expected a positive integer constant", 4)
+
+def test_various_constant_exprs():
+    def array(n):
+        return [Prim(cffi_opcode.PRIM_CHAR), '->', Array(0), n]
+    assert parse("char[21]") == array(21)
+    assert parse("char[0x10]") == array(16)
+    assert parse("char[0X21]") == array(33)
+    assert parse("char[0Xb]") == array(11)
+    assert parse("char[0x1C]") == array(0x1C)
+    assert parse("char[0xc6]") == array(0xC6)
+    assert parse("char[010]") == array(8)
+    assert parse("char[021]") == array(17)
+    parse_error("char[08]", "invalid number", 5)
+    parse_error("char[1C]", "invalid number", 5)
+    parse_error("char[0C]", "invalid number", 5)
+    # not supported (really obscure):
+    #    "char[+5]"
+    #    "char['A']"


More information about the pypy-commit mailing list