[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