--- /dev/null
+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)
+ );
+}
+// extern time_t time(time_t *t);
function psi\time() : int {
let t = NULL;
return to_int(time);
#include "php_psi.h"
#include "zend_exceptions.h"
+#include "zend_interfaces.h"
+#include "ext/spl/spl_iterators.h"
#include "parser.h"
#include "engine.h"
}
}
+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;
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);
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:
}
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)
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);
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;
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;
+ }
}
}
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) {
}
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;
}
}
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) {
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);
#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)
{
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);
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;
}
/* 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) {
}
}
-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);
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];
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
}
}
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;
}
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]+)?;
'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);}
#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.
#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) \
#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
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.)
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) {
}
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,
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);
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)
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)
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_;
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)
#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
%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 *}
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);
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_). {
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);
}
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,
# 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 <stdlib.h>
#include <stdio.h>
}
}
+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;
}
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;
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);
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;
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,
}
}
-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) {
}
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;
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
#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) {
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)) {
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;
}
}
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;
}
#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);
#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;
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);
}
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:
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;
}
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;
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);
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
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
/* 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;
}
--- /dev/null
+--TEST--
+getopt
+--INI--
+psi.directory={PWD}:{PWD}/../../psi.d
+--SKIPIF--
+<?php
+extension_loaded("psi") or die("skip - need ext/psi");
+function_exists("psi\\div") or die("skip - need psi\\div()");
+?>
+--ENV--
+POSIXLY_CORRECT=
+--FILE--
+===TEST===
+<?php
+
+$args = [
+ "progname", "huh", "-v", "-x", 1, "-s", "foo", "--", "-gotcha", "--bar", "baz"
+];
+
+$opts = "v::x:s:";
+
+while (($opt = chr(psi\getopt($args, $opts)))) {
+ switch ($opt) {
+ case "v":
+ printf("got v\n");
+ break;
+ case "x":
+ case "s":
+ printf("got %s: %s\n", $opt, psi\optarg());
+ break;
+ default:
+ printf("error '%s'\n", $opt);
+ case chr(-1):
+ break 2;
+ }
+}
+
+$pos = psi\optind();
+while ($pos < count($args)) {
+ printf("arg: %s\n", $args[$pos++]);
+}
+
+var_dump($args);
+
+?>
+===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===
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);
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),
}
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) {
--FILE--
===TEST===
<?php
+
function validate($check, $psi) {
$file = __DIR__."/001.psi";
file_put_contents($file, $psi);
Warning: Unknown variable 'X' in numeric expression in %s001.psi on line 4
Warning: PSI syntax error: Unexpected token '(' at pos 26 in %s001.psi on line 1
+
+Warning: PSI syntax error: Unexpected token '(' at pos 32 in %s001.psi on line 1
===DONE===