eolian: add support for static and terminated arrays

Adds two new type types, STATIC_ARRAY and TERMINATED_ARRAY. Static arrays are
only allowed as struct members right now - they translate to regular C static
arrays (allowing them elsewhere wouldn't be good, as C isn't very good at
working with the size information). Terminated arrays are basically sequences
of data terminated at the end. The base type of static arrays can be any type
that is not marked ref (explicit ref may get allowed later). The base type of
terminated arrays has the same restriction plus that it has to be either
implicitly reference type (i.e. translating to pointer in C), integer type
or a character. In case of ref types, the terminator is NULL. In case of
integer types, the terminator is a zero. In case of character types, the
terminator is also a zero (null terminator like C strings).

@feature
This commit is contained in:
Daniel Kolesa 2016-06-30 14:04:03 +01:00
parent ff7a5e4f1b
commit ab2e608239
13 changed files with 180 additions and 39 deletions

View File

@ -70,10 +70,23 @@ _type_generate(const Eolian_Typedecl *tp, Eina_Bool full, Eina_Bool use_legacy)
EINA_ITERATOR_FOREACH(members, member)
{
const Eolian_Type *type = eolian_typedecl_struct_field_type_get(member);
Eina_Stringshare *c_type = eolian_type_c_type_get(type);
eina_strbuf_append_printf(buf, " %s%s%s;",
c_type, strchr(c_type, '*')?"":" ",
eolian_typedecl_struct_field_name_get(member));
Eina_Stringshare *c_type = NULL;
if (eolian_type_type_get(type) == EOLIAN_TYPE_STATIC_ARRAY)
{
c_type = eolian_type_c_type_get(eolian_type_base_type_get(type));
eina_strbuf_append_printf(buf, " %s%s%s[%zu];",
c_type, strchr(c_type, '*')?"":" ",
eolian_typedecl_struct_field_name_get(member),
eolian_type_array_size_get(type));
}
else
{
c_type = eolian_type_c_type_get(type);
eina_strbuf_append_printf(buf, " %s%s%s;",
c_type, strchr(c_type, '*')?"":" ",
eolian_typedecl_struct_field_name_get(member));
}
eina_stringshare_del(c_type);
const Eolian_Documentation *fdoc
= eolian_typedecl_struct_field_documentation_get(member);
if (fdoc)

View File

@ -76,6 +76,8 @@ ffi.cdef [[
EOLIAN_TYPE_COMPLEX,
EOLIAN_TYPE_POINTER,
EOLIAN_TYPE_CLASS,
EOLIAN_TYPE_STATIC_ARRAY,
EOLIAN_TYPE_TERMINATED_ARRAY,
EOLIAN_TYPE_UNDEFINED
} Eolian_Type_Type;
@ -300,6 +302,7 @@ ffi.cdef [[
const Eolian_Type *eolian_typedecl_aliased_base_get(const Eolian_Typedecl *tp);
const Eolian_Class *eolian_type_class_get(const Eolian_Type *tp);
size_t eolian_type_array_size_get(const Eolian_Type *tp);
Eina_Bool eolian_type_is_own(const Eolian_Type *tp);
Eina_Bool eolian_type_is_const(const Eolian_Type *tp);
Eina_Bool eolian_type_is_ref(const Eolian_Type *tp);
@ -448,13 +451,15 @@ M.declaration_type = {
}
M.type_type = {
UNKNOWN = 0,
VOID = 1,
REGULAR = 2,
COMPLEX = 3,
POINTER = 4,
CLASS = 5,
UNDEFINED = 6
UNKNOWN = 0,
VOID = 1,
REGULAR = 2,
COMPLEX = 3,
POINTER = 4,
CLASS = 5,
STATIC_ARRAY = 6,
TERMINATED_ARRAY = 7,
UNDEFINED = 8
}
M.typedecl_type = {
@ -650,6 +655,10 @@ M.Type = ffi.metatype("Eolian_Type", {
return v
end,
array_size_get = function(self)
return tonumber(eolian.eolian_type_array_size_get(self))
end,
is_own = function(self)
return eolian.eolian_type_is_own(self) ~= 0
end,

View File

@ -220,6 +220,8 @@ typedef enum
EOLIAN_TYPE_COMPLEX,
EOLIAN_TYPE_POINTER,
EOLIAN_TYPE_CLASS,
EOLIAN_TYPE_STATIC_ARRAY,
EOLIAN_TYPE_TERMINATED_ARRAY,
EOLIAN_TYPE_UNDEFINED
} Eolian_Type_Type;
@ -1726,6 +1728,16 @@ EAPI const Eolian_Type *eolian_type_aliased_base_get(const Eolian_Type *tp);
*/
EAPI const Eolian_Class *eolian_type_class_get(const Eolian_Type *tp);
/*
* @brief Get the size of an EOLIAN_TYPE_STATIC_ARRAY.
*
* @param[in] tp the type.
* @return the size or 0.
*
* @ingroup Eolian
*/
EAPI size_t eolian_type_array_size_get(const Eolian_Type *tp);
/*
* @brief Get whether the given type is owned.
*

View File

@ -101,9 +101,10 @@ database_type_to_str(const Eolian_Type *tp, Eina_Strbuf *buf, const char *name)
eina_strbuf_append(buf, "__undefined_type");
else
{
/* handles arrays and pointers as they all serialize to pointers */
Eolian_Type *btp = tp->base_type;
database_type_to_str(tp->base_type, buf, NULL);
if (btp->type != EOLIAN_TYPE_POINTER || btp->is_const)
if (eina_strbuf_string_get(buf)[eina_strbuf_length_get(buf) - 1] != '*')
eina_strbuf_append_char(buf, ' ');
eina_strbuf_append_char(buf, '*');
if (tp->is_const) eina_strbuf_append(buf, " const");

View File

@ -313,6 +313,13 @@ eolian_type_class_get(const Eolian_Type *tp)
return eolian_class_get_by_name(tp->full_name);
}
EAPI size_t
eolian_type_array_size_get(const Eolian_Type *tp)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(tp, 0);
return tp->static_size;
}
EAPI Eina_Bool
eolian_type_is_own(const Eolian_Type *tp)
{

View File

@ -242,6 +242,8 @@ _validate_type(const Validator *vs, const Eolian_Type *tp)
return _validate_typedecl(vs, tpp);
}
case EOLIAN_TYPE_POINTER:
case EOLIAN_TYPE_STATIC_ARRAY:
case EOLIAN_TYPE_TERMINATED_ARRAY:
return _validate_type(vs, tp->base_type);
case EOLIAN_TYPE_CLASS:
{

View File

@ -72,6 +72,8 @@ static const char * const ctypes[] =
"void",
NULL, NULL, /* array types */
"Eina_Accessor", "Eina_Array", "Eina_Iterator", "Eina_Hash", "Eina_List",
"Eina_Promise",
"Eina_Value", "const char *", "Eina_Stringshare *",
@ -943,7 +945,6 @@ lex(Eo_Lexer *ls, Eo_Token *tok)
{
int dcol = ls->column;
next_char(ls);
if (!ls->expr_mode) return '.';
if (!isdigit(ls->current)) return '.';
eina_strbuf_reset(ls->buff);
eina_strbuf_append_char(ls->buff, '.');
@ -959,7 +960,7 @@ lex(Eo_Lexer *ls, Eo_Token *tok)
next_char(ls);
continue;
}
else if (ls->expr_mode && isdigit(ls->current))
else if (isdigit(ls->current))
{
int col = ls->column;
eina_strbuf_reset(ls->buff);

View File

@ -50,6 +50,8 @@ enum Tokens
\
KW(void), \
\
KW(static_array), KW(terminated_array), \
\
KW(accessor), KW(array), KW(iterator), KW(hash), KW(list), \
KW(promise), \
KW(generic_value), KW(string), KW(stringshare), \

View File

@ -187,7 +187,7 @@ static Eina_Strbuf *
parse_name(Eo_Lexer *ls, Eina_Strbuf *buf)
{
check(ls, TOK_VALUE);
if (eo_lexer_get_c_type(ls->t.kw))
if (eo_lexer_is_type_keyword(ls->t.kw))
eo_lexer_syntax_error(ls, "invalid name");
eina_strbuf_reset(buf);
for (;;)
@ -198,7 +198,7 @@ parse_name(Eo_Lexer *ls, Eina_Strbuf *buf)
eo_lexer_get(ls);
eina_strbuf_append(buf, ".");
check(ls, TOK_VALUE);
if (eo_lexer_get_c_type(ls->t.kw))
if (eo_lexer_is_type_keyword(ls->t.kw))
eo_lexer_syntax_error(ls, "invalid name");
}
return buf;
@ -460,14 +460,15 @@ parse_expr(Eo_Lexer *ls)
return parse_expr_bin(ls, 1);
}
static Eolian_Type *parse_type_void(Eo_Lexer *ls, Eina_Bool allow_ref);
static Eolian_Type *parse_type_void(Eo_Lexer *ls, Eina_Bool allow_ref,
Eina_Bool allow_sarray);
static Eolian_Type *
parse_type(Eo_Lexer *ls, Eina_Bool allow_ref)
parse_type(Eo_Lexer *ls, Eina_Bool allow_ref, Eina_Bool allow_sarray)
{
Eolian_Type *ret;
eo_lexer_context_push(ls);
ret = parse_type_void(ls, allow_ref);
ret = parse_type_void(ls, allow_ref, allow_sarray);
if (ret->type == EOLIAN_TYPE_VOID)
{
eo_lexer_context_restore(ls);
@ -516,7 +517,7 @@ parse_struct(Eo_Lexer *ls, const char *name, Eina_Bool is_extern,
def->field_list = eina_list_append(def->field_list, fdef);
eo_lexer_get(ls);
check_next(ls, ':');
tp = parse_type(ls, EINA_TRUE);
tp = parse_type(ls, EINA_TRUE, EINA_TRUE);
FILL_BASE(fdef->base, ls, fline, fcol);
fdef->type = tp;
fdef->name = eina_stringshare_ref(fname);
@ -693,6 +694,18 @@ _parse_dep(Eo_Lexer *ls, const char *fname, const char *name)
}
}
static const Eina_Bool _ownable_types[] = {
EINA_FALSE, /* unknown */
EINA_FALSE, /* void */
EINA_FALSE, /* regular */
EINA_TRUE, /* complex */
EINA_TRUE, /* pointer */
EINA_TRUE, /* class */
EINA_TRUE, /* static array */
EINA_TRUE, /* terminated array */
EINA_FALSE /* undefined */
};
static Eina_Bool
_type_is_ownable(Eolian_Type *tp)
{
@ -706,13 +719,25 @@ _type_is_ownable(Eolian_Type *tp)
return EINA_FALSE;
return (ct[strlen(ct) - 1] == '*');
}
return (tp->type == EOLIAN_TYPE_POINTER ||
tp->type == EOLIAN_TYPE_COMPLEX ||
tp->type == EOLIAN_TYPE_CLASS);
return _ownable_types[tp->type];
}
static Eina_Bool
_type_is_terminatable(Eolian_Type *tp)
{
if (_type_is_ownable(tp))
return EINA_TRUE;
if (tp->type == EOLIAN_TYPE_REGULAR)
{
int kwid = eo_lexer_keyword_str_to_id(tp->name);
/* don't include bool, it only has 2 values so it's useless */
return (kwid >= KW_byte && kwid < KW_bool);
}
return EINA_FALSE;
}
static Eolian_Type *
parse_type_void(Eo_Lexer *ls, Eina_Bool allow_ref)
parse_type_void(Eo_Lexer *ls, Eina_Bool allow_ref, Eina_Bool allow_sarray)
{
Eolian_Type *def;
Eina_Strbuf *buf;
@ -726,7 +751,7 @@ parse_type_void(Eo_Lexer *ls, Eina_Bool allow_ref)
pline = ls->line_number;
pcol = ls->column;
check_next(ls, '(');
def = parse_type_void(ls, allow_ref);
def = parse_type_void(ls, allow_ref, EINA_FALSE);
FILL_BASE(def->base, ls, line, col);
def->is_const = EINA_TRUE;
check_match(ls, ')', '(', pline, pcol);
@ -739,7 +764,7 @@ parse_type_void(Eo_Lexer *ls, Eina_Bool allow_ref)
pline = ls->line_number;
pcol = ls->column;
check_next(ls, '(');
def = parse_type_void(ls, EINA_FALSE);
def = parse_type_void(ls, EINA_FALSE, EINA_FALSE);
FILL_BASE(def->base, ls, line, col);
def->is_ref = EINA_TRUE;
check_match(ls, ')', '(', pline, pcol);
@ -753,7 +778,7 @@ parse_type_void(Eo_Lexer *ls, Eina_Bool allow_ref)
pcolumn = ls->column;
check_next(ls, '(');
eo_lexer_context_push(ls);
def = parse_type_void(ls, allow_ref);
def = parse_type_void(ls, allow_ref, EINA_FALSE);
if (!_type_is_ownable(def))
{
eo_lexer_context_restore(ls);
@ -773,7 +798,7 @@ parse_type_void(Eo_Lexer *ls, Eina_Bool allow_ref)
pcolumn = ls->column;
check_next(ls, '(');
eo_lexer_context_push(ls);
def = parse_type_void(ls, allow_ref);
def = parse_type_void(ls, allow_ref, EINA_FALSE);
if (!_type_is_ownable(def))
{
eo_lexer_context_restore(ls);
@ -803,12 +828,61 @@ parse_type_void(Eo_Lexer *ls, Eina_Bool allow_ref)
def->type = EOLIAN_TYPE_UNDEFINED;
eo_lexer_get(ls);
}
else if (ls->t.kw == KW_static_array)
{
if (!allow_sarray)
eo_lexer_syntax_error(ls, "static arrays not allowed in this context");
def->type = EOLIAN_TYPE_STATIC_ARRAY;
eo_lexer_get(ls);
check_next(ls, '<');
def->base_type = parse_type(ls, EINA_FALSE, EINA_FALSE);
pop_type(ls);
check_next(ls, ',');
check(ls, TOK_NUMBER);
eo_lexer_context_push(ls);
if (ls->t.kw == NUM_FLOAT || ls->t.kw == NUM_DOUBLE)
{
eo_lexer_context_restore(ls);
eo_lexer_syntax_error(ls, "integer expected");
}
eo_lexer_context_pop(ls);
switch (ls->t.kw)
{
case NUM_INT : def->static_size = ls->t.value.i; break;
case NUM_UINT : def->static_size = ls->t.value.u; break;
case NUM_LONG : def->static_size = ls->t.value.l; break;
case NUM_ULONG : def->static_size = ls->t.value.ul; break;
case NUM_LLONG : def->static_size = ls->t.value.ll; break;
case NUM_ULLONG: def->static_size = ls->t.value.ull; break;
default:
eo_lexer_syntax_error(ls, "wrong type, internal error");
break;
}
eo_lexer_get(ls);
check_next(ls, '>');
}
else if (ls->t.kw == KW_terminated_array)
{
def->type = EOLIAN_TYPE_TERMINATED_ARRAY;
eo_lexer_get(ls);
check_next(ls, '<');
eo_lexer_context_push(ls);
def->base_type = parse_type(ls, EINA_FALSE, EINA_FALSE);
if (!_type_is_terminatable(def->base_type))
{
eo_lexer_context_restore(ls);
eo_lexer_syntax_error(ls, "terminatable type expected");
}
eo_lexer_context_pop(ls);
pop_type(ls);
check_next(ls, '>');
}
else
{
int tpid = ls->t.kw;
def->type = EOLIAN_TYPE_REGULAR;
check(ls, TOK_VALUE);
if (eo_lexer_get_c_type(ls->t.kw))
if (eo_lexer_is_type_keyword(ls->t.kw))
{
_fill_name(eina_stringshare_ref(ls->t.value.s), &def->full_name,
&def->name, &def->namespaces);
@ -818,17 +892,17 @@ parse_type_void(Eo_Lexer *ls, Eina_Bool allow_ref)
int bline = ls->line_number, bcol = ls->column;
def->type = EOLIAN_TYPE_COMPLEX;
check_next(ls, '<');
def->base_type = parse_type(ls, EINA_FALSE);
def->base_type = parse_type(ls, EINA_FALSE, EINA_FALSE);
pop_type(ls);
if (tpid == KW_hash)
{
check_next(ls, ',');
def->base_type->next_type = parse_type(ls, EINA_FALSE);
def->base_type->next_type = parse_type(ls, EINA_FALSE, EINA_FALSE);
pop_type(ls);
}
else if(tpid == KW_promise && test_next(ls, ','))
{
def->base_type->next_type = parse_type(ls, EINA_FALSE);
def->base_type->next_type = parse_type(ls, EINA_FALSE, EINA_FALSE);
pop_type(ls);
}
check_match(ls, '>', '<', bline, bcol);
@ -920,7 +994,7 @@ parse_typedef(Eo_Lexer *ls)
}
eo_lexer_context_pop(ls);
check_next(ls, ':');
def->base_type = parse_type(ls, EINA_FALSE);
def->base_type = parse_type(ls, EINA_FALSE, EINA_FALSE);
pop_type(ls);
check_next(ls, ';');
FILL_DOC(ls, def, doc);
@ -959,7 +1033,7 @@ parse_variable(Eo_Lexer *ls, Eina_Bool global)
}
eo_lexer_context_pop(ls);
check_next(ls, ':');
def->base_type = parse_type(ls, EINA_FALSE);
def->base_type = parse_type(ls, EINA_FALSE, EINA_FALSE);
pop_type(ls);
if ((ls->t.token == '=') && !has_extern)
{
@ -988,9 +1062,9 @@ parse_return(Eo_Lexer *ls, Eo_Ret_Def *ret, Eina_Bool allow_void)
eo_lexer_get(ls);
check_next(ls, ':');
if (allow_void)
ret->type = parse_type_void(ls, EINA_TRUE);
ret->type = parse_type_void(ls, EINA_TRUE, EINA_FALSE);
else
ret->type = parse_type(ls, EINA_TRUE);
ret->type = parse_type(ls, EINA_TRUE, EINA_FALSE);
ret->doc = NULL;
ret->default_ret_val = NULL;
ret->warn_unused = EINA_FALSE;
@ -1049,9 +1123,9 @@ parse_param(Eo_Lexer *ls, Eina_List **params, Eina_Bool allow_inout,
eo_lexer_get(ls);
check_next(ls, ':');
if (par->param_dir == EOLIAN_OUT_PARAM || par->param_dir == EOLIAN_INOUT_PARAM)
par->type = parse_type_void(ls, EINA_TRUE);
par->type = parse_type_void(ls, EINA_TRUE, EINA_FALSE);
else
par->type = parse_type(ls, EINA_TRUE);
par->type = parse_type(ls, EINA_TRUE, EINA_FALSE);
pop_type(ls);
if ((is_vals || (par->param_dir == EOLIAN_OUT_PARAM)) && (ls->t.token == '('))
{
@ -1649,7 +1723,7 @@ end:
if (ls->t.token == ':')
{
eo_lexer_get(ls);
ev->type = parse_type(ls, EINA_TRUE);
ev->type = parse_type(ls, EINA_TRUE, EINA_FALSE);
pop_type(ls);
}
check(ls, ';');

View File

@ -173,6 +173,7 @@ struct _Eolian_Type
Eina_Stringshare *full_name;
Eina_List *namespaces;
Eina_Stringshare *freefunc;
size_t static_size;
Eina_Bool is_const :1;
Eina_Bool is_own :1;
Eina_Bool is_ref :1;

View File

@ -1,6 +1,8 @@
struct Named {
field: ref(int);
something: string;
arr: static_array<int, 16>;
tarr: terminated_array<string>;
}
struct Another {

View File

@ -15,6 +15,8 @@ typedef struct _Named
{
int *field;
const char *something;
int arr[16];
const char **tarr;
} Named;
typedef struct _Another

View File

@ -692,6 +692,21 @@ START_TEST(eolian_struct)
fail_if(!(type_name = eolian_type_c_type_get(ftype)));
fail_if(strcmp(type_name, "const char *"));
eina_stringshare_del(type_name);
fail_if(!(field = eolian_typedecl_struct_field_get(tdl, "arr")));
fail_if(!(ftype = eolian_typedecl_struct_field_type_get(field)));
fail_if(eolian_type_is_ref(ftype));
fail_if(eolian_type_array_size_get(ftype) != 16);
fail_if(eolian_type_type_get(ftype) != EOLIAN_TYPE_STATIC_ARRAY);
fail_if(!(type_name = eolian_type_c_type_get(ftype)));
fail_if(strcmp(type_name, "int *"));
eina_stringshare_del(type_name);
fail_if(!(field = eolian_typedecl_struct_field_get(tdl, "tarr")));
fail_if(!(ftype = eolian_typedecl_struct_field_type_get(field)));
fail_if(eolian_type_is_ref(ftype));
fail_if(!(type_name = eolian_type_c_type_get(ftype)));
fail_if(eolian_type_type_get(ftype) != EOLIAN_TYPE_TERMINATED_ARRAY);
fail_if(strcmp(type_name, "const char **"));
eina_stringshare_del(type_name);
/* referencing */
fail_if(!(tdl = eolian_typedecl_struct_get_by_name("Another")));