eolian: initial parsing code and API declarations for enums

This commit is contained in:
Daniel Kolesa 2014-08-11 14:56:50 +01:00
parent d4031a21bf
commit be68f9e1fa
6 changed files with 231 additions and 18 deletions

View File

@ -131,9 +131,11 @@ typedef enum
EOLIAN_TYPE_VOID,
EOLIAN_TYPE_REGULAR,
EOLIAN_TYPE_REGULAR_STRUCT,
EOLIAN_TYPE_REGULAR_ENUM,
EOLIAN_TYPE_POINTER,
EOLIAN_TYPE_FUNCTION,
EOLIAN_TYPE_STRUCT,
EOLIAN_TYPE_ENUM,
EOLIAN_TYPE_ALIAS,
EOLIAN_TYPE_CLASS
} Eolian_Type_Type;
@ -847,6 +849,16 @@ EAPI const Eolian_Type *eolian_type_alias_get_by_name(const char *name);
*/
EAPI const Eolian_Type *eolian_type_struct_get_by_name(const char *name);
/*
* @brief Get an enum by name. Supports namespaces.
*
* @param[in] name the name of the struct
* @return the struct or NULL
*
* @ingroup Eolian
*/
EAPI const Eolian_Type *eolian_type_enum_get_by_name(const char *name);
/*
* @brief Get an iterator to all aliases contained in a file.
*
@ -871,6 +883,18 @@ EAPI Eina_Iterator *eolian_type_aliases_get_by_file(const char *fname);
*/
EAPI Eina_Iterator *eolian_type_structs_get_by_file(const char *fname);
/*
* @brief Get an iterator to all enums contained in a file.
*
* @param[in] fname the file name without full path
* @return the iterator or NULL
*
* Thanks to internal caching, this is an O(1) operation.
*
* @ingroup Eolian
*/
EAPI Eina_Iterator *eolian_type_enums_get_by_file(const char *fname);
/*
* @brief Get the type of a type (regular, function, pointer)
*
@ -936,6 +960,54 @@ EAPI const Eolian_Type *eolian_type_struct_field_get(const Eolian_Type *tp, cons
*/
EAPI Eina_Stringshare *eolian_type_struct_field_description_get(const Eolian_Type *tp, const char *field);
/*
* @brief Get an iterator to all field names of an enum type.
*
* @param[in] tp the type.
* @return the iterator when @c tp is EOLIAN_TYPE_ENUM, NULL otherwise.
*
* @ingroup Eolian
*/
EAPI Eina_Iterator *eolian_type_enum_field_names_get(const Eolian_Type *tp);
/*
* @brief Get whether an enum field exists.
*
* @param[in] tp the type.
* @param[in] field the field name.
* @return EINA_TRUE when the field exists, EINA_FALSE otherwise.
*
* @ingroup Eolian
*/
EAPI Eina_Bool eolian_type_enum_field_exists(const Eolian_Type *tp, const char *field);
/*
* @brief Get a field of an enum type.
*
* @param[in] tp the type.
* @param[in] field the field name.
* @return the field when @c tp is EOLIAN_TYPE_ENUM, @c field is not NULL,
* field exists and has a value set, NULL otherwise.
*
* Keep in mind that this can return NULL for an existing field, particularly
* when the field has no value set (i.e. increments by 1 over previous value).
*
* @ingroup Eolian
*/
EAPI const Eolian_Expression *eolian_type_enum_field_get(const Eolian_Type *tp, const char *field);
/*
* @brief Get the description of a field of an enum type.
*
* @param[in] tp the type.
* @param[in] field the field name.
* @return the description when @c tp is EOLIAN_TYPE_ENUM, @c field is not NULL
* and the field exists, NULL otherwise.
*
* @ingroup Eolian
*/
EAPI Eina_Stringshare *eolian_type_enum_field_description_get(const Eolian_Type *tp, const char *field);
/*
* @brief Get the description of a struct/alias type.
*

View File

@ -18,6 +18,7 @@ database_type_del(Eolian_Type *tp)
if (tp->namespaces) EINA_LIST_FREE(tp->namespaces, sp)
eina_stringshare_del(sp);
if (tp->comment) eina_stringshare_del(tp->comment);
if (tp->legacy) eina_stringshare_del(tp->legacy);
free(tp);
}

View File

@ -21,7 +21,8 @@ enum Tokens
/* all keywords in eolian, they can still be used as names (they're TOK_VALUE)
* they just fill in the "kw" field of the token */
#define KEYWORDS KW(class), KW(const), KW(return), KW(struct), KW(virtual), \
#define KEYWORDS KW(class), KW(const), KW(enum), KW(return), KW(struct), \
KW(virtual), \
\
KW(abstract), KW(constructor), KW(constructors), KW(data), \
KW(destructor), KW(eo_prefix), KW(events), KW(func), KW(get), \

