support delimter separated pathlist
[m6w6/ext-psi] / src / context.c
index 3ff510f2f8aa47a6002dcedafb9ce9b45890fb78..e499c5f0d24052c0f5a32475f0f0878d2a0b1fc2 100644 (file)
@@ -57,6 +57,17 @@ static const psi_predef_struct psi_predef_structs[] = {
 };
 #define psi_predef_struct_count() psi_predef_count(_struct)
 
+PHP_PSI_MACROS
+
+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;
@@ -66,11 +77,7 @@ static int validate_lib(PSI_Data *data, void **dlopened) {
                /* FIXME: assume stdlib */
                return 1;
        } else if (!strchr(ptr, '/')) {
-#ifdef DARWIN
-               len = snprintf(lib, MAXPATHLEN, "lib%s.dylib", ptr);
-#else
-               len = snprintf(lib, MAXPATHLEN, "lib%s.so", ptr);
-#endif
+               len = snprintf(lib, MAXPATHLEN, "lib%s.%s", ptr, PHP_PSI_SHLIB_SUFFIX);
                if (MAXPATHLEN == len) {
                        data->error(PSI_WARNING, "Library name too long: '%s'", ptr);
                }
@@ -230,8 +237,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;
 }
@@ -263,7 +282,7 @@ static inline decl_arg *locate_struct_member(decl_struct *s, decl_var *var) {
                decl_arg *darg = s->args->args[i];
 
                if (!strcmp(var->name, darg->var->name)) {
-                       return darg;
+                       return var->arg = darg;
                }
        }
 
@@ -271,6 +290,8 @@ static inline decl_arg *locate_struct_member(decl_struct *s, decl_var *var) {
 }
 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:
@@ -291,22 +312,22 @@ static inline int validate_set_value(PSI_Data *data, set_value *set, decl_arg *r
        EMPTY_SWITCH_DEFAULT_CASE();
        }
 
-       if (strcmp(set->vars->vars[0]->name, ref->var->name)) {
+       if (strcmp(set_var->name, ref->var->name)) {
                return 0;
        }
 
-       if (set->count && (set->func->type != PSI_T_TO_ARRAY || real_decl_type(ref->type)->type != PSI_T_STRUCT)) {
+       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_arg *sub_ref = locate_struct_member(real_decl_type(ref->type)->strct, set->inner[i]->vars->vars[0]);
+               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) {
-                       return 0;
-               }
-               if (!validate_set_value(data, set->inner[i], sub_ref)) {
-                       return 0;
+               if (sub_ref) {
+                       if (!validate_set_value(data, set->inner[i], sub_ref)) {
+                               return 0;
+                       }
                }
        }
 
@@ -461,34 +482,59 @@ static inline int validate_impl_set_stmts(PSI_Data *data, impl *impl) {
        }
        return 1;
 }
