From: Daniel Kolesa Date: Mon, 11 Aug 2014 13:56:50 +0000 (+0100) Subject: eolian: initial parsing code and API declarations for enums X-Git-Tag: upstream/1.11.0+73+gfce1e61~38 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=be68f9e1faf05e565f9b8175e8264f90f287b9b6;p=platform%2Fupstream%2Fefl.git eolian: initial parsing code and API declarations for enums --- diff --git a/src/lib/eolian/Eolian.h b/src/lib/eolian/Eolian.h index 5bf7fbb..e79eaa6 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 e1af071..0df7f59 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 14d895d..c6be00d 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 46ffd6b..12b6b01 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 3873206..e619bad 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 c8c0ad6..4bc8a17 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);