View File

@ -158,7 +158,8 @@ redef_error(Eo_Lexer *ls, Eolian_Type_Type type, Eolian_Type *old)
eina_stringshare_del(file);
snprintf(buf, sizeof(buf),
"%s '%s' redefined (originally at line %d, column %d%s)",
(type == EOLIAN_TYPE_STRUCT) ? "struct" : "type alias",
(type == EOLIAN_TYPE_ENUM) ? "enum" : ((type == EOLIAN_TYPE_STRUCT)
? "struct" : "type alias"),
old->full_name, old->base.line, old->base.column, fbuf);
eo_lexer_syntax_error(ls, buf);
}
@ -475,7 +476,7 @@ parse_expr(Eo_Lexer *ls)
}
static Eolian_Type *parse_type_void(Eo_Lexer *ls);
static Eolian_Type *parse_type_struct_void(Eo_Lexer *ls, Eina_Bool allow_struct);
static Eolian_Type *parse_type_named_void(Eo_Lexer *ls, Eina_Bool allow_named);
static Eolian_Type *
parse_type(Eo_Lexer *ls)
@ -493,11 +494,11 @@ parse_type(Eo_Lexer *ls)
}
static Eolian_Type *
parse_type_struct(Eo_Lexer *ls, Eina_Bool allow_struct)
parse_type_named(Eo_Lexer *ls, Eina_Bool allow_named)
{
Eolian_Type *ret;
eo_lexer_context_push(ls);
ret = parse_type_struct_void(ls, allow_struct);
ret = parse_type_named_void(ls, allow_named);
if (ret->type == EOLIAN_TYPE_VOID)
{
eo_lexer_context_restore(ls);
@ -601,8 +602,107 @@ parse_struct(Eo_Lexer *ls, const char *name, Eina_Bool is_extern,
return def;
}
static void
_enum_field_free(Eolian_Enum_Field *def)
{
if (def->base.file) eina_stringshare_del(def->base.file);
database_expr_del(def->value);
if (def->comment) eina_stringshare_del(def->comment);
free(def);
}
static Eolian_Type *
parse_type_struct_void(Eo_Lexer *ls, Eina_Bool allow_struct)
parse_enum(Eo_Lexer *ls, const char *name, Eina_Bool is_extern,
int line, int column)
{
int bline = ls->line_number, bcolumn = ls->column;
Eolian_Type *def = push_type(ls);
def->is_extern = is_extern;
_fill_type_name(def, name);
def->type = EOLIAN_TYPE_ENUM;
def->fields = eina_hash_string_small_new(EINA_FREE_CB(_enum_field_free));
check_next(ls, '{');
if (ls->t.token == TOK_COMMENT)
{
def->comment = eina_stringshare_ref(ls->t.value.s);
eo_lexer_get(ls);
}
if (ls->t.token == TOK_VALUE && ls->t.kw == KW_legacy)
{
if (eo_lexer_lookahead(ls) == ':')
{
/* consume keyword */
eo_lexer_get(ls);
/* consume colon */
eo_lexer_get(ls);
check(ls, TOK_VALUE);
def->legacy = eina_stringshare_ref(ls->t.value.s);
eo_lexer_get(ls);
check_next(ls, ';');
}
}
Eolian_Expression *prev_exp = NULL;
for (;;)
{
const char *fname;
Eolian_Enum_Field *fdef;
int fline = ls->line_number, fcol = ls->column;
check(ls, TOK_VALUE);
if (eina_hash_find(def->fields, ls->t.value.s))
eo_lexer_syntax_error(ls, "double field definition");
fname = eina_stringshare_ref(ls->t.value.s);
eo_lexer_get(ls);
fdef = calloc(1, sizeof(Eolian_Enum_Field));
fdef->base.file = eina_stringshare_ref(ls->filename);
fdef->base.line = fline;
fdef->base.column = fcol;
if (ls->t.token != '=')
{
if (!prev_exp)
{
prev_exp = push_expr(ls);
prev_exp->base.file = eina_stringshare_ref(ls->filename);
prev_exp->base.line = -1;
prev_exp->base.column = -1;
prev_exp->type = EOLIAN_EXPR_INT;
prev_exp->value.i = 0;
fdef->value = prev_exp;
pop_expr(ls);
}
}
else
{
ls->expr_mode = EINA_TRUE;
eo_lexer_get(ls);
fdef->value = parse_expr(ls);
ls->expr_mode = EINA_FALSE;
if (!prev_exp)
prev_exp = fdef->value;
pop_expr(ls);
}
eina_hash_add(def->fields, fname, fdef);
eina_stringshare_del(fname);
Eina_Bool want_next = (ls->t.token == ',');
if (want_next)
eo_lexer_get(ls);
if (ls->t.token == TOK_COMMENT)
{
fdef->comment = eina_stringshare_ref(ls->t.value.s);
eo_lexer_get(ls);
}
if (!want_next)
break;
}
check_match(ls, '}', '{', bline, bcolumn);
def->base.file = eina_stringshare_ref(ls->filename);
def->base.line = line;
def->base.column = column;
if (name) database_struct_add(def);
return def;
}
static Eolian_Type *
parse_type_named_void(Eo_Lexer *ls, Eina_Bool allow_named)
{
Eolian_Type *def;
const char *ctype;
@ -649,17 +749,26 @@ parse_type_struct_void(Eo_Lexer *ls, Eina_Bool allow_struct)
goto parse_ptr;
}
case KW_struct:
case KW_enum:
{
Eina_Bool is_enum = (ls->t.kw == KW_enum);
Eina_Bool is_extern = EINA_FALSE;
eo_lexer_get(ls);
if (ls->t.kw == KW_at_extern)
{
if (!allow_struct)
eo_lexer_syntax_error(ls, "only named structs can be extern");
if (!allow_named)
{
if (is_enum)
eo_lexer_syntax_error(ls,
"only enum declarations can be extern");
else
eo_lexer_syntax_error(ls,
"only named structs can be extern");
}
is_extern = EINA_TRUE;
eo_lexer_get(ls);
}
if (ls->t.token == '{')
if (!is_enum && (ls->t.token == '{'))
{
if (is_extern)
eo_lexer_syntax_error(ls, "extern anonymous struct");
@ -673,9 +782,9 @@ parse_type_struct_void(Eo_Lexer *ls, Eina_Bool allow_struct)
sname = eina_stringshare_add(eina_strbuf_string_get(buf));
pop_strbuf(ls);
/* if we're extern and allow structs, gotta enforce it */
if (allow_struct && is_extern)
if (allow_named && is_extern)
check(ls, '{');
if (allow_struct && ls->t.token == '{')
if (allow_named && ls->t.token == '{')
{
Eolian_Type *tp = (Eolian_Type*)eina_hash_find(_structs,
sname);
@ -683,14 +792,18 @@ parse_type_struct_void(Eo_Lexer *ls, Eina_Bool allow_struct)
{
eina_stringshare_del(sname);
eo_lexer_context_restore(ls);
redef_error(ls, EOLIAN_TYPE_STRUCT, tp);
redef_error(ls, is_enum ? EOLIAN_TYPE_ENUM
: EOLIAN_TYPE_STRUCT, tp);
}
eo_lexer_context_pop(ls);
if (is_enum)
return parse_enum(ls, sname, is_extern, line, col);
return parse_struct(ls, sname, is_extern, line, col);
}
eo_lexer_context_pop(ls);
def = push_type(ls);
def->type = EOLIAN_TYPE_REGULAR_STRUCT;
def->type = is_enum ? EOLIAN_TYPE_REGULAR_ENUM
: EOLIAN_TYPE_REGULAR_STRUCT;
_fill_type_name(def, sname);
goto parse_ptr;
}
@ -789,7 +902,7 @@ parse_ptr:
static Eolian_Type *
parse_type_void(Eo_Lexer *ls)
{
return parse_type_struct_void(ls, EINA_FALSE);
return parse_type_named_void(ls, EINA_FALSE);
}
static Eolian_Type *
@ -821,7 +934,7 @@ parse_typedef(Eo_Lexer *ls)
}
eo_lexer_context_pop(ls);
check_next(ls, ':');
def->base_type = parse_type_struct(ls, EINA_TRUE);
def->base_type = parse_type_named(ls, EINA_TRUE);
pop_type(ls);
check_next(ls, ';');
if (ls->t.token == TOK_COMMENT)
@ -864,6 +977,7 @@ parse_variable(Eo_Lexer *ls, Eina_Bool global)
eo_lexer_get(ls);
def->value = parse_expr(ls);
ls->expr_mode = EINA_FALSE;
pop_expr(ls);
}
check_next(ls, ';');
if (ls->t.token == TOK_COMMENT)
@ -893,6 +1007,7 @@ parse_return(Eo_Lexer *ls, Eina_Bool allow_void)
eo_lexer_get(ls);
ret->default_ret_val = parse_expr(ls);
ls->expr_mode = EINA_FALSE;
pop_expr(ls);
check_match(ls, ')', '(', line, col);
}
if (ls->t.kw == KW_at_warn_unused)
@ -1609,7 +1724,9 @@ parse_unit(Eo_Lexer *ls, Eina_Bool eot)
break;
}
case KW_struct:
case KW_enum:
{
Eina_Bool is_enum = (ls->t.kw == KW_enum);
const char *name;
int line, col;
Eolian_Type *tp;
@ -1627,16 +1744,21 @@ parse_unit(Eo_Lexer *ls, Eina_Bool eot)
col = ls->column;
parse_name(ls, buf);
name = eina_stringshare_add(eina_strbuf_string_get(buf));
tp = (Eolian_Type*)eina_hash_find(_structs, name);
tp = (Eolian_Type*)eina_hash_find(is_enum ? _enums
: _structs, name);
if (tp)
{
eina_stringshare_del(name);
eo_lexer_context_restore(ls);
redef_error(ls, EOLIAN_TYPE_STRUCT, tp);
redef_error(ls, is_enum ? EOLIAN_TYPE_ENUM
: EOLIAN_TYPE_STRUCT, tp);
}
eo_lexer_context_pop(ls);
pop_strbuf(ls);
parse_struct(ls, name, is_extern, line, col);
if (is_enum)
parse_enum(ls, name, is_extern, line, col);
else
parse_struct(ls, name, is_extern, line, col);
pop_type(ls);
break;
}

