2015-07-07 07:21:45 -07:00
|
|
|
#include <ctype.h>
|
2017-10-24 14:19:22 -07:00
|
|
|
#include <assert.h>
|
2015-07-07 07:21:45 -07:00
|
|
|
|
2014-09-23 12:48:16 -07:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include "config.h"
|
|
|
|
#endif
|
|
|
|
|
2014-08-22 05:10:29 -07:00
|
|
|
#include "eo_lexer.h"
|
2017-10-30 22:20:09 -07:00
|
|
|
#include "eolian_priv.h"
|
2014-08-22 05:10:29 -07:00
|
|
|
|
2018-02-13 01:14:49 -08:00
|
|
|
typedef struct _Validate_State
|
|
|
|
{
|
|
|
|
Eina_Bool warned;
|
2018-04-26 07:07:28 -07:00
|
|
|
Eina_Bool event_redef;
|
2018-02-13 01:14:49 -08:00
|
|
|
} Validate_State;
|
|
|
|
|
2017-10-24 08:48:57 -07:00
|
|
|
static Eina_Bool
|
|
|
|
_validate(Eolian_Object *obj)
|
|
|
|
{
|
|
|
|
obj->validated = EINA_TRUE;
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
2015-07-07 07:21:45 -07:00
|
|
|
static Eina_Bool
|
2018-04-18 06:26:11 -07:00
|
|
|
_validate_docstr(Eina_Stringshare *str, const Eolian_Object *info, Eina_List **rdbg)
|
2015-07-07 07:21:45 -07:00
|
|
|
{
|
2016-12-07 04:55:56 -08:00
|
|
|
if (!str || !str[0]) return EINA_TRUE;
|
2015-07-07 07:21:45 -07:00
|
|
|
|
2016-12-07 04:55:56 -08:00
|
|
|
Eina_Bool ret = EINA_TRUE;
|
|
|
|
Eina_List *pl = eolian_documentation_string_split(str);
|
|
|
|
char *par;
|
|
|
|
EINA_LIST_FREE(pl, par)
|
2015-07-07 07:21:45 -07:00
|
|
|
{
|
2016-12-07 04:55:56 -08:00
|
|
|
const char *doc = par;
|
|
|
|
Eolian_Doc_Token tok;
|
|
|
|
eolian_doc_token_init(&tok);
|
|
|
|
while (ret && (doc = eolian_documentation_tokenize(doc, &tok)))
|
2018-04-12 06:22:33 -07:00
|
|
|
{
|
|
|
|
if (eolian_doc_token_type_get(&tok) == EOLIAN_DOC_TOKEN_REF)
|
|
|
|
{
|
2018-04-18 07:34:49 -07:00
|
|
|
/* check staging first, then main */
|
|
|
|
Eolian_Object_Type tp = database_doc_token_ref_resolve(&tok,
|
|
|
|
&info->unit->state->staging.unit,
|
|
|
|
&info->unit->state->main.unit,
|
|
|
|
NULL, NULL);
|
|
|
|
if (tp == EOLIAN_OBJECT_UNKNOWN)
|
2018-04-12 06:22:33 -07:00
|
|
|
{
|
|
|
|
size_t dbgn = (size_t)eina_list_data_get(*rdbg);
|
|
|
|
char *refn = eolian_doc_token_text_get(&tok);
|
|
|
|
Eolian_Object tmp;
|
|
|
|
memset(&tmp, 0, sizeof(Eolian_Object));
|
|
|
|
tmp.unit = info->unit;
|
|
|
|
tmp.file = info->file;
|
|
|
|
tmp.line = (int)(dbgn & 0xFFFFF);
|
|
|
|
tmp.column = (int)(dbgn >> 20);
|
|
|
|
eolian_state_log_obj(info->unit->state, &tmp,
|
|
|
|
"failed validating reference '%s'", refn);
|
|
|
|
free(refn);
|
|
|
|
ret = EINA_FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
*rdbg = eina_list_next(*rdbg);
|
|
|
|
}
|
|
|
|
}
|
2016-12-07 05:06:02 -08:00
|
|
|
free(par);
|
2015-07-07 07:21:45 -07:00
|
|
|
}
|
|
|
|
|
2016-12-07 04:55:56 -08:00
|
|
|
return ret;
|
2015-07-07 07:21:45 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static Eina_Bool
|
2018-03-27 04:48:58 -07:00
|
|
|
_validate_doc(Eolian_Documentation *doc)
|
2015-07-07 07:21:45 -07:00
|
|
|
{
|
2017-10-24 14:41:59 -07:00
|
|
|
if (!doc)
|
2017-10-24 08:48:57 -07:00
|
|
|
return EINA_TRUE;
|
2015-07-07 07:21:45 -07:00
|
|
|
|
2018-04-12 06:22:33 -07:00
|
|
|
Eina_List *rdbg = doc->ref_dbg;
|
|
|
|
|
2018-04-18 06:26:11 -07:00
|
|
|
if (!_validate_docstr(doc->summary, &doc->base, &rdbg))
|
2015-07-07 07:21:45 -07:00
|
|
|
return EINA_FALSE;
|
2018-04-18 06:26:11 -07:00
|
|
|
if (!_validate_docstr(doc->description, &doc->base, &rdbg))
|
2015-07-07 07:21:45 -07:00
|
|
|
return EINA_FALSE;
|
|
|
|
|
2017-10-24 08:48:57 -07:00
|
|
|
return _validate(&doc->base);
|
2015-07-07 07:21:45 -07:00
|
|
|
}
|
|
|
|
|
2018-03-27 04:48:58 -07:00
|
|
|
static Eina_Bool _validate_type(Validate_State *vals, Eolian_Type *tp);
|
|
|
|
static Eina_Bool _validate_expr(Eolian_Expression *expr,
|
2014-08-22 05:10:29 -07:00
|
|
|
const Eolian_Type *tp,
|
|
|
|
Eolian_Expression_Mask msk);
|
2018-02-13 01:14:49 -08:00
|
|
|
static Eina_Bool _validate_function(Validate_State *vals,
|
2018-01-12 10:13:55 -08:00
|
|
|
Eolian_Function *func,
|
|
|
|
Eina_Hash *nhash);
|
2014-08-22 05:10:29 -07:00
|
|
|
|
2017-12-04 02:44:56 -08:00
|
|
|
typedef struct _Cb_Ret
|
|
|
|
{
|
2018-02-13 01:14:49 -08:00
|
|
|
Validate_State *vals;
|
2017-12-04 02:44:56 -08:00
|
|
|
Eina_Bool succ;
|
|
|
|
} Cb_Ret;
|
|
|
|
|
2014-08-22 05:10:29 -07:00
|
|
|
static Eina_Bool
|
|
|
|
_sf_map_cb(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED,
|
2017-12-04 02:44:56 -08:00
|
|
|
const Eolian_Struct_Type_Field *sf, Cb_Ret *sc)
|
2014-08-22 05:10:29 -07:00
|
|
|
{
|
2018-03-27 04:48:58 -07:00
|
|
|
sc->succ = _validate_type(sc->vals, sf->type);
|
2015-07-07 07:21:45 -07:00
|
|
|
|
2017-12-04 02:44:56 -08:00
|
|
|
if (!sc->succ)
|
2015-07-07 07:21:45 -07:00
|
|
|
return EINA_FALSE;
|
|
|
|
|
2018-03-27 04:48:58 -07:00
|
|
|
sc->succ = _validate_doc(sf->doc);
|
2015-07-07 07:21:45 -07:00
|
|
|
|
2017-12-04 02:44:56 -08:00
|
|
|
return sc->succ;
|
2014-08-22 05:10:29 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static Eina_Bool
|
|
|
|
_ef_map_cb(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED,
|
2017-12-04 02:44:56 -08:00
|
|
|
const Eolian_Enum_Type_Field *ef, Cb_Ret *sc)
|
2014-08-22 05:10:29 -07:00
|
|
|
{
|
2014-09-02 04:39:38 -07:00
|
|
|
if (ef->value)
|
2018-03-27 04:48:58 -07:00
|
|
|
sc->succ = _validate_expr(ef->value, NULL, EOLIAN_MASK_INT);
|
2014-09-02 04:39:38 -07:00
|
|
|
else
|
2017-12-04 02:44:56 -08:00
|
|
|
sc->succ = EINA_TRUE;
|
2015-07-07 07:21:45 -07:00
|
|
|
|
2017-12-04 02:44:56 -08:00
|
|
|
if (!sc->succ)
|
2015-07-07 07:21:45 -07:00
|
|
|
return EINA_FALSE;
|
|
|
|
|
2018-03-27 04:48:58 -07:00
|
|
|
sc->succ = _validate_doc(ef->doc);
|
2015-07-07 07:21:45 -07:00
|
|
|
|
2017-12-04 02:44:56 -08:00
|
|
|
return sc->succ;
|
2014-08-22 05:10:29 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static Eina_Bool
|
2017-10-24 14:39:14 -07:00
|
|
|
_obj_error(const Eolian_Object *o, const char *msg)
|
2014-08-22 05:10:29 -07:00
|
|
|
{
|
2018-03-20 09:05:22 -07:00
|
|
|
eolian_state_log_obj(o->unit->state, o, "%s", msg);
|
2016-04-19 09:04:33 -07:00
|
|
|
return EINA_FALSE;
|
2014-08-22 05:10:29 -07:00
|
|
|
}
|
2014-08-21 08:23:37 -07:00
|
|
|
|
2014-08-21 08:53:23 -07:00
|
|
|
static Eina_Bool
|
2018-03-27 04:48:58 -07:00
|
|
|
_validate_typedecl(Validate_State *vals, Eolian_Typedecl *tp)
|
2014-08-21 08:53:23 -07:00
|
|
|
{
|
2017-10-24 08:48:57 -07:00
|
|
|
if (tp->base.validated)
|
|
|
|
return EINA_TRUE;
|
|
|
|
|
2018-03-27 04:48:58 -07:00
|
|
|
if (!_validate_doc(tp->doc))
|
2015-07-07 07:21:45 -07:00
|
|
|
return EINA_FALSE;
|
|
|
|
|
2016-03-01 05:40:24 -08:00
|
|
|
switch (tp->type)
|
|
|
|
{
|
|
|
|
case EOLIAN_TYPEDECL_ALIAS:
|
2018-03-27 04:48:58 -07:00
|
|
|
if (!_validate_type(vals, tp->base_type))
|
2017-09-13 15:12:46 -07:00
|
|
|
return EINA_FALSE;
|
|
|
|
if (!tp->freefunc && tp->base_type->freefunc)
|
|
|
|
tp->freefunc = eina_stringshare_ref(tp->base_type->freefunc);
|
2017-10-24 08:48:57 -07:00
|
|
|
return _validate(&tp->base);
|
2016-03-01 05:40:24 -08:00
|
|
|
case EOLIAN_TYPEDECL_STRUCT:
|
|
|
|
{
|
2018-03-27 04:48:58 -07:00
|
|
|
Cb_Ret rt = { vals, EINA_TRUE };
|
2017-12-04 02:44:56 -08:00
|
|
|
eina_hash_foreach(tp->fields, (Eina_Hash_Foreach)_sf_map_cb, &rt);
|
|
|
|
if (!rt.succ)
|
2017-10-24 08:48:57 -07:00
|
|
|
return EINA_FALSE;
|
|
|
|
return _validate(&tp->base);
|
2016-03-01 05:40:24 -08:00
|
|
|
}
|
|
|
|
case EOLIAN_TYPEDECL_STRUCT_OPAQUE:
|
2017-10-24 08:48:57 -07:00
|
|
|
return _validate(&tp->base);
|
2016-03-01 05:40:24 -08:00
|
|
|
case EOLIAN_TYPEDECL_ENUM:
|
|
|
|
{
|
2018-03-27 04:48:58 -07:00
|
|
|
Cb_Ret rt = { vals, EINA_TRUE };
|
2017-12-04 02:44:56 -08:00
|
|
|
eina_hash_foreach(tp->fields, (Eina_Hash_Foreach)_ef_map_cb, &rt);
|
|
|
|
if (!rt.succ)
|
2017-10-24 08:48:57 -07:00
|
|
|
return EINA_FALSE;
|
|
|
|
return _validate(&tp->base);
|
2016-03-01 05:40:24 -08:00
|
|
|
}
|
2017-04-07 09:54:55 -07:00
|
|
|
case EOLIAN_TYPEDECL_FUNCTION_POINTER:
|
2018-03-27 04:48:58 -07:00
|
|
|
if (!_validate_function(vals, tp->function_pointer, NULL))
|
2018-01-12 10:13:55 -08:00
|
|
|
return EINA_FALSE;
|
2017-10-24 08:48:57 -07:00
|
|
|
return _validate(&tp->base);
|
2016-03-01 05:40:24 -08:00
|
|
|
default:
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
2017-10-24 08:48:57 -07:00
|
|
|
return _validate(&tp->base);
|
2016-03-01 05:40:24 -08:00
|
|
|
}
|
|
|
|
|
2017-09-14 06:52:49 -07:00
|
|
|
static const char * const eo_complex_frees[] =
|
|
|
|
{
|
2018-05-02 04:40:18 -07:00
|
|
|
"eina_accessor_free", "eina_array_free", NULL, /* future */
|
2017-11-23 16:46:55 -08:00
|
|
|
"eina_iterator_free", "eina_hash_free",
|
2018-04-30 15:21:58 -07:00
|
|
|
"eina_list_free", "eina_inarray_free", "eina_inlist_free"
|
2017-09-14 06:52:49 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
static const char *eo_obj_free = "efl_del";
|
|
|
|
static const char *eo_str_free = "free";
|
|
|
|
static const char *eo_strshare_free = "eina_stringshare_del";
|
2017-09-22 11:25:31 -07:00
|
|
|
static const char *eo_value_free = "eina_value_flush";
|
|
|
|
static const char *eo_value_ptr_free = "eina_value_free";
|
2017-09-14 06:52:49 -07:00
|
|
|
|
2016-03-01 05:40:24 -08:00
|
|
|
static Eina_Bool
|
2018-03-27 04:48:58 -07:00
|
|
|
_validate_type(Validate_State *vals, Eolian_Type *tp)
|
2016-03-01 05:40:24 -08:00
|
|
|
{
|
2018-03-27 04:48:58 -07:00
|
|
|
const Eolian_Unit *src = tp->base.unit;
|
|
|
|
|
2017-09-08 05:22:13 -07:00
|
|
|
char buf[256];
|
2018-05-03 08:10:31 -07:00
|
|
|
if (tp->owned && !database_type_is_ownable(src, tp, EINA_FALSE))
|
2017-09-08 05:22:13 -07:00
|
|
|
{
|
2018-03-08 10:30:40 -08:00
|
|
|
snprintf(buf, sizeof(buf), "type '%s' is not ownable", tp->base.name);
|
2017-10-24 14:39:14 -07:00
|
|
|
return _obj_error(&tp->base, buf);
|
2017-09-08 05:22:13 -07:00
|
|
|
}
|
|
|
|
|
2017-11-03 07:30:10 -07:00
|
|
|
if (tp->is_ptr && !tp->legacy)
|
|
|
|
{
|
|
|
|
tp->is_ptr = EINA_FALSE;
|
2018-05-03 08:10:31 -07:00
|
|
|
Eina_Bool still_ownable = database_type_is_ownable(src, tp, EINA_FALSE);
|
2017-11-03 07:30:10 -07:00
|
|
|
tp->is_ptr = EINA_TRUE;
|
|
|
|
if (still_ownable)
|
|
|
|
{
|
|
|
|
return _obj_error(&tp->base, "cannot take a pointer to pointer type");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-22 05:10:29 -07:00
|
|
|
switch (tp->type)
|
|
|
|
{
|
|
|
|
case EOLIAN_TYPE_VOID:
|
2015-11-19 06:04:37 -08:00
|
|
|
case EOLIAN_TYPE_UNDEFINED:
|
2017-10-24 08:48:57 -07:00
|
|
|
return _validate(&tp->base);
|
2014-08-22 05:10:29 -07:00
|
|
|
case EOLIAN_TYPE_REGULAR:
|
|
|
|
{
|
2017-09-22 08:46:02 -07:00
|
|
|
if (tp->base_type)
|
|
|
|
{
|
2018-03-08 10:30:40 -08:00
|
|
|
int kwid = eo_lexer_keyword_str_to_id(tp->base.name);
|
2017-09-22 08:46:02 -07:00
|
|
|
if (!tp->freefunc)
|
|
|
|
{
|
|
|
|
tp->freefunc = eina_stringshare_add(eo_complex_frees[
|
2017-11-02 05:51:02 -07:00
|
|
|
kwid - KW_accessor]);
|
2017-09-22 08:46:02 -07:00
|
|
|
}
|
2017-09-28 14:22:05 -07:00
|
|
|
Eolian_Type *itp = tp->base_type;
|
|
|
|
/* validate types in brackets so freefuncs get written... */
|
|
|
|
while (itp)
|
|
|
|
{
|
2018-03-27 04:48:58 -07:00
|
|
|
if (!_validate_type(vals, itp))
|
2017-09-28 14:22:05 -07:00
|
|
|
return EINA_FALSE;
|
2018-05-03 08:10:31 -07:00
|
|
|
if ((kwid >= KW_accessor) && (kwid <= KW_list) && (kwid != KW_future))
|
2017-11-02 05:51:02 -07:00
|
|
|
{
|
2018-05-03 08:10:31 -07:00
|
|
|
if (!database_type_is_ownable(src, itp, EINA_TRUE))
|
2017-11-02 05:51:02 -07:00
|
|
|
{
|
|
|
|
snprintf(buf, sizeof(buf),
|
|
|
|
"%s cannot contain value types (%s)",
|
2018-03-08 10:30:40 -08:00
|
|
|
tp->base.name, itp->base.name);
|
2017-11-02 05:51:02 -07:00
|
|
|
return _obj_error(&itp->base, buf);
|
|
|
|
}
|
|
|
|
}
|
2017-09-28 14:22:05 -07:00
|
|
|
itp = itp->next_type;
|
|
|
|
}
|
2017-10-24 08:48:57 -07:00
|
|
|
return _validate(&tp->base);
|
2017-09-22 08:46:02 -07:00
|
|
|
}
|
2014-08-22 05:10:29 -07:00
|
|
|
/* builtins */
|
2018-03-08 10:30:40 -08:00
|
|
|
int id = eo_lexer_keyword_str_to_id(tp->base.name);
|
2014-08-22 05:10:29 -07:00
|
|
|
if (id)
|
2017-09-14 06:52:49 -07:00
|
|
|
{
|
|
|
|
if (!eo_lexer_is_type_keyword(id))
|
|
|
|
return EINA_FALSE;
|
|
|
|
if (!tp->freefunc)
|
|
|
|
switch (id)
|
|
|
|
{
|
2018-11-12 06:23:58 -08:00
|
|
|
case KW_mstring:
|
2017-09-14 06:52:49 -07:00
|
|
|
tp->freefunc = eina_stringshare_add(eo_str_free);
|
|
|
|
break;
|
|
|
|
case KW_stringshare:
|
|
|
|
tp->freefunc = eina_stringshare_add(eo_strshare_free);
|
|
|
|
break;
|
2017-09-22 11:16:06 -07:00
|
|
|
case KW_any_value:
|
2017-09-22 07:08:56 -07:00
|
|
|
tp->freefunc = eina_stringshare_add(eo_value_free);
|
|
|
|
break;
|
2017-09-22 11:25:31 -07:00
|
|
|
case KW_any_value_ptr:
|
|
|
|
tp->freefunc = eina_stringshare_add(eo_value_ptr_free);
|
|
|
|
break;
|
2017-09-14 06:52:49 -07:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2017-10-24 08:48:57 -07:00
|
|
|
return _validate(&tp->base);
|
2017-09-14 06:52:49 -07:00
|
|
|
}
|
2014-08-22 05:10:29 -07:00
|
|
|
/* user defined */
|
2018-01-12 08:52:44 -08:00
|
|
|
tp->tdecl = database_type_decl_find(src, tp);
|
2018-01-12 08:25:23 -08:00
|
|
|
if (!tp->tdecl)
|
2014-08-22 05:10:29 -07:00
|
|
|
{
|
2018-03-08 10:30:40 -08:00
|
|
|
snprintf(buf, sizeof(buf), "undefined type %s", tp->base.name);
|
2017-10-24 14:39:14 -07:00
|
|
|
return _obj_error(&tp->base, buf);
|
2014-08-22 05:10:29 -07:00
|
|
|
}
|
2018-03-27 04:48:58 -07:00
|
|
|
if (!_validate_typedecl(vals, tp->tdecl))
|
2017-09-13 15:12:46 -07:00
|
|
|
return EINA_FALSE;
|
2018-01-12 08:25:23 -08:00
|
|
|
if (tp->tdecl->freefunc && !tp->freefunc)
|
|
|
|
tp->freefunc = eina_stringshare_ref(tp->tdecl->freefunc);
|
2017-10-24 08:48:57 -07:00
|
|
|
return _validate(&tp->base);
|
2014-08-22 05:10:29 -07:00
|
|
|
}
|
|
|
|
case EOLIAN_TYPE_CLASS:
|
|
|
|
{
|
2018-03-08 10:30:40 -08:00
|
|
|
tp->klass = (Eolian_Class *)eolian_unit_class_by_name_get(src, tp->base.name);
|
2018-01-12 08:25:23 -08:00
|
|
|
if (!tp->klass)
|
2014-08-22 05:10:29 -07:00
|
|
|
{
|
|
|
|
snprintf(buf, sizeof(buf), "undefined class %s "
|
2018-03-08 10:30:40 -08:00
|
|
|
"(likely wrong namespacing)", tp->base.name);
|
2017-10-24 14:39:14 -07:00
|
|
|
return _obj_error(&tp->base, buf);
|
2014-08-22 05:10:29 -07:00
|
|
|
}
|
2017-09-13 15:12:46 -07:00
|
|
|
if (!tp->freefunc)
|
2017-09-14 06:52:49 -07:00
|
|
|
tp->freefunc = eina_stringshare_add(eo_obj_free);
|
2017-10-24 08:48:57 -07:00
|
|
|
return _validate(&tp->base);
|
2014-08-22 05:10:29 -07:00
|
|
|
}
|
|
|
|
default:
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
2017-10-24 08:48:57 -07:00
|
|
|
return _validate(&tp->base);
|
2014-08-21 08:53:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static Eina_Bool
|
2018-03-27 04:48:58 -07:00
|
|
|
_validate_expr(Eolian_Expression *expr, const Eolian_Type *tp,
|
|
|
|
Eolian_Expression_Mask msk)
|
2014-08-21 08:53:23 -07:00
|
|
|
{
|
2014-08-22 05:10:29 -07:00
|
|
|
Eolian_Value val;
|
|
|
|
if (tp)
|
2018-04-20 06:58:06 -07:00
|
|
|
val = database_expr_eval_type(expr->base.unit, expr, tp, NULL, NULL);
|
2014-08-22 05:10:29 -07:00
|
|
|
else
|
2018-04-20 06:58:06 -07:00
|
|
|
val = database_expr_eval(expr->base.unit, expr, msk, NULL, NULL);
|
2017-10-24 08:48:57 -07:00
|
|
|
|
|
|
|
if (val.type == EOLIAN_EXPR_UNKNOWN)
|
|
|
|
return EINA_FALSE;
|
|
|
|
|
|
|
|
return _validate(&expr->base);
|
2014-08-21 08:53:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static Eina_Bool
|
2018-03-27 04:48:58 -07:00
|
|
|
_validate_param(Validate_State *vals, Eolian_Function_Parameter *param)
|
2014-08-21 08:53:23 -07:00
|
|
|
{
|
2018-03-27 04:48:58 -07:00
|
|
|
if (!_validate_type(vals, param->type))
|
2014-08-21 08:53:23 -07:00
|
|
|
return EINA_FALSE;
|
|
|
|
|
2018-03-27 04:48:58 -07:00
|
|
|
if (param->value && !_validate_expr(param->value, param->type, 0))
|
2018-01-16 07:10:43 -08:00
|
|
|
return EINA_FALSE;
|
|
|
|
|
2018-03-27 04:48:58 -07:00
|
|
|
if (!_validate_doc(param->doc))
|
2015-07-07 07:21:45 -07:00
|
|
|
return EINA_FALSE;
|
|
|
|
|
2017-10-24 08:48:57 -07:00
|
|
|
return _validate(¶m->base);
|
2014-08-21 08:53:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static Eina_Bool
|
2018-03-27 04:48:58 -07:00
|
|
|
_validate_function(Validate_State *vals, Eolian_Function *func, Eina_Hash *nhash)
|
2014-08-21 08:53:23 -07:00
|
|
|
{
|
|
|
|
Eina_List *l;
|
2017-10-24 08:48:57 -07:00
|
|
|
Eolian_Function_Parameter *param;
|
2017-10-24 14:39:14 -07:00
|
|
|
char buf[512];
|
2017-10-24 08:48:57 -07:00
|
|
|
|
2018-04-26 07:23:13 -07:00
|
|
|
const Eolian_Object *oobj = nhash ? eina_hash_find(nhash, &func->base.name) : NULL;
|
2018-04-26 07:14:13 -07:00
|
|
|
if (EINA_UNLIKELY(oobj && (oobj != &func->base)))
|
2017-10-24 14:39:14 -07:00
|
|
|
{
|
|
|
|
snprintf(buf, sizeof(buf),
|
2018-04-26 07:14:13 -07:00
|
|
|
"%sfunction '%s' conflicts with another symbol (at %s:%d:%d)",
|
|
|
|
func->is_beta ? "beta " : "", func->base.name, oobj->file,
|
|
|
|
oobj->line, oobj->column);
|
2018-02-15 10:50:56 -08:00
|
|
|
_obj_error(&func->base, buf);
|
|
|
|
vals->warned = EINA_TRUE;
|
2017-10-24 14:39:14 -07:00
|
|
|
}
|
|
|
|
|
2017-12-22 06:26:36 -08:00
|
|
|
/* if already validated, no need to perform the other checks...
|
|
|
|
* but duplicate checks need to be performed every time
|
|
|
|
*/
|
|
|
|
if (func->base.validated)
|
2018-01-18 03:49:05 -08:00
|
|
|
{
|
|
|
|
/* it might be validated, but need to add it anyway */
|
2018-04-26 07:14:13 -07:00
|
|
|
if (!oobj && nhash)
|
2018-04-26 07:23:13 -07:00
|
|
|
eina_hash_add(nhash, &func->base.name, &func->base);
|
2018-01-18 03:49:05 -08:00
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
2017-12-22 06:26:36 -08:00
|
|
|
|
2018-03-27 04:48:58 -07:00
|
|
|
if (func->get_ret_type && !_validate_type(vals, func->get_ret_type))
|
2014-08-21 08:53:23 -07:00
|
|
|
return EINA_FALSE;
|
|
|
|
|
2018-03-27 04:48:58 -07:00
|
|
|
if (func->set_ret_type && !_validate_type(vals, func->set_ret_type))
|
2014-08-21 08:53:23 -07:00
|
|
|
return EINA_FALSE;
|
|
|
|
|
2018-03-27 04:48:58 -07:00
|
|
|
if (func->get_ret_val && !_validate_expr(func->get_ret_val,
|
2014-08-22 05:10:29 -07:00
|
|
|
func->get_ret_type, 0))
|
2014-08-21 08:53:23 -07:00
|
|
|
return EINA_FALSE;
|
|
|
|
|
2018-03-27 04:48:58 -07:00
|
|
|
if (func->set_ret_val && !_validate_expr(func->set_ret_val,
|
2014-08-22 05:10:29 -07:00
|
|
|
func->set_ret_type, 0))
|
2014-08-21 08:53:23 -07:00
|
|
|
return EINA_FALSE;
|
|
|
|
|
2015-05-20 09:42:00 -07:00
|
|
|
#define EOLIAN_PARAMS_VALIDATE(params) \
|
|
|
|
EINA_LIST_FOREACH(params, l, param) \
|
2018-03-27 04:48:58 -07:00
|
|
|
if (!_validate_param(vals, param)) \
|
2014-08-21 08:53:23 -07:00
|
|
|
return EINA_FALSE;
|
|
|
|
|
2015-05-20 09:42:00 -07:00
|
|
|
EOLIAN_PARAMS_VALIDATE(func->prop_values);
|
|
|
|
EOLIAN_PARAMS_VALIDATE(func->prop_values_get);
|
|
|
|
EOLIAN_PARAMS_VALIDATE(func->prop_values_set);
|
|
|
|
EOLIAN_PARAMS_VALIDATE(func->prop_keys);
|
|
|
|
EOLIAN_PARAMS_VALIDATE(func->prop_keys_get);
|
|
|
|
EOLIAN_PARAMS_VALIDATE(func->prop_keys_set);
|
|
|
|
|
|
|
|
#undef EOLIAN_PARAMS_VALIDATE
|
2014-08-21 08:53:23 -07:00
|
|
|
|
2018-03-27 04:48:58 -07:00
|
|
|
if (!_validate_doc(func->get_return_doc))
|
2015-07-07 07:21:45 -07:00
|
|
|
return EINA_FALSE;
|
2018-03-27 04:48:58 -07:00
|
|
|
if (!_validate_doc(func->set_return_doc))
|
2015-07-07 07:21:45 -07:00
|
|
|
return EINA_FALSE;
|
|
|
|
|
2017-10-25 04:03:20 -07:00
|
|
|
/* just for now, when dups become errors there will be no need to check */
|
2018-04-26 07:14:13 -07:00
|
|
|
if (!oobj && nhash)
|
2018-04-26 07:23:13 -07:00
|
|
|
eina_hash_add(nhash, &func->base.name, &func->base);
|
2017-10-25 04:03:20 -07:00
|
|
|
|
2017-10-24 08:48:57 -07:00
|
|
|
return _validate(&func->base);
|
2014-08-21 08:53:23 -07:00
|
|
|
}
|
|
|
|
|
2017-11-01 05:19:33 -07:00
|
|
|
static Eina_Bool
|
2018-03-27 04:48:58 -07:00
|
|
|
_validate_part(Eolian_Part *part, Eina_Hash *nhash)
|
2017-11-01 05:19:33 -07:00
|
|
|
{
|
2018-04-26 07:23:13 -07:00
|
|
|
const Eolian_Object *oobj = eina_hash_find(nhash, &part->base.name);
|
2018-04-26 07:14:13 -07:00
|
|
|
if (oobj)
|
2017-11-01 05:19:33 -07:00
|
|
|
{
|
|
|
|
char buf[512];
|
|
|
|
snprintf(buf, sizeof(buf),
|
2018-04-26 07:14:13 -07:00
|
|
|
"part '%s' conflicts with another symbol (at %s:%d:%d)",
|
|
|
|
part->base.name, oobj->file, oobj->line, oobj->column);
|
2017-11-01 05:19:33 -07:00
|
|
|
_obj_error(&part->base, buf);
|
|
|
|
}
|
|
|
|
|
2017-12-22 06:26:36 -08:00
|
|
|
/* see _validate_function above */
|
|
|
|
if (part->base.validated)
|
2018-04-26 07:14:13 -07:00
|
|
|
{
|
|
|
|
if (!oobj)
|
2018-04-26 07:23:13 -07:00
|
|
|
eina_hash_add(nhash, &part->base.name, &part->base);
|
2018-04-26 07:14:13 -07:00
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
2017-12-22 06:26:36 -08:00
|
|
|
|
2018-03-27 04:48:58 -07:00
|
|
|
if (!_validate_doc(part->doc))
|
2017-12-22 06:26:36 -08:00
|
|
|
return EINA_FALSE;
|
|
|
|
|
2018-01-31 09:06:17 -08:00
|
|
|
/* switch the class name for class */
|
2018-03-27 04:48:58 -07:00
|
|
|
Eolian_Class *pcl = eina_hash_find(part->base.unit->classes, part->klass_name);
|
2018-01-31 09:06:17 -08:00
|
|
|
if (!pcl)
|
|
|
|
{
|
|
|
|
char buf[PATH_MAX];
|
|
|
|
snprintf(buf, sizeof(buf), "unknown part class '%s' (incorrect case?)",
|
|
|
|
part->klass_name);
|
|
|
|
_obj_error(&part->base, buf);
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
eina_stringshare_del(part->klass_name);
|
|
|
|
part->klass = pcl;
|
|
|
|
|
2018-04-26 07:14:13 -07:00
|
|
|
if (!oobj)
|
2018-04-26 07:23:13 -07:00
|
|
|
eina_hash_add(nhash, &part->base.name, &part->base);
|
2018-04-26 07:14:13 -07:00
|
|
|
|
2017-11-01 05:19:33 -07:00
|
|
|
return _validate(&part->base);
|
|
|
|
}
|
|
|
|
|
2014-08-21 08:53:23 -07:00
|
|
|
static Eina_Bool
|
2018-04-26 07:41:32 -07:00
|
|
|
_validate_event(Validate_State *vals, Eolian_Event *event, Eina_Hash *nhash)
|
2014-08-21 08:53:23 -07:00
|
|
|
{
|
2018-05-09 06:44:36 -07:00
|
|
|
char buf[512];
|
2018-04-26 07:41:32 -07:00
|
|
|
const Eolian_Object *oobj = NULL;
|
2018-05-09 06:44:36 -07:00
|
|
|
|
2018-04-26 07:41:32 -07:00
|
|
|
if (vals->event_redef)
|
2018-04-26 07:07:28 -07:00
|
|
|
{
|
2018-04-26 07:41:32 -07:00
|
|
|
oobj = eina_hash_find(nhash, &event->base.name);
|
|
|
|
if (EINA_UNLIKELY(!!oobj))
|
|
|
|
{
|
|
|
|
snprintf(buf, sizeof(buf),
|
2018-11-21 07:26:00 -08:00
|
|
|
"event '%s' conflicts with another event (at %s:%d:%d)",
|
2018-04-26 07:41:32 -07:00
|
|
|
event->base.name, oobj->file, oobj->line, oobj->column);
|
|
|
|
_obj_error(&event->base, buf);
|
|
|
|
vals->warned = EINA_TRUE;
|
|
|
|
}
|
2018-04-26 07:07:28 -07:00
|
|
|
}
|
|
|
|
|
2017-12-22 06:26:36 -08:00
|
|
|
if (event->base.validated)
|
2018-04-26 07:41:32 -07:00
|
|
|
{
|
|
|
|
if (vals->event_redef && !oobj)
|
|
|
|
eina_hash_add(nhash, &event->base.name, &event->base);
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
2017-12-22 06:26:36 -08:00
|
|
|
|
2018-05-18 16:49:06 -07:00
|
|
|
if (!_validate_type(vals, event->type))
|
2014-08-21 08:53:23 -07:00
|
|
|
return EINA_FALSE;
|
2015-07-07 07:21:45 -07:00
|
|
|
|
2018-03-27 04:48:58 -07:00
|
|
|
if (!_validate_doc(event->doc))
|
2015-07-07 07:21:45 -07:00
|
|
|
return EINA_FALSE;
|
|
|
|
|
2018-04-26 07:41:32 -07:00
|
|
|
if (vals->event_redef && !oobj)
|
|
|
|
eina_hash_add(nhash, &event->base.name, &event->base);
|
2018-04-26 07:07:28 -07:00
|
|
|
|
2017-10-24 08:48:57 -07:00
|
|
|
return _validate(&event->base);
|
2014-08-21 08:53:23 -07:00
|
|
|
}
|
|
|
|
|
2018-01-30 05:01:40 -08:00
|
|
|
const Eolian_Class *
|
|
|
|
_get_impl_class(const Eolian_Class *cl, const char *cln)
|
|
|
|
{
|
2018-03-08 10:30:40 -08:00
|
|
|
if (!cl || !strcmp(cl->base.name, cln))
|
2018-01-30 05:01:40 -08:00
|
|
|
return cl;
|
|
|
|
Eina_List *l;
|
2018-11-22 07:21:52 -08:00
|
|
|
Eolian_Class *icl = cl->parent;
|
|
|
|
if (icl)
|
2018-01-30 05:01:40 -08:00
|
|
|
{
|
|
|
|
/* we can do a depth first search, it's easier and doesn't matter
|
|
|
|
* which part of the inheritance tree we find the class in
|
|
|
|
*/
|
|
|
|
const Eolian_Class *fcl = _get_impl_class(icl, cln);
|
|
|
|
if (fcl)
|
|
|
|
return fcl;
|
|
|
|
}
|
2018-11-22 07:21:52 -08:00
|
|
|
EINA_LIST_FOREACH(cl->extends, l, icl)
|
|
|
|
{
|
|
|
|
const Eolian_Class *fcl = _get_impl_class(icl, cln);
|
|
|
|
if (fcl)
|
|
|
|
return fcl;
|
|
|
|
}
|
2018-01-30 05:01:40 -08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define _eo_parser_log(_base, ...) \
|
2018-03-20 09:05:22 -07:00
|
|
|
eolian_state_log_obj((_base)->unit->state, (_base), __VA_ARGS__)
|
2018-01-30 05:01:40 -08:00
|
|
|
|
|
|
|
static Eina_Bool
|
|
|
|
_db_fill_implement(Eolian_Class *cl, Eolian_Implement *impl)
|
|
|
|
{
|
|
|
|
Eolian_Function_Type ftype = EOLIAN_METHOD;
|
|
|
|
|
|
|
|
if (impl->is_prop_get && impl->is_prop_set)
|
|
|
|
ftype = EOLIAN_PROPERTY;
|
|
|
|
else if (impl->is_prop_get)
|
|
|
|
ftype = EOLIAN_PROP_GET;
|
|
|
|
else if (impl->is_prop_set)
|
|
|
|
ftype = EOLIAN_PROP_SET;
|
|
|
|
|
2018-03-08 10:30:40 -08:00
|
|
|
size_t imlen = strlen(impl->base.name);
|
2018-01-30 05:01:40 -08:00
|
|
|
char *clbuf = alloca(imlen + 1);
|
2018-03-08 10:30:40 -08:00
|
|
|
memcpy(clbuf, impl->base.name, imlen + 1);
|
2018-01-30 05:01:40 -08:00
|
|
|
|
|
|
|
char *ldot = strrchr(clbuf, '.');
|
|
|
|
if (!ldot)
|
|
|
|
return EINA_FALSE; /* unreachable in practice, for static analysis */
|
|
|
|
|
|
|
|
*ldot = '\0'; /* split between class name and func name */
|
|
|
|
const char *clname = clbuf;
|
|
|
|
const char *fnname = ldot + 1;
|
|
|
|
|
|
|
|
const Eolian_Class *tcl = _get_impl_class(cl, clname);
|
|
|
|
if (!tcl)
|
|
|
|
{
|
|
|
|
_eo_parser_log(&impl->base, "class '%s' not found within the inheritance tree of '%s'",
|
2018-03-08 10:30:40 -08:00
|
|
|
clname, cl->base.name);
|
2018-01-30 05:01:40 -08:00
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl->klass = tcl;
|
2018-11-04 07:08:48 -08:00
|
|
|
impl->implklass = cl;
|
2018-01-30 05:01:40 -08:00
|
|
|
|
2018-03-16 06:25:44 -07:00
|
|
|
const Eolian_Function *fid = eolian_class_function_by_name_get(tcl, fnname, EOLIAN_UNRESOLVED);
|
2018-01-30 05:01:40 -08:00
|
|
|
if (!fid)
|
|
|
|
{
|
|
|
|
_eo_parser_log(&impl->base, "function '%s' not known in class '%s'", fnname, clname);
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
Eolian_Function_Type aftype = eolian_function_type_get(fid);
|
|
|
|
|
|
|
|
Eina_Bool auto_empty = (impl->get_auto || impl->get_empty);
|
|
|
|
|
|
|
|
/* match implement type against function type */
|
|
|
|
if (ftype == EOLIAN_PROPERTY)
|
|
|
|
{
|
|
|
|
/* property */
|
|
|
|
if (aftype != EOLIAN_PROPERTY)
|
|
|
|
{
|
|
|
|
_eo_parser_log(&impl->base, "function '%s' is not a complete property", fnname);
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
auto_empty = auto_empty && (impl->set_auto || impl->set_empty);
|
|
|
|
}
|
|
|
|
else if (ftype == EOLIAN_PROP_SET)
|
|
|
|
{
|
|
|
|
/* setter */
|
|
|
|
if ((aftype != EOLIAN_PROP_SET) && (aftype != EOLIAN_PROPERTY))
|
|
|
|
{
|
|
|
|
_eo_parser_log(&impl->base, "function '%s' doesn't have a setter", fnname);
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
auto_empty = (impl->set_auto || impl->set_empty);
|
|
|
|
}
|
|
|
|
else if (ftype == EOLIAN_PROP_GET)
|
|
|
|
{
|
|
|
|
/* getter */
|
|
|
|
if ((aftype != EOLIAN_PROP_GET) && (aftype != EOLIAN_PROPERTY))
|
|
|
|
{
|
|
|
|
_eo_parser_log(&impl->base, "function '%s' doesn't have a getter", fnname);
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (aftype != EOLIAN_METHOD)
|
|
|
|
{
|
|
|
|
_eo_parser_log(&impl->base, "function '%s' is not a method", fnname);
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((fid->klass == cl) && !auto_empty)
|
|
|
|
{
|
|
|
|
/* only allow explicit implements from other classes, besides auto and
|
|
|
|
* empty... also prevents pure virtuals from being implemented
|
|
|
|
*/
|
2018-03-08 10:30:40 -08:00
|
|
|
_eo_parser_log(&impl->base, "invalid implement '%s'", impl->base.name);
|
2018-01-30 05:01:40 -08:00
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl->foo_id = fid;
|
|
|
|
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Eina_Bool
|
|
|
|
_db_fill_implements(Eolian_Class *cl)
|
|
|
|
{
|
|
|
|
Eolian_Implement *impl;
|
|
|
|
Eina_List *l;
|
|
|
|
|
|
|
|
Eina_Bool ret = EINA_TRUE;
|
|
|
|
|
|
|
|
Eina_Hash *th = eina_hash_string_small_new(NULL),
|
|
|
|
*pth = eina_hash_string_small_new(NULL);
|
|
|
|
EINA_LIST_FOREACH(cl->implements, l, impl)
|
|
|
|
{
|
|
|
|
Eina_Bool prop = (impl->is_prop_get || impl->is_prop_set);
|
2018-03-08 10:30:40 -08:00
|
|
|
if (eina_hash_find(prop ? pth : th, impl->base.name))
|
2018-01-30 05:01:40 -08:00
|
|
|
{
|
2018-03-08 10:30:40 -08:00
|
|
|
_eo_parser_log(&impl->base, "duplicate implement '%s'", impl->base.name);
|
2018-01-30 05:01:40 -08:00
|
|
|
ret = EINA_FALSE;
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
if (impl->klass != cl)
|
|
|
|
{
|
|
|
|
if (!_db_fill_implement(cl, impl))
|
|
|
|
{
|
|
|
|
ret = EINA_FALSE;
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
if (eolian_function_is_constructor(impl->foo_id, impl->klass))
|
|
|
|
database_function_constructor_add((Eolian_Function *)impl->foo_id, cl);
|
|
|
|
}
|
|
|
|
if ((impl->klass != cl) && !_db_fill_implement(cl, impl))
|
|
|
|
{
|
|
|
|
ret = EINA_FALSE;
|
|
|
|
goto end;
|
|
|
|
}
|
2018-03-08 10:30:40 -08:00
|
|
|
eina_hash_add(prop ? pth : th, impl->base.name, impl->base.name);
|
2018-01-30 05:01:40 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
end:
|
|
|
|
eina_hash_free(th);
|
|
|
|
eina_hash_free(pth);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Eina_Bool
|
|
|
|
_db_fill_ctors(Eolian_Class *cl)
|
|
|
|
{
|
|
|
|
Eolian_Constructor *ctor;
|
|
|
|
Eina_List *l;
|
|
|
|
|
|
|
|
Eina_Bool ret = EINA_TRUE;
|
|
|
|
|
|
|
|
Eina_Hash *th = eina_hash_string_small_new(NULL);
|
|
|
|
EINA_LIST_FOREACH(cl->constructors, l, ctor)
|
|
|
|
{
|
2018-03-08 10:30:40 -08:00
|
|
|
if (eina_hash_find(th, ctor->base.name))
|
2018-01-30 05:01:40 -08:00
|
|
|
{
|
2018-03-08 10:30:40 -08:00
|
|
|
_eo_parser_log(&ctor->base, "duplicate ctor '%s'", ctor->base.name);
|
2018-01-30 05:01:40 -08:00
|
|
|
ret = EINA_FALSE;
|
|
|
|
goto end;
|
|
|
|
}
|
2018-03-08 10:30:40 -08:00
|
|
|
const char *ldot = strrchr(ctor->base.name, '.');
|
2018-01-30 05:01:40 -08:00
|
|
|
if (!ldot)
|
|
|
|
{
|
|
|
|
ret = EINA_FALSE;
|
|
|
|
goto end;
|
|
|
|
}
|
2018-03-08 10:30:40 -08:00
|
|
|
char *cnbuf = alloca(ldot - ctor->base.name + 1);
|
|
|
|
memcpy(cnbuf, ctor->base.name, ldot - ctor->base.name);
|
|
|
|
cnbuf[ldot - ctor->base.name] = '\0';
|
2018-01-30 05:01:40 -08:00
|
|
|
const Eolian_Class *tcl = _get_impl_class(cl, cnbuf);
|
|
|
|
if (!tcl)
|
|
|
|
{
|
|
|
|
_eo_parser_log(&ctor->base, "class '%s' not found within the inheritance tree of '%s'",
|
2018-03-08 10:30:40 -08:00
|
|
|
cnbuf, cl->base.name);
|
2018-01-30 05:01:40 -08:00
|
|
|
ret = EINA_FALSE;
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
ctor->klass = tcl;
|
|
|
|
const Eolian_Function *cfunc = eolian_constructor_function_get(ctor);
|
|
|
|
if (!cfunc)
|
|
|
|
{
|
2018-03-08 10:30:40 -08:00
|
|
|
_eo_parser_log(&ctor->base, "unable to find function '%s'", ctor->base.name);
|
2018-01-30 05:01:40 -08:00
|
|
|
ret = EINA_FALSE;
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
database_function_constructor_add((Eolian_Function *)cfunc, tcl);
|
2018-03-08 10:30:40 -08:00
|
|
|
eina_hash_add(th, ctor->base.name, ctor->base.name);
|
2018-01-30 05:01:40 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
end:
|
|
|
|
eina_hash_free(th);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-11-22 07:21:52 -08:00
|
|
|
static Eina_Bool
|
|
|
|
_db_swap_inherit(Eolian_Class *cl, Eina_Bool succ, Eina_Stringshare *in_cl,
|
|
|
|
Eolian_Class **out_cl)
|
|
|
|
{
|
|
|
|
if (!succ)
|
|
|
|
{
|
|
|
|
eina_stringshare_del(in_cl);
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
Eolian_Class *icl = eina_hash_find(cl->base.unit->classes, in_cl);
|
|
|
|
if (!icl)
|
|
|
|
{
|
|
|
|
succ = EINA_FALSE;
|
|
|
|
char buf[PATH_MAX];
|
|
|
|
snprintf(buf, sizeof(buf), "unknown inherit '%s' (incorrect case?)", in_cl);
|
|
|
|
_obj_error(&cl->base, buf);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
*out_cl = icl;
|
|
|
|
eina_stringshare_del(in_cl);
|
|
|
|
return succ;
|
|
|
|
}
|
|
|
|
|
2018-01-30 08:03:37 -08:00
|
|
|
static Eina_Bool
|
2018-03-27 04:27:32 -07:00
|
|
|
_db_fill_inherits(Eolian_Class *cl, Eina_Hash *fhash)
|
2018-01-30 08:03:37 -08:00
|
|
|
{
|
2018-04-26 07:23:13 -07:00
|
|
|
if (eina_hash_find(fhash, &cl->base.name))
|
2018-01-30 08:03:37 -08:00
|
|
|
return EINA_TRUE;
|
|
|
|
|
2018-04-11 05:58:41 -07:00
|
|
|
/* already merged outside of staging, therefore validated, and skipped */
|
|
|
|
if (eina_hash_find(cl->base.unit->state->main.unit.classes, cl->base.name))
|
|
|
|
return EINA_TRUE;
|
|
|
|
|
2018-11-22 07:21:52 -08:00
|
|
|
Eina_List *il = cl->extends;
|
2018-01-30 08:03:37 -08:00
|
|
|
Eina_Stringshare *inn = NULL;
|
2018-11-22 07:21:52 -08:00
|
|
|
cl->extends = NULL;
|
2018-01-30 08:03:37 -08:00
|
|
|
Eina_Bool succ = EINA_TRUE;
|
|
|
|
|
2018-11-22 07:21:52 -08:00
|
|
|
if (cl->parent_name)
|
2018-01-30 08:03:37 -08:00
|
|
|
{
|
2018-11-22 07:21:52 -08:00
|
|
|
succ = _db_swap_inherit(cl, succ, cl->parent_name, &cl->parent);
|
|
|
|
if (succ)
|
2018-01-30 08:03:37 -08:00
|
|
|
{
|
2018-04-11 05:31:03 -07:00
|
|
|
/* fill if not found, but do not return right away because
|
|
|
|
* the rest of the list needs to be freed in order not to
|
|
|
|
* leak any memory
|
|
|
|
*/
|
2018-11-22 07:21:52 -08:00
|
|
|
succ = _db_fill_inherits(cl->parent, fhash);
|
2018-01-30 08:03:37 -08:00
|
|
|
}
|
2018-11-22 07:21:52 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
EINA_LIST_FREE(il, inn)
|
|
|
|
{
|
|
|
|
Eolian_Class *out_cl = NULL;
|
|
|
|
succ = _db_swap_inherit(cl, succ, inn, &out_cl);
|
|
|
|
if (!succ)
|
|
|
|
continue;
|
|
|
|
cl->extends = eina_list_append(cl->extends, out_cl);
|
|
|
|
succ = _db_fill_inherits(out_cl, fhash);
|
2018-01-30 08:03:37 -08:00
|
|
|
}
|
|
|
|
|
2018-04-11 05:31:03 -07:00
|
|
|
/* failed on the way, no point in filling further
|
|
|
|
* the failed stuff will get dropped so it's ok if it's inconsistent
|
|
|
|
*/
|
|
|
|
if (!succ)
|
|
|
|
return EINA_FALSE;
|
|
|
|
|
2018-04-26 07:23:13 -07:00
|
|
|
eina_hash_add(fhash, &cl->base.name, cl);
|
2018-01-30 08:03:37 -08:00
|
|
|
|
|
|
|
/* make sure impls/ctors are filled first, but do it only once */
|
|
|
|
if (!_db_fill_implements(cl))
|
|
|
|
return EINA_FALSE;
|
|
|
|
|
|
|
|
if (!_db_fill_ctors(cl))
|
|
|
|
return EINA_FALSE;
|
|
|
|
|
2018-04-11 05:31:03 -07:00
|
|
|
return EINA_TRUE;
|
2018-01-30 08:03:37 -08:00
|
|
|
}
|
|
|
|
|
2017-01-19 05:56:23 -08:00
|
|
|
static Eina_Bool
|
2018-03-27 04:48:58 -07:00
|
|
|
_validate_implement(Eolian_Implement *impl)
|
2017-01-19 05:56:23 -08:00
|
|
|
{
|
2017-12-22 06:26:36 -08:00
|
|
|
if (impl->base.validated)
|
|
|
|
return EINA_TRUE;
|
|
|
|
|
2018-03-27 04:48:58 -07:00
|
|
|
if (!_validate_doc(impl->common_doc))
|
2017-01-19 05:56:23 -08:00
|
|
|
return EINA_FALSE;
|
2018-03-27 04:48:58 -07:00
|
|
|
if (!_validate_doc(impl->get_doc))
|
2017-01-19 05:56:23 -08:00
|
|
|
return EINA_FALSE;
|
2018-03-27 04:48:58 -07:00
|
|
|
if (!_validate_doc(impl->set_doc))
|
2017-01-19 05:56:23 -08:00
|
|
|
return EINA_FALSE;
|
|
|
|
|
2017-10-24 08:48:57 -07:00
|
|
|
return _validate(&impl->base);
|
2017-01-19 05:56:23 -08:00
|
|
|
}
|
|
|
|
|
2014-08-21 08:53:23 -07:00
|
|
|
static Eina_Bool
|
2018-03-27 04:27:32 -07:00
|
|
|
_validate_class(Validate_State *vals, Eolian_Class *cl,
|
2018-11-21 07:26:00 -08:00
|
|
|
Eina_Hash *nhash, Eina_Hash *ehash, Eina_Hash *chash)
|
2014-08-21 08:53:23 -07:00
|
|
|
{
|
|
|
|
Eina_List *l;
|
2017-10-24 08:48:57 -07:00
|
|
|
Eolian_Function *func;
|
|
|
|
Eolian_Event *event;
|
2017-11-01 05:19:33 -07:00
|
|
|
Eolian_Part *part;
|
2017-10-24 08:48:57 -07:00
|
|
|
Eolian_Implement *impl;
|
2017-10-25 07:23:57 -07:00
|
|
|
Eolian_Class *icl;
|
2017-10-24 14:19:22 -07:00
|
|
|
|
|
|
|
if (!cl)
|
|
|
|
return EINA_FALSE; /* if this happens something is very wrong though */
|
2017-10-24 08:48:57 -07:00
|
|
|
|
2018-03-15 15:24:38 -07:00
|
|
|
/* we've gone through this part */
|
2018-04-26 07:23:13 -07:00
|
|
|
if (eina_hash_find(chash, &cl))
|
2018-03-15 15:24:38 -07:00
|
|
|
return EINA_TRUE;
|
2014-08-21 08:53:23 -07:00
|
|
|
|
2018-03-15 15:24:38 -07:00
|
|
|
Eina_Bool valid = cl->base.validated;
|
2018-01-30 05:01:40 -08:00
|
|
|
|
2018-11-22 07:21:52 -08:00
|
|
|
if (cl->parent)
|
2017-10-24 14:19:22 -07:00
|
|
|
{
|
2017-12-22 03:41:29 -08:00
|
|
|
/* first inherit needs some checking done on it */
|
2018-11-22 07:21:52 -08:00
|
|
|
if (!valid) switch (cl->type)
|
2017-12-22 03:41:29 -08:00
|
|
|
{
|
|
|
|
case EOLIAN_CLASS_REGULAR:
|
|
|
|
case EOLIAN_CLASS_ABSTRACT:
|
2018-11-22 07:21:52 -08:00
|
|
|
if (cl->parent->type != EOLIAN_CLASS_REGULAR && cl->parent->type != EOLIAN_CLASS_ABSTRACT)
|
2017-12-22 03:41:29 -08:00
|
|
|
{
|
|
|
|
char buf[PATH_MAX];
|
|
|
|
snprintf(buf, sizeof(buf), "regular classes ('%s') cannot inherit from non-regular classes ('%s')",
|
2018-11-22 07:21:52 -08:00
|
|
|
cl->base.name, cl->parent->base.name);
|
2017-12-22 03:41:29 -08:00
|
|
|
return _obj_error(&cl->base, buf);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2018-11-22 07:21:52 -08:00
|
|
|
if (!_validate_class(vals, cl->parent, nhash, ehash, chash))
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
EINA_LIST_FOREACH(cl->extends, l, icl)
|
|
|
|
{
|
2018-11-21 07:26:00 -08:00
|
|
|
if (!_validate_class(vals, icl, nhash, ehash, chash))
|
2017-12-22 06:34:53 -08:00
|
|
|
return EINA_FALSE;
|
2017-10-24 14:19:22 -07:00
|
|
|
}
|
|
|
|
|
2014-08-21 08:53:23 -07:00
|
|
|
EINA_LIST_FOREACH(cl->properties, l, func)
|
2018-03-27 04:48:58 -07:00
|
|
|
if (!_validate_function(vals, func, nhash))
|
2017-12-22 06:34:53 -08:00
|
|
|
return EINA_FALSE;
|
2014-08-21 08:53:23 -07:00
|
|
|
|
|
|
|
EINA_LIST_FOREACH(cl->methods, l, func)
|
2018-03-27 04:48:58 -07:00
|
|
|
if (!_validate_function(vals, func, nhash))
|
2017-12-22 06:34:53 -08:00
|
|
|
return EINA_FALSE;
|
2014-08-21 08:53:23 -07:00
|
|
|
|
|
|
|
EINA_LIST_FOREACH(cl->events, l, event)
|
2018-11-21 07:26:00 -08:00
|
|
|
if (!_validate_event(vals, event, ehash))
|
2017-12-22 06:34:53 -08:00
|
|
|
return EINA_FALSE;
|
2014-08-21 08:53:23 -07:00
|
|
|
|
2017-11-01 05:19:33 -07:00
|
|
|
EINA_LIST_FOREACH(cl->parts, l, part)
|
2018-03-27 04:48:58 -07:00
|
|
|
if (!_validate_part(part, nhash))
|
2017-12-22 06:34:53 -08:00
|
|
|
return EINA_FALSE;
|
2017-11-01 05:19:33 -07:00
|
|
|
|
2017-01-19 05:56:23 -08:00
|
|
|
EINA_LIST_FOREACH(cl->implements, l, impl)
|
2018-03-27 04:48:58 -07:00
|
|
|
if (!_validate_implement(impl))
|
2017-12-22 06:34:53 -08:00
|
|
|
return EINA_FALSE;
|
2017-01-19 05:56:23 -08:00
|
|
|
|
2017-12-22 06:26:36 -08:00
|
|
|
/* all the checks that need to be done every time are performed now */
|
|
|
|
if (valid)
|
2018-03-15 15:24:38 -07:00
|
|
|
{
|
|
|
|
/* no need to go through this next time */
|
2018-04-26 07:23:13 -07:00
|
|
|
eina_hash_add(chash, &cl, cl);
|
2018-03-15 15:24:38 -07:00
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
2015-07-07 07:21:45 -07:00
|
|
|
|
2018-03-27 04:48:58 -07:00
|
|
|
if (!_validate_doc(cl->doc))
|
2017-10-24 14:39:14 -07:00
|
|
|
return EINA_FALSE;
|
2017-12-22 06:34:53 -08:00
|
|
|
|
2018-03-15 15:24:38 -07:00
|
|
|
/* also done */
|
2018-04-26 07:23:13 -07:00
|
|
|
eina_hash_add(chash, &cl, cl);
|
2018-03-15 15:24:38 -07:00
|
|
|
|
2017-10-24 08:48:57 -07:00
|
|
|
return _validate(&cl->base);
|
2014-08-21 08:53:23 -07:00
|
|
|
}
|
|
|
|
|
2014-08-22 03:17:22 -07:00
|
|
|
static Eina_Bool
|
2018-03-27 04:48:58 -07:00
|
|
|
_validate_variable(Validate_State *vals, Eolian_Variable *var)
|
2014-08-22 03:17:22 -07:00
|
|
|
{
|
2017-10-24 08:48:57 -07:00
|
|
|
if (var->base.validated)
|
|
|
|
return EINA_TRUE;
|
|
|
|
|
2018-03-27 04:48:58 -07:00
|
|
|
if (!_validate_type(vals, var->base_type))
|
2014-08-22 03:17:22 -07:00
|
|
|
return EINA_FALSE;
|
|
|
|
|
2018-03-27 04:48:58 -07:00
|
|
|
if (var->value && !_validate_expr(var->value, var->base_type, 0))
|
2014-08-22 03:17:22 -07:00
|
|
|
return EINA_FALSE;
|
|
|
|
|
2018-03-27 04:48:58 -07:00
|
|
|
if (!_validate_doc(var->doc))
|
2015-07-07 07:21:45 -07:00
|
|
|
return EINA_FALSE;
|
|
|
|
|
2017-10-24 08:48:57 -07:00
|
|
|
return _validate(&var->base);
|
2014-08-22 03:17:22 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static Eina_Bool
|
2016-03-01 07:37:57 -08:00
|
|
|
_typedecl_map_cb(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED,
|
2017-12-04 02:44:56 -08:00
|
|
|
Eolian_Typedecl *tp, Cb_Ret *sc)
|
2014-08-22 03:17:22 -07:00
|
|
|
{
|
2018-03-27 04:48:58 -07:00
|
|
|
return (sc->succ = _validate_typedecl(sc->vals, tp));
|
2014-08-22 03:17:22 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static Eina_Bool
|
|
|
|
_var_map_cb(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED,
|
2017-12-04 02:44:56 -08:00
|
|
|
Eolian_Variable *var, Cb_Ret *sc)
|
2014-08-22 03:17:22 -07:00
|
|
|
{
|
2018-03-27 04:48:58 -07:00
|
|
|
return (sc->succ = _validate_variable(sc->vals, var));
|
2014-08-22 03:17:22 -07:00
|
|
|
}
|
|
|
|
|
2014-08-21 08:23:37 -07:00
|
|
|
Eina_Bool
|
2018-03-15 16:14:13 -07:00
|
|
|
database_validate(const Eolian_Unit *src)
|
2014-08-21 08:23:37 -07:00
|
|
|
{
|
2017-10-24 08:48:57 -07:00
|
|
|
Eolian_Class *cl;
|
2014-08-22 03:17:22 -07:00
|
|
|
|
2018-05-09 06:44:36 -07:00
|
|
|
Validate_State vals = {
|
|
|
|
EINA_FALSE,
|
2018-05-18 16:45:38 -07:00
|
|
|
!!getenv("EOLIAN_EVENT_REDEF_WARN")
|
2018-05-09 06:44:36 -07:00
|
|
|
};
|
2018-02-13 01:14:49 -08:00
|
|
|
|
2018-03-15 15:24:38 -07:00
|
|
|
/* do an initial pass to refill inherits */
|
2018-03-07 04:08:49 -08:00
|
|
|
Eina_Iterator *iter = eolian_unit_classes_get(src);
|
2018-04-26 07:23:13 -07:00
|
|
|
Eina_Hash *fhash = eina_hash_pointer_new(NULL);
|
2018-03-15 15:24:38 -07:00
|
|
|
EINA_ITERATOR_FOREACH(iter, cl)
|
|
|
|
{
|
2018-03-27 04:27:32 -07:00
|
|
|
if (!_db_fill_inherits(cl, fhash))
|
2018-03-15 15:24:38 -07:00
|
|
|
{
|
|
|
|
eina_hash_free(fhash);
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
}
|
2018-04-11 05:31:03 -07:00
|
|
|
eina_hash_free(fhash);
|
2018-03-15 15:24:38 -07:00
|
|
|
eina_iterator_free(iter);
|
|
|
|
|
|
|
|
iter = eolian_unit_classes_get(src);
|
2018-04-26 07:23:13 -07:00
|
|
|
Eina_Hash *nhash = eina_hash_pointer_new(NULL);
|
2018-11-21 07:26:00 -08:00
|
|
|
Eina_Hash *ehash = eina_hash_pointer_new(NULL);
|
2018-04-26 07:23:13 -07:00
|
|
|
Eina_Hash *chash = eina_hash_pointer_new(NULL);
|
2014-08-21 08:53:23 -07:00
|
|
|
EINA_ITERATOR_FOREACH(iter, cl)
|
2017-12-22 06:34:53 -08:00
|
|
|
{
|
|
|
|
eina_hash_free_buckets(nhash);
|
2018-11-21 07:26:00 -08:00
|
|
|
eina_hash_free_buckets(ehash);
|
2018-04-26 06:45:12 -07:00
|
|
|
eina_hash_free_buckets(chash);
|
2018-11-21 07:26:00 -08:00
|
|
|
if (!_validate_class(&vals, cl, nhash, ehash, chash))
|
2017-12-22 06:34:53 -08:00
|
|
|
{
|
|
|
|
eina_iterator_free(iter);
|
|
|
|
eina_hash_free(nhash);
|
2018-11-21 07:26:00 -08:00
|
|
|
eina_hash_free(ehash);
|
2018-03-15 15:24:38 -07:00
|
|
|
eina_hash_free(chash);
|
2017-12-22 06:34:53 -08:00
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
}
|
2018-03-15 15:24:38 -07:00
|
|
|
eina_hash_free(chash);
|
2018-11-21 07:26:00 -08:00
|
|
|
eina_hash_free(ehash);
|
2017-12-22 06:34:53 -08:00
|
|
|
eina_hash_free(nhash);
|
2014-08-21 08:53:23 -07:00
|
|
|
eina_iterator_free(iter);
|
2014-08-22 03:17:22 -07:00
|
|
|
|
2018-03-27 04:48:58 -07:00
|
|
|
Cb_Ret rt = { &vals, EINA_TRUE };
|
2014-08-22 03:17:22 -07:00
|
|
|
|
2018-03-15 16:14:13 -07:00
|
|
|
eina_hash_foreach(src->aliases, (Eina_Hash_Foreach)_typedecl_map_cb, &rt);
|
2017-12-04 02:44:56 -08:00
|
|
|
if (!rt.succ)
|
2014-08-22 03:17:22 -07:00
|
|
|
return EINA_FALSE;
|
|
|
|
|
2018-03-15 16:14:13 -07:00
|
|
|
eina_hash_foreach(src->structs, (Eina_Hash_Foreach)_typedecl_map_cb, &rt);
|
2017-12-04 02:44:56 -08:00
|
|
|
if (!rt.succ)
|
2014-08-22 03:17:22 -07:00
|
|
|
return EINA_FALSE;
|
|
|
|
|
2018-03-15 16:14:13 -07:00
|
|
|
eina_hash_foreach(src->enums, (Eina_Hash_Foreach)_typedecl_map_cb, &rt);
|
2017-12-04 02:44:56 -08:00
|
|
|
if (!rt.succ)
|
2014-08-22 03:17:22 -07:00
|
|
|
return EINA_FALSE;
|
|
|
|
|
2018-03-15 16:14:13 -07:00
|
|
|
eina_hash_foreach(src->globals, (Eina_Hash_Foreach)_var_map_cb, &rt);
|
2017-12-04 02:44:56 -08:00
|
|
|
if (!rt.succ)
|
2014-08-22 03:17:22 -07:00
|
|
|
return EINA_FALSE;
|
|
|
|
|
2018-03-15 16:14:13 -07:00
|
|
|
eina_hash_foreach(src->constants, (Eina_Hash_Foreach)_var_map_cb, &rt);
|
2017-12-04 02:44:56 -08:00
|
|
|
if (!rt.succ)
|
2014-08-22 03:17:22 -07:00
|
|
|
return EINA_FALSE;
|
|
|
|
|
2018-02-13 01:14:49 -08:00
|
|
|
if(vals.warned)
|
|
|
|
return EINA_FALSE;
|
|
|
|
|
2014-08-21 08:23:37 -07:00
|
|
|
return EINA_TRUE;
|
|
|
|
}
|