+static inline decl *locate_free_decl(decls *decls, free_call *f) {
+       size_t i;
+
+       for (i = 0; i < decls->count; ++i) {
+               if (!strcmp(decls->list[i]->func->var->name, f->func)) {
+                       f->decl = decls->list[i];
+                       return decls->list[i];
+               }
+       }
+       return NULL;
+}
 static inline int validate_impl_free_stmts(PSI_Data *data, impl *impl) {
-       size_t i, j, k;
+       size_t i, j, k, l;
        /* we can have any count of free stmts; freeing any out vars */
        for (i = 0; i < impl->stmts->fre.count; ++i) {
                free_stmt *fre = impl->stmts->fre.list[i];
 
-               for (j = 0; j < fre->vars->count; ++j) {
-                       decl_var *free_var = fre->vars->vars[j];
-                       int check = 0;
+               for (j = 0; j < fre->calls->count; ++j) {
+                       free_call *free_call = fre->calls->list[j];
 
-                       if (!strcmp(free_var->name, impl->decl->func->var->name)) {
-                               continue;
+                       /* first find the decl of the free func */
+                       if (!locate_free_decl(data->decls, free_call)) {
+                               data->error(PSI_WARNING, "Unknown function '%s' in `free` statement"
+                                               " of implementation '%s'", free_call->func, impl->func->name);
+                               return 0;
+                       }
+                       if (!impl->decl->args) {
+                               data->error(PSI_WARNING, "Declaration '%s' of implementation '%s'"
+                                               " does not have any arguments to free",
+                                               impl->decl->func->var->name, impl->func->name);
                        }
-                       if (impl->decl->args) for (k = 0; k < impl->decl->args->count; ++k) {
-                               decl_arg *free_arg = impl->decl->args->args[k];
 
-                               if (!strcmp(free_var->name, free_arg->var->name)) {
-                                       check = 1;
-                                       free_var->arg = free_arg;
-                                       break;
+                       /* now check for known vars */
+                       for (l = 0; l < free_call->vars->count; ++l) {
+                               int check = 0;
+                               decl_var *free_var = free_call->vars->vars[l];
+
+                               for (k = 0; k < impl->decl->args->count; ++k) {
+                                       decl_arg *free_arg = impl->decl->args->args[k];
+
+                                       if (!strcmp(free_var->name, free_arg->var->name)) {
+                                               check = 1;
+                                               free_var->arg = free_arg;
+                                               break;
+                                       }
                                }
-                       }
 
-                       if (!check) {
-                               data->error(PSI_WARNING, "Unknown variable '%s' of `free` statement"
-                                               " of implementation '%s'",
-                                               free_var->name, impl->func->name);
-                               return 0;
+                               if (!check) {
+                                       data->error(PSI_WARNING, "Unknown variable '%s' of `free` statement"
+                                                       " of implementation '%s'",
+                                                       free_var->name, impl->func->name);
+                                       return 0;
+                               }
                        }
                }
        }
@@ -682,47 +728,62 @@ static int psi_select_dirent(const struct dirent *entry)
        return 0 == fnmatch("*.psi", entry->d_name, FNM_CASEFOLD);
 }
 
-void PSI_ContextBuild(PSI_Context *C, const char *path)
+void PSI_ContextBuild(PSI_Context *C, const char *paths)
 {
        int i, n;
+       char *sep = NULL, *cpy = strdup(paths), *ptr = cpy;
        struct dirent **entries = NULL;
 
-       n = php_scandir(path, &entries, psi_select_dirent, alphasort);
 
-       if (n < 0) {
-               return;
-       } else for (i = 0; i < n; ++i) {
-               char psi[MAXPATHLEN];
-               PSI_Parser P;
+       do {
+               sep = strchr(ptr, ':');
+
+               if (sep) {
+                       *sep = 0;
+               }
+
+               n = php_scandir(ptr, &entries, psi_select_dirent, alphasort);
+
+               if (n > 0) {
+                       for (i = 0; i < n; ++i) {
+                               char psi[MAXPATHLEN];
+                               PSI_Parser P;
 
-               if (MAXPATHLEN <= slprintf(psi, MAXPATHLEN, "%s/%s", path, entries[i]->d_name)) {
-                       C->error(PSI_WARNING, "Path to PSI file too long: %s/%s",
-                               path, entries[i]->d_name);
+                               if (MAXPATHLEN <= slprintf(psi, MAXPATHLEN, "%s/%s", ptr, entries[i]->d_name)) {
+                                       C->error(PSI_WARNING, "Path to PSI file too long: %s/%s",
+                                               ptr, entries[i]->d_name);
+                               }
+                               if (!PSI_ParserInit(&P, psi, C->error, 0)) {
+                                       C->error(PSI_WARNING, "Failed to init PSI parser (%s): %s",
+                                               psi, strerror(errno));
+                                       continue;
+                               }
+
+                               while (-1 != PSI_ParserScan(&P)) {
+                                       PSI_ParserParse(&P, PSI_TokenAlloc(&P));
+                               };
+                               PSI_ParserParse(&P, NULL);
+                               PSI_ContextValidate(C, &P);
+                               PSI_ParserDtor(&P);
+                       }
                }
-               if (!PSI_ParserInit(&P, psi, C->error, 0)) {
-                       C->error(PSI_WARNING, "Failed to init PSI parser (%s): %s",
-                               psi, strerror(errno));
-                       continue;
+
+               if (entries) {
+                       for (i = 0; i < n; ++i) {
+                               free(entries[i]);
+                       }
+                       free(entries);
                }
 
-               while (-1 != PSI_ParserScan(&P)) {
-                       PSI_ParserParse(&P, PSI_TokenAlloc(&P));
-               };
-               PSI_ParserParse(&P, NULL);
-               PSI_ContextValidate(C, &P);
-               PSI_ParserDtor(&P);
-       }
+               ptr = sep + 1;
+       } while (sep);
+
 
        if (PSI_ContextCompile(C) && SUCCESS != zend_register_functions(NULL, C->closures, NULL, MODULE_PERSISTENT)) {
                C->error(PSI_WARNING, "Failed to register functions!");
        }
 
-       if (entries) {
-               for (i = 0; i < n; ++i) {
-                       free(entries[i]);
-               }
-               free(entries);
-       }
+       free(cpy);
 
 }
 
@@ -761,6 +822,12 @@ zend_function_entry *PSI_ContextCompile(PSI_Context *C)
        return C->closures = C->ops->compile(C);
 }
 
+
+void PSI_ContextCall(PSI_Context *C, impl_val *ret_val, decl *decl, impl_val **args)
+{
+       C->ops->call(C, ret_val, decl, args);
+}
+
 void PSI_ContextDtor(PSI_Context *C)
 {
        size_t i;