cpp: fix relative includes
[m6w6/ext-psi] / src / types / cpp_exp.c
index f2a29bcc7b9be9f3c5a19da9b03cbc0e25c876a9..6e01843ac4aae08067cc765e8d5066b76b5515a9 100644 (file)
@@ -28,6 +28,7 @@
 #include <assert.h>
 
 #include "data.h"
+#include "cpp.h"
 
 struct psi_cpp_exp *psi_cpp_exp_init(token_t type, void *data)
 {
@@ -36,8 +37,12 @@ struct psi_cpp_exp *psi_cpp_exp_init(token_t type, void *data)
        switch ((exp->type = type)) {
        case PSI_T_WARNING:
        case PSI_T_ERROR:
+       case PSI_T_UNDEF:
        case PSI_T_IFDEF:
        case PSI_T_IFNDEF:
+       case PSI_T_IMPORT:
+       case PSI_T_INCLUDE:
+       case PSI_T_INCLUDE_NEXT:
                exp->data.tok = data;
                break;
        case PSI_T_DEFINE:
@@ -49,11 +54,13 @@ struct psi_cpp_exp *psi_cpp_exp_init(token_t type, void *data)
                break;
        case PSI_T_ENDIF:
        case PSI_T_ELSE:
+       case PSI_T_PRAGMA_ONCE:
                break;
        default:
                assert(0);
                break;
        }
+
        return exp;
 }
 
@@ -66,8 +73,16 @@ void psi_cpp_exp_free(struct psi_cpp_exp **exp_ptr)
                switch (exp->type) {
                case PSI_T_WARNING:
                case PSI_T_ERROR:
+                       if (!exp->data.tok) {
+                               break;
+                       }
+                       /* no break */
+               case PSI_T_UNDEF:
                case PSI_T_IFDEF:
                case PSI_T_IFNDEF:
+               case PSI_T_IMPORT:
+               case PSI_T_INCLUDE:
+               case PSI_T_INCLUDE_NEXT:
                        free(exp->data.tok);
                        exp->data.tok = NULL;
                        break;
@@ -80,6 +95,7 @@ void psi_cpp_exp_free(struct psi_cpp_exp **exp_ptr)
                        break;
                case PSI_T_ENDIF:
                case PSI_T_ELSE:
+               case PSI_T_PRAGMA_ONCE:
                        break;
                default:
                        assert(0);
@@ -98,10 +114,24 @@ void psi_cpp_exp_dump(int fd, struct psi_cpp_exp *exp)
        switch (exp->type) {
        case PSI_T_WARNING:
        case PSI_T_ERROR:
+               if (!exp->data.tok) {
+                       break;
+               }
+               /* no break */
+       case PSI_T_UNDEF:
        case PSI_T_IFDEF:
        case PSI_T_IFNDEF:
                dprintf(fd, "%s", exp->data.tok->text);
                break;
+       case PSI_T_IMPORT:
+       case PSI_T_INCLUDE:
+       case PSI_T_INCLUDE_NEXT:
+               if (exp->data.tok->type == PSI_T_CPP_HEADER) {
+                       dprintf(fd, "<%s>", exp->data.tok->text);
+               } else {
+                       dprintf(fd, "\"%s\"", exp->data.tok->text);
+               }
+               break;
        case PSI_T_DEFINE:
                psi_cpp_macro_decl_dump(fd, exp->data.decl);
                break;
@@ -111,6 +141,7 @@ void psi_cpp_exp_dump(int fd, struct psi_cpp_exp *exp)
                break;
        case PSI_T_ENDIF:
        case PSI_T_ELSE:
+       case PSI_T_PRAGMA_ONCE:
                break;
        default:
                assert(0);
@@ -118,3 +149,188 @@ void psi_cpp_exp_dump(int fd, struct psi_cpp_exp *exp)
        }
        dprintf(fd, "\n");
 }
