eolian: add API to query information about Objects
authorDaniel Kolesa <d.kolesa@osg.samsung.com>
Thu, 8 Mar 2018 16:30:30 +0000 (17:30 +0100)
committerWonki Kim <wonki_.kim@samsung.com>
Tue, 10 Apr 2018 11:10:50 +0000 (20:10 +0900)
As nearly every Eolian handle is backed by an Eolian_Object,
this information is now publicly exposed and has an API. This
opens up an array of new possibilities for tooling, as you
can now externally query file names, line numbers etc.,
as well as cast arbitrary handles to Eolian_Object pointers
and back.

This will be expanded later and it will replace the Declaration
system, as it's cleaner, better integrated and more versatile.

@feature

src/lib/eolian/Eolian.h
src/lib/eolian/eo_parser.c
src/lib/eolian/eolian_database.c
src/lib/eolian/eolian_database.h

index 900c9f1..e74832f 100644 (file)
@@ -93,6 +93,14 @@ extern "C" {
  */
 typedef struct _Eolian_State Eolian_State;
 
+/* Any Eolian object
+ *
+ * @see Eolian_Object_Type
+ *
+ * @ingroup Eolian
+ */
+typedef struct _Eolian_Object Eolian_Object;
+
 /* Class type used to extract information on classes
  *
  * @ingroup Eolian
@@ -191,6 +199,26 @@ typedef struct _Eolian_Unit Eolian_Unit;
 
 typedef enum
 {
+   EOLIAN_OBJECT_UNKNOWN = 0,
+   EOLIAN_OBJECT_CLASS,
+   EOLIAN_OBJECT_TYPEDECL,
+   EOLIAN_OBJECT_STRUCT_FIELD,
+   EOLIAN_OBJECT_ENUM_FIELD,
+   EOLIAN_OBJECT_TYPE,
+   EOLIAN_OBJECT_VARIABLE,
+   EOLIAN_OBJECT_EXPRESSION,
+   EOLIAN_OBJECT_FUNCTION,
+   EOLIAN_OBJECT_FUNCTION_PARAMETER,
+   EOLIAN_OBJECT_EVENT,
+   EOLIAN_OBJECT_PART,
+   EOLIAN_OBJECT_IMPLEMENT,
+   EOLIAN_OBJECT_CONSTRUCTOR,
+   EOLIAN_OBJECT_DOCUMENTATION,
+   EOLIAN_OBJECT_DECLARATION
+} Eolian_Object_Type;
+
+typedef enum
+{
    EOLIAN_UNRESOLVED = 0,
    EOLIAN_PROPERTY,
    EOLIAN_PROP_SET,
@@ -500,6 +528,64 @@ EAPI Eolian_State *eolian_state_new(void);
 EAPI void eolian_state_free(Eolian_State *state);
 
 /*
+ * @brief Get the type of an Eolian object.
+ *
+ * Most handles returned by Eolian somewhere are Eolian_Objects. You can cast
+ * them to Eolian_Object, store or manipulate them and then use this function
+ * to check their type in order to for example cast it back.
+ *
+ * @see eolian_object_file_get
+ * @see eolian_object_line_get
+ * @see eolian_object_column_get
+ *
+ * @ingroup Eolian
+ */
+EAPI Eolian_Object_Type eolian_object_type_get(const Eolian_Object *obj);
+
+/*
+ * @brief Get the name of the file the object comes from.
+ *
+ * This returns the name of the file the object was declared in. It's not
+ * a full path, just the file name.
+ *
+ * @see eolian_object_type_get
+ * @see eolian_object_line_get
+ * @see eolian_object_column_get
+ *
+ * @ingroup Eolian
+ */
+EAPI const char *eolian_object_file_get(const Eolian_Object *obj);
+
+/*
+ * @brief Get the line the object was declared at.
+ *
+ * This returns the line number in the file the object was declared at.
+ *
+ * @see eolian_object_type_get
+ * @see eolian_object_file_get
+ * @see eolian_object_column_get
+ *
+ * @ingroup Eolian
+ */
+EAPI int eolian_object_line_get(const Eolian_Object *obj);
+
+/*
+ * @brief Get the column the object was declared at.
+ *
+ * This returns the column number in the file the object was declared at,
+ * that means which character on the line. It is Unicode-aware, Eolian
+ * assumes all input files are encoded in UTF-8, so this is really the
+ * code point number, not the byte number.
+ *
+ * @see eolian_object_type_get
+ * @see eolian_object_file_get
+ * @see eolian_object_line_get
+ *
+ * @ingroup Eolian
+ */
+EAPI int eolian_object_column_get(const Eolian_Object *obj);
+
+/*
  * @brief Scan the given directory for .eo and .eot files.
  *
  * You need to add every directory you plan to use .eo/.eot files from.
index 6ed9039..7c8003d 100644 (file)
      eo_lexer_syntax_error(ls, "double " msg); \
    has_##var = EINA_TRUE;
 
-#define FILL_BASE(exp, ls, l, c) \
+#define FILL_BASE(exp, ls, l, c, tp) \
    (exp).file = eina_stringshare_ref(ls->filename); \
    (exp).line = l; \
-   (exp).column = c;
+   (exp).column = c; \
+   (exp).type = EOLIAN_OBJECT_##tp
 
 #define FILL_DOC(ls, def, docf) \
    if (ls->t.token == TOK_DOC) \
@@ -333,7 +334,7 @@ parse_expr_simple(Eo_Lexer *ls)
         Eolian_Expression *exp = parse_expr_bin(ls, UNARY_PRECEDENCE);
         pop_expr(ls);
         expr = push_expr(ls);
-        FILL_BASE(expr->base, ls, line, col);
+        FILL_BASE(expr->base, ls, line, col, EXPRESSION);
         expr->unop = unop;
         expr->type = EOLIAN_EXPR_UNARY;
         expr->expr = exp;
@@ -345,7 +346,7 @@ parse_expr_simple(Eo_Lexer *ls)
         {
            int line = ls->line_number, col = ls->column;
            expr = push_expr(ls);
-           FILL_BASE(expr->base, ls, line, col);
+           FILL_BASE(expr->base, ls, line, col, EXPRESSION);
            expr->type = ls->t.kw + 1; /* map Numbers from lexer to expr type */
            memcpy(&expr->value, &ls->t.value, sizeof(expr->value));
            eo_lexer_get(ls);
@@ -355,7 +356,7 @@ parse_expr_simple(Eo_Lexer *ls)
         {
            int line = ls->line_number, col = ls->column;
            expr = push_expr(ls);
-           FILL_BASE(expr->base, ls, line, col);
+           FILL_BASE(expr->base, ls, line, col, EXPRESSION);
            expr->type = EOLIAN_EXPR_STRING;
            expr->value.s = eina_stringshare_ref(ls->t.value.s);
            eo_lexer_get(ls);
@@ -365,7 +366,7 @@ parse_expr_simple(Eo_Lexer *ls)
         {
            int line = ls->line_number, col = ls->column;
            expr = push_expr(ls);
-           FILL_BASE(expr->base, ls, line, col);
+           FILL_BASE(expr->base, ls, line, col, EXPRESSION);
            expr->type = EOLIAN_EXPR_CHAR;
            expr->value.c = ls->t.value.c;
            eo_lexer_get(ls);
@@ -404,7 +405,7 @@ parse_expr_simple(Eo_Lexer *ls)
                    break;
                 }
              }
-           FILL_BASE(expr->base, ls, line, col);
+           FILL_BASE(expr->base, ls, line, col, EXPRESSION);
            break;
         }
       case '(':
