flush
[m6w6/ext-psi] / src / context.c
index 35cedeeb22f661ce3a920c892a30389ade7b8047..7d353bed872cc5e8af756622a9b334a34a9e2f80 100644 (file)
@@ -57,6 +57,15 @@ static const psi_predef_struct psi_predef_structs[] = {
 };
 #define psi_predef_struct_count() psi_predef_count(_struct)
 
+typedef struct psi_predef_func {
+       const char *name;
+       void (*func)(void);
+} psi_predef_func;
+static psi_predef_func psi_predef_funcs[] = {
+       PHP_PSI_FUNCS{0}
+};
+#define psi_predef_func_count() psi_predef_count(_func)
+
 static int validate_lib(PSI_Data *data, void **dlopened) {
        char lib[MAXPATHLEN];
        const char *ptr = data->psi.file.ln;
@@ -230,8 +239,20 @@ static inline int validate_decl_func(PSI_Data *data, void *dl, decl *decl, decl_
 #endif
        decl->dlptr = dlsym(dl ?: RTLD_NEXT, func->var->name);
        if (!decl->dlptr) {
-               data->error(PSI_WARNING, "Failed to locate symbol '%s': %s",
-                       func->var->name, dlerror());
+               size_t i;
+
+               for (i = 0; i < psi_predef_func_count(); ++i) {
+                       psi_predef_func *pre = &psi_predef_funcs[i];
+
+                       if (!strcmp(func->var->name, pre->name)) {
+                               decl->dlptr = pre->func;
+                               break;
+                       }
+               }
+               if (!decl->dlptr) {
+                       data->error(PSI_WARNING, "Failed to locate symbol '%s': %s",
+                               func->var->name, dlerror());
+               }
        }
        return 1;
 }
@@ -254,21 +275,80 @@ static inline int validate_decl(PSI_Data *data, void *dl, decl *decl) {
        }
        return 1;
 }
-static inline int validate_set_value(PSI_Data *data, set_value *set) {
-       set->
+
+static inline decl_arg *locate_struct_member(decl_struct *s, decl_var *var) {
+       size_t i;
+
+       ZEND_ASSERT(s);
+       for (i = 0; i < s->args->count; ++i) {
+               decl_arg *darg = s->args->args[i];
+
+               if (!strcmp(var->name, darg->var->name)) {
+                       return var->arg = darg;
+               }
+       }
+
+       return NULL;
+}
+static inline int validate_set_value(PSI_Data *data, set_value *set, decl_arg *ref) {
+       size_t i;
+       decl_type *ref_type = real_decl_type(ref->type);
+       decl_var *set_var = set->vars->vars[0];
+
+       switch (set->func->type) {
+       case PSI_T_TO_BOOL:
+               set->func->handler = psi_to_bool;
+               break;
+       case PSI_T_TO_INT:
+               set->func->handler = psi_to_int;
+               break;
+       case PSI_T_TO_FLOAT:
+               set->func->handler = psi_to_double;
+               break;
+       case PSI_T_TO_STRING:
+               set->func->handler = psi_to_string;
+               break;
+       case PSI_T_TO_ARRAY:
+               set->func->handler = psi_to_array;
+               break;
+       EMPTY_SWITCH_DEFAULT_CASE();
+       }
+
+       if (strcmp(set_var->name, ref->var->name)) {
+               return 0;
+       }
+
+       if (set->count && (set->func->type != PSI_T_TO_ARRAY || ref_type->type != PSI_T_STRUCT)) {
+               data->error(E_WARNING, "Inner `set` statement casts only work with to_array() casts on structs");
+               return 0;
+       }
+       for (i = 0; i < set->count; ++i) {
+               decl_var *sub_var = set->inner[i]->vars->vars[0];
+               decl_arg *sub_ref = locate_struct_member(ref_type->strct, sub_var);
+
+               if (sub_ref) {
+                       if (!validate_set_value(data, set->inner[i], sub_ref)) {
+                               return 0;
+                       }
+               }
+       }
+
+       return 1;
 }
 static inline decl *locate_impl_decl(decls *decls, return_stmt *ret) {
        size_t i;
 
        for (i = 0; i < decls->count; ++i) {
-               if (!strcmp(decls->list[i]->func->var->name, ret->decl->name)) {
-                       ret->decl->arg = decls->list[i]->func;
+               if (!strcmp(decls->list[i]->func->var->name, ret->set->vars->vars[0]->name)) {
+                       ret->decl = decls->list[i]->func;
                        return decls->list[i];
                }
        }
        return NULL;
 }
 static inline int validate_impl_ret_stmt(PSI_Data *data, impl *impl) {
+       return_stmt *ret;
+
        /* we must have exactly one ret stmt delcaring the native func to call */
        /* and which type cast to apply */
        if (impl->stmts->ret.count != 1) {
@@ -282,14 +362,17 @@ static inline int validate_impl_ret_stmt(PSI_Data *data, impl *impl) {
                }
                return 0;
        }
-       if (!validate_impl_set_value(data, impl->stmts->ret.list[0]->set)) {
-               return 0;
-       }
-       if (!(impl->decl = locate_impl_decl(data->decls, impl->stmts->ret.list[0]))) {
+
+       ret = impl->stmts->ret.list[0];
+
+       if (!(impl->decl = locate_impl_decl(data->decls, ret))) {
                data->error(PSI_WARNING, "Missing declaration for implementation %s",
                                impl->func->name);
                return 0;
        }
+       if (!validate_set_value(data, ret->set, ret->decl)) {
+               return 0;
+       }
 
        return 1;
 }
@@ -383,6 +466,9 @@ static inline int validate_impl_set_stmts(PSI_Data *data, impl *impl) {
 
                                if (!strcmp(set_var->name, set_arg->var->name)) {
                                        check = 1;
+                                       if (!validate_set_value(data, set->val, set_arg)) {
+                                               return 0;
+                                       }
                                        set_var->arg = set_arg;
                                        break;
                                }