psi_dump() & psi_validate()
authorMichael Wallner <mike@php.net>
Wed, 27 Jan 2016 11:02:52 +0000 (12:02 +0100)
committerMichael Wallner <mike@php.net>
Wed, 27 Jan 2016 11:02:52 +0000 (12:02 +0100)
src/context.c
src/context.h
src/context_validate.c
src/module.c
src/parser.re
tests/parser/dump/dump001.phpt

index 1887a7c..de72810 100644 (file)
@@ -137,7 +137,7 @@ PSI_Context *PSI_ContextInit(PSI_Context *C, PSI_ContextOps *ops, PSI_ContextErr
                predef_decl = farg;
        }
 
-       PSI_ContextValidatePredef(C, &T);
+       PSI_ContextValidateData(PSI_DATA(C), &T);
 
        C->count = 1;
        C->data = malloc(sizeof(*C->data));
index 386304b..a54e69a 100644 (file)
@@ -29,7 +29,7 @@ struct PSI_Context {
 PSI_Context *PSI_ContextInit(PSI_Context *C, PSI_ContextOps *ops, PSI_ContextErrorFunc error);
 void PSI_ContextBuild(PSI_Context *C, const char *path);
 int PSI_ContextValidate(PSI_Context *C, PSI_Parser *P);
-void PSI_ContextValidatePredef(PSI_Context *C, PSI_Data *D);
+int PSI_ContextValidateData(PSI_Data *C, PSI_Data *D);
 zend_function_entry *PSI_ContextCompile(PSI_Context *C);
 void PSI_ContextCall(PSI_Context *C, decl_callinfo *decl_call, impl_vararg *va);
 void PSI_ContextDump(PSI_Context *C, int fd);
index da760c6..38e0f84 100644 (file)
@@ -919,39 +919,70 @@ int PSI_ContextValidate(PSI_Context *C, PSI_Parser *P)
        return 1;
 }
 
