[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