eolian: enum API implementation
authorDaniel Kolesa <d.kolesa@samsung.com>
Tue, 12 Aug 2014 13:25:53 +0000 (14:25 +0100)
committerDaniel Kolesa <d.kolesa@samsung.com>
Thu, 21 Aug 2014 08:26:04 +0000 (09:26 +0100)
This implements the previously declared APIs to manipulate enum types. Also,
it implements the appropriate lookups in expression evaluation so that you
can refer to constants and enums inside constant expressions.

src/lib/eolian/Eolian.h
src/lib/eolian/database_expr.c
src/lib/eolian/database_type.c
src/lib/eolian/database_type_api.c
src/lib/eolian/eo_parser.c

index e79eaa6..080ca45 100644 (file)
@@ -157,6 +157,7 @@ typedef enum
    EOLIAN_EXPR_NULL,
    EOLIAN_EXPR_BOOL,
    EOLIAN_EXPR_NAME,
+   EOLIAN_EXPR_ENUM,
    EOLIAN_EXPR_UNARY,
    EOLIAN_EXPR_BINARY
 } Eolian_Expression_Type;
index 48889a6..f2b202c 100644 (file)
@@ -59,6 +59,14 @@ expr_type_error(const Eolian_Expression *expr, int type, int mask)
    return node_error((const Eolian_Object*)expr, buf);
 }
 
