summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Kolesa <d.kolesa@samsung.com>2014-08-11 14:56:50 +0100
committerDaniel Kolesa <d.kolesa@samsung.com>2014-08-21 09:26:04 +0100
commitbe68f9e1faf05e565f9b8175e8264f90f287b9b6 (patch)
treef262b99c64a568f835d2dfa2db53f66e6d75b84b
parentd4031a21bf340cc36f094c1461d6f84076cae1c9 (diff)
downloadefl-be68f9e1faf05e565f9b8175e8264f90f287b9b6.tar.gz
eolian: initial parsing code and API declarations for enums
-rw-r--r--src/lib/eolian/Eolian.h72
-rw-r--r--src/lib/eolian/database_type.c1
-rw-r--r--src/lib/eolian/eo_lexer.h3
-rw-r--r--src/lib/eolian/eo_parser.c156
-rw-r--r--src/lib/eolian/eolian_database.c6
-rw-r--r--src/lib/eolian/eolian_database.h11
6 files changed, 231 insertions, 18 deletions
diff --git a/src/lib/eolian/Eolian.h b/src/lib/eolian/Eolian.h
index 5bf7fbb926..e79eaa66a7 100644
--- a/src/lib/eolian/Eolian.h
+++ b/src/lib/eolian/Eolian.h
@@ -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;
@@ -848,6 +850,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.
*
* @param[in] fname the file name without full path
@@ -872,6 +884,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)
*
* @param[in] tp the type.
@@ -937,6 +961,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.
*
* @param[in] tp the type.
diff --git a/src/lib/eolian/database_type.c b/src/lib/eolian/database_type.c
index e1af071006..0df7f59c7f 100644
--- a/src/lib/eolian/database_type.c
+++ b/src/lib/eolian/database_type.c
@@ -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);
}
diff --git a/src/lib/eolian/eo_lexer.h b/src/lib/eolian/eo_lexer.h
index 14d895ddd7..c6be00d11a 100644
--- a/src/lib/eolian/eo_lexer.h
+++ b/src/lib/eolian/eo_lexer.h
@@ -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), \
diff --git a/src/lib/eolian/eo_parser.c b/src/lib/eolian/eo_parser.c
index 46ffd6b1f5..12b6b019f5 100644
--- a/src/lib/eolian/eo_parser.c
+++ b/src/lib/eolian/eo_parser.c
@@ -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;
}
diff --git a/src/lib/eolian/eolian_database.c b/src/lib/eolian/eolian_database.c
index 3873206a26..e619bad9b9 100644
--- a/src/lib/eolian/eolian_database.c
+++ b/src/lib/eolian/eolian_database.c
@@ -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);
diff --git a/src/lib/eolian/eolian_database.h b/src/lib/eolian/eolian_database.h
index c8c0ad6388..4bc8a171c1 100644
--- a/src/lib/eolian/eolian_database.h
+++ b/src/lib/eolian/eolian_database.h
@@ -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);