@@ -441,7 +442,7 @@ parse_expr_bin(Eo_Lexer *ls, int min_prec)
         pop_expr(ls);
         pop_expr(ls);
         bin = push_expr(ls);
-        FILL_BASE(bin->base, ls, line, col);
+        FILL_BASE(bin->base, ls, line, col, EXPRESSION);
         bin->binop = op;
         bin->type = EOLIAN_EXPR_BINARY;
         bin->lhs = lhs;
@@ -515,7 +516,7 @@ parse_struct(Eo_Lexer *ls, const char *name, Eina_Bool is_extern,
         eo_lexer_get(ls);
         check_next(ls, ':');
         tp = parse_type(ls);
-        FILL_BASE(fdef->base, ls, fline, fcol);
+        FILL_BASE(fdef->base, ls, fline, fcol, STRUCT_FIELD);
         fdef->type = tp;
         fdef->name = eina_stringshare_ref(fname);
         pop_type(ls);
@@ -525,7 +526,7 @@ parse_struct(Eo_Lexer *ls, const char *name, Eina_Bool is_extern,
         FILL_DOC(ls, fdef, doc);
      }
    check_match(ls, '}', '{', bline, bcolumn);
-   FILL_BASE(def->base, ls, line, column);
+   FILL_BASE(def->base, ls, line, column, TYPEDECL);
    if (name) database_struct_add(ls->unit, def);
    return def;
 }