+static Eina_Bool
+expr_error(const Eolian_Expression *expr, const char *msg)
+{
+   char buf[512];
+   snprintf(buf, sizeof(buf), "%s '%s'", msg, expr->value.s);
+   return node_error((const Eolian_Object*)expr, buf);
+}
+
 static int
 expr_type_to_mask(const Eolian_Expression *expr)
 {
@@ -407,6 +415,22 @@ eval_binary(const Eolian_Expression *expr, Eolian_Expression_Mask mask,
 }
 
 static Eina_Bool
+split_enum_name(const char *str, char **ename, char **memb)
+{
+   char *fulln  = strdup(str);
+   char *memb_s = strrchr(fulln, '.');
+   if  (!memb_s)
+     {
+        free(fulln);
+        return EINA_FALSE;
+     }
+   *(memb_s++) = '\0';
+   *ename = fulln;
+   *memb  = memb_s;
+   return EINA_TRUE;
+}
+
+static Eina_Bool
 eval_exp(const Eolian_Expression *expr, Eolian_Expression_Mask mask,
          Eolian_Expression *out)
 {
@@ -467,6 +491,90 @@ eval_exp(const Eolian_Expression *expr, Eolian_Expression_Mask mask,
            *out = *expr;
            return EINA_TRUE;
         }
+      case EOLIAN_EXPR_NAME:
+        {
+           const Eolian_Variable *var = eolian_variable_constant_get_by_name
+             (expr->value.s);
+           const Eolian_Expression *exp = NULL;
+
+           if (!var)
+             {
+                const Eolian_Type *etp;
+
+                /* try aliases, hoping it'll be enum */
+                char *fulln = NULL, *memb = NULL;
+
+                if (!split_enum_name(expr->value.s, &fulln, &memb))
+                  return expr_error(expr, "undefined variable");
+
+                etp = eolian_type_alias_get_by_name(fulln);
+                while (etp && etp->type == EOLIAN_TYPE_ALIAS)
+                  {
+                     etp = eolian_type_base_type_get(etp);
+                     if (etp->type == EOLIAN_TYPE_ENUM)
+                       break;
+                     if (etp->type == EOLIAN_TYPE_REGULAR_ENUM)
+                       break;
+                     if (etp->type != EOLIAN_TYPE_REGULAR)
+                       {
+                          etp = NULL;
+                          break;
+                       }
+                     etp = eolian_type_alias_get_by_name(etp->full_name);
+                  }
+
+                if (etp && etp->type == EOLIAN_TYPE_REGULAR_ENUM)
+                  etp = eolian_type_enum_get_by_name(etp->full_name);
+
+                if (!etp || etp->type != EOLIAN_TYPE_ENUM)
+                  {
+                     free(fulln);
+                     return expr_error(expr, "undefined variable");
+                  }
+
+                exp = eolian_type_enum_field_get(etp, memb);
+                free(fulln);
+
+                if (!exp)
+                  return expr_error(expr, "invalid enum field");
+             }
+           else
+             exp = var->value;
+
+           if (!exp)
+             return expr_error(expr, "undefined variable");
+
+           return eval_exp(exp, mask, out);
+        }
+      case EOLIAN_EXPR_ENUM:
+        {
+           const Eolian_Type *etp;
+           const Eolian_Expression *exp;
+
+           char *fulln = NULL, *memb = NULL;
+           if (!split_enum_name(expr->value.s, &fulln, &memb))
+             {
+                return expr_error(expr, "invalid enum");
+             }
+
+           etp = eolian_type_enum_get_by_name(fulln);
+           if (etp && etp->type == EOLIAN_TYPE_REGULAR_ENUM)
+             etp = eolian_type_enum_get_by_name(etp->full_name);
+
+           if (!etp)
+             {
+                free(fulln);
+                return expr_error(expr, "invalid enum");
+             }
+
+           exp = eolian_type_enum_field_get(etp, memb);
+           free(fulln);
+
+           if (!exp)
+             return expr_error(expr, "invalid enum field");
+
+           return eval_exp(exp, mask, out);
+        }
       case EOLIAN_EXPR_UNARY:
         return eval_unary(expr, mask, out);
       case EOLIAN_EXPR_BINARY:
index 0df7f59..abf252b 100644 (file)
@@ -27,9 +27,14 @@ database_typedef_del(Eolian_Type *tp)
 {
    if (!tp) return;
    Eolian_Type *btp = tp->base_type;
-   /* prevent deletion of named structs as they're deleted later on */
-   if (btp && btp->type == EOLIAN_TYPE_STRUCT && btp->name)
-     tp->base_type = NULL;
+   /* prevent deletion of named structs/enums as they're deleted later on */
+   if (btp)
+     {
+        if (btp->type == EOLIAN_TYPE_ENUM)
+          tp->base_type = NULL;
+        else if (btp->type == EOLIAN_TYPE_STRUCT && btp->name)
+          tp->base_type = NULL;
+     }
    database_type_del(tp);
 }
 
@@ -52,6 +57,15 @@ Eina_Bool database_struct_add(Eolian_Type *tp)
    return EINA_TRUE;
 }
 
+Eina_Bool database_enum_add(Eolian_Type *tp)
+{
+   if (!_enums) return EINA_FALSE;
+   eina_hash_set(_enums, tp->full_name, tp);
+   eina_hash_set(_enumsf, tp->base.file, eina_list_append
+                ((Eina_List*)eina_hash_find(_enumsf, tp->base.file), tp));
+   return EINA_TRUE;
+}
+
 static void
 _ftype_to_str(const Eolian_Type *tp, Eina_Strbuf *buf, const char *name)
 {
index 2fa6404..ab0ea75 100644 (file)
@@ -22,6 +22,16 @@ eolian_type_struct_get_by_name(const char *name)
    return tp;
 }
 
+EAPI const Eolian_Type *
+eolian_type_enum_get_by_name(const char *name)
+{
+   if (!_enums) return NULL;
+   Eina_Stringshare *shr = eina_stringshare_add(name);
+   Eolian_Type *tp = eina_hash_find(_enums, shr);
+   eina_stringshare_del(shr);
+   return tp;
+}
+
 EAPI Eina_Iterator *
 eolian_type_aliases_get_by_file(const char *fname)
 {
@@ -44,6 +54,17 @@ eolian_type_structs_get_by_file(const char *fname)
    return eina_list_iterator_new(l);
 }
 
+EAPI Eina_Iterator *
+eolian_type_enums_get_by_file(const char *fname)
+{
+   if (!_structsf) return NULL;
+   Eina_Stringshare *shr = eina_stringshare_add(fname);
+   Eina_List *l = eina_hash_find(_enumsf, shr);
+   eina_stringshare_del(shr);
+   if (!l) return NULL;
+   return eina_list_iterator_new(l);
+}
+
 EAPI Eolian_Type_Type
 eolian_type_type_get(const Eolian_Type *tp)
 {
@@ -106,6 +127,50 @@ eolian_type_struct_field_description_get(const Eolian_Type *tp, const char *fiel
    return sf->comment;
 }
 
+EAPI Eina_Iterator *
+eolian_type_enum_field_names_get(const Eolian_Type *tp)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(tp, NULL);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(tp->type == EOLIAN_TYPE_ENUM, NULL);
+   return eina_hash_iterator_key_new(tp->fields);
+}
+
+EAPI Eina_Bool
+eolian_type_enum_field_exists(const Eolian_Type *tp, const char *field)
+{
+   Eolian_Enum_Field *ef = NULL;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(tp, EINA_FALSE);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(tp->type == EOLIAN_TYPE_ENUM, EINA_FALSE);
+   ef = eina_hash_find(tp->fields, field);
+   if (!ef)
+     return EINA_FALSE;
+   return EINA_TRUE;
+}
+
+EAPI const Eolian_Expression *
+eolian_type_enum_field_get(const Eolian_Type *tp, const char *field)
+{
+   Eolian_Enum_Field *ef = NULL;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(tp, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(field, NULL);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(tp->type == EOLIAN_TYPE_ENUM, NULL);
+   ef = eina_hash_find(tp->fields, field);
+   if (!ef) return NULL;
+   return ef->value;
+}
+
+EAPI Eina_Stringshare *
+eolian_type_enum_field_description_get(const Eolian_Type *tp, const char *field)
+{
+   Eolian_Enum_Field *ef = NULL;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(tp, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(field, NULL);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(tp->type == EOLIAN_TYPE_ENUM, NULL);
+   ef = eina_hash_find(tp->fields, field);
+   if (!ef) return NULL;
+   return ef->comment;
+}
+
 EAPI Eina_Stringshare *
 eolian_type_description_get(const Eolian_Type *tp)
 {
index ceb82c0..133ada5 100644 (file)
@@ -411,11 +411,18 @@ parse_expr_simple(Eo_Lexer *ls)
                    eo_lexer_get(ls);
                    break;
                 }
+              case KW_enum:
               default:
                 {
                    Eina_Strbuf *buf = push_strbuf(ls);
+                   Eolian_Expression_Type tp = EOLIAN_EXPR_NAME;
+                   if (ls->t.kw == KW_enum)
+                     {
+                        eo_lexer_get(ls);
+                        tp = EOLIAN_EXPR_ENUM;
+                     }
                    expr = push_expr(ls);
-                   expr->type = EOLIAN_EXPR_NAME;
+                   expr->type = tp;
                    parse_name(ls, buf);
                    expr->value.s = eina_stringshare_add(eina_strbuf_string_get
                        (buf));
@@ -701,7 +708,7 @@ parse_enum(Eo_Lexer *ls, const char *name, Eina_Bool is_extern,
    def->base.file = eina_stringshare_ref(ls->filename);
    def->base.line = line;
    def->base.column = column;
-   if (name) database_struct_add(def);
+   if (name) database_enum_add(def);
    return def;
 }