eolian: initial parsing code and API declarations for enums
authorDaniel Kolesa <d.kolesa@samsung.com>
Mon, 11 Aug 2014 13:56:50 +0000 (14:56 +0100)
committerDaniel Kolesa <d.kolesa@samsung.com>
Thu, 21 Aug 2014 08:26:04 +0000 (09:26 +0100)
src/lib/eolian/Eolian.h
src/lib/eolian/database_type.c
src/lib/eolian/eo_lexer.h
src/lib/eolian/eo_parser.c
src/lib/eolian/eolian_database.c
src/lib/eolian/eolian_database.h

index 5bf7fbb..e79eaa6 100644 (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;
@@ -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.
index e1af071..0df7f59 100644 (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);
 }
 
index 14d895d..c6be00d 100644 (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), \
index 46ffd6b..12b6b01 100644 (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;
         }
index 3873206..e619bad 100644 (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);
index c8c0ad6..4bc8a17 100644 (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);