View File

@ -6,11 +6,13 @@
Eina_Hash *_classes = NULL;
Eina_Hash *_aliases = NULL;
Eina_Hash *_structs = NULL;
Eina_Hash *_enums = NULL;
Eina_Hash *_globals = NULL;
Eina_Hash *_constants = NULL;
Eina_Hash *_classesf = NULL;
Eina_Hash *_aliasesf = NULL;
Eina_Hash *_structsf = NULL;
Eina_Hash *_enumsf = NULL;
Eina_Hash *_globalsf = NULL;
Eina_Hash *_constantsf = NULL;
Eina_Hash *_filenames = NULL;
@ -32,11 +34,13 @@ database_init()
_classes = eina_hash_stringshared_new(EINA_FREE_CB(database_class_del));
_aliases = eina_hash_stringshared_new(EINA_FREE_CB(database_typedef_del));
_structs = eina_hash_stringshared_new(EINA_FREE_CB(database_type_del));
_enums = eina_hash_stringshared_new(EINA_FREE_CB(database_type_del));
_globals = eina_hash_stringshared_new(EINA_FREE_CB(database_var_del));
_constants = eina_hash_stringshared_new(EINA_FREE_CB(database_var_del));
_classesf = eina_hash_stringshared_new(NULL);
_aliasesf = eina_hash_stringshared_new(_hashlist_free);
_structsf = eina_hash_stringshared_new(_hashlist_free);
_enumsf = eina_hash_stringshared_new(_hashlist_free);
_globalsf = eina_hash_stringshared_new(_hashlist_free);
_constantsf = eina_hash_stringshared_new(_hashlist_free);
_filenames = eina_hash_string_small_new(free);
@ -59,11 +63,13 @@ database_shutdown()
eina_hash_free(_classes);
eina_hash_free(_aliases);
eina_hash_free(_structs);
eina_hash_free(_enums);
eina_hash_free(_globals);
eina_hash_free(_constants);
eina_hash_free(_classesf);
eina_hash_free(_aliasesf);
eina_hash_free(_structsf);
eina_hash_free(_enumsf);
eina_hash_free(_globalsf);
eina_hash_free(_constantsf);
eina_hash_free(_filenames);

