[pypy-commit] cffi cffi-1.0: Structs and unions

arigo noreply at buildbot.pypy.org
Sat Apr 11 09:26:31 CEST 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: cffi-1.0
Changeset: r1692:3162ab4fa3b8
Date: 2015-04-11 09:27 +0200
http://bitbucket.org/cffi/cffi/changeset/3162ab4fa3b8/

Log:	Structs and unions

diff --git a/new/parse_c_type.c b/new/parse_c_type.c
--- a/new/parse_c_type.c
+++ b/new/parse_c_type.c
@@ -1,4 +1,5 @@
 #include <stdlib.h>
+#include <string.h>
 #include <assert.h>
 #include "parse_c_type.h"
 
@@ -175,10 +176,8 @@
 {
     if (tok->kind != TOK_ERROR) {
         tok->kind = TOK_ERROR;
-        if (tok->info->error_location)
-            *tok->info->error_location = tok->p;
-        if (tok->info->error_message)
-            *tok->info->error_message = msg;
+        tok->info->error_location = tok->p;
+        tok->info->error_message = msg;
     }
     return -1;
 }
@@ -410,6 +409,25 @@
 }
 #endif
 
+static int search_struct_union(struct _cffi_type_context_s *ctx,
+                               const char *search, size_t search_len)
+{
+    int left = 0, right = ctx->num_structs_unions;
+
+    while (left < right) {
+        int middle = (left + right) / 2;
+        const char *src = ctx->structs_unions[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;
+}
+
 static int parse_complete(token_t *tok)
 {
  qualifiers:
@@ -554,27 +572,20 @@
         case TOK_STRUCT:
         case TOK_UNION:
         {
-            abort();
-#if 0
-            char identifier[1024];
             int kind = tok->kind;
             next_token(tok);
-            if (tok->kind != TOK_IDENTIFIER) {
-                parse_error(tok, "struct or union name expected");
-                return;
-            }
-            if (tok->size >= 1024) {
-                parse_error(tok, "struct or union name too long");
-                return;
-            }
-            memcpy(identifier, tok->p, tok->size);
-            identifier[tok->size] = 0;
-            if (kind == TOK_STRUCT)
-                t1 = tok->cb->get_struct_type(tok->cb, identifier);
-            else
-                t1 = tok->cb->get_union_type(tok->cb, identifier);
+            if (tok->kind != TOK_IDENTIFIER)
+                return parse_error(tok, "struct or union name expected");
+
+            int n = search_struct_union(tok->info->ctx, tok->p, tok->size);
+            if (n < 0)
+                return parse_error(tok, "undefined struct/union name");
+            if (((tok->info->ctx->structs_unions[n].flags & CT_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;
-#endif
         }
         default:
             return parse_error(tok, "identifier expected");
diff --git a/new/parse_c_type.h b/new/parse_c_type.h
--- a/new/parse_c_type.h
+++ b/new/parse_c_type.h
@@ -57,6 +57,8 @@
     int num_fields;
     int first_field_index;   // -> _cffi_fields array
 };
+#define CT_UNION            128
+#define CT_IS_OPAQUE        4096
 
 struct _cffi_field_s {
     const char *name;
@@ -94,8 +96,8 @@
     struct _cffi_type_context_s *ctx;
     _cffi_opcode_t *output;
     int output_size;
-    const char **error_location;
-    const char **error_message;
+    const char *error_location;
+    const char *error_message;
 };
 
 int parse_c_type(struct _cffi_parse_info_s *info, const char *input);
diff --git a/new/test_parse_c_type.py b/new/test_parse_c_type.py
--- a/new/test_parse_c_type.py
+++ b/new/test_parse_c_type.py
@@ -1,5 +1,6 @@
 import re
 import os
+import py
 import cffi
 
 r_macro = re.compile(r"#define \w+[(][^\n]*")
@@ -17,9 +18,23 @@
 class ParseError(Exception):
     pass
 
+struct_names = ["bar_s", "foo", "foo_", "foo_s", "foo_s1", "foo_s12"]
+assert struct_names == sorted(struct_names)
+
+ctx = ffi.new("struct _cffi_type_context_s *")
+c_names = [ffi.new("char[]", _n) 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_names[_i]
+ctx_structs[3].flags = lib.CT_UNION
+ctx.structs_unions = ctx_structs
+ctx.num_structs_unions = len(struct_names)
+
+
 def parse(input):
     out = ffi.new("_cffi_opcode_t[]", 100)
     info = ffi.new("struct _cffi_parse_info_s *")
+    info.ctx = ctx
     info.output = out
     info.output_size = len(out)
     for j in range(len(out)):
@@ -28,7 +43,7 @@
     res = lib.parse_c_type(info, c_input)
     if res < 0:
         raise ParseError(ffi.string(info.error_message),
-                         ffi.string(info.error_location) - c_input)
+                         info.error_location - c_input)
     assert 0 <= res < len(out)
     result = []
     for j in range(len(out)):
@@ -49,6 +64,11 @@
         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(lib, '_CFFI_OP_' + name)
     def getter(value):
@@ -62,6 +82,7 @@
 NoOp = make_getter('NOOP')
 Func = make_getter('FUNCTION')
 FuncEnd = make_getter('FUNCTION_END')
+Struct = make_getter('STRUCT_UNION')
 
 
 def test_simple():
@@ -164,3 +185,14 @@
         '->', Func(0), Pointer(4), FuncEnd(0),
         Prim(lib._CFFI_PRIM_CHAR),
         OpenArray(4)]
+
+def test_error():
+    parse_error("short short int", "'short' after another 'short' or 'long'", 6)
+
+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)]


More information about the pypy-commit mailing list