improved type validation
authorMichael Wallner <mike@php.net>
Tue, 2 May 2017 15:55:50 +0000 (17:55 +0200)
committerMichael Wallner <mike@php.net>
Wed, 3 May 2017 06:47:54 +0000 (08:47 +0200)
17 files changed:
src/data.c
src/data.h
src/marshal.c
src/marshal.h
src/types/decl.c
src/types/decl.h
src/types/decl_arg.c
src/types/decl_arg.h
src/types/decl_struct.c
src/types/decl_struct.h
src/types/decl_type.c
src/types/decl_type.h
src/types/decl_union.c
src/types/decl_union.h
src/types/let_callback.c
src/types/let_func.c
tests/parser/validate004.phpt

index 9c2cefb..102c022 100644 (file)
@@ -243,12 +243,15 @@ bool psi_data_validate(struct psi_data *dst, struct psi_data *src)
        struct psi_plist *check_enums = src->enums;
        unsigned flags = dst->flags;
        unsigned errors = src->errors;
+       struct psi_validate_stack type_stack;
 
        /* fail early if library is not found */
        if (!psi_decl_file_validate(dst, src, &dlopened)) {
                return false;
        }
 
+       psi_validate_stack_ctor(&type_stack);
+
        dst->flags |= PSI_SILENT;
 
        while (check_count) {
@@ -293,13 +296,14 @@ bool psi_data_validate(struct psi_data *dst, struct psi_data *src)
 
                                while (psi_plist_get(check_types, i++, &def)) {
                                        *dst->last_error = 0;
+                                       dst->types = psi_plist_add(dst->types, &def);
                                        PSI_DEBUG_PRINT(dst, "PSI: validate typedef %s ", def->var->name);
-                                       if (psi_decl_arg_validate_typedef(PSI_DATA(dst), def)) {
+                                       if (psi_decl_arg_validate_typedef(PSI_DATA(dst), def, &type_stack)) {
                                                PSI_DEBUG_PRINT(dst, "%s\n", "✔");
-                                               dst->types = psi_plist_add(dst->types, &def);
                                        } else {
                                                PSI_DEBUG_PRINT(dst, "%s (%s)\n", "✘", dst->last_error);
                                                recheck_types = psi_plist_add(recheck_types, &def);
+                                               psi_plist_pop(dst->types, NULL);
                                        }
                                }
                        }
@@ -311,7 +315,7 @@ bool psi_data_validate(struct psi_data *dst, struct psi_data *src)
                                        *dst->last_error = 0;
                                        dst->structs = psi_plist_add(dst->structs, &str);
                                        PSI_DEBUG_PRINT(dst, "PSI: validate struct %s ", str->name);
-                                       if (psi_decl_struct_validate(PSI_DATA(dst), str)) {
+                                       if (psi_decl_struct_validate(PSI_DATA(dst), str, &type_stack)) {
                                                PSI_DEBUG_PRINT(dst, "%s ::(%zu, %zu)\n", "✔", str->align, str->size);
                                        } else {
                                                PSI_DEBUG_PRINT(dst, "%s (%s)\n", "✘", dst->last_error);
@@ -328,7 +332,7 @@ bool psi_data_validate(struct psi_data *dst, struct psi_data *src)
                                        *dst->last_error = 0;
                                        dst->unions = psi_plist_add(dst->unions, &unn);
                                        PSI_DEBUG_PRINT(dst, "PSI: validate union %s ", unn->name);
-                                       if (psi_decl_union_validate(PSI_DATA(dst), unn)) {
+                                       if (psi_decl_union_validate(PSI_DATA(dst), unn, &type_stack)) {
                                                PSI_DEBUG_PRINT(dst, "%s ::(%zu, %zu)\n", "✔", unn->align, unn->size);
 
                                        } else {
@@ -401,7 +405,7 @@ bool psi_data_validate(struct psi_data *dst, struct psi_data *src)
                while (psi_plist_get(src->decls, i++, &decl)) {
                        *dst->last_error = 0;
                        PSI_DEBUG_PRINT(dst, "PSI: validate decl %s ", decl->func->var->name);
-                       if (psi_decl_validate(PSI_DATA(dst), decl, dlopened)) {
+                       if (psi_decl_validate(PSI_DATA(dst), decl, dlopened, &type_stack)) {
                                PSI_DEBUG_PRINT(dst, "%s\n", "✔");
                                dst->decls = psi_plist_add(dst->decls, &decl);
                        } else {
@@ -428,6 +432,8 @@ bool psi_data_validate(struct psi_data *dst, struct psi_data *src)
                }
        }
 
+       psi_validate_stack_dtor(&type_stack);
+
        return true;
 }
 
index 5356a7e..57bc5c5 100644 (file)
@@ -70,4 +70,52 @@ bool psi_data_validate(struct psi_data *dst, struct psi_data *src);
 void psi_data_dtor(struct psi_data *data);
 void psi_data_dump(int fd, struct psi_data *data);
 
+struct psi_validate_stack {
+       HashTable types;
+       HashTable structs;
+       HashTable unions;
+};
+
+static inline void psi_validate_stack_ctor(struct psi_validate_stack *stack)
+{
+       zend_hash_init(&stack->types, 0, NULL, NULL, 0);
+       zend_hash_init(&stack->structs, 0, NULL, NULL, 0);
+       zend_hash_init(&stack->unions, 0, NULL, NULL, 0);
+}
+
+static inline void psi_validate_stack_dtor(struct psi_validate_stack *stack)
+{
+       zend_hash_destroy(&stack->types);
+       zend_hash_destroy(&stack->structs);
+       zend_hash_destroy(&stack->unions);
+}
+
+#define psi_validate_stack_has_type(s, t) \
+       ((s) ? zend_hash_str_exists(&(s)->types, (t), strlen(t)) : false)
+#define psi_validate_stack_has_struct(s, t) \
+       ((s) ? zend_hash_str_exists(&(s)->structs, (t), strlen(t)) : false)
+#define psi_validate_stack_has_union(s, t) \
+       ((s) ? zend_hash_str_exists(&(s)->unions, (t), strlen(t)) : false)
+
+#define psi_validate_stack_add_type(s, t, p) \
+       do { if (s) zend_hash_str_add_ptr(&(s)->types, (t), strlen(t), (p)); } while(0)
+#define psi_validate_stack_add_struct(s, t, p) \
+       do { if (s) zend_hash_str_add_ptr(&(s)->structs, (t), strlen(t), (p)); } while(0)
+#define psi_validate_stack_add_union(s, t, p) \
+       do { if (s) zend_hash_str_add_ptr(&(s)->unions, (t), strlen(t), (p)); } while(0)
+
+#define psi_validate_stack_get_type(s, t) \
+       ((s) ? zend_hash_str_find_ptr(&(s)->types, (t), strlen(t)) : NULL)
+#define psi_validate_stack_get_struct(s, t) \
+       ((s) ? zend_hash_str_find_ptr(&(s)->structs, (t), strlen(t)) : NULL)
+#define psi_validate_stack_get_union(s, t) \
+       ((s) ? zend_hash_str_find_ptr(&(s)->unions, (t), strlen(t)) : NULL)
+
+#define psi_validate_stack_del_type(s, t) \
+       do { if (s) zend_hash_str_del(&(s)->types, (t), strlen(t)); } while(0)
+#define psi_validate_stack_del_struct(s, t) \
+       do { if (s) zend_hash_str_del(&(s)->structs, (t), strlen(t)); } while(0)
+#define psi_validate_stack_del_union(s, t) \
+       do { if (s) zend_hash_str_del(&(s)->unions, (t), strlen(t)); } while(0)
+
 #endif
index e7ffc67..fcd107f 100644 (file)
@@ -154,7 +154,7 @@ void psi_set_void(zval *return_value, struct psi_set_exp *set, impl_val *ret_val
 /*
  * ?
  */
-impl_val *psi_let_void(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+impl_val *psi_let_void(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
 {
        return tmp;
 }
@@ -169,7 +169,7 @@ void psi_set_zval(zval *return_value, struct psi_set_exp *set, impl_val *ret_val
 /*
  * let dvar = zval($ivar)
  */
-impl_val *psi_let_zval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+impl_val *psi_let_zval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
 {
        *to_free = tmp->ptr = emalloc(sizeof(zval));
        ZVAL_COPY_VALUE(tmp->ptr, zvalue);
@@ -208,10 +208,10 @@ static inline impl_val *psi_val_boolval(impl_val *tmp, token_t real_type, zend_b
 /*
  * let dvar = boolval($ivar)
  */
-impl_val *psi_let_boolval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+impl_val *psi_let_boolval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
 {
        zend_bool boolval;
-       token_t real_type = spec ? psi_decl_type_get_real(spec)->type : PSI_T_UINT8;
+       token_t real_type = spec ? psi_decl_type_get_real(spec->type)->type : PSI_T_UINT8;
 
        if (ival && impl_type == PSI_T_BOOL) {
                boolval = ival->zend.bval;
@@ -248,15 +248,22 @@ void psi_set_to_int(zval *return_value, struct psi_set_exp *set, impl_val *ret_v
        case PSI_T_UINT32:              RETVAL_LONG(v->u32);                            break;
        case PSI_T_INT64:               RETVAL_LONG(v->i64);                            break;
        case PSI_T_UINT64:              RETVAL_LONG_U64(v->u64);                        break;
-       case PSI_T_FLOAT:               RETVAL_DOUBLE((double) v->fval);        break;
-       case PSI_T_DOUBLE:              RETVAL_DOUBLE(v->dval);                         break;
+       case PSI_T_FLOAT:
+               RETVAL_DOUBLE((double) v->fval);
+               convert_to_long(return_value);
+               break;
+       case PSI_T_DOUBLE:
+               RETVAL_DOUBLE(v->dval);
+               convert_to_long(return_value);
+               break;
 #ifdef HAVE_LONG_DOUBLE
-       case PSI_T_LONG_DOUBLE: RETVAL_DOUBLE((double) v->ldval);       break;
+       case PSI_T_LONG_DOUBLE:
+               RETVAL_DOUBLE((double) v->ldval);
+               convert_to_long(return_value);
+               break;
 #endif
        EMPTY_SWITCH_DEFAULT_CASE();
        }
-
-       convert_to_long(return_value);
 }
 
 static inline impl_val *psi_val_intval(impl_val *tmp, token_t real_type, zend_long intval) {
@@ -285,10 +292,10 @@ static inline impl_val *psi_val_intval(impl_val *tmp, token_t real_type, zend_lo
 /*
  * let dvar = intval($ivar)
  */
-impl_val *psi_let_intval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+impl_val *psi_let_intval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
 {
        zend_long intval;
-       token_t real_type = spec ? psi_decl_type_get_real(spec)->type : PSI_T_LONG;
+       token_t real_type = spec ? psi_decl_type_get_real(spec->type)->type : PSI_T_LONG;
 
        if (ival && impl_type == PSI_T_INT) {
                intval = ival->zend.lval;
@@ -350,10 +357,10 @@ static inline impl_val *psi_val_floatval(impl_val *tmp, token_t real_type, doubl
 /*
  * let dvar = floatval($ivar)
  */
-impl_val *psi_let_floatval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+impl_val *psi_let_floatval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
 {
        double floatval;
-       token_t real_type = spec ? psi_decl_type_get_real(spec)->type : PSI_T_DOUBLE;
+       token_t real_type = spec ? psi_decl_type_get_real(spec->type)->type : PSI_T_DOUBLE;
 
        if (ival && (impl_type == PSI_T_FLOAT || impl_type == PSI_T_DOUBLE)) {
                floatval = ival->dval;
@@ -407,7 +414,7 @@ void psi_set_to_stringl(zval *return_value, struct psi_set_exp *set, impl_val *r
 /*
  * let dvar = strval($ivar)
  */
-impl_val *psi_let_strval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+impl_val *psi_let_strval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
 {
        if (ival && impl_type == PSI_T_STRING) {
                if (ival->zend.str) {
@@ -428,7 +435,7 @@ impl_val *psi_let_strval(impl_val *tmp, struct psi_decl_type *spec, token_t impl
 /*
  * let dvar = pathval($ivar)
  */
-impl_val *psi_let_pathval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+impl_val *psi_let_pathval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
 {
        tmp = psi_let_strval(tmp, spec, impl_type, ival, zvalue, to_free);
        if (SUCCESS != php_check_open_basedir(tmp->ptr)) {
@@ -442,7 +449,7 @@ impl_val *psi_let_pathval(impl_val *tmp, struct psi_decl_type *spec, token_t imp
 /*
  * let dvar = strlen($ivar)
  */
-impl_val *psi_let_strlen(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+impl_val *psi_let_strlen(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
 {
        if (ival && impl_type == PSI_T_STRING) {
                if (ival->zend.str) {
@@ -580,49 +587,12 @@ void psi_set_to_array(zval *return_value, struct psi_set_exp *set, impl_val *r_v
        }
 }
 
-//impl_val *psi_let_arrval(impl_val *tmp, decl_type *spec, decl_var *spec_var, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
-//{
-//     decl_type *real = real_decl_type(spec);
-//     HashTable *arr;
-//     zval *zv;
-//     size_t i, sz;
-//     decl_arg tmp_arg = {0};
-//
-//     if (impl_type != PSI_T_ARRAY) {
-//             SEPARATE_ARG_IF_REF(zvalue);
-//             convert_to_array(zvalue);
-//     }
-//     arr = HASH_OF(zvalue);
-//
-//     switch (real->type) {
-//     case PSI_T_STRUCT:
-//             *to_free = tmp = psi_array_to_struct(real->real.strct, arr);
-//             break;
-//     case PSI_T_UNION:
-//             *to_free = tmp = psi_array_to_union(real->real.unn, arr);
-//             break;
-//     default:
-//             sz = psi_t_size(real->type);
-//             tmp = *to_free = ecalloc(zend_hash_num_elements(arr), sz);
-//             tmp_arg.type = spec;
-//             tmp_arg.var = spec_var;
-//             ZEND_HASH_FOREACH_VAL_IND(arr, zv)
-//             {
-//                     void *ptr = ((char *) tmp) + (i++ * sz);
-//                     psi_from_zval_ex(NULL, (impl_val **) &ptr, &tmp_arg, 0, zv, NULL);
-//             }
-//             ZEND_HASH_FOREACH_END();
-//     }
-//
-//     return tmp;
-//}
-
 /*
  * let dvar = count($ivar)
  */
-impl_val *psi_let_count(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+impl_val *psi_let_count(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
 {
-       return psi_val_intval(tmp, psi_decl_type_get_real(spec)->type, psi_zval_count(zvalue));
+       return psi_val_intval(tmp, psi_decl_type_get_real(spec->type)->type, psi_zval_count(zvalue));
 }
 
 /*
@@ -644,7 +614,7 @@ void psi_set_to_object(zval *return_value, struct psi_set_exp *set, impl_val *r_
 /*
  * let dvar = objval($ivar)
  */
-impl_val *psi_let_objval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+impl_val *psi_let_objval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
 {
        psi_object *obj;
 
index 8067fb3..be5b3c6 100644 (file)
@@ -31,7 +31,7 @@
 
 struct psi_let_exp;
 struct psi_set_exp;
-struct psi_decl_type;
+struct psi_decl_arg;
 struct psi_call_frame;
 struct psi_impl;
 struct psi_impl_type;
@@ -41,7 +41,7 @@ zend_internal_arg_info *psi_internal_arginfo(struct psi_impl *impl);
 int psi_internal_type(struct psi_impl_type *type);
 
 typedef void (*psi_marshal_set)(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame);
-typedef impl_val *(*psi_marshal_let)(impl_val *tmp, struct psi_decl_type *psi_decl_type, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
+typedef impl_val *(*psi_marshal_let)(impl_val *tmp, struct psi_decl_arg *type_spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
 
 void psi_set_void(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame);
 void psi_set_to_bool(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame);
@@ -56,15 +56,15 @@ void psi_set_to_array(zval *return_value, struct psi_set_exp *set, impl_val *ret
 void psi_set_to_object(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame);
 void psi_set_zval(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame);
 
-impl_val *psi_let_void(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
-impl_val *psi_let_boolval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
-impl_val *psi_let_intval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
-impl_val *psi_let_floatval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
-impl_val *psi_let_strval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
-impl_val *psi_let_pathval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
-impl_val *psi_let_strlen(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
-impl_val *psi_let_objval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
-impl_val *psi_let_zval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
-impl_val *psi_let_count(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free);
+impl_val *psi_let_void(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
+impl_val *psi_let_boolval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
+impl_val *psi_let_intval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
+impl_val *psi_let_floatval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
+impl_val *psi_let_strval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
+impl_val *psi_let_pathval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
+impl_val *psi_let_strlen(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
+impl_val *psi_let_objval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
+impl_val *psi_let_zval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
+impl_val *psi_let_count(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free);
 
 #endif
index df04656..afad6be 100644 (file)
@@ -114,9 +114,10 @@ static inline bool psi_decl_validate_func(struct psi_data *data,
        return true;
 }
 
-bool psi_decl_validate(struct psi_data *data, struct psi_decl *decl, void *dl)
+bool psi_decl_validate(struct psi_data *data, struct psi_decl *decl, void *dl,
+               struct psi_validate_stack *type_stack)
 {
-       if (!psi_decl_validate_nodl(data, decl)) {
+       if (!psi_decl_validate_nodl(data, decl, type_stack)) {
                return false;
        }
        if (!psi_decl_validate_func(data, decl, decl->func, dl)) {
@@ -126,7 +127,8 @@ bool psi_decl_validate(struct psi_data *data, struct psi_decl *decl, void *dl)
        return true;
 }
 
-bool psi_decl_validate_nodl(struct psi_data *data, struct psi_decl *decl)
+bool psi_decl_validate_nodl(struct psi_data *data, struct psi_decl *decl,
+               struct psi_validate_stack *type_stack)
 {
        if (!decl->abi) {
                decl->abi = psi_decl_abi_init("default");
@@ -135,7 +137,7 @@ bool psi_decl_validate_nodl(struct psi_data *data, struct psi_decl *decl)
                                "Invalid calling convention: '%s'", decl->abi->token->text);
                return false;
        }
-       if (!psi_decl_arg_validate(data, decl->func)) {
+       if (!psi_decl_arg_validate(data, decl->func, type_stack)) {
                return false;
        }
        if (decl->args) {
@@ -143,7 +145,7 @@ bool psi_decl_validate_nodl(struct psi_data *data, struct psi_decl *decl)
                struct psi_decl_arg *arg;
 
                while (psi_plist_get(decl->args, i++, &arg)) {
-                       if (!psi_decl_arg_validate(data, arg)) {
+                       if (!psi_decl_arg_validate(data, arg, type_stack)) {
                                return false;
                        }
                }
index 67529e8..1ca56d5 100644 (file)
@@ -44,8 +44,8 @@ struct psi_decl *psi_decl_init(struct psi_decl_arg *func, struct psi_plist *args
 void psi_decl_free(struct psi_decl **d_ptr);
 void psi_decl_dump(int fd, struct psi_decl *decl);
 
-bool psi_decl_validate(struct psi_data *data, struct psi_decl *decl, void *dl);
-bool psi_decl_validate_nodl(struct psi_data *data, struct psi_decl *decl);
+bool psi_decl_validate(struct psi_data *data, struct psi_decl *decl, void *dl, struct psi_validate_stack *type_stack);
+bool psi_decl_validate_nodl(struct psi_data *data, struct psi_decl *decl, struct psi_validate_stack *type_stack);
 
 static inline struct psi_decl_arg *psi_decl_get_arg(struct psi_decl *decl, struct psi_decl_var *var) {
        return psi_decl_arg_get_by_var(var, decl->args, decl->func);
index ba77e79..bec8ddc 100644 (file)
@@ -92,9 +92,10 @@ void psi_decl_arg_dump(int fd, struct psi_decl_arg *arg, unsigned level)
        }
 }
 
-bool psi_decl_arg_validate(struct psi_data *data, struct psi_decl_arg *arg)
+bool psi_decl_arg_validate(struct psi_data *data, struct psi_decl_arg *arg,
+               struct psi_validate_stack *type_stack)
 {
-       if (!psi_decl_type_validate(data, arg->type, NULL)) {
+       if (!psi_decl_type_validate(data, arg->type, type_stack)) {
                data->error(data, arg->type->token, PSI_WARNING,
                                "Cannot use '%s' as type for '%s': %s", arg->type->name,
                                arg->var->name, data->last_error);
@@ -103,30 +104,14 @@ bool psi_decl_arg_validate(struct psi_data *data, struct psi_decl_arg *arg)
        return true;
 }
 
-bool psi_decl_arg_validate_typedef(struct psi_data *data, struct psi_decl_arg *def)
+bool psi_decl_arg_validate_typedef(struct psi_data *data,
+               struct psi_decl_arg *def, struct psi_validate_stack *type_stack)
 {
-       if (!psi_decl_type_validate(data, def->type, def)) {
-               const char *pre;
-
-               switch (def->type->type) {
-               case PSI_T_STRUCT:
-                       pre = "struct ";
-                       break;
-               case PSI_T_UNION:
-                       pre = "union ";
-                       break;
-               case PSI_T_ENUM:
-                       pre = "enum ";
-                       break;
-               default:
-                       pre = "";
-                       break;
-               }
-               data->error(data, def->token, PSI_WARNING,
-                               "Type '%s' cannot be aliased to '%s%s': %s", def->var->name, pre,
-                               def->type->name, data->last_error);
-               return false;
+       if (psi_validate_stack_has_type(type_stack, def->var->name)) {
+               return true;
        }
+       psi_validate_stack_add_type(type_stack, def->var->name, def);
+
        if (def->type->type == PSI_T_VOID) {
                if (def->var->pointer_level) {
                        def->type->type = PSI_T_POINTER;
@@ -135,6 +120,29 @@ bool psi_decl_arg_validate_typedef(struct psi_data *data, struct psi_decl_arg *d
                                        "Type '%s' cannot be aliased to 'void'", def->type->name);
                        return false;
                }
+       } else if (!def->var->pointer_level) {
+               if (!psi_decl_type_validate(data, def->type, type_stack)) {
+                       const char *pre;
+
+                       switch (def->type->type) {
+                       case PSI_T_STRUCT:
+                               pre = "struct ";
+                               break;
+                       case PSI_T_UNION:
+                               pre = "union ";
+                               break;
+                       case PSI_T_ENUM:
+                               pre = "enum ";
+                               break;
+                       default:
+                               pre = "";
+                               break;
+                       }
+                       data->error(data, def->token, PSI_WARNING,
+                                       "Type '%s' cannot be aliased to '%s%s': %s", def->var->name, pre,
+                                       def->type->name, data->last_error);
+                       return false;
+               }
        }
 
        return true;
@@ -144,10 +152,10 @@ size_t psi_decl_arg_align(struct psi_decl_arg *darg, size_t *pos, size_t *len)
 {
        size_t align = psi_decl_arg_get_align(darg);
 
-       assert(align > 0);
-
-       *len = psi_decl_arg_get_size(darg);
-       *pos = psi_align(align, *pos);
+       if (align) {
+               *len = psi_decl_arg_get_size(darg);
+               *pos = psi_align(align, *pos);
+       }
 
        return align;
 }
index 0ac1fc2..17033f0 100644 (file)
@@ -32,6 +32,7 @@ struct psi_plist;
 struct psi_decl_type;
 struct psi_decl_var;
 struct psi_layout;
+struct psi_validate_stack;
 
 struct psi_decl_arg {
        struct psi_token *token;
@@ -44,8 +45,8 @@ struct psi_decl_arg *psi_decl_arg_init(struct psi_decl_type *type, struct psi_de
 void psi_decl_arg_free(struct psi_decl_arg **arg_ptr);
 void psi_decl_arg_dump(int fd, struct psi_decl_arg *arg, unsigned level);
 
-bool psi_decl_arg_validate(struct psi_data *data, struct psi_decl_arg *arg);
-bool psi_decl_arg_validate_typedef(struct psi_data *data, struct psi_decl_arg *def);
+bool psi_decl_arg_validate(struct psi_data *data, struct psi_decl_arg *arg, struct psi_validate_stack *type_stack);
+bool psi_decl_arg_validate_typedef(struct psi_data *data, struct psi_decl_arg *def, struct psi_validate_stack *type_stack);
 
 size_t psi_decl_arg_align(struct psi_decl_arg *darg, size_t *pos, size_t *len);
 size_t psi_decl_arg_get_align(struct psi_decl_arg *darg);
index ab0d9a1..973f633 100644 (file)
@@ -78,11 +78,17 @@ struct psi_decl_arg *psi_decl_struct_get_arg(struct psi_decl_struct *s,
        return NULL;
 }
 
-bool psi_decl_struct_validate(struct psi_data *data, struct psi_decl_struct *s)
+bool psi_decl_struct_validate(struct psi_data *data, struct psi_decl_struct *s,
+               struct psi_validate_stack *type_stack)
 {
        size_t i, pos, len, size, align;
        struct psi_decl_arg *darg, *prev_arg;
 
+       if (psi_validate_stack_has_struct(type_stack, s->name)) {
+               return true;
+       }
+       psi_validate_stack_add_struct(type_stack, s->name, s);
+
        if (!s->size && !psi_plist_count(s->args)) {
                data->error(data, s->token, PSI_WARNING,
                                "Cannot compute size of empty struct '%s'", s->name);
@@ -92,7 +98,7 @@ bool psi_decl_struct_validate(struct psi_data *data, struct psi_decl_struct *s)
        for (i = 0; psi_plist_get(s->args, i, &darg); ++i) {
                darg->var->arg = darg;
 
-               if (!psi_decl_arg_validate(data, darg)) {
+               if (!psi_decl_arg_validate(data, darg, type_stack)) {
                        return false;
                }
 
@@ -100,6 +106,13 @@ bool psi_decl_struct_validate(struct psi_data *data, struct psi_decl_struct *s)
                        pos = darg->layout->pos;
                        align = psi_decl_arg_align(darg, &pos, &len);
 
+                       if (!align) {
+                               data->error(data, darg->token, PSI_WARNING,
+                                               "Computed zero alignment of %s.%s of type '%s'",
+                                               len, s->name, darg->var->name, darg->type->name);
+                               return false;
+                       }
+
                        if (darg->layout->len != len) {
                                data->error(data, darg->token, PSI_WARNING,
                                                "Computed size %zu of %s.%s does not match"
index 4ac9e8c..ca22f3b 100644 (file)
@@ -30,6 +30,7 @@ struct psi_data;
 struct psi_token;
 struct psi_plist;
 struct psi_decl_var;
+struct psi_validate_stack;
 
 struct psi_decl_struct {
        struct psi_token *token;
@@ -47,7 +48,7 @@ struct psi_decl_struct *psi_decl_struct_init(const char *name, struct psi_plist
 void psi_decl_struct_free(struct psi_decl_struct **s_ptr);
 void psi_decl_struct_dump(int fd, struct psi_decl_struct *strct);
 
-bool psi_decl_struct_validate(struct psi_data *data, struct psi_decl_struct *s);
+bool psi_decl_struct_validate(struct psi_data *data, struct psi_decl_struct *s, struct psi_validate_stack *type_stack);
 
 struct psi_decl_arg *psi_decl_struct_get_arg(struct psi_decl_struct *s, struct psi_decl_var *var);
 size_t psi_decl_struct_get_align(struct psi_decl_struct *s);
index c3901ca..73e8959 100644 (file)
@@ -213,36 +213,53 @@ bool psi_decl_type_get_decl(struct psi_decl_type *type, struct psi_plist *decls)
 }
 
 bool psi_decl_type_validate(struct psi_data *data, struct psi_decl_type *type,
-               struct psi_decl_arg *def)
+               struct psi_validate_stack *type_stack)
 {
        if (psi_decl_type_is_weak(type)) {
                if (!psi_decl_type_get_alias(type, data->types)) {
-                       return false;
+                       if (!psi_validate_stack_has_type(type_stack, type->name)) {
+                               return false;
+                       }
+                       type->real.def = psi_validate_stack_get_type(type_stack, type->name);
                }
                if (type->real.def) {
                        return psi_decl_type_validate(data, type->real.def->type,
-                                       type->real.def);
+                                       type_stack);
                }
                return true;
        }
 
        switch (type->type) {
        case PSI_T_STRUCT:
-               if (!psi_decl_type_get_struct(type, data->structs) && !def) {
-                       data->error(data, type->token, PSI_WARNING,
-                                       "Unknown struct '%s'", type->name);
+               if (!psi_decl_type_get_struct(type, data->structs)) {
+                       if (psi_validate_stack_has_struct(type_stack, type->name)) {
+                               type->real.strct = psi_validate_stack_get_struct(type_stack, type->name);
+                       } else {
+                               data->error(data, type->token, PSI_WARNING,
+                                               "Unknown struct '%s'", type->name);
+                               return false;
+                       }
+               }
+               if (!psi_decl_struct_validate(data, type->real.strct, type_stack)) {
                        return false;
                }
                break;
        case PSI_T_UNION:
-               if (!psi_decl_type_get_union(type, data->unions) && !def) {
-                       data->error(data, type->token, PSI_WARNING,
-                                       "Unknown union '%s'", type->name);
+               if (!psi_decl_type_get_union(type, data->unions)) {
+                       if (psi_validate_stack_has_union(type_stack, type->name)) {
+                               type->real.unn = psi_validate_stack_get_union(type_stack, type->name);
+                       } else {
+                               data->error(data, type->token, PSI_WARNING,
+                                               "Unknown union '%s'", type->name);
+                               return false;
+                       }
+               }
+               if (!psi_decl_union_validate(data, type->real.unn, type_stack)) {
                        return false;
                }
                break;
        case PSI_T_ENUM:
-               if (!psi_decl_type_get_enum(type, data->enums) && !def) {
+               if (!psi_decl_type_get_enum(type, data->enums)) {
                        data->error(data, type->token, PSI_WARNING,
                                        "Unknown enum '%s'", type->name);
                        return false;
@@ -254,11 +271,14 @@ bool psi_decl_type_validate(struct psi_data *data, struct psi_decl_type *type,
                                        "Unknown decl '%s'", type->name);
                        return false;
                }
-               if (!psi_decl_validate_nodl(data, type->real.func)) {
+               if (!psi_decl_validate_nodl(data, type->real.func, type_stack)) {
                        return false;
                }
                break;
+       default:
+               break;
        }
+
        return true;
 }
 
index e7c341f..a31f317 100644 (file)
@@ -36,6 +36,7 @@ struct psi_decl_struct;
 struct psi_decl_union;
 struct psi_decl_enum;
 struct psi_decl;
+struct psi_validate_stack;
 
 struct psi_decl_type {
        struct psi_token *token;
@@ -57,7 +58,7 @@ struct psi_decl_type *psi_decl_type_init(token_t type, const char *name);
 struct psi_decl_type *psi_decl_type_copy(struct psi_decl_type *src);
 void psi_decl_type_free(struct psi_decl_type **type_ptr);
 void psi_decl_type_dump(int fd, struct psi_decl_type *t, unsigned level);
-bool psi_decl_type_validate(struct psi_data *data, struct psi_decl_type *type, struct psi_decl_arg *def);
+bool psi_decl_type_validate(struct psi_data *data, struct psi_decl_type *type, struct psi_validate_stack *type_stack);
 
 bool psi_decl_type_validate_args(struct psi_data *data, struct psi_decl_type *decl_type, token_t type, void *current);
 
index 71e70eb..1d24f95 100644 (file)
@@ -74,11 +74,17 @@ struct psi_decl_arg *psi_decl_union_get_arg(struct psi_decl_union *u,
        return NULL;
 }
 
-bool psi_decl_union_validate(struct psi_data *data, struct psi_decl_union *u)
+bool psi_decl_union_validate(struct psi_data *data, struct psi_decl_union *u,
+               struct psi_validate_stack *type_stack)
 {
        size_t i, pos, len, size = 0, align;
        struct psi_decl_arg *darg;
 
+       if (psi_validate_stack_has_union(type_stack, u->name)) {
+               return true;
+       }
+       psi_validate_stack_add_union(type_stack, u->name, u);
+
        if (!u->size && !psi_plist_count(u->args)) {
                data->error(data, u->token, PSI_WARNING,
                                "Cannot compute size of empty union %s", u->name);
@@ -88,7 +94,7 @@ bool psi_decl_union_validate(struct psi_data *data, struct psi_decl_union *u)
        for (i = 0; psi_plist_get(u->args, i, &darg); ++i) {
                darg->var->arg = darg;
 
-               if (!psi_decl_arg_validate(data, darg)) {
+               if (!psi_decl_arg_validate(data, darg, type_stack)) {
                        return false;
                }
 
index 619b3f5..95184e2 100644 (file)
@@ -29,6 +29,7 @@ struct psi_data;
 struct psi_token;
 struct psi_plist;
 struct psi_decl_var;
+struct psi_validate_stack;
 
 struct psi_decl_union {
        struct psi_token *token;
@@ -42,7 +43,7 @@ struct psi_decl_union *psi_decl_union_init(const char *name, struct psi_plist *a
 void psi_decl_union_free(struct psi_decl_union **u_ptr);
 void psi_decl_union_dump(int fd, struct psi_decl_union *unn);
 
-bool psi_decl_union_validate(struct psi_data *data, struct psi_decl_union *u);
+bool psi_decl_union_validate(struct psi_data *data, struct psi_decl_union *u, struct psi_validate_stack *type_stack);
 
 size_t psi_decl_union_get_align(struct psi_decl_union *u);
 struct psi_decl_arg *psi_decl_union_get_arg(struct psi_decl_union *u, struct psi_decl_var *var);
index f6b08ba..632289f 100644 (file)
@@ -74,7 +74,7 @@ bool psi_let_callback_validate(struct psi_data *data, struct psi_let_exp *exp,
                }
        }
 
-       if (!psi_decl_validate_nodl(data, cb_func)) {
+       if (!psi_decl_validate_nodl(data, cb_func,  NULL /* FIXME type_stack */)) {
                return false;
        }
 
index 27c3702..abf69a4 100644 (file)
@@ -255,7 +255,7 @@ static void *exec_let_func_arrval(struct psi_let_exp *val,
                struct psi_call_frame *frame);
 
 void exec_let_func_arrval_seq(struct psi_let_func *func,
-               struct psi_decl_arg *darg, struct psi_decl_type *darg_type,
+               struct psi_decl_arg *darg,
                struct psi_call_frame_argument *frame_arg,
                struct psi_let_exp *inner_let_exp, void *container,
                struct psi_call_frame *frame)
@@ -287,7 +287,7 @@ void exec_let_func_arrval_seq(struct psi_let_func *func,
                impl_val val = {0}, *ptr, *sub;
 
                if (let_fn) {
-                       ptr = let_fn(&val, darg_type, 0, NULL, zval_ptr, &temp);
+                       ptr = let_fn(&val, darg, 0, NULL, zval_ptr, &temp);
                        if (temp) {
                                psi_call_frame_push_auto(frame, temp);
                        }
@@ -315,10 +315,9 @@ static void *exec_let_func_arrval(struct psi_let_exp *val,
 {
        void *container = NULL;
        struct psi_call_frame_argument *frame_arg;
-       struct psi_decl_type *darg_type;
        struct psi_plist *darg_members;
 
-       darg_members = psi_decl_type_get_args(darg->type, &darg_type);
+       darg_members = psi_decl_type_get_args(darg->type, NULL);
        frame_arg = psi_call_frame_get_argument(frame, func->var->fqn);
 
        if (frame_arg->zval_ptr && Z_TYPE_P(frame_arg->zval_ptr) != IS_ARRAY) {
@@ -368,8 +367,7 @@ static void *exec_let_func_arrval(struct psi_let_exp *val,
                container = ecalloc(arcount + 1, psi_decl_var_get_size(inner->var));
                inner->var->pointer_level -= inner->is_reference;
 
-               exec_let_func_arrval_seq(func, darg, darg_type, frame_arg, inner,
-                               container, frame);
+               exec_let_func_arrval_seq(func, darg, frame_arg, inner, container, frame);
        } else {
                assert(0);
        }
@@ -393,8 +391,7 @@ void *psi_let_func_exec(struct psi_let_exp *val, struct psi_let_func *func,
 
                assert(iarg);
 
-               frame_sym->ival_ptr = let_fn(&frame_sym->temp_val,
-                               psi_decl_type_get_real(darg->type),
+               frame_sym->ival_ptr = let_fn(&frame_sym->temp_val, darg,
                                iarg->spec ? iarg->spec->type->type : 0, iarg->ival_ptr,
                                iarg->zval_ptr, &temp);
                if (temp) {
index 31b8509..aa94c41 100644 (file)
@@ -12,6 +12,4 @@ psi_validate_string("struct a; \ntypedef struct a a_t;");
 ===DONE===
 --EXPECTF--
 ===TEST===
-
-Warning: Cannot compute size of empty struct 'a' in %s on line 1
 ===DONE===