View File

@ -38,11 +38,13 @@ extern Eina_Prefix *_eolian_prefix;
extern Eina_Hash *_classes;
extern Eina_Hash *_aliases;
extern Eina_Hash *_structs;
extern Eina_Hash *_enums;
extern Eina_Hash *_globals;
extern Eina_Hash *_constants;
extern Eina_Hash *_classesf;
extern Eina_Hash *_aliasesf;
extern Eina_Hash *_structsf;
extern Eina_Hash *_enumsf;
extern Eina_Hash *_globalsf;
extern Eina_Hash *_constantsf;
extern Eina_Hash *_filenames; /* Hash: filename without extension -> full path */
@ -129,6 +131,7 @@ struct _Eolian_Type
Eina_List *namespaces;
Eina_Hash *fields;
Eina_Stringshare *comment;
Eina_Stringshare *legacy;
};
};
Eina_Bool is_const :1;
@ -157,6 +160,13 @@ typedef struct _Eolian_Struct_Field
Eina_Stringshare *comment;
} Eolian_Struct_Field;
typedef struct _Eolian_Enum_Field
{
Eolian_Object base;
Eolian_Expression *value;
Eina_Stringshare *comment;
} Eolian_Enum_Field;
typedef union
{
char c;
@ -252,6 +262,7 @@ int database_shutdown();
Eina_Bool database_type_add(Eolian_Type *def);
Eina_Bool database_struct_add(Eolian_Type *tp);
Eina_Bool database_enum_add(Eolian_Type *tp);
void database_type_del(Eolian_Type *tp);
void database_typedef_del(Eolian_Type *tp);