-void PSI_ContextValidatePredef(PSI_Context *C, PSI_Data *D)
+int PSI_ContextValidateData(PSI_Data *dest, PSI_Data *source)
 {
        size_t i;
+       int errors = 0;
 
-       for (i = 0; i < D->defs->count; ++i) {
-               decl_typedef *def = D->defs->list[i];
+       if (source->defs) for (i = 0; i < source->defs->count; ++i) {
+               decl_typedef *def = source->defs->list[i];
 
-               if (validate_decl_typedef(D, def)) {
-                       C->defs = add_decl_typedef(C->defs, def);
+               if (validate_decl_typedef(source, def)) {
+                       if (dest) {
+                               dest->defs = add_decl_typedef(dest->defs, def);
+                       }
+               } else {
+                       ++errors;
                }
        }
 
-       for (i = 0; i < D->consts->count; ++i) {
-               constant *constant = D->consts->list[i];
+       if (source->consts) for (i = 0; i < source->consts->count; ++i) {
+               constant *constant = source->consts->list[i];
 
-               if (validate_constant(D, constant)) {
-                       C->consts = add_constant(C->consts, constant);
+               if (validate_constant(source, constant)) {
+                       if (dest) {
+                               dest->consts = add_constant(dest->consts, constant);
+                       }
+               } else {
+                       ++errors;
                }
        }
 
-       for (i = 0; i < D->structs->count; ++i) {
-               decl_struct *dstruct = D->structs->list[i];
+       if (source->structs) for (i = 0; i < source->structs->count; ++i) {
+               decl_struct *dstruct = source->structs->list[i];
 
-               if (validate_decl_struct(D, dstruct)) {
-                       C->structs = add_decl_struct(C->structs, dstruct);
+               if (validate_decl_struct(source, dstruct)) {
+                       if (dest) {
+                               dest->structs = add_decl_struct(dest->structs, dstruct);
+                       }
+               } else {
+                       ++errors;
                }
        }
 
-       for (i = 0; i < D->decls->count; ++i) {
-               decl *decl = D->decls->list[i];
+       if (source->decls) for (i = 0; i < source->decls->count; ++i) {
+               decl *decl = source->decls->list[i];
 
-               if (validate_decl(D, NULL, decl)) {
-                       C->decls = add_decl(C->decls, decl);
+               if (validate_decl(source, NULL, decl)) {
+                       if (dest) {
+                               dest->decls = add_decl(dest->decls, decl);
+                       }
+               } else {
+                       ++errors;
                }
        }
+
+       if (source->impls) for (i = 0; i < source->impls->count; ++i) {
+               impl *impl = source->impls->list[i];
+
+               if (validate_impl(source, impl)) {
+                       if (dest) {
+                               dest->impls = add_impl(dest->impls, impl);
+                       }
+               } else {
+                       ++errors;
+               }
+       }
+
+       return errors;
 }
index 1fe5bf3..c3728a7 100644 (file)
@@ -40,11 +40,25 @@ zend_class_entry *psi_object_get_class_entry()
 void psi_error_wrapper(PSI_Token *t, int type, const char *msg, ...)
 {
        va_list argv;
+       const char *fn = NULL;
+       unsigned ln = 0;
+
+       if (t) {
+               fn = t->file;
+               ln = t->line;
+       } else if (zend_is_executing()) {
+               fn = zend_get_executed_filename();
+               ln = zend_get_executed_lineno();
+       } else if (zend_is_compiling()) {
+               fn = zend_get_compiled_filename();
+               ln = zend_get_compiled_lineno();
+       }
 
        va_start(argv, msg);
-       psi_verror(type, t?t->file:"Unknown", t?t->line:0, msg, argv);
+       psi_verror(type, fn, ln, msg, argv);
        va_end(argv);
 }
+
 void psi_error(int type, const char *fn, unsigned ln, const char *msg, ...)
 {
        va_list argv;
@@ -53,6 +67,7 @@ void psi_error(int type, const char *fn, unsigned ln, const char *msg, ...)
        psi_verror(type, fn, ln, msg, argv);
        va_end(argv);
 }
+
 void psi_verror(int type, const char *fn, unsigned ln, const char *msg, va_list argv)
 {
        zend_error_cb(type, fn, ln, msg, argv);
@@ -80,7 +95,59 @@ static zend_object *psi_object_init(zend_class_entry *ce)
        return &o->std;
 }
 
-PHP_MINIT_FUNCTION(psi)
+ZEND_BEGIN_ARG_INFO_EX(ai_psi_dump, 0, 0, 0)
+       ZEND_ARG_INFO(0, stream)
+ZEND_END_ARG_INFO();
+static PHP_FUNCTION(psi_dump) {
+       php_stream *s;
+       zval *r = NULL;
+       int fd = STDOUT_FILENO;
+
+       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "|r!", &r)) {
+               return;
+       }
+       if (r) {
+               php_stream_from_zval(s, r);
+
+               if (SUCCESS != php_stream_cast(s, PHP_STREAM_AS_FD | PHP_STREAM_CAST_INTERNAL, (void **)&fd, 1)) {
+                       RETURN_FALSE;
+               }
+       }
+       PSI_ContextDump(&PSI_G(context), fd);
+}
+
+ZEND_BEGIN_ARG_INFO_EX(ai_psi_validate, 0, 0, 1)
+       ZEND_ARG_INFO(0, file)
+ZEND_END_ARG_INFO();
+static PHP_FUNCTION(psi_validate) {
+       zend_string *file;
+       PSI_Parser P;
+
+       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "P", &file)) {
+               return;
+       }
+
+       if (!PSI_ParserInit(&P, file->val, psi_error_wrapper, 0)) {
+               RETURN_FALSE;
+       }
+
+       while (0 < PSI_ParserScan(&P)) {
+               PSI_ParserParse(&P, PSI_TokenAlloc(&P));
+               if (P.num == PSI_T_EOF) {
+                       break;
+               }
+       }
+       PSI_ParserParse(&P, NULL);
+
+       if (0 == PSI_ContextValidateData(NULL, PSI_DATA(&P)) && !P.errors) {
+               RETVAL_TRUE;
+       } else {
+               RETVAL_FALSE;
+       }
+       PSI_ParserDtor(&P);
+}
+
+static PHP_MINIT_FUNCTION(psi)
 {
        PSI_ContextOps *ops = NULL;
        zend_class_entry ce = {0};
@@ -120,7 +187,7 @@ PHP_MINIT_FUNCTION(psi)
        return SUCCESS;
 }
 
-PHP_MSHUTDOWN_FUNCTION(psi)
+static PHP_MSHUTDOWN_FUNCTION(psi)
 {
        PSI_ContextDtor(&PSI_G(context));
 
@@ -130,14 +197,14 @@ PHP_MSHUTDOWN_FUNCTION(psi)
 }
 
 #if defined(COMPILE_DL_PSI) && defined(ZTS)
-PHP_RINIT_FUNCTION(psi)
+static PHP_RINIT_FUNCTION(psi)
 {
        ZEND_TSRMLS_CACHE_UPDATE();
        return SUCCESS;
 }
 #endif
 
-PHP_MINFO_FUNCTION(psi)
+static PHP_MINFO_FUNCTION(psi)
 {
        php_info_print_table_start();
        php_info_print_table_header(2, "psi support", "enabled");
@@ -145,7 +212,10 @@ PHP_MINFO_FUNCTION(psi)
 
        DISPLAY_INI_ENTRIES();
 }
-const zend_function_entry psi_functions[] = {
+
+static const zend_function_entry psi_functions[] = {
+       PHP_FE(psi_dump, ai_psi_dump)
+       PHP_FE(psi_validate, ai_psi_validate)
        PHP_FE_END
 };
 
index 0922ba1..7ab169e 100644 (file)
@@ -1,6 +1,8 @@
 #include <stddef.h>
 #include <stdio.h>
 #include <assert.h>
+#include <errno.h>
+#include <string.h>
 
 #include "parser.h"
 #include "parser_proc.h"
@@ -14,15 +16,11 @@ PSI_Parser *PSI_ParserInit(PSI_Parser *P, const char *filename, psi_error_cb err
 {
        FILE *fp;
 
-       if (!P) {
-               P = malloc(sizeof(*P));
-       }
-       memset(P, 0, sizeof(*P));
-
        fp = fopen(filename, "r");
 
        if (!fp) {
-               perror(filename);
+               error(NULL, PSI_WARNING, "Could not open '%s' for reading: %s",
+                               filename, strerror(errno));
                return NULL;
        }
 
index 68f23c2..da8589c 100644 (file)
@@ -7,14 +7,20 @@ extension_loaded("psi") or die("skip - need ext/psi");
 --FILE--
 ===TEST===
 <?php 
-echo shell_exec("PSI_DUMP=1 ".PHP_BINARY." -r '' > ".__DIR__."/dump.psi");
-var_dump(file_exists(__DIR__."/dump.psi"));
-echo shell_exec(PHP_BINARY." -d psi.directory=".__DIR__." -r ''");
+$fn = __DIR__."/dump.psi";
+$fd = fopen($fn, "w");
+psi_dump($fd);
+fclose($fd);
+
+var_dump(file_exists($fn));
+var_dump(psi_validate($fn));
+
 ?>
 ===DONE===
 --EXPECT--
 ===TEST===
 bool(true)
+bool(true)
 ===DONE===
 --CLEAN--
 <?php