+
+
+static inline bool psi_cpp_level_skipped(struct psi_cpp *cpp)
+{
+       return cpp->skip == cpp->level;
+}
+
+static inline void psi_cpp_level_skip(struct psi_cpp *cpp)
+{
+       assert(!cpp->skip);
+       cpp->skip = cpp->level;
+}
+
+static inline void psi_cpp_level_unskip(struct psi_cpp *cpp)
+{
+       if (psi_cpp_level_skipped(cpp)) {
+               cpp->skip = 0;
+       }
+}
+
+static inline bool psi_cpp_level_masked(struct psi_cpp *cpp)
+{
+       return cpp->seen & (1 << cpp->level);
+}
+
+static inline void psi_cpp_level_mask(struct psi_cpp *cpp)
+{
+       assert(!psi_cpp_level_masked(cpp));
+       cpp->seen |= (1 << cpp->level);
+}
+
+static inline void psi_cpp_level_unmask(struct psi_cpp *cpp)
+{
+       cpp->seen &= ~(1 << cpp->level);
+}
+
+void psi_cpp_exp_exec(struct psi_cpp_exp *exp, struct psi_cpp *cpp, struct psi_data *D)
+{
+       PSI_DEBUG_PRINT(D, "PSI: CPP EVAL < %s (level=%u, skip=%u)\n",
+                       exp->token->text, cpp->level, cpp->skip);
+
+#if PSI_CPP_DEBUG
+       psi_cpp_exp_dump(2, exp);
+#endif
+
+       switch (exp->type) {
+       case PSI_T_ERROR:
+               if (!cpp->skip) {
+                       D->error(D, exp->token, PSI_ERROR, "%s",
+                                       exp->data.tok ? exp->data.tok->text : "");
+               }
+               break;
+       case PSI_T_WARNING:
+               if (!cpp->skip) {
+                       D->error(D, exp->token, PSI_WARNING, "%s",
+                                       exp->data.tok ? exp->data.tok->text : "");
+               }
+               break;
+       case PSI_T_UNDEF:
+               if (!cpp->skip) {
+                       psi_cpp_undef(cpp, exp->data.tok);
+               }
+               break;
+       case PSI_T_DEFINE:
+               if (!cpp->skip) {
+                       psi_cpp_define(cpp, exp->data.decl);
+                       /* FIXME: copy */
+                       exp->data.decl = NULL;
+               }
+               break;
+       case PSI_T_IFDEF:
+               ++cpp->level;
+               if (!cpp->skip) {
+                       if (psi_cpp_defined(cpp, exp->data.tok)) {
+                               psi_cpp_level_mask(cpp);
+                       } else {
+                               psi_cpp_level_skip(cpp);
+                       }
+               }
+               break;
+       case PSI_T_IFNDEF:
+               ++cpp->level;
+               if (!cpp->skip) {
+                       if (psi_cpp_defined(cpp, exp->data.tok)) {
+                               psi_cpp_level_skip(cpp);
+                       } else {
+                               psi_cpp_level_mask(cpp);
+                       }
+               }
+               break;
+       case PSI_T_IF:
+               ++cpp->level;
+               if (!cpp->skip) {
+                       if (psi_cpp_if(cpp, exp)) {
+                               psi_cpp_level_mask(cpp);
+                       } else {
+                               psi_cpp_level_skip(cpp);
+                       }
+               }
+               break;
+       case PSI_T_ENDIF:
+               if (!cpp->level) {
+                       D->error(D, exp->token, PSI_WARNING, "Ingoring lone #endif");
+               } else {
+                       psi_cpp_level_unskip(cpp);
+                       psi_cpp_level_unmask(cpp);
+                       --cpp->level;
+               }
+               break;
+       case PSI_T_ELSE:
+               /* FIXME: catch "else" after "else" */
+               if (!cpp->level) {
+                       D->error(D, exp->token, PSI_WARNING, "Ingoring lone #else");
+               } else if (psi_cpp_level_skipped(cpp) && !psi_cpp_level_masked(cpp)) {
+                       /*
+                        * if skip is set on this level and the level has
+                        * not been masked yet, then unskip and mask this level
+                        */
+                       psi_cpp_level_unskip(cpp);
+                       psi_cpp_level_mask(cpp);
+               } else if (!cpp->skip && psi_cpp_level_masked(cpp)) {
+                       /*
+                        * previous block masked this level
+                        */
+                       psi_cpp_level_skip(cpp);
+               } else {
+                       assert(cpp->skip <= cpp->level);
+               }
+               break;
+       case PSI_T_ELIF:
+               if (!cpp->level) {
+                       D->error(D, exp->token, PSI_WARNING, "Ingoring lone #elif");
+               } else if (psi_cpp_level_skipped(cpp) && !psi_cpp_level_masked(cpp)) {
+                       /*
+                        * if skip is set on this level and the level has
+                        * not been masked yet, then unskip and mask this
+                        * level, if the condition evals truthy
+                        */
+                       if (psi_cpp_if(cpp, exp)) {
+                               psi_cpp_level_unskip(cpp);
+                               psi_cpp_level_mask(cpp);
+                       }
+               } else if (!cpp->skip && psi_cpp_level_masked(cpp)) {
+                       /*
+                        * previous block masked this level
+                        */
+                       psi_cpp_level_skip(cpp);
+               } else {
+                       assert(cpp->skip <= cpp->level);
+               }
+               break;
+       case PSI_T_INCLUDE:
+               if (!cpp->skip) {
+                       if (!psi_cpp_include(cpp, exp->data.tok, PSI_CPP_INCLUDE)) {
+                               D->error(D, exp->token, PSI_WARNING, "Failed to include %s", exp->data.tok->text);
+                       }
+               }
+               break;
+       case PSI_T_INCLUDE_NEXT:
+               if (!cpp->skip) {
+                       if (!psi_cpp_include(cpp, exp->data.tok, PSI_CPP_INCLUDE_NEXT)) {
+                               D->error(D, exp->token, PSI_WARNING, "Failed to include %s", exp->data.tok->text);
+                       }
+               }
+               break;
+       case PSI_T_IMPORT:
+               if (!cpp->skip) {
+                       if (!psi_cpp_include(cpp, exp->data.tok, PSI_CPP_INCLUDE_ONCE)) {
+                               D->error(D, exp->token, PSI_WARNING, "Failed to include %s", exp->data.tok->text);
+                       }
+               }
+               break;
+       case PSI_T_PRAGMA_ONCE:
+               if (!cpp->skip) {
+                       zend_hash_str_add_empty_element(&cpp->once, exp->token->file, strlen(exp->token->file));
+               }
+               break;
+       default:
+               assert(0);
+               break;
+       }
+
+       PSI_DEBUG_PRINT(D, "PSI: CPP EVAL > %s (level=%u, skip=%u)\n",
+                       exp->token->text, cpp->level, cpp->skip);
+}