dprintf(fd, ", ");
dump_num_exp(fd, set->num);
}
- if (set->inner && set->func->type != PSI_T_ELLIPSIS) {
+ if (set->inner && set->inner->vals && set->func->type != PSI_T_ELLIPSIS) {
dprintf(fd, ",\n");
- for (i = 0; i < set->count; ++i) {
- dump_impl_set_value(fd, set->inner[i], level+1, i == (set->count - 1));
+ for (i = 0; i < set->inner->count; ++i) {
+ dump_impl_set_value(fd, set->inner->vals[i], level+1, i == (set->inner->count - 1));
}
/* only if inner stmts, i.e. with new lines, were dumped */
dump_level(fd, level);
if (set->outer.set && set->outer.set->func->type == PSI_T_TO_ARRAY) {
set->func->handler = psi_to_recursive;
set->inner = set->outer.set->inner;
- set->count = set->outer.set->count;
break;
}
/* no break */
}
ref_type = real_decl_type(ref->type);
- if (set->count) {
+ if (set->inner && set->inner->count) {
int is_to_array = (set->func->type == PSI_T_TO_ARRAY);
int is_pointer_to_struct = (ref_type->type == PSI_T_STRUCT && ref->var->pointer_level);
if (ref_type->type == PSI_T_STRUCT) {
/* to_array(struct, to_...) */
- if (!set->outer.set || set->outer.set->inner != set->inner) {
- for (i = 0; i < set->count; ++i) {
- decl_var *sub_var = set->inner[i]->vars->vars[0];
+ if (!set->outer.set || set->outer.set->inner->vals != set->inner->vals) {
+ for (i = 0; i < set->inner->count; ++i) {
+ decl_var *sub_var = set->inner->vals[i]->vars->vars[0];
decl_arg *sub_ref = locate_struct_member(ref_type->strct, sub_var);
if (sub_ref) {
- if (!validate_set_value_ex(data, set->inner[i], sub_ref, ref_type->strct->args)) {
+ if (!validate_set_value_ex(data, set->inner->vals[i], sub_ref, ref_type->strct->args)) {
return 0;
}
}
}
}
- } else if (set->count == 1) {
+ } else if (set->inner && set->inner->count == 1) {
/* to_array(ptr, to_string(*ptr)) */
- decl_var *sub_var = set->inner[0]->vars->vars[0];
+ decl_var *sub_var = set->inner->vals[0]->vars->vars[0];
decl_arg *sub_ref = locate_decl_var_arg(sub_var, ref_list, ref);
if (sub_ref) {
data->error(data, sub_var->token, E_WARNING, "Inner `set` statement casts on pointers must reference the same variable");
return 0;
}
- if (!validate_set_value_ex(data, set->inner[0], sub_ref, ref_list)) {
+ if (!validate_set_value_ex(data, set->inner->vals[0], sub_ref, ref_list)) {
return 0;
}
}
- } else if (set->count > 1) {
+ } else if (set->inner && set->inner->count > 1) {
data->error(data, set->func->token, E_WARNING, "Inner `set` statement casts on pointers may only occur once");
return 0;
}
return 1;
}
+static inline int validate_let_func(PSI_Data *data, let_func *func, impl *impl) {
+ int check = 0;
+ size_t j;
+
+ if (impl->func->args) {
+ for (j = 0; j < impl->func->args->count; ++j) {
+ impl_arg *iarg = impl->func->args->args[j];
+
+ if (!strcmp(func->var->name, iarg->var->name)) {
+ func->arg = iarg;
+ check = 1;
+ break;
+ }
+ }
+ }
+ if (!check) {
+ data->error(data, func->var->token, PSI_WARNING, "Unknown value '$%s' of `let` statement"
+ " for cast '%s' of implementation '%s'",
+ func->var->name, func->name, impl->func->name);
+ return 0;
+ }
+ return 1;
+}
+
+static inline int validate_let_callback(PSI_Data *data, decl_var *let_var, let_callback *cb, impl *impl) {
+ decl_type *cb_type;
+ decl *cb_func;
+ size_t i;
+
+ if (!validate_let_func(data, cb->func, impl)) {
+ return 0;
+ }
+
+ cb_type = real_decl_type(let_var->arg->type);
+ if (cb_type->type != PSI_T_FUNCTION) {
+ data->error(data, let_var->token, PSI_WARNING, "Not a function: %s", let_var->name);
+ return 0;
+ }
+ cb_func = cb_type->func;
+ for (i = 0; i < cb->args->count; ++i) {
+ if (!validate_set_value(data, cb->args->vals[i], cb_func->args->count, cb_func->args->args, 0)) {
+ return 0;
+ }
+ }
+}
+
static inline int validate_impl_let_stmts(PSI_Data *data, impl *impl) {
size_t i, j;
/* we can have multiple let stmts */
return 0;
}
break;
- case PSI_LET_FUNC:
- if (impl->func->args) {
- for (j = 0; j < impl->func->args->count; ++j) {
- impl_arg *iarg = impl->func->args->args[j];
-
- if (!strcmp(let->val->data.func->var->name, iarg->var->name)) {
- let->val->data.func->arg = iarg;
- check = 1;
- break;
- }
- }
+ case PSI_LET_CALLBACK:
+ if (!validate_let_callback(data, let->var, let->val->data.callback, impl)) {
+ return 0;
}
- if (!check) {
- data->error(data, let->var->token, PSI_WARNING, "Unknown value '$%s' of `let` statement"
- " for variable '%s' of implementation '%s'",
- let->val->data.func->var->name, let->var->name, impl->func->name);
+ break;
+ case PSI_LET_FUNC:
+ if (!validate_let_func(data, let->val->data.func, impl)) {
return 0;
}
break;
} else if (PSI_T_MIXED == iarg->type->type) {
Z_PARAM_PROLOGUE(0);
} else if (PSI_T_CALLABLE == iarg->type->type) {
- Z_PARAM_FUNC_EX(iarg->val.zend.cb.fci, iarg->val.zend.cb.fcc, 1, 0);
+ zend_fcall_info fci;
+ zend_fcall_info_cache fcc;
+
+ Z_PARAM_FUNC_EX(fci, fcc, 1, 0);
+
+ if (fci.size) {
+ iarg->val.zend.cb = calloc(1, sizeof(zend_fcall));
+ iarg->val.zend.cb->fci = fci;
+ iarg->val.zend.cb->fcc = fcc;
+ }
} else {
error_code = ZPP_ERROR_FAILURE;
break;
arg_val->ptr = obj->data;
}
break;
- case PSI_T_CBVAL:
+ case PSI_T_CALLBACK:
if (iarg->type->type == PSI_T_CALLABLE) {
}
arg_val->ptr = psi_do_calloc(let->val->data.alloc);
darg->mem = arg_val->ptr;
break;
+ case PSI_LET_CALLBACK:
+ arg_val->ptr = 0 /* callback closure */;
+ break;
case PSI_LET_NUMEXP:
arg_val->zend.lval = psi_long_num_exp(let->val->data.num, NULL);
break;
}
}
-static inline void psi_do_set(zval *return_value, set_value *set)
-{
- decl_arg *set_arg = set->vars->vars[0]->arg;
-
- zval_dtor(return_value);
- set->func->handler(return_value, set, set_arg->let ? set_arg->let->ptr : set_arg->ptr);
-}
-
static inline void psi_do_return(zval *return_value, return_stmt *ret)
{
ret->set->func->handler(return_value, ret->set, ret->set->vars->vars[0]->arg->ptr);
return diff;
}
+static inline void psi_do_set(zval *return_value, set_value *set)
+{
+ decl_arg *set_arg = set->vars->vars[0]->arg;
+
+ zval_dtor(return_value);
+ set->func->handler(return_value, set, set_arg->let ? set_arg->let->ptr : set_arg->ptr);
+}
+
int psi_internal_type(impl_type *type);
zend_internal_arg_info *psi_internal_arginfo(impl *impl);
size_t psi_num_min_args(impl *impl);
unsigned argc = _sig->nargs;
void **argv = _args;
ffi_arg *res = _result;
- decl *decl = _data;
- size_t i;
+ let_stmt *let;
+ decl_arg *darg = let->var->arg;
+ decl *decl_cb = darg->type->func;
+ let_callback *cb = let->val->data.callback;
+ impl_arg *iarg = cb->func->arg;
+ size_t i, argc = cb->args->count;
+ zval *argv = calloc(argc, sizeof(*argv));
// prepare args for the userland call
- for (i = 0; i < decl->args->count; ++i) {
+ for (i = 0; i < decl_cb->args->count; ++i) {
}
- // marshal return value of the userland call
- switch (decl->func->type->type) {
-
+ for (i = 0; i < cb->args->count; ++i) {
+ psi_do_set(&argv[i], cb->args->vals[i]);
}
+ zend_fcall_info_argp(iarg->val.zend.cb->fci, argc, argv);
+ // marshal return value of the userland call
+ darg->ptr = psi_let_val(cb->func->type, iarg, darg->ptr, real_decl_type(darg->type)->strct, &darg->mem);
}
static inline ffi_type *psi_ffi_decl_arg_type(decl_arg *darg);
PSI_LibffiCall *call = PSI_LibffiCallAlloc(&PSI_G(context), real->func);
ffi_status rc;
- rc = psi_ffi_prep_closure(&real->func->call.closure.data, &real->func->call.sym,
- &call->signature, psi_ffi_handler, NULL);
+ rc = psi_ffi_prep_closure(
+ (void *) &real->func->call.closure.data,
+ &real->func->call.sym, &call->signature, psi_ffi_handler, NULL);
if (FFI_OK == rc) {
real->func->call.info = call;
real->func->call.closure.dtor = psi_ffi_closure_free;
if (t == PSI_T_STRUCT) {
// decl_struct *s = real_decl_type(var->arg->type)->strct;
- if (set->count) {
+ if (set->inner && set->inner->count) {
/* explicit member casts */
- for (i = 0; i < set->count; ++i) {
- set_value *sub_set = set->inner[i];
+ for (i = 0; i < set->inner->count; ++i) {
+ set_value *sub_set = set->inner->vals[i];
decl_var *sub_var = sub_set->vars->vars[0];
sub_set->outer.val = ret_val;
char *ptr;
zend_long i, n = psi_long_num_exp(set->num, set->outer.val);
size_t size = psi_t_size(var->arg->var->pointer_level ? PSI_T_POINTER : t);
- set_value *sub_set = set->inner[0];
+ set_value *sub_set = set->inner->vals[0];
sub_set->outer.val = set->outer.val;
for (i = 0; i < n; ++i) {
zval ele;
char *ptr = ret_val->ptr;
size_t size = psi_t_size(var->arg->var->pointer_level ? PSI_T_POINTER : t);
- set_value *sub_set = set->inner[0];
+ set_value *sub_set = set->inner->vals[0];
sub_set->outer.val = set->outer.val;
while (*(void **) ptr) {
static inline PSI_Token *PSI_TokenCopy(PSI_Token *src);
+typedef struct zend_fcall {
+ zend_fcall_info fci;
+ zend_fcall_info_cache fcc;
+} zend_fcall;
+
typedef union impl_val {
char cval;
int8_t i8;
zend_bool bval;
zend_long lval;
zend_string *str;
- struct {
- zend_fcall_info *fci;
- zend_fcall_info_cache *fcc;
- } cb;
+ zend_fcall *cb;
} zend;
void *ptr;
uint8_t _dbg[sizeof(void *)];
return var;
}
+static inline impl_var *copy_impl_var(impl_var *var) {
+ impl_var *cpy = malloc(sizeof(*cpy));
+
+ memcpy(cpy, var, sizeof(*cpy));
+ cpy->name = strdup(cpy->name);
+ if (cpy->token) {
+ cpy->token = PSI_TokenCopy(cpy->token);
+ }
+ return cpy;
+}
+
static inline void free_impl_var(impl_var *var) {
if (var->token) {
free(var->token);
free(alloc);
}
+typedef struct let_callback {
+ struct let_func *func;
+ struct set_values *args;
+} let_callback;
+
+static inline void free_let_func(struct let_func *func);
+static inline void free_set_values(struct set_values *vals);
+static inline let_callback *init_let_callback(struct let_func *func, struct set_values *args) {
+ let_callback *cb = calloc(1, sizeof(*cb));
+
+ cb->func = func;
+ cb->args = args;
+ return cb;
+}
+
+static inline void free_let_callback(let_callback *cb) {
+ free_let_func(cb->func);
+ free_set_values(cb->args);
+ free(cb);
+}
+
typedef struct let_func {
token_t type;
char *name;
impl_var *var;
impl_arg *arg;
- set_values *callback;
} let_func;
static inline let_func *init_let_func(token_t type, const char *name, impl_var *var) {
PSI_LET_NULL,
PSI_LET_NUMEXP,
PSI_LET_CALLOC,
+ PSI_LET_CALLBACK,
PSI_LET_FUNC,
PSI_LET_TMP,
} kind;
union {
num_exp *num;
let_calloc *alloc;
+ let_callback *callback;
let_func *func;
decl_var *var;
} data;
case PSI_LET_CALLOC:
let->data.alloc = data;
break;
+ case PSI_LET_CALLBACK:
+ let->data.callback = data;
+ break;
case PSI_LET_FUNC:
let->data.func = data;
break;
case PSI_LET_CALLOC:
free_let_calloc(let->data.alloc);
break;
+ case PSI_LET_CALLBACK:
+ free_let_callback(let->data.callback);
+ break;
case PSI_LET_FUNC:
free_let_func(let->data.func);
break;
struct set_value *set;
impl_val *val;
} outer;
- struct set_value **inner;
- size_t count;
+ struct set_values *inner;
} set_value;
+typedef struct set_values {
+ set_value **vals;
+ size_t count;
+} set_values;
+
+
static inline set_value *init_set_value(set_func *func, decl_vars *vars) {
set_value *val = calloc(1, sizeof(*val));
val->func = func;
return val;
}
static inline set_value *add_inner_set_value(set_value *val, set_value *inner) {
- val->inner = realloc(val->inner, ++val->count * sizeof(*val->inner));
- val->inner[val->count-1] = inner;
+ val->inner->vals = realloc(val->inner->vals, ++val->inner->count * sizeof(*val->inner->vals));
+ val->inner->vals[val->inner->count-1] = inner;
inner->outer.set = val;
return val;
}
}
if (val->inner && (!val->outer.set || val->outer.set->inner != val->inner)) {
size_t i;
- for (i = 0; i < val->count; ++i) {
- free_set_value(val->inner[i]);
+ for (i = 0; i < val->inner->count; ++i) {
+ free_set_value(val->inner->vals[i]);
}
- free(val->inner);
+ free(val->inner->vals);
}
if (val->num) {
free_num_exp(val->num);
free(val);
}
-typedef struct set_values {
- set_value **vals;
- size_t count;
-} set_values;
-
static inline set_values *init_set_values(set_value *val) {
set_values *vals = calloc(1, sizeof(*vals));
if (val) {
#define PSI_T_TRUE 54
#define PSI_T_FALSE 55
#define PSI_T_DOLLAR_NAME 56
-#define PSI_T_CBVAL 57
-#define PSI_T_OBJVAL 58
-#define PSI_T_ARRVAL 59
-#define PSI_T_PATHVAL 60
-#define PSI_T_STRLEN 61
-#define PSI_T_STRVAL 62
-#define PSI_T_FLOATVAL 63
-#define PSI_T_INTVAL 64
-#define PSI_T_BOOLVAL 65
+#define PSI_T_OBJVAL 57
+#define PSI_T_ARRVAL 58
+#define PSI_T_PATHVAL 59
+#define PSI_T_STRLEN 60
+#define PSI_T_STRVAL 61
+#define PSI_T_FLOATVAL 62
+#define PSI_T_INTVAL 63
+#define PSI_T_BOOLVAL 64
+#define PSI_T_CALLBACK 65
#define PSI_T_TO_OBJECT 66
#define PSI_T_TO_ARRAY 67
#define PSI_T_TO_STRING 68
let = init_let_stmt(var, init_let_val(PSI_LET_TMP, val));
}
-%type let_val {let_val*}
-%destructor let_val {free_let_val($$);}
-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);
-}
-
%type let_calloc {let_calloc*}
%destructor let_calloc {free_let_calloc($$);}
let_calloc(alloc) ::= num_exp(nmemb) COMMA num_exp(size). {
func = init_let_func(T->type, T->text, var);
free(T);
}
-let_func(func_) ::= CALLBACK let_func_token(T) LPAREN impl_var(var) callback_arg_list(args_) RPAREN. {
- func_ = init_let_func(T->type, T->text, var);
- func_->callback.func = func_;
- func_->callback.args = args_;
- free(T);
-}
+%type callback_arg_list {set_values *}
+%destructor callback_arg_list {free_set_values($$);}
callback_arg_list ::= .
callback_arg_list(args) ::= COMMA callback_args(args_). {
args = args_;
}
+%type callback_args {set_values *}
+%destructor callback_args {free_set_values($$);}
callback_args(args) ::= set_value(val). {
args = init_set_values(val);
}
args = add_set_value(args_, val);
}
+%type let_val {let_val*}
+%destructor let_val {free_let_val($$);}
+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 let_func_token(F) LPAREN impl_var(var) callback_arg_list(args_) RPAREN. {
+ val = init_let_val(PSI_LET_CALLBACK, init_let_callback(
+ init_let_func(F->type, F->text, var), args_));
+ free(F);
+}
+
%type set_stmt {set_stmt*}
%destructor set_stmt {free_set_stmt($$);}
set_stmt(set) ::= SET impl_var(var) EQUALS set_value(val) EOS. {