From 9594f09156abe649c7015b452765100ed7e2f54b Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Thu, 8 Mar 2018 17:30:30 +0100 Subject: [PATCH] eolian: add API to query information about Objects 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 | 86 ++++++++++++++++++++++++++++++++ src/lib/eolian/eo_parser.c | 73 ++++++++++++++------------- src/lib/eolian/eolian_database.c | 28 +++++++++++ src/lib/eolian/eolian_database.h | 5 +- 4 files changed, 154 insertions(+), 38 deletions(-) diff --git a/src/lib/eolian/Eolian.h b/src/lib/eolian/Eolian.h index 900c9f167b..e74832f70c 100644 --- a/src/lib/eolian/Eolian.h +++ b/src/lib/eolian/Eolian.h @@ -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 @@ -189,6 +197,26 @@ typedef struct _Eolian_Documentation Eolian_Documentation; */ 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, @@ -499,6 +527,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. * diff --git a/src/lib/eolian/eo_parser.c b/src/lib/eolian/eo_parser.c index 6ed90395d3..7c8003d0f7 100644 --- a/src/lib/eolian/eo_parser.c +++ b/src/lib/eolian/eo_parser.c @@ -12,10 +12,11 @@ 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; diff --git a/src/lib/eolian/eolian_database.c b/src/lib/eolian/eolian_database.c index 4d206dc182..8e3d77fbaa 100644 --- a/src/lib/eolian/eolian_database.c +++ b/src/lib/eolian/eolian_database.c @@ -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" diff --git a/src/lib/eolian/eolian_database.h b/src/lib/eolian/eolian_database.h index 675373c690..556cfce1ba 100644 --- a/src/lib/eolian/eolian_database.h +++ b/src/lib/eolian/eolian_database.h @@ -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)