@@ -582,7 +583,7 @@ parse_enum(Eo_Lexer *ls, const char *name, Eina_Bool is_extern,
         def->field_list = eina_list_append(def->field_list, fdef);
         eolian_object_ref(&fdef->base);
         eo_lexer_get(ls);
-        FILL_BASE(fdef->base, ls, fline, fcol);
+        FILL_BASE(fdef->base, ls, fline, fcol, ENUM_FIELD);
         fdef->base_enum = def;
         fdef->name = eina_stringshare_ref(fname);
         if (ls->t.token != '=')
@@ -590,7 +591,7 @@ parse_enum(Eo_Lexer *ls, const char *name, Eina_Bool is_extern,
              if (!prev_fl)
                {
                   Eolian_Expression *eexp = push_expr(ls);
-                  FILL_BASE(eexp->base, ls, -1, -1);
+                  FILL_BASE(eexp->base, ls, -1, -1, EXPRESSION);
                   eexp->type = EOLIAN_EXPR_INT;
                   eexp->value.i = 0;
                   fdef->value = eexp;
@@ -603,8 +604,8 @@ parse_enum(Eo_Lexer *ls, const char *name, Eina_Bool is_extern,
                {
                   Eolian_Expression *rhs = push_expr(ls),
                                     *bin = push_expr(ls);
-                  FILL_BASE(rhs->base, ls, -1, -1);
-                  FILL_BASE(bin->base, ls, -1, -1);
+                  FILL_BASE(rhs->base, ls, -1, -1, EXPRESSION);
+                  FILL_BASE(bin->base, ls, -1, -1, EXPRESSION);
 
                   rhs->type = EOLIAN_EXPR_INT;
                   rhs->value.i = ++fl_nadd;
@@ -637,7 +638,7 @@ parse_enum(Eo_Lexer *ls, const char *name, Eina_Bool is_extern,
           break;
      }
    check_match(ls, '}', '{', bline, bcolumn);
-   FILL_BASE(def->base, ls, line, column);
+   FILL_BASE(def->base, ls, line, column, TYPEDECL);
    if (name) database_enum_add(ls->unit, def);
    return def;
 }
@@ -691,7 +692,7 @@ parse_type_void(Eo_Lexer *ls)
            pcol = ls->column;
            check_next(ls, '(');
            def = parse_type_void(ls);
-           FILL_BASE(def->base, ls, line, col);
+           FILL_BASE(def->base, ls, line, col, TYPE);
            def->is_const = EINA_TRUE;
            check_match(ls, ')', '(', pline, pcol);
            return def;
@@ -704,7 +705,7 @@ parse_type_void(Eo_Lexer *ls)
            pcol = ls->column;
            check_next(ls, '(');
            def = parse_type_void(ls);
-           FILL_BASE(def->base, ls, line, col);
+           FILL_BASE(def->base, ls, line, col, TYPE);
            def->is_ptr = EINA_TRUE;
            check_match(ls, ')', '(', pline, pcol);
            return def;
@@ -717,7 +718,7 @@ parse_type_void(Eo_Lexer *ls)
            pcol = ls->column;
            check_next(ls, '(');
            def = parse_type_void(ls);
-           FILL_BASE(def->base, ls, line, col);
+           FILL_BASE(def->base, ls, line, col, TYPE);
            def->legacy = EINA_TRUE;
            check_match(ls, ')', '(', pline, pcol);
            return def;
@@ -734,7 +735,7 @@ parse_type_void(Eo_Lexer *ls)
            check(ls, TOK_VALUE);
            def->freefunc = eina_stringshare_ref(ls->t.value.s);
            eo_lexer_get(ls);
-           FILL_BASE(def->base, ls, line, col);
+           FILL_BASE(def->base, ls, line, col, TYPE);
            check_match(ls, ')', '(', pline, pcolumn);
            return def;
         }
@@ -742,7 +743,7 @@ parse_type_void(Eo_Lexer *ls)
         break;
      }
    def = push_type(ls);
-   FILL_BASE(def->base, ls, line, col);
+   FILL_BASE(def->base, ls, line, col, TYPE);
    if (ls->t.kw == KW_void)
      {
         def->type = EOLIAN_TYPE_VOID;
@@ -844,7 +845,7 @@ parse_typedef(Eo_Lexer *ls)
    def->is_extern = has_extern;
    buf = push_strbuf(ls);
    eo_lexer_context_push(ls);
-   FILL_BASE(def->base, ls, ls->line_number, ls->column);
+   FILL_BASE(def->base, ls, ls->line_number, ls->column, TYPEDECL);
    parse_name(ls, buf);
    _fill_name(eina_stringshare_add(eina_strbuf_string_get(buf)),
               &def->full_name, &def->name, &def->namespaces);
@@ -880,7 +881,7 @@ parse_variable(Eo_Lexer *ls, Eina_Bool global)
    def->type = global ? EOLIAN_VAR_GLOBAL : EOLIAN_VAR_CONSTANT;
    buf = push_strbuf(ls);
    eo_lexer_context_push(ls);
-   FILL_BASE(def->base, ls, ls->line_number, ls->column);
+   FILL_BASE(def->base, ls, ls->line_number, ls->column, VARIABLE);
    parse_name(ls, buf);
    _fill_name(eina_stringshare_add(eina_strbuf_string_get(buf)),
               &def->full_name, &def->name, &def->namespaces);
@@ -974,7 +975,7 @@ parse_param(Eo_Lexer *ls, Eina_List **params, Eina_Bool allow_inout,
    Eina_Bool cref = (ls->t.kw == KW_at_cref);
    Eolian_Function_Parameter *par = calloc(1, sizeof(Eolian_Function_Parameter));
    par->param_dir = EOLIAN_IN_PARAM;
-   FILL_BASE(par->base, ls, ls->line_number, ls->column);
+   FILL_BASE(par->base, ls, ls->line_number, ls->column, FUNCTION_PARAMETER);
    *params = eina_list_append(*params, par);
    eolian_object_ref(&par->base);
    if (cref || (allow_inout && (ls->t.kw == KW_at_in)))
@@ -1088,7 +1089,7 @@ parse_accessor(Eo_Lexer *ls, Eolian_Function *prop)
      {
         if (prop->base.file)
           eina_stringshare_del(prop->base.file);
-        FILL_BASE(prop->base, ls, ls->line_number, ls->column);
+        FILL_BASE(prop->base, ls, ls->line_number, ls->column, FUNCTION);
         if (prop->type == EOLIAN_PROP_SET)
           prop->type = EOLIAN_PROPERTY;
         else
@@ -1096,7 +1097,7 @@ parse_accessor(Eo_Lexer *ls, Eolian_Function *prop)
      }
    else
      {
-        FILL_BASE(prop->set_base, ls, ls->line_number, ls->column);
+        FILL_BASE(prop->set_base, ls, ls->line_number, ls->column, FUNCTION);
         if (prop->type == EOLIAN_PROP_GET)
           prop->type = EOLIAN_PROPERTY;
         else
@@ -1236,11 +1237,11 @@ parse_property(Eo_Lexer *ls)
    prop->klass = ls->tmp.kls;
    prop->type = EOLIAN_UNRESOLVED;
    prop->get_scope = prop->set_scope = EOLIAN_SCOPE_PUBLIC;
-   FILL_BASE(prop->base, ls, ls->line_number, ls->column);
+   FILL_BASE(prop->base, ls, ls->line_number, ls->column, FUNCTION);
    impl = calloc(1, sizeof(Eolian_Implement));
    impl->klass = ls->tmp.kls;
    impl->foo_id = prop;
-   FILL_BASE(impl->base, ls, ls->line_number, ls->column);
+   FILL_BASE(impl->base, ls, ls->line_number, ls->column, IMPLEMENT);
    prop->impl = impl;
    ls->tmp.kls->properties = eina_list_append(ls->tmp.kls->properties, prop);
    ls->tmp.kls->implements = eina_list_append(ls->tmp.kls->implements, impl);
@@ -1382,8 +1383,8 @@ parse_function_pointer(Eo_Lexer *ls)
 end:
    check_match(ls, '}', '{', bline, bcol);
    check_next(ls, ';');
-   FILL_BASE(def->base, ls, line, col);
-   FILL_BASE(meth->base, ls, line, col);
+   FILL_BASE(def->base, ls, line, col, TYPEDECL);
+   FILL_BASE(meth->base, ls, line, col, FUNCTION);
    return def;
 }
 
@@ -1402,11 +1403,11 @@ parse_method(Eo_Lexer *ls)
    meth->klass = ls->tmp.kls;
    meth->type = EOLIAN_METHOD;
    meth->get_scope = meth->set_scope = EOLIAN_SCOPE_PUBLIC;
-   FILL_BASE(meth->base, ls, ls->line_number, ls->column);
+   FILL_BASE(meth->base, ls, ls->line_number, ls->column, FUNCTION);
    impl = calloc(1, sizeof(Eolian_Implement));
    impl->klass = ls->tmp.kls;
    impl->foo_id = meth;
-   FILL_BASE(impl->base, ls, ls->line_number, ls->column);
+   FILL_BASE(impl->base, ls, ls->line_number, ls->column, IMPLEMENT);
    meth->impl = impl;
    ls->tmp.kls->methods = eina_list_append(ls->tmp.kls->methods, meth);
    ls->tmp.kls->implements = eina_list_append(ls->tmp.kls->implements, impl);
@@ -1593,7 +1594,7 @@ parse_implement(Eo_Lexer *ls, Eina_Bool iface)
    else
      {
         impl = calloc(1, sizeof(Eolian_Implement));
-        FILL_BASE(impl->base, ls, iline, icol);
+        FILL_BASE(impl->base, ls, iline, icol, IMPLEMENT);
         ls->tmp.kls->implements = eina_list_append(ls->tmp.kls->implements, impl);
         eolian_object_ref(&impl->base);
      }
@@ -1698,7 +1699,7 @@ parse_constructor(Eo_Lexer *ls)
    Eina_Strbuf *buf = NULL;
    Eolian_Constructor *ctor = NULL;
    ctor = calloc(1, sizeof(Eolian_Constructor));
-   FILL_BASE(ctor->base, ls, ls->line_number, ls->column);
+   FILL_BASE(ctor->base, ls, ls->line_number, ls->column, CONSTRUCTOR);
    ls->tmp.kls->constructors = eina_list_append(ls->tmp.kls->constructors, ctor);
    eolian_object_ref(&ctor->base);
    if (ls->t.token == '.')
@@ -1747,7 +1748,7 @@ static void
 parse_event(Eo_Lexer *ls)
 {
    Eolian_Event *ev = calloc(1, sizeof(Eolian_Event));
-   FILL_BASE(ev->base, ls, ls->line_number, ls->column);
+   FILL_BASE(ev->base, ls, ls->line_number, ls->column, EVENT);
    ev->scope = EOLIAN_SCOPE_PUBLIC;
    Eina_Strbuf *buf = push_strbuf(ls);
    ls->tmp.kls->events = eina_list_append(ls->tmp.kls->events, ev);
@@ -2054,7 +2055,7 @@ parse_class(Eo_Lexer *ls, Eolian_Class_Type type)
    int line, col;
    Eina_Strbuf *buf = push_strbuf(ls);
    ls->tmp.kls = calloc(1, sizeof(Eolian_Class));
-   FILL_BASE(ls->tmp.kls->base, ls, ls->line_number, ls->column);
+   FILL_BASE(ls->tmp.kls->base, ls, ls->line_number, ls->column, DECLARATION);
    eo_lexer_get(ls);
    ls->tmp.kls->type = type;
    eo_lexer_context_push(ls);
@@ -2207,7 +2208,7 @@ parse_unit(Eo_Lexer *ls, Eina_Bool eot)
                 _fill_name(name, &def->full_name, &def->name, &def->namespaces);
                 eo_lexer_get(ls);
                 FILL_DOC(ls, def, doc);
-                FILL_BASE(def->base, ls, line, col);
+                FILL_BASE(def->base, ls, line, col, TYPEDECL);
                 database_struct_add(ls->unit, def);
                 pop_typedecl(ls);
                 break;
index 4d206dc..8e3d77f 100644 (file)
@@ -602,6 +602,34 @@ eolian_state_free(Eolian_State *state)
    free(state);
 }
 
+EAPI Eolian_Object_Type
+eolian_object_type_get(const Eolian_Object *obj)
+{
+   if (!obj) return EOLIAN_OBJECT_UNKNOWN;
+   return obj->type;
+}
+
+EAPI const char *
+eolian_object_file_get(const Eolian_Object *obj)
+{
+   if (!obj) return NULL;
+   return obj->file;
+}
+
+EAPI int
+eolian_object_line_get(const Eolian_Object *obj)
+{
+   if (!obj) return 0;
+   return obj->line;
+}
+
+EAPI int
+eolian_object_column_get(const Eolian_Object *obj)
+{
+   if (!obj) return 0;
+   return obj->column;
+}
+
 #define EO_SUFFIX ".eo"
 #define EOT_SUFFIX ".eot"
 
index 675373c..556cfce 100644 (file)
@@ -64,14 +64,15 @@ struct _Eolian_State
    Eina_Hash *decls_f;
 };
 
-typedef struct _Eolian_Object
+struct _Eolian_Object
 {
    const char *file;
    int line;
    int column;
    int refcount;
+   Eolian_Object_Type type;
    Eina_Bool validated;
-} Eolian_Object;
+};
 
 static inline void
 eolian_object_ref(Eolian_Object *obj)