From a107dfcca2dfd0fc5a2779a8d679f778cb8f3290 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Mon, 24 Oct 2016 19:56:18 +0200 Subject: [PATCH] flush --- psi.d/getopt.psi | 24 +++ psi.d/time.psi | 1 + src/engine.c | 214 ++++++++++++++++++++------ src/engine.h | 1 + src/marshal.c | 35 ++++- src/marshal.h | 22 +-- src/parser.re | 5 +- src/parser_def.h | 277 ++++++++++++++++++++++++---------- src/parser_proc.h | 149 +++++++++--------- src/parser_proc.y | 119 ++++++++++----- src/types.h | 2 +- src/types/decl.c | 6 + src/types/decl_type.c | 19 ++- src/types/decl_type.h | 2 + src/types/let_callback.c | 4 - src/types/let_func.c | 71 ++++++--- src/types/let_func.h | 3 +- src/types/let_stmt.c | 24 ++- src/types/let_stmt.h | 4 +- src/types/let_val.c | 99 +++--------- src/types/let_val.h | 50 +++--- src/types/let_vals.h | 14 ++ src/types/set_stmt.c | 4 +- tests/getopt/getopt001.phpt | 80 ++++++++++ tests/ndbm/ndbm.psi | 14 +- tests/ndbm/ndbm001.phpt | 8 +- tests/parser/validate001.phpt | 3 + 27 files changed, 831 insertions(+), 423 deletions(-) create mode 100644 psi.d/getopt.psi create mode 100644 tests/getopt/getopt001.phpt diff --git a/psi.d/getopt.psi b/psi.d/getopt.psi new file mode 100644 index 0000000..5f5bae6 --- /dev/null +++ b/psi.d/getopt.psi @@ -0,0 +1,24 @@ +function psi\opterr() : int { + return to_int(opterr); +} +function psi\optind() : int { + return to_int(optind); +} +function psi\optopt() : int { + return to_int(optopt); +} +function psi\optarg() : string { + return to_string(optarg); +} + +function psi\getopt(array &$argv, string $options) : int { + let argc = count($argv); + let argv = &arrval($argv, + *argv = strval($argv) + ); + let optstring = strval($options); + return to_int(getopt); + set $argv = to_array(argv, + to_string(argv) + ); +} diff --git a/psi.d/time.psi b/psi.d/time.psi index 30f713b..9302b13 100644 --- a/psi.d/time.psi +++ b/psi.d/time.psi @@ -1,3 +1,4 @@ +// extern time_t time(time_t *t); function psi\time() : int { let t = NULL; return to_int(time); diff --git a/src/engine.c b/src/engine.c index 09dc429..6fba400 100644 --- a/src/engine.c +++ b/src/engine.c @@ -8,6 +8,8 @@ #include "php_psi.h" #include "zend_exceptions.h" +#include "zend_interfaces.h" +#include "ext/spl/spl_iterators.h" #include "parser.h" #include "engine.h" @@ -41,6 +43,43 @@ int psi_internal_type(impl_type *type) } } +zend_long psi_zval_count(zval *zvalue) +{ + /* mimic PHP count() */ + zend_long count; + zval retval; + + switch (Z_TYPE_P(zvalue)) { + default: + count = 1; + break; + case IS_NULL: + count = 0; + break; + case IS_ARRAY: + count = zend_array_count(Z_ARRVAL_P(zvalue)); + break; + case IS_OBJECT: + count = 1; + if (Z_OBJ_HT_P(zvalue)->count_elements) { + if (SUCCESS == Z_OBJ_HT_P(zvalue)->count_elements(zvalue, &count)) { + break; + } + } + + if (instanceof_function(Z_OBJCE_P(zvalue), spl_ce_Countable)) { + zend_call_method_with_0_params(zvalue, NULL, NULL, "count", &retval); + if (Z_TYPE(retval) != IS_UNDEF) { + count = zval_get_long(&retval); + zval_ptr_dtor(&retval); + } + } + break; + } + + return count; +} + zend_internal_arg_info *psi_internal_arginfo(impl *impl) { size_t i; @@ -251,29 +290,14 @@ static inline void *psi_let_val(let_val *val, decl_arg *darg) break; } - if (val && val->flags.one.is_reference) { + if (val && val->is_reference) { return darg->let = &darg->ptr; } else { return darg->let = darg->ptr; } } -static void marshal_func(void *cb_ctx, impl_val **ptr, decl_arg *spec, token_t cast, zval *zv, void **tmp) { - let_vals *vals = cb_ctx; - size_t i; - - for (i = 0; i < vals->count; ++i) { - impl_var *var = locate_let_val_impl_var(vals->vals[i]); - - if (!strcmp(&var->name[1], spec->var->name)) { - *ptr = psi_let_val(vals->vals[i], spec); - *tmp = spec->mem; - break; - } - } -} - -static inline impl_val *psi_let_func_ex(let_func *func, void *dptr, decl_type *dtype, token_t itype, impl_val *ival, zval *zvalue, void **to_free) { +static inline impl_val *psi_let_func_ex(let_func *func, void *dptr, decl_type *dtype, decl_var *dvar, token_t itype, impl_val *ival, zval *zvalue, void **to_free) { switch (func->type) { case PSI_T_BOOLVAL: return psi_let_boolval(dptr, dtype, itype, ival, zvalue, to_free); @@ -293,19 +317,78 @@ static inline impl_val *psi_let_func_ex(let_func *func, void *dptr, decl_type *d return psi_let_zval(dptr, dtype, itype, ival, zvalue, to_free); case PSI_T_VOID: return psi_let_void(dptr, dtype, itype, ival, zvalue, to_free); - break; + case PSI_T_COUNT: + return psi_let_count(dptr, dtype, itype, ival, zvalue, to_free); case PSI_T_ARRVAL: if (func->inner) { - decl_type *real = real_decl_type(dtype); + char *mem = NULL; + size_t i, j = 0; + decl_type *real; + decl_args *args = extract_decl_type_args(dtype, &real); if (itype != PSI_T_ARRAY) { SEPARATE_ARG_IF_REF(zvalue); convert_to_array(zvalue); } - return *to_free = psi_array_to_struct_ex(real->real.strct, Z_ARRVAL_P(zvalue), marshal_func, func->inner); + if (args) { + size_t size = extract_decl_type_size(real, NULL); + + mem = ecalloc(1, size + args->count * sizeof(void *)); + + for (i = 0; i < args->count; ++i) { + decl_arg *darg = args->args[i]; + let_val *lval = locate_let_vals_val(func->inner, darg->var->name); + impl_val *ptr = NULL; + + if (lval) { + if ((ptr = psi_let_val(lval, darg))) { + memcpy(mem + darg->layout->pos, ptr, darg->layout->len); + if (darg->mem) { + ((void **)(mem + size))[j++] = darg->mem; + } + } + if (real->type == PSI_T_UNION) { + break; + } + } + } + } else { + zval *zv; + let_val *inner = func->inner->vals[0]; + decl_var *sub_var; + size_t size; + + if (inner->var) { + sub_var = inner->var; + } else { + sub_var = copy_decl_var(dvar); + assert(sub_var->pointer_level); + --sub_var->pointer_level; + } + + size = sub_var->pointer_level ? SIZEOF_VOID_P : extract_decl_type_size(real, NULL); + mem = ecalloc(1, size * (1 + zend_array_count(Z_ARRVAL_P(zvalue)))); + + ZEND_HASH_FOREACH_VAL_IND(Z_ARRVAL_P(zvalue), zv) + { + void *tmp = NULL; + impl_val val = {0}, *ptr, *sub; + + ptr = psi_let_func_ex(inner->data.func, &val, real, dvar, 0, NULL, zv, &tmp); + sub = deref_impl_val(ptr, sub_var); + + memcpy(&mem[size * j++], &sub, size); + } + ZEND_HASH_FOREACH_END(); + + if (sub_var != inner->var) { + free_decl_var(sub_var); + } + } + return *to_free = mem; } else { - return psi_let_arrval(dptr, dtype, itype, ival, zvalue, to_free); + return psi_let_arrval(dptr, dtype, dvar, itype, ival, zvalue, to_free); } break; default: @@ -315,25 +398,41 @@ static inline impl_val *psi_let_func_ex(let_func *func, void *dptr, decl_type *d } static inline impl_val *psi_let_func(let_func *func, decl_arg *darg) { - impl_arg *iarg = func->var->arg; - if (func->outer && !iarg) { - impl_arg *outer_arg = locate_let_val_impl_var(func->outer)->arg; - iarg = init_impl_arg( + if (func->var->arg) { + return darg->ptr = psi_let_func_ex(func, + darg->ptr, darg->type, darg->var, + func->var->arg->type->type, + &func->var->arg->val, + func->var->arg->_zv, + &darg->mem); + } else { + impl_var *ivar = locate_let_val_impl_var(func->outer); + zval *entry = zend_symtable_str_find(Z_ARRVAL_P(ivar->arg->_zv), func->var->name+1, strlen(func->var->name)-1); + impl_arg *iarg = init_impl_arg( init_impl_type(PSI_T_MIXED, "mixed"), copy_impl_var(func->var), NULL); + func->var->arg = iarg; + if (entry) { + iarg->_zv = entry; + } else { + zval ztmp; - if (!(iarg->_zv = zend_hash_str_find(Z_ARRVAL_P(outer_arg->_zv), &iarg->var->name[1], strlen(iarg->var->name)-1))) { - iarg->_zv = zend_hash_str_add_empty_element(Z_ARRVAL_P(outer_arg->_zv), &iarg->var->name[1], strlen(iarg->var->name)-1); + ZVAL_NULL(&ztmp); + iarg->_zv = zend_symtable_str_update_ind(Z_ARRVAL_P(ivar->arg->_zv), func->var->name+1, strlen(func->var->name)-1, &ztmp); } + + psi_let_func(func, darg); + free_impl_arg(iarg); + return darg->ptr; } - return darg->ptr = psi_let_func_ex(func, darg->ptr, darg->type, iarg->type->type, &iarg->val, iarg->_zv, &darg->mem); + } static inline void *psi_do_let(let_stmt *let) { - return psi_let_val(let->val, let->var->arg); + return psi_let_val(let->val, let->val->var->arg); } static inline void psi_do_return(zval *return_value, return_stmt *ret) @@ -365,7 +464,6 @@ static inline void psi_clean_array_struct(let_val *val, decl_arg *darg) { if (val->kind == PSI_LET_FUNC && val->data.func->type == PSI_T_ARRVAL) { decl_type *type = real_decl_type(darg->type); - decl_args *args = NULL; if (type->type == PSI_T_STRUCT) { void **ptr = (void **) ((char *) darg->mem + type->real.strct->size); @@ -373,15 +471,16 @@ static inline void psi_clean_array_struct(let_val *val, decl_arg *darg) { while (*ptr) { efree(*ptr++); } - args = type->real.strct->args; + // args = type->real.strct->args; } else if (type->type == PSI_T_UNION) { void **ptr = (void **) ((char *) darg->mem + type->real.unn->size); if (*ptr) { efree(*ptr); } - args = type->real.unn->args; + // args = type->real.unn->args; } +#if 0 if (args && val->data.func->inner) { size_t i; @@ -392,13 +491,40 @@ static inline void psi_clean_array_struct(let_val *val, decl_arg *darg) { if (subarg) { psi_clean_array_struct(val->data.func->inner->vals[i], subarg); - if (subarg && subarg->mem) { + if (subarg->mem) { efree(subarg->mem); subarg->mem = NULL; } } } } +#endif + } +} + +static inline void psi_clean_let_val(let_val *val) { + + let_func *func = locate_let_val_func(val); + + if (func && func->inner) { + size_t i; + + for (i = 0; i < func->inner->count; ++i) { + let_val *inner = func->inner->vals[i]; + psi_clean_let_val(inner); + } + } + if (val->var) { + decl_arg *darg = val->var->arg; + if (darg) { + if (darg->mem) { + psi_clean_array_struct(val, darg); + efree(darg->mem); + darg->mem = NULL; + } + darg->ptr = &darg->val; + darg->let = darg->ptr; + } } } @@ -433,15 +559,7 @@ static inline void psi_do_clean(impl *impl) for (i = 0; i < impl->stmts->let.count; ++i) { let_stmt *let = impl->stmts->let.list[i]; - decl_arg *darg = let->var->arg; - - if (darg->mem) { - psi_clean_array_struct(let->val, darg); - efree(darg->mem); - darg->mem = NULL; - } - darg->ptr = &darg->val; - darg->let = darg->ptr; + psi_clean_let_val(let->val); } if (impl->func->args->vararg.args) { @@ -477,14 +595,16 @@ static inline void psi_do_args(impl *impl) { } if (!impl->decl->func->var->pointer_level) { - decl_type *real = real_decl_type(impl->decl->func->type); + decl_type *real; + decl_args *args = extract_decl_type_args(impl->decl->func->type, &real); switch (real->type) { case PSI_T_STRUCT: - impl->decl->func->ptr = psi_array_to_struct(real->real.strct, NULL); - break; case PSI_T_UNION: - impl->decl->func->ptr = psi_array_to_union(real->real.unn, NULL); + impl->decl->func->ptr = ecalloc(1, + extract_decl_type_size(real, NULL) + args->count * sizeof(void*)); + break; + default: break; } } @@ -631,7 +751,7 @@ ZEND_RESULT_CODE psi_callback(let_callback *cb, void *retval, unsigned argc, voi case PSI_T_STRING: zend_parse_arg_str(iarg->_zv, &iarg->val.zend.str, 0); break; } */ - result = psi_let_func_ex(cb->func, retval, decl_cb->func->type, 0, &iarg->val, iarg->_zv, &to_free); + result = psi_let_func_ex(cb->func, retval, decl_cb->func->type, decl_cb->func->var, 0, &iarg->val, iarg->_zv, &to_free); // result = cb->func->handler(retval, decl_cb->func->type, iarg, &to_free); if (result != retval) { diff --git a/src/engine.h b/src/engine.h index d7891a2..624ddfb 100644 --- a/src/engine.h +++ b/src/engine.h @@ -4,6 +4,7 @@ int psi_internal_type(impl_type *type); zend_internal_arg_info *psi_internal_arginfo(impl *impl); size_t psi_num_min_args(impl *impl); +zend_long psi_zval_count(zval *zvalue); ZEND_RESULT_CODE psi_call(zend_execute_data *execute_data, zval *return_value, impl *impl); ZEND_RESULT_CODE psi_callback(let_callback *cb, void *retval, unsigned argc, void **argv); diff --git a/src/marshal.c b/src/marshal.c index 00c1a81..1e71a64 100644 --- a/src/marshal.c +++ b/src/marshal.c @@ -8,6 +8,7 @@ #include "php_psi.h" #include "parser.h" #include "marshal.h" +#include "engine.h" #include "calc.h" void psi_to_void(zval *return_value, set_value *set, impl_val *ret_val) @@ -244,11 +245,14 @@ impl_val *psi_let_strval(impl_val *tmp, decl_type *spec, token_t impl_type, impl { if (ival && impl_type == PSI_T_STRING) { if (ival->zend.str) { - tmp->ptr = estrndup(ival->zend.str->val, ival->zend.str->len); - *to_free = tmp->ptr; + /*tmp->ptr = estrndup(ival->zend.str->val, ival->zend.str->len); + *to_free = tmp->ptr;*/ + tmp->ptr = ival->zend.str->val; } else { tmp->ptr = ""; } + } else if (0 && Z_TYPE_P(zvalue) == IS_STRING) { + tmp->ptr = Z_STRVAL_P(zvalue); } else { zend_string *zs = zval_get_string(zvalue); tmp->ptr = estrdup(zs->val); @@ -290,7 +294,7 @@ impl_val *psi_let_strlen(impl_val *tmp, decl_type *spec, token_t impl_type, impl static impl_val *iterate(impl_val *val, size_t size, unsigned i, impl_val *tmp) { memset(tmp, 0, sizeof(*tmp)); - memcpy(tmp, ((void*) val) + size * i, size); + memcpy(tmp, ((char *) val) + size * i, size); return tmp; } @@ -472,7 +476,7 @@ void psi_to_array(zval *return_value, set_value *set, impl_val *r_val) /* to_array(foo[NUMBER]) */ for (i = 0; i < var->arg->var->array_size; ++i) { size_t size = psi_t_size(var->arg->var->pointer_level > 1 ? PSI_T_POINTER : t); - impl_val *ptr = iterate(ret_val, size, i, &tmp); + impl_val *ptr = iterate(ret_val->ptr, size, i, &tmp); zval ele; switch (t) { @@ -520,10 +524,13 @@ void psi_to_array(zval *return_value, set_value *set, impl_val *r_val) } } -impl_val *psi_let_arrval(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free) +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); @@ -538,12 +545,28 @@ impl_val *psi_let_arrval(impl_val *tmp, decl_type *spec, token_t impl_type, impl case PSI_T_UNION: *to_free = tmp = psi_array_to_union(real->real.unn, arr); break; - EMPTY_SWITCH_DEFAULT_CASE(); + 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; } +impl_val *psi_let_count(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free) +{ + return psi_val_intval(tmp, real_decl_type(spec)->type, psi_zval_count(zvalue)); +} + + void psi_to_object(zval *return_value, set_value *set, impl_val *r_val) { decl_var *var = set->vars->vars[0]; diff --git a/src/marshal.h b/src/marshal.h index c1d3de8..bf9267d 100644 --- a/src/marshal.h +++ b/src/marshal.h @@ -24,15 +24,15 @@ void psi_from_zval_ex(void *cb_ctx, impl_val **ptr, decl_arg *spec, token_t cast void *psi_array_to_struct_ex(decl_struct *s, HashTable *arr, psi_marshal_zval cb, void *cb_ctx); void *psi_array_to_union_ex(decl_union *u, HashTable *arr, psi_marshal_zval cb, void *cb_ctx); -impl_val *psi_let_void(impl_val *tmp, decl_type *decl_type, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free); -impl_val *psi_let_boolval(impl_val *tmp, decl_type *decl_type, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free); -impl_val *psi_let_intval(impl_val *tmp, decl_type *decl_type, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free); -impl_val *psi_let_floatval(impl_val *tmp, decl_type *decl_type, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free); -impl_val *psi_let_strval(impl_val *tmp, decl_type *decl_type, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free); -impl_val *psi_let_pathval(impl_val *tmp, decl_type *decl_type, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free); -impl_val *psi_let_strlen(impl_val *tmp, decl_type *decl_type, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free); -impl_val *psi_let_arrval(impl_val *tmp, decl_type *decl_type, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free); -impl_val *psi_let_objval(impl_val *tmp, decl_type *decl_type, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free); -impl_val *psi_let_zval(impl_val *tmp, decl_type *decl_type, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free); - +impl_val *psi_let_void(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free); +impl_val *psi_let_boolval(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free); +impl_val *psi_let_intval(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free); +impl_val *psi_let_floatval(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free); +impl_val *psi_let_strval(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free); +impl_val *psi_let_pathval(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free); +impl_val *psi_let_strlen(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free); +impl_val *psi_let_arrval(impl_val *tmp, decl_type *spec, decl_var *spec_var, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free); +impl_val *psi_let_objval(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free); +impl_val *psi_let_zval(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free); +impl_val *psi_let_count(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free); #endif diff --git a/src/parser.re b/src/parser.re index dcc76e3..48e90ed 100644 --- a/src/parser.re +++ b/src/parser.re @@ -91,7 +91,7 @@ ssize_t psi_parser_fill(struct psi_parser *P, size_t n) } } if (P->flags & PSI_PARSER_DEBUG) { - fprintf(stderr, "PSI> Fill: avail=%zd\n", P->lim - P->cur); + fprintf(stderr, "PSI> Fill: avail=%td\n", P->lim - P->cur); } return P->lim - P->cur; } @@ -171,7 +171,7 @@ token_t psi_parser_scan(struct psi_parser *P) W = [a-zA-Z0-9_]; NAME = [a-zA-Z_]W*; NSNAME = (NAME)? ("\\" NAME)+; - DOLLAR_NAME = '$' NAME; + DOLLAR_NAME = '$' W+; QUOTED_STRING = "\"" ([^\"])+ "\""; NUMBER = [+-]? [0-9]* "."? [0-9]+ ([eE] [+-]? [0-9]+)?; @@ -243,6 +243,7 @@ token_t psi_parser_scan(struct psi_parser *P) 'ARRVAL' {RETURN(PSI_T_ARRVAL);} 'OBJVAL' {RETURN(PSI_T_OBJVAL);} 'ZVAL' {RETURN(PSI_T_ZVAL);} + 'COUNT' {RETURN(PSI_T_COUNT);} 'CALLOC' {RETURN(PSI_T_CALLOC);} 'TO_OBJECT' {RETURN(PSI_T_TO_OBJECT);} 'TO_ARRAY' {RETURN(PSI_T_TO_ARRAY);} diff --git a/src/parser_def.h b/src/parser_def.h index af3ea8a..42106b2 100644 --- a/src/parser_def.h +++ b/src/parser_def.h @@ -4,7 +4,7 @@ #ifdef GENERATE #define DEF(dn, dv) dn dv -#define LET(nt, rule) nt ::= rule. +#define PASS(nt, rule) nt ::= rule. #define PARSE(nt, rule) nt ::= rule. #define PARSE_NAMED(nt, nt_name, rule) NAMED(nt, nt_name) ::= rule. #define PARSE_TYPED(nt, nt_name, rule) TYPED(nt, nt_name) ::= rule. @@ -18,7 +18,10 @@ #include "parser.h" #endif #define DEF(dn, dv) -#define LET(nt, rule) +#define PASS(nt, rule) \ + static void COUNTED(nt) (struct psi_parser *P) { \ + (void) #rule; \ + } #define PARSE(nt, rule) \ static void COUNTED(nt) (struct psi_parser *P rule) #define PARSE_NAMED(nt, nt_name, rule) \ @@ -28,7 +31,7 @@ #define TOKEN(t) #define NAMED(t, name) , struct psi_token *name #define TYPED(t, name) , TOKEN_TYPE_NAME(t) name -#define TOKEN_TYPE_NAME(token) _##token##_type +#define TOKEN_TYPE_NAME(token) ##token##_parse_t #define TOKEN_TYPE(token, type) typedef type TOKEN_TYPE_NAME(token); #define TOKEN_DTOR(token, dtor) #endif @@ -52,15 +55,16 @@ DEF(%syntax_error, { DEF(%nonassoc, NAME.) DEF(%left, PLUS MINUS.) -DEF(%left, SLASH ASTERISK.) -DEF(%fallback, NAME TEMP FREE SET LET RETURN CALLOC CALLBACK ZVAL LIB STRING.) +DEF(%left, ASTERISK SLASH.) +DEF(%nonassoc, AMPERSAND.) +DEF(%fallback, NAME TEMP FREE SET LET RETURN CALLOC CALLBACK ZVAL LIB STRING COUNT.) DEF(%token_class, const_type_token BOOL INT FLOAT STRING.) DEF(%token_class, decl_type_token FLOAT DOUBLE INT8 UINT8 INT16 UINT16 INT32 UINT32 INT64 UINT64 NAME.) DEF(%token_class, impl_def_val_token NULL NUMBER TRUE FALSE QUOTED_STRING.) DEF(%token_class, num_exp_token NUMBER NSNAME.) DEF(%token_class, num_exp_op_token PLUS MINUS ASTERISK SLASH.) -DEF(%token_class, let_func_token ZVAL OBJVAL ARRVAL PATHVAL STRLEN STRVAL FLOATVAL INTVAL BOOLVAL.) +DEF(%token_class, let_func_token ZVAL OBJVAL ARRVAL PATHVAL STRLEN STRVAL FLOATVAL INTVAL BOOLVAL COUNT.) DEF(%token_class, set_func_token TO_OBJECT TO_ARRAY TO_STRING TO_INT TO_FLOAT TO_BOOL ZVAL VOID.) DEF(%token_class, impl_type_token VOID MIXED BOOL INT FLOAT STRING ARRAY OBJECT CALLABLE.) @@ -173,12 +177,12 @@ TOKEN_TYPE(reference, char) TOKEN_TYPE(indirection, unsigned) TOKEN_TYPE(pointers, unsigned) -LET(file, blocks) -LET(blocks, block) -LET(blocks, blocks block) +PASS(file, blocks) +PASS(blocks, block) +PASS(blocks, blocks block) -LET(block, EOF) -LET(block, EOS) +PASS(block, EOF) +PASS(block, EOS) PARSE(block, NAMED(LIB, token) NAMED(QUOTED_STRING, libname) TOKEN(EOS)) { if (P->psi.file.ln) { @@ -537,20 +541,32 @@ PARSE_TYPED(decl_abi, abi, } PARSE_TYPED(decl_var, var, - TYPED(indirection, p) - NAMED(NAME, T)) { - var = init_decl_var(T->text, p, 0); + NAMED(NAME, T) + NAMED(decl_var_array_size, as)) { + var = init_decl_var(T->text, 0, as?atol(as->text):0); var->token = T; + if (as) { + free(as); + } } PARSE_TYPED(decl_var, var, - TYPED(indirection, p) + TYPED(pointers, p) NAMED(NAME, T) + NAMED(decl_var_array_size, as)) { + var = init_decl_var(T->text, p+!!as, as?atol(as->text):0); + var->token = T; + if (as) { + free(as); + } +} +PARSE_NAMED(decl_var_array_size, as, ) { + as = NULL; +} +PARSE_NAMED(decl_var_array_size, as, TOKEN(LBRACKET) NAMED(NUMBER, D) TOKEN(RBRACKET)) { - var = init_decl_var(T->text, p+1, atol(D->text)); - var->token = T; - free(D); + as = D; } PARSE_TYPED(decl_vars, vars, @@ -620,8 +636,8 @@ PARSE_TYPED(decl_arg, arg_, arg_->token = N; } -LET(decl_args, ) -LET(decl_args, VOID) +PASS(decl_args, ) +PASS(decl_args, VOID) PARSE_TYPED(decl_args, args, TYPED(decl_arg, arg)) { args = init_decl_args(arg); @@ -965,38 +981,153 @@ PARSE_TYPED(num_exp, exp, free(operator_); } +TOKEN_TYPE(let_exp, let_val*) +TOKEN_DTOR(let_exp, free_let_val($$);) + +TOKEN_TYPE(let_callback, let_callback*) +TOKEN_DTOR(let_callback, free_let_callback($$);) + +/* + * let_val: NULL + */ +PARSE_TYPED(let_val, val, + TOKEN(NULL)) { + val = init_let_val(PSI_LET_NULL, NULL); +} +/* + * let_val: &NULL + */ +PARSE_TYPED(let_val, val, + TOKEN(AMPERSAND) + TOKEN(NULL)) { + val = init_let_val(PSI_LET_NULL, NULL); + val->is_reference = 1; +} +/* + * let_val: callback + */ +PARSE_TYPED(let_val, val, + TYPED(let_callback, cb)) { + val = init_let_val(PSI_LET_CALLBACK, cb); +} +/* + * let_val: calloc + */ +PARSE_TYPED(let_val, val, + TYPED(let_calloc, ca)) { + val = init_let_val(PSI_LET_CALLOC, ca); +} +/* + * let_val: &calloc + */ +PARSE_TYPED(let_val, val, + TOKEN(AMPERSAND) + TYPED(let_calloc, ca)) { + val = init_let_val(PSI_LET_CALLOC, ca); + val->is_reference = 1; +} +/* + * let_val: func + */ +PARSE_TYPED(let_val, val, + TYPED(let_func, fn)) { + val = init_let_val_ex(NULL, PSI_LET_FUNC, fn); +} +/* + * let_val: &func + */ +PARSE_TYPED(let_val, val, + TOKEN(AMPERSAND) + TYPED(let_func, fn)) { + val = init_let_val_ex(NULL, PSI_LET_FUNC, fn); + val->is_reference = 1; +} +/* + * let_val: 1234 + */ +PARSE_TYPED(let_val, val, + TYPED(num_exp, exp)) { + val = init_let_val_ex(NULL, PSI_LET_NUMEXP, exp); +} +/* + * let_val: &1234 + */ +PARSE_TYPED(let_val, val, + TOKEN(AMPERSAND) + TYPED(num_exp, exp)) { + val = init_let_val_ex(NULL, PSI_LET_NUMEXP, exp); + val->is_reference = 1; +} + +/* + * let_exp: var = val + */ +PARSE_TYPED(let_exp, exp, + TYPED(decl_var, var_) + TOKEN(EQUALS) + TYPED(let_val, val)) { + exp = val; + exp->var = var_; +} + +/* + * let_stmt: LET exp ; + */ PARSE_TYPED(let_stmt, let, - TOKEN(LET) - TYPED(decl_var, var) + NAMED(LET, T) + TYPED(let_exp, val) TOKEN(EOS)) { - let = init_let_stmt(var, init_let_val(PSI_LET_NULL, NULL)); + let = init_let_stmt(val); + let->token = T; } + +/* + * let_stmt: TEMP foo = bar ; + */ PARSE_TYPED(let_stmt, let, - TOKEN(LET) + NAMED(TEMP, T) TYPED(decl_var, var) TOKEN(EQUALS) TYPED(reference, r) - TYPED(let_val, val) + TYPED(decl_var, val_) TOKEN(EOS)) { - val->flags.one.is_reference = r ? 1 : 0; - let = init_let_stmt(var, val); + let = init_let_stmt(init_let_val_ex(var, PSI_LET_TMP, val_)); + let->token = T; + let->val->is_reference = r ? 1 : 0; } -PARSE_TYPED(let_stmt, let, - TOKEN(TEMP) - TYPED(decl_var, var) - TOKEN(EQUALS) - TYPED(decl_var, val) - TOKEN(EOS)) { - let = init_let_stmt(var, init_let_val(PSI_LET_TMP, val)); + +/* + * let_callback: CALLBACK cast($var($args)) + */ +PARSE_TYPED(let_callback, cb, + TOKEN(CALLBACK) + NAMED(callback_rval, F) + TOKEN(LPAREN) + TYPED(impl_var, var) + TOKEN(LPAREN) + TYPED(callback_arg_list, args_) + TOKEN(RPAREN) + TOKEN(RPAREN)) { + cb = init_let_callback(init_let_func(F->type, F->text, var), args_); + free(F); } +/* + * let_calloc: CALLOC ( num_exp nmemb , num_exp size ) + */ PARSE_TYPED(let_calloc, alloc, + TOKEN(CALLOC) + TOKEN(LPAREN) TYPED(num_exp, nmemb) TOKEN(COMMA) - TYPED(num_exp, size)) { + TYPED(num_exp, size) + TOKEN(RPAREN)) { alloc = init_let_calloc(nmemb, size); } +/* + * let_func: FUNC ( $var ) + */ PARSE_TYPED(let_func, func, NAMED(let_func_token, T) TOKEN(LPAREN) @@ -1005,18 +1136,9 @@ PARSE_TYPED(let_func, func, func = init_let_func(T->type, T->text, var); free(T); } - -PARSE_TYPED(let_vals, vals, - TYPED(let_val, val)) { - vals = init_let_vals(val); -} -PARSE_TYPED(let_vals, vals, - TYPED(let_vals, vals_) - TOKEN(COMMA) - TYPED(let_val, val)) { - vals = add_let_val(vals_, val); -} - +/* + * let_func: FUNC ( $var (,exps)? ) + */ PARSE_TYPED(let_func, func, NAMED(let_func_token, T) TOKEN(LPAREN) @@ -1028,8 +1150,34 @@ PARSE_TYPED(let_func, func, func->inner = vals; free(T); } +/* + * let_vals: exps = exp + */ +PARSE_TYPED(let_vals, vals, + TYPED(let_exp, val)) { + vals = init_let_vals(val); +} +PARSE_TYPED(let_vals, vals, + TYPED(let_val, val)) { + vals = init_let_vals(val); +} +/* + * let_vals: exps = exps, exp + */ +PARSE_TYPED(let_vals, vals, + TYPED(let_vals, vals_) + TOKEN(COMMA) + TYPED(let_exp, val)) { + vals = add_let_val(vals_, val); +} +PARSE_TYPED(let_vals, vals, + TYPED(let_vals, vals_) + TOKEN(COMMA) + TYPED(let_val, val)) { + vals = add_let_val(vals_, val); +} -LET(callback_arg_list, ) +PASS(callback_arg_list, ) PARSE_TYPED(callback_arg_list, args, TYPED(callback_args, args_)) { args = args_; @@ -1054,39 +1202,6 @@ PARSE_NAMED(callback_rval, rval, rval = V; } -PARSE_TYPED(let_val, val, - TOKEN(NULL)) { - val = init_let_val(PSI_LET_NULL, NULL); -} -PARSE_TYPED(let_val, val, - TYPED(num_exp, exp)) { - val = init_let_val(PSI_LET_NUMEXP, exp); -} -PARSE_TYPED(let_val, val, - TOKEN(CALLOC) - TOKEN(LPAREN) - TYPED(let_calloc, alloc) - TOKEN(RPAREN)) { - val = init_let_val(PSI_LET_CALLOC, alloc); -} -PARSE_TYPED(let_val, val, - TYPED(let_func, func_)) { - val = init_let_val(PSI_LET_FUNC, func_); -} -PARSE_TYPED(let_val, val, - TOKEN(CALLBACK) - NAMED(callback_rval, F) - TOKEN(LPAREN) - TYPED(impl_var, var) - TOKEN(LPAREN) - TYPED(callback_arg_list, args_) - TOKEN(RPAREN) - TOKEN(RPAREN)) { - val = init_let_val(PSI_LET_CALLBACK, init_let_callback( - init_let_func(F->type, F->text, var), args_)); - free(F); -} - PARSE_TYPED(set_stmt, set, TOKEN(SET) TYPED(impl_var, var) diff --git a/src/parser_proc.h b/src/parser_proc.h index 2acef5a..ff30cc1 100644 --- a/src/parser_proc.h +++ b/src/parser_proc.h @@ -1,77 +1,78 @@ #define PSI_T_NAME 1 #define PSI_T_PLUS 2 #define PSI_T_MINUS 3 -#define PSI_T_SLASH 4 -#define PSI_T_ASTERISK 5 -#define PSI_T_TEMP 6 -#define PSI_T_FREE 7 -#define PSI_T_SET 8 -#define PSI_T_LET 9 -#define PSI_T_RETURN 10 -#define PSI_T_CALLOC 11 -#define PSI_T_CALLBACK 12 -#define PSI_T_ZVAL 13 -#define PSI_T_LIB 14 -#define PSI_T_STRING 15 -#define PSI_T_BOOL 16 -#define PSI_T_INT 17 -#define PSI_T_FLOAT 18 -#define PSI_T_DOUBLE 19 -#define PSI_T_INT8 20 -#define PSI_T_UINT8 21 -#define PSI_T_INT16 22 -#define PSI_T_UINT16 23 -#define PSI_T_INT32 24 -#define PSI_T_UINT32 25 -#define PSI_T_INT64 26 -#define PSI_T_UINT64 27 -#define PSI_T_NULL 28 -#define PSI_T_NUMBER 29 -#define PSI_T_TRUE 30 -#define PSI_T_FALSE 31 -#define PSI_T_QUOTED_STRING 32 -#define PSI_T_NSNAME 33 -#define PSI_T_OBJVAL 34 -#define PSI_T_ARRVAL 35 -#define PSI_T_PATHVAL 36 -#define PSI_T_STRLEN 37 -#define PSI_T_STRVAL 38 -#define PSI_T_FLOATVAL 39 -#define PSI_T_INTVAL 40 -#define PSI_T_BOOLVAL 41 -#define PSI_T_TO_OBJECT 42 -#define PSI_T_TO_ARRAY 43 -#define PSI_T_TO_STRING 44 -#define PSI_T_TO_INT 45 -#define PSI_T_TO_FLOAT 46 -#define PSI_T_TO_BOOL 47 -#define PSI_T_VOID 48 -#define PSI_T_MIXED 49 -#define PSI_T_ARRAY 50 -#define PSI_T_OBJECT 51 -#define PSI_T_CALLABLE 52 -#define PSI_T_EOF 53 -#define PSI_T_EOS 54 -#define PSI_T_ENUM 55 -#define PSI_T_LBRACE 56 -#define PSI_T_RBRACE 57 -#define PSI_T_COMMA 58 -#define PSI_T_EQUALS 59 -#define PSI_T_UNION 60 -#define PSI_T_STRUCT 61 -#define PSI_T_COLON 62 -#define PSI_T_LPAREN 63 -#define PSI_T_RPAREN 64 -#define PSI_T_CONST 65 -#define PSI_T_TYPEDEF 66 -#define PSI_T_LBRACKET 67 -#define PSI_T_RBRACKET 68 -#define PSI_T_ELLIPSIS 69 -#define PSI_T_CHAR 70 -#define PSI_T_SHORT 71 -#define PSI_T_LONG 72 -#define PSI_T_UNSIGNED 73 -#define PSI_T_SIGNED 74 -#define PSI_T_FUNCTION 75 -#define PSI_T_DOLLAR_NAME 76 -#define PSI_T_AMPERSAND 77 +#define PSI_T_ASTERISK 4 +#define PSI_T_SLASH 5 +#define PSI_T_AMPERSAND 6 +#define PSI_T_TEMP 7 +#define PSI_T_FREE 8 +#define PSI_T_SET 9 +#define PSI_T_LET 10 +#define PSI_T_RETURN 11 +#define PSI_T_CALLOC 12 +#define PSI_T_CALLBACK 13 +#define PSI_T_ZVAL 14 +#define PSI_T_LIB 15 +#define PSI_T_STRING 16 +#define PSI_T_COUNT 17 +#define PSI_T_BOOL 18 +#define PSI_T_INT 19 +#define PSI_T_FLOAT 20 +#define PSI_T_DOUBLE 21 +#define PSI_T_INT8 22 +#define PSI_T_UINT8 23 +#define PSI_T_INT16 24 +#define PSI_T_UINT16 25 +#define PSI_T_INT32 26 +#define PSI_T_UINT32 27 +#define PSI_T_INT64 28 +#define PSI_T_UINT64 29 +#define PSI_T_NULL 30 +#define PSI_T_NUMBER 31 +#define PSI_T_TRUE 32 +#define PSI_T_FALSE 33 +#define PSI_T_QUOTED_STRING 34 +#define PSI_T_NSNAME 35 +#define PSI_T_OBJVAL 36 +#define PSI_T_ARRVAL 37 +#define PSI_T_PATHVAL 38 +#define PSI_T_STRLEN 39 +#define PSI_T_STRVAL 40 +#define PSI_T_FLOATVAL 41 +#define PSI_T_INTVAL 42 +#define PSI_T_BOOLVAL 43 +#define PSI_T_TO_OBJECT 44 +#define PSI_T_TO_ARRAY 45 +#define PSI_T_TO_STRING 46 +#define PSI_T_TO_INT 47 +#define PSI_T_TO_FLOAT 48 +#define PSI_T_TO_BOOL 49 +#define PSI_T_VOID 50 +#define PSI_T_MIXED 51 +#define PSI_T_ARRAY 52 +#define PSI_T_OBJECT 53 +#define PSI_T_CALLABLE 54 +#define PSI_T_EOF 55 +#define PSI_T_EOS 56 +#define PSI_T_ENUM 57 +#define PSI_T_LBRACE 58 +#define PSI_T_RBRACE 59 +#define PSI_T_COMMA 60 +#define PSI_T_EQUALS 61 +#define PSI_T_UNION 62 +#define PSI_T_STRUCT 63 +#define PSI_T_COLON 64 +#define PSI_T_LPAREN 65 +#define PSI_T_RPAREN 66 +#define PSI_T_CONST 67 +#define PSI_T_TYPEDEF 68 +#define PSI_T_LBRACKET 69 +#define PSI_T_RBRACKET 70 +#define PSI_T_ELLIPSIS 71 +#define PSI_T_CHAR 72 +#define PSI_T_SHORT 73 +#define PSI_T_LONG 74 +#define PSI_T_UNSIGNED 75 +#define PSI_T_SIGNED 76 +#define PSI_T_FUNCTION 77 +#define PSI_T_DOLLAR_NAME 78 diff --git a/src/parser_proc.y b/src/parser_proc.y index 5813b42..a5696b5 100644 --- a/src/parser_proc.y +++ b/src/parser_proc.y @@ -22,14 +22,15 @@ %syntax_error { ++P->errors; if (TOKEN && TOKEN->type != PSI_T_EOF) { psi_error(PSI_WARNING, TOKEN->file, TOKEN->line, "PSI syntax error: Unexpected token '%s' at pos %u", TOKEN->text, TOKEN->col); } else { psi_error(PSI_WARNING, P->psi.file.fn, P->line, "PSI syntax error: Unexpected end of input"); } } %nonassoc NAME. %left PLUS MINUS. -%left SLASH ASTERISK. -%fallback NAME TEMP FREE SET LET RETURN CALLOC CALLBACK ZVAL LIB STRING. +%left ASTERISK SLASH. +%nonassoc AMPERSAND. +%fallback NAME TEMP FREE SET LET RETURN CALLOC CALLBACK ZVAL LIB STRING COUNT. %token_class const_type_token BOOL INT FLOAT STRING. %token_class decl_type_token FLOAT DOUBLE INT8 UINT8 INT16 UINT16 INT32 UINT32 INT64 UINT64 NAME. %token_class impl_def_val_token NULL NUMBER TRUE FALSE QUOTED_STRING. %token_class num_exp_token NUMBER NSNAME. %token_class num_exp_op_token PLUS MINUS ASTERISK SLASH. -%token_class let_func_token ZVAL OBJVAL ARRVAL PATHVAL STRLEN STRVAL FLOATVAL INTVAL BOOLVAL. +%token_class let_func_token ZVAL OBJVAL ARRVAL PATHVAL STRLEN STRVAL FLOATVAL INTVAL BOOLVAL COUNT. %token_class set_func_token TO_OBJECT TO_ARRAY TO_STRING TO_INT TO_FLOAT TO_BOOL ZVAL VOID. %token_class impl_type_token VOID MIXED BOOL INT FLOAT STRING ARRAY OBJECT CALLABLE. %type decl_enum {decl_enum *} @@ -376,14 +377,25 @@ decl_abi(abi) ::= NAME(T). { abi = init_decl_abi(T->text); abi->token = T; } -decl_var(var) ::= indirection(p) NAME(T). { - var = init_decl_var(T->text, p, 0); +decl_var(var) ::= NAME(T) decl_var_array_size(as). { + var = init_decl_var(T->text, 0, as?atol(as->text):0); var->token = T; + if (as) { + free(as); + } } -decl_var(var) ::= indirection(p) NAME(T) LBRACKET NUMBER(D) RBRACKET. { - var = init_decl_var(T->text, p+1, atol(D->text)); +decl_var(var) ::= pointers(p) NAME(T) decl_var_array_size(as). { + var = init_decl_var(T->text, p+!!as, as?atol(as->text):0); var->token = T; - free(D); + if (as) { + free(as); + } +} +decl_var_array_size(as) ::= . { + as = NULL; +} +decl_var_array_size(as) ::= LBRACKET NUMBER(D) RBRACKET. { + as = D; } decl_vars(vars) ::= decl_var(var). { vars = init_decl_vars(var); @@ -652,33 +664,81 @@ num_exp(exp) ::= num_exp(exp_) num_exp_op_token(operator_) num_exp(operand_). { exp = exp_; free(operator_); } -let_stmt(let) ::= LET decl_var(var) EOS. { - let = init_let_stmt(var, init_let_val(PSI_LET_NULL, NULL)); +%type let_exp {let_val*} +%destructor let_exp {free_let_val($$);} +%type let_callback {let_callback*} +%destructor let_callback {free_let_callback($$);} +let_val(val) ::= NULL. { + val = init_let_val(PSI_LET_NULL, NULL); +} +let_val(val) ::= AMPERSAND NULL. { + val = init_let_val(PSI_LET_NULL, NULL); + val->is_reference = 1; +} +let_val(val) ::= let_callback(cb). { + val = init_let_val(PSI_LET_CALLBACK, cb); +} +let_val(val) ::= let_calloc(ca). { + val = init_let_val(PSI_LET_CALLOC, ca); +} +let_val(val) ::= AMPERSAND let_calloc(ca). { + val = init_let_val(PSI_LET_CALLOC, ca); + val->is_reference = 1; } -let_stmt(let) ::= LET decl_var(var) EQUALS reference(r) let_val(val) EOS. { - val->flags.one.is_reference = r ? 1 : 0; - let = init_let_stmt(var, val); +let_val(val) ::= let_func(fn). { + val = init_let_val_ex(NULL, PSI_LET_FUNC, fn); } -let_stmt(let) ::= TEMP decl_var(var) EQUALS decl_var(val) EOS. { - let = init_let_stmt(var, init_let_val(PSI_LET_TMP, val)); +let_val(val) ::= AMPERSAND let_func(fn). { + val = init_let_val_ex(NULL, PSI_LET_FUNC, fn); + val->is_reference = 1; } -let_calloc(alloc) ::= num_exp(nmemb) COMMA num_exp(size). { +let_val(val) ::= num_exp(exp). { + val = init_let_val_ex(NULL, PSI_LET_NUMEXP, exp); +} +let_val(val) ::= AMPERSAND num_exp(exp). { + val = init_let_val_ex(NULL, PSI_LET_NUMEXP, exp); + val->is_reference = 1; +} +let_exp(exp) ::= decl_var(var_) EQUALS let_val(val). { + exp = val; + exp->var = var_; +} +let_stmt(let) ::= LET(T) let_exp(val) EOS. { + let = init_let_stmt(val); + let->token = T; +} +let_stmt(let) ::= TEMP(T) decl_var(var) EQUALS reference(r) decl_var(val_) EOS. { + let = init_let_stmt(init_let_val_ex(var, PSI_LET_TMP, val_)); + let->token = T; + let->val->is_reference = r ? 1 : 0; +} +let_callback(cb) ::= CALLBACK callback_rval(F) LPAREN impl_var(var) LPAREN callback_arg_list(args_) RPAREN RPAREN. { + cb = init_let_callback(init_let_func(F->type, F->text, var), args_); + free(F); +} +let_calloc(alloc) ::= CALLOC LPAREN num_exp(nmemb) COMMA num_exp(size) RPAREN. { alloc = init_let_calloc(nmemb, size); } let_func(func) ::= let_func_token(T) LPAREN impl_var(var) RPAREN. { func = init_let_func(T->type, T->text, var); free(T); } +let_func(func) ::= let_func_token(T) LPAREN impl_var(var) COMMA let_vals(vals) RPAREN. { + func = init_let_func(T->type, T->text, var); + func->inner = vals; + free(T); +} +let_vals(vals) ::= let_exp(val). { + vals = init_let_vals(val); +} let_vals(vals) ::= let_val(val). { vals = init_let_vals(val); } -let_vals(vals) ::= let_vals(vals_) COMMA let_val(val). { +let_vals(vals) ::= let_vals(vals_) COMMA let_exp(val). { vals = add_let_val(vals_, val); } -let_func(func) ::= let_func_token(T) LPAREN impl_var(var) COMMA let_vals(vals) RPAREN. { - func = init_let_func(T->type, T->text, var); - func->inner = vals; - free(T); +let_vals(vals) ::= let_vals(vals_) COMMA let_val(val). { + vals = add_let_val(vals_, val); } callback_arg_list ::= . callback_arg_list(args) ::= callback_args(args_). { @@ -696,23 +756,6 @@ callback_rval(rval) ::= let_func_token(F). { callback_rval(rval) ::= VOID(V). { rval = V; } -let_val(val) ::= NULL. { - val = init_let_val(PSI_LET_NULL, NULL); -} -let_val(val) ::= num_exp(exp). { - val = init_let_val(PSI_LET_NUMEXP, exp); -} -let_val(val) ::= CALLOC LPAREN let_calloc(alloc) RPAREN. { - val = init_let_val(PSI_LET_CALLOC, alloc); -} -let_val(val) ::= let_func(func_). { - val = init_let_val(PSI_LET_FUNC, func_); -} -let_val(val) ::= CALLBACK callback_rval(F) LPAREN impl_var(var) LPAREN callback_arg_list(args_) RPAREN RPAREN. { - val = init_let_val(PSI_LET_CALLBACK, init_let_callback( - init_let_func(F->type, F->text, var), args_)); - free(F); -} set_stmt(set) ::= SET impl_var(var) EQUALS set_value(val) EOS. { set = init_set_stmt(var, val); } diff --git a/src/types.h b/src/types.h index 7c4c896..97f00d4 100644 --- a/src/types.h +++ b/src/types.h @@ -57,7 +57,7 @@ static inline impl_val *deref_impl_val(impl_val *ret_val, decl_var *var) { unsigned i; - ZEND_ASSERT(var->arg->var != var); + ZEND_ASSERT(!var->arg || var->arg->var != var); #if 0 fprintf(stderr, "deref: %s pl=%u:%u as=%u:%u %p\n", var->name, var->pointer_level, var->arg->var->pointer_level, diff --git a/src/types/decl.c b/src/types/decl.c index eda2303..ef6bd6d 100644 --- a/src/types/decl.c +++ b/src/types/decl.c @@ -29,8 +29,14 @@ # include "php_config.h" #endif +#if __GNUC__ >= 5 +# pragma GCC diagnostic ignored "-Wdiscarded-qualifiers" +#endif #include "php_psi_macros.h" #include "php_psi_redirs.h" +#if __GNUC__ >= 5 +# pragma GCC diagnostic pop +#endif #include #include diff --git a/src/types/decl_type.c b/src/types/decl_type.c index 8e5f9e6..c7b19b6 100644 --- a/src/types/decl_type.c +++ b/src/types/decl_type.c @@ -71,6 +71,23 @@ decl_args *extract_decl_type_args(decl_type *dtyp, decl_type **real_typ_ptr) { } } +size_t extract_decl_type_size(decl_type *dtyp, decl_type **real_typ_ptr) { + decl_type *var_typ; + var_typ = real_decl_type(dtyp); + if (real_typ_ptr) { + *real_typ_ptr = var_typ; + } + switch (var_typ->type) { + case PSI_T_STRUCT: + return var_typ->real.strct->size; + case PSI_T_UNION: + return var_typ->real.unn->size; + default: + return psi_t_size(var_typ->type); + } +} + + int locate_decl_type_alias(decl_typedefs *defs, decl_type *type) { size_t i; @@ -244,7 +261,7 @@ int weak_decl_type(decl_type *type) { } decl_type *real_decl_type(decl_type *type) { - while (weak_decl_type(type)) { + while (weak_decl_type(type) && type->real.def) { type = type->real.def->type; } return type; diff --git a/src/types/decl_type.h b/src/types/decl_type.h index d7c01fb..4f88ef9 100644 --- a/src/types/decl_type.h +++ b/src/types/decl_type.h @@ -49,6 +49,8 @@ void free_decl_type(decl_type *type); void dump_decl_type(int fd, decl_type *t, unsigned level); struct decl_args *extract_decl_type_args(decl_type *dtyp, decl_type** real_typ_ptr); +size_t extract_decl_type_size(decl_type *dtyp, decl_type **real_typ_ptr); + int weak_decl_type(decl_type *type); decl_type *real_decl_type(decl_type *type); diff --git a/src/types/let_callback.c b/src/types/let_callback.c index 4c5809c..e1a6ac9 100644 --- a/src/types/let_callback.c +++ b/src/types/let_callback.c @@ -52,10 +52,6 @@ int validate_let_callback(struct psi_data *data, decl_var *cb_var, let_callback decl *cb_func; decl_type *cb_type = real_decl_type(cb_var->arg->type); - if (!validate_let_func(data, cb->func, cb_var, impl)) { - return 0; - } - if (cb_type->type != PSI_T_FUNCTION) { data->error(data, cb_var->token, PSI_WARNING, "Not a function: %s", cb_var->name); return 0; diff --git a/src/types/let_func.c b/src/types/let_func.c index d32b00b..42180ec 100644 --- a/src/types/let_func.c +++ b/src/types/let_func.c @@ -83,6 +83,7 @@ static inline int validate_let_func_type(struct psi_data *data, let_func *func, case PSI_T_OBJVAL: case PSI_T_ZVAL: case PSI_T_VOID: + case PSI_T_COUNT: return 1; default: data->error(data, func->var->token, PSI_WARNING, @@ -92,44 +93,66 @@ static inline int validate_let_func_type(struct psi_data *data, let_func *func, } } -static inline int validate_let_func_inner(struct psi_data *data, let_func *func, decl_var *let_var, impl *impl) { +static inline int validate_let_func_inner(struct psi_data *data, let_val *val, let_func *func, decl_var *let_var, impl *impl) { + if (func->inner) { size_t i; decl_type *var_typ; decl_args *sub_args = extract_decl_type_args(let_var->arg->type, &var_typ); - if (!sub_args) { - data->error(data, let_var->token, PSI_WARNING, - "Inner let statement's values must refer to a structure type," - " got '%s' for '%s'", - var_typ->name, let_var->name); - return 0; - } - - for (i = 0; i < func->inner->count; ++i) { - let_val *inner = func->inner->vals[i]; - let_val *outer = func->outer; - const char *name = locate_let_val_varname(inner); - decl_arg *sub_arg; - - if (name) { - sub_arg = locate_decl_arg(sub_args, name); + if (func->type == PSI_T_ARRVAL && sub_args) { + /* struct = arrval($array, + * member = strval($member) ...) + */ + size_t i; + + for (i = 0; i < func->inner->count; ++i) { + let_val *inner = func->inner->vals[i]; + const char *name = locate_let_val_varname(inner); + let_func *fn = locate_let_val_func(inner); + decl_arg *sub_arg; + + if (name) { + sub_arg = locate_decl_arg(sub_args, name); + } + if (!name || !sub_arg) { + data->error(data, let_var->token, PSI_WARNING, + "Unknown variable '%s'", name); + return 0; + } + + fn->outer = val; + fn->ref = sub_arg; + + if (!validate_let_val(data, inner, sub_arg->var, impl)) { + return 0; + } } - if (!name || !sub_arg) { - data->error(data, let_var->token, PSI_WARNING, - "Unknown variable '%s' of '%s'", - name, var_typ->real.strct->name); + } else if (func->type == PSI_T_ARRVAL && func->inner->count == 1 && let_var->arg->var->pointer_level) { + /* array = arrval($array, + * strval($array)) // cast foreach entry + */ + impl_var *sub_var = locate_let_val_impl_var(val); + impl_var *sub_ref = locate_let_val_impl_var(func->inner->vals[0]); + + if (strcmp(sub_var->name, sub_ref->name)) { + data->error(data, sub_var->token, E_WARNING, "Inner `set` statement casts on pointers must reference the same variable"); return 0; } - if (!validate_let_val(data, inner, sub_arg->var, impl)) { + if (!validate_let_val(data, func->inner->vals[0], let_var, impl)) { return 0; } + } else { + data->error(data, let_var->token, PSI_WARNING, + "Inner let statement's values must refer to a structure or array type, got '%s%s' for '%s'", + var_typ->name, psi_t_indirection(let_var->arg->var->pointer_level), let_var->name); + return 0; } } return 1; } -int validate_let_func(struct psi_data *data, let_func *func, decl_var *let_var, impl *impl) { +int validate_let_func(struct psi_data *data, let_val *val, let_func *func, decl_var *let_var, impl *impl) { if (func->outer) { } @@ -147,7 +170,7 @@ int validate_let_func(struct psi_data *data, let_func *func, decl_var *let_var, if (!validate_let_func_type(data, func, impl)) { return 0; } - if (!validate_let_func_inner(data, func, let_var, impl)) { + if (!validate_let_func_inner(data, val, func, let_var, impl)) { return 0; } return 1; diff --git a/src/types/let_func.h b/src/types/let_func.h index b02d20c..936c38d 100644 --- a/src/types/let_func.h +++ b/src/types/let_func.h @@ -46,7 +46,8 @@ void dump_let_func(int fd, let_func *func, unsigned level); struct psi_data; struct impl; +struct let_val; -int validate_let_func(struct psi_data *data, let_func *func, decl_var *let_var, struct impl *impl); +int validate_let_func(struct psi_data *data, struct let_val *val, let_func *func, decl_var *let_var, struct impl *impl); #endif diff --git a/src/types/let_stmt.c b/src/types/let_stmt.c index db24d10..5474ae2 100644 --- a/src/types/let_stmt.c +++ b/src/types/let_stmt.c @@ -34,30 +34,26 @@ #include "data.h" -let_stmt *init_let_stmt(decl_var *var, let_val *val) { +let_stmt *init_let_stmt(let_val *val) { let_stmt *let = calloc(1, sizeof(*let)); - let->var = var; let->val = val; + return let; } void free_let_stmt(let_stmt *stmt) { if (stmt->val) { - if (stmt->val->kind == PSI_LET_TMP && stmt->var->arg) { - free_decl_arg(stmt->var->arg); - } free_let_val(stmt->val); } - free_decl_var(stmt->var); + if (stmt->token) { + free(stmt->token); + } free(stmt); } void dump_let_stmt(int fd, let_stmt *let) { - dprintf(fd, "\tlet %s", let->var->name); - if (let->val) { - dprintf(fd, " = "); - dump_let_val(fd, let->val, 1, 1); - } + dprintf(fd, "\t%s ", let->val->kind == PSI_LET_TMP ? "temp" : "let"); + dump_let_val(fd, let->val, 1, 1); } int validate_let_stmts(struct psi_data *data, impl *impl) { @@ -73,7 +69,7 @@ int validate_let_stmts(struct psi_data *data, impl *impl) { if (let->val && let->val->kind == PSI_LET_TMP) { let_var = let->val->data.var; } else { - let_var = let->var; + let_var = let->val->var; } if (!locate_decl_var_arg(let_var, impl->decl->args, impl->decl->func)) { @@ -97,7 +93,7 @@ int validate_let_stmts(struct psi_data *data, impl *impl) { return 0; } - if (!validate_let_val(data, let->val, let->var, impl)) { + if (!validate_let_val(data, let->val, let->val->var, impl)) { return 0; } } @@ -109,7 +105,7 @@ int validate_let_stmts(struct psi_data *data, impl *impl) { for (j = 0; j < impl->stmts->let.count; ++j) { let_stmt *let = impl->stmts->let.list[j]; - if (!strcmp(let->var->name, darg->var->name)) { + if (!strcmp(let->val->var->name, darg->var->name)) { check = 1; break; } diff --git a/src/types/let_stmt.h b/src/types/let_stmt.h index 1ffd56e..3b6ab3c 100644 --- a/src/types/let_stmt.h +++ b/src/types/let_stmt.h @@ -30,11 +30,11 @@ #include "let_val.h" typedef struct let_stmt { - decl_var *var; + struct psi_token *token; let_val *val; } let_stmt; -let_stmt *init_let_stmt(decl_var *var, let_val *val); +let_stmt *init_let_stmt(let_val *val); void free_let_stmt(let_stmt *stmt); void dump_let_stmt(int fd, let_stmt *let); diff --git a/src/types/let_val.c b/src/types/let_val.c index 3be8e88..23b3afc 100644 --- a/src/types/let_val.c +++ b/src/types/let_val.c @@ -35,10 +35,17 @@ #include "data.h" +let_val *init_let_val_ex(decl_var *var, enum let_val_kind kind, void *data) { + let_val *val = init_let_val(kind, data); + val->var = var; + return val; +} + let_val *init_let_val(enum let_val_kind kind, void *data) { let_val *let = calloc(1, sizeof(*let)); switch (let->kind = kind) { case PSI_LET_NULL: + assert(!data); break; case PSI_LET_NUMEXP: let->data.num = data; @@ -78,11 +85,17 @@ void free_let_val(let_val *let) { free_let_func(let->data.func); break; case PSI_LET_TMP: + if (let->var->arg) { + free_decl_arg(let->var->arg); + } free_decl_var(let->data.var); break; default: assert(0); } + if (let->var) { + free_decl_var(let->var); + } free(let); } @@ -92,7 +105,13 @@ void dump_let_val(int fd, let_val *val, unsigned level, int last) { dprintf(fd, "%s", psi_t_indent(level)); } - dprintf(fd, "%s", val->flags.one.is_reference ? "&" : ""); + if (val->var) { + dump_decl_var(fd, val->var); + dprintf(fd, " = "); + } + if (val->is_reference) { + dprintf(fd, "&"); + } switch (val->kind) { case PSI_LET_NULL: @@ -152,7 +171,7 @@ int validate_let_val(struct psi_data *data, let_val *val, decl_var *let_var, imp case PSI_LET_TMP: if (!let_var) { data->error(data, NULL, PSI_WARNING, - "Ivalid let statement value of implementation '%s'", + "Ivalid temp statement value of implementation '%s'", impl->func->name); return 0; } @@ -188,85 +207,15 @@ int validate_let_val(struct psi_data *data, let_val *val, decl_var *let_var, imp impl->func->name); return 0; } - if (val->data.callback->func->inner) { - size_t i; - decl_type *var_typ = real_decl_type(let_var->arg->type); - decl_args *sub_args; - - switch (var_typ->type) { - case PSI_T_STRUCT: - sub_args = var_typ->real.strct->args; - break; - case PSI_T_UNION: - sub_args = var_typ->real.unn->args; - break; - default: - data->error(data, let_var->token, PSI_WARNING, - "Inner let statement's values must refer to a structure type, got '%s' for '%s'", - real_decl_type(let_var->arg->type)->name, let_var->name); - return 0; - } - for (i = 0; i < val->data.callback->func->inner->count; ++i) { - let_val *inner = val->data.callback->func->inner->vals[i]; - switch (inner->kind) { - case PSI_LET_FUNC: - inner->data.func->outer = val; - inner->data.func->ref = locate_decl_arg(sub_args, - &inner->data.func->var->name[1]); - break; - - break; - case PSI_LET_CALLBACK: - inner->data.callback->func->outer = val; - inner->data.callback->func->ref = locate_decl_arg(sub_args, - &inner->data.callback->func->var->name[1]); - break; - } - } + if (!validate_let_func(data, val, val->data.callback->func, let_var, impl)) { + return 0; } if (!validate_let_callback(data, let_var, val->data.callback, impl)) { return 0; } break; case PSI_LET_FUNC: - if (val->data.func->inner) { - size_t i; - decl_type *var_typ = real_decl_type(let_var->arg->type); - decl_args *sub_args; - - switch (var_typ->type) { - case PSI_T_STRUCT: - sub_args = var_typ->real.strct->args; - break; - case PSI_T_UNION: - sub_args = var_typ->real.unn->args; - break; - default: - data->error(data, let_var->token, PSI_WARNING, - "Inner let statement's values must refer to a structure type, got '%s' for '%s'", - real_decl_type(let_var->arg->type)->name, let_var->name); - return 0; - } - for (i = 0; i < val->data.func->inner->count; ++i) { - let_val *inner = val->data.func->inner->vals[i]; - switch (inner->kind) { - case PSI_LET_FUNC: - inner->data.func->outer = val; - inner->data.func->ref = locate_decl_arg(sub_args, - &inner->data.func->var->name[1]); - break; - case PSI_LET_CALLBACK: - inner->data.callback->func->outer = val; - inner->data.callback->func->ref = locate_decl_arg(sub_args, - &inner->data.callback->func->var->name[1]); - break; - } - } - } - - val->data.func->var; - - if (!validate_let_func(data, val->data.func, let_var, impl)) { + if (!validate_let_func(data, val, val->data.func, let_var, impl)) { return 0; } break; diff --git a/src/types/let_val.h b/src/types/let_val.h index c3b5f38..c741633 100644 --- a/src/types/let_val.h +++ b/src/types/let_val.h @@ -53,15 +53,12 @@ typedef struct let_val { let_func *func; decl_var *var; } data; - union { - struct { - unsigned is_reference:1; - } one; - unsigned all; - } flags; + unsigned is_reference:1; } let_val; + let_val* init_let_val(enum let_val_kind kind, void* data); +let_val* init_let_val_ex(decl_var *var, enum let_val_kind kind, void* data); void free_let_val(let_val* let); void dump_let_val(int fd, let_val *val, unsigned level, int last); @@ -70,42 +67,43 @@ struct impl; int validate_let_val(struct psi_data *data, let_val *val, decl_var *let_var, struct impl *impl); -static inline decl_arg *locate_let_val_inner_ref(let_val *val) { - decl_arg *ref = NULL; - - switch (val->kind) { - case PSI_LET_CALLBACK: - ref = val->data.callback->func->ref; - break; - case PSI_LET_FUNC: - ref = val->data.func->ref; - break; - default: - break; - } - return ref; -} -static inline impl_var *locate_let_val_impl_var(let_val *val) { +static inline let_func *locate_let_val_func(let_val *val) { if (val) { switch (val->kind) { case PSI_LET_CALLBACK: - return val->data.callback->func->var; + return val->data.callback->func; case PSI_LET_FUNC: - return val->data.func->var; + return val->data.func; default: break; } } + return NULL; } +static inline decl_arg *locate_let_val_inner_ref(let_val *val) { + let_func *fn = locate_let_val_func(val); + return fn ? fn->ref: NULL; +} + +static inline impl_var *locate_let_val_impl_var(let_val *val) { + let_func *fn = locate_let_val_func(val); + return fn ? fn->var : NULL; +} + static inline const char *locate_let_val_varname(let_val *val) { - impl_var *var = locate_let_val_impl_var(val); + impl_var *var; + + if (val->var) { + return val->var->name; + } + + var = locate_let_val_impl_var(val); if (var) { return &var->name[1]; } return NULL; } - #endif diff --git a/src/types/let_vals.h b/src/types/let_vals.h index 442ba59..01b1d84 100644 --- a/src/types/let_vals.h +++ b/src/types/let_vals.h @@ -37,4 +37,18 @@ let_vals *init_let_vals(struct let_val *val); let_vals *add_let_val(let_vals *vals, struct let_val *val); void free_let_vals(let_vals *vals); +static inline let_val *locate_let_vals_val(let_vals *vals, const char *name) { + size_t i; + + for (i = 0; i < vals->count; ++i) { + let_val *val = vals->vals[i]; + const char *var = locate_let_val_varname(val); + + if (!strcmp(var, name)) { + return val; + } + } + + return NULL; +} #endif diff --git a/src/types/set_stmt.c b/src/types/set_stmt.c index ad67340..8827063 100644 --- a/src/types/set_stmt.c +++ b/src/types/set_stmt.c @@ -100,9 +100,9 @@ int validate_set_stmts(struct psi_data *data, impl *impl) { /* check temp vars */ if (let->val && let->val->kind == PSI_LET_TMP) { - if (!strcmp(set_var->name, let->var->name)) { + if (!strcmp(set_var->name, let->val->var->name)) { check = 1; - set_var->arg = let->var->arg; + set_var->arg = let->val->var->arg; if (!validate_set_value(data, set->val, 1, &set_var->arg, 1, &impl->decl->func, impl->decl->args->count, impl->decl->args->args, 0)) { return 0; } diff --git a/tests/getopt/getopt001.phpt b/tests/getopt/getopt001.phpt new file mode 100644 index 0000000..462b470 --- /dev/null +++ b/tests/getopt/getopt001.phpt @@ -0,0 +1,80 @@ +--TEST-- +getopt +--INI-- +psi.directory={PWD}:{PWD}/../../psi.d +--SKIPIF-- + +--ENV-- +POSIXLY_CORRECT= +--FILE-- +===TEST=== + +===DONE=== +--EXPECT-- +===TEST=== +got v +got x: 1 +got s: foo +arg: huh +arg: -gotcha +arg: --bar +arg: baz +array(11) { + [0]=> + string(8) "progname" + [1]=> + string(2) "-v" + [2]=> + string(2) "-x" + [3]=> + string(1) "1" + [4]=> + string(2) "-s" + [5]=> + string(3) "foo" + [6]=> + string(2) "--" + [7]=> + string(3) "huh" + [8]=> + string(7) "-gotcha" + [9]=> + string(5) "--bar" + [10]=> + string(3) "baz" +} +===DONE=== diff --git a/tests/ndbm/ndbm.psi b/tests/ndbm/ndbm.psi index 139f446..fd132a9 100644 --- a/tests/ndbm/ndbm.psi +++ b/tests/ndbm/ndbm.psi @@ -5,15 +5,15 @@ function psi\dbm_open(string $file, int $open_flags, int $file_mode) : object { return to_object(dbm_open); } -function psi\dbm_store(object $db, array $key, array $data, int $mode) : int { +function psi\dbm_store(object $db, string $key, string $data, int $mode) : int { let db = objval($db); let key = arrval($key, - strval($dptr), - intval($dsize) + dptr = strval($0), + dsize = strlen($0) ); let content = arrval($data, - strval($dptr), - intval($dsize) + dptr = strval($0), + dsize = strlen($0) ); let store_mode = intval($mode); return to_int(dbm_store); @@ -22,8 +22,8 @@ function psi\dbm_store(object $db, array $key, array $data, int $mode) : int { function psi\dbm_fetch(object $db, array $key) : array { let db = objval($db); let key = arrval($key, - strval($dptr), - intval($dsize) + dptr = strval($dptr), + dsize = intval($dsize) ); return to_array(dbm_fetch, to_string(dptr, dsize), diff --git a/tests/ndbm/ndbm001.phpt b/tests/ndbm/ndbm001.phpt index 2914bac..403bdc3 100644 --- a/tests/ndbm/ndbm001.phpt +++ b/tests/ndbm/ndbm001.phpt @@ -24,13 +24,7 @@ class db { } function __set($k, $v) { - return psi\dbm_store($this->db, [ - "dptr" => $k, - "dsize" => strlen($k) - ], [ - "dptr" => $v, - "dsize" => strlen($v) - ], psi\DBM_REPLACE); + return psi\dbm_store($this->db, $k, $v, psi\DBM_REPLACE); } function __get($k) { diff --git a/tests/parser/validate001.phpt b/tests/parser/validate001.phpt index 378db8d..4cb8b2d 100644 --- a/tests/parser/validate001.phpt +++ b/tests/parser/validate001.phpt @@ -7,6 +7,7 @@ extension_loaded("psi") or die("skip - need ext/psi"); --FILE-- ===TEST===