raising the head after a three-weeks refactoring
authorMichael Wallner <mike@php.net>
Tue, 22 Nov 2016 14:33:08 +0000 (15:33 +0100)
committerMichael Wallner <mike@php.net>
Tue, 22 Nov 2016 14:33:08 +0000 (15:33 +0100)
162 files changed:
TODO
m4/posix/signal.m4
m4/posix/unistd.m4
m4/psi/psi.m4
m4/psi/psi_type.m4
package.xml
php_psi.h
psi.d/getopt.psi
psi.d/glob.psi
psi.d/netdb.psi
psi.d/time.psi
src/calc.c
src/calc.h
src/call.c [new file with mode: 0644]
src/call.h [new file with mode: 0644]
src/context.c
src/context.h
src/data.c
src/data.h
src/engine.c [deleted file]
src/engine.h [deleted file]
src/error.c
src/error.h
src/libffi.c
src/libffi.h
src/libjit.c
src/libjit.h
src/marshal.c
src/marshal.h
src/module.c
src/parser.h
src/parser.re
src/parser_def.h
src/parser_def.h.bak
src/parser_proc.h
src/parser_proc.inc
src/parser_proc.y
src/parser_proc.y.bak
src/plist.c [new file with mode: 0644]
src/plist.h [new file with mode: 0644]
src/token.c
src/token.h
src/types.h
src/types/const.c [new file with mode: 0644]
src/types/const.h [new file with mode: 0644]
src/types/const_type.c
src/types/const_type.h
src/types/constant.c [deleted file]
src/types/constant.h [deleted file]
src/types/constants.c [deleted file]
src/types/constants.h [deleted file]
src/types/decl.c
src/types/decl.h
src/types/decl_abi.c
src/types/decl_abi.h
src/types/decl_arg.c
src/types/decl_arg.h
src/types/decl_args.c [deleted file]
src/types/decl_args.h [deleted file]
src/types/decl_callinfo.h [deleted file]
src/types/decl_enum.c
src/types/decl_enum.h
src/types/decl_enum_item.c
src/types/decl_enum_item.h
src/types/decl_enum_items.c [deleted file]
src/types/decl_enum_items.h [deleted file]
src/types/decl_enums.c [deleted file]
src/types/decl_enums.h [deleted file]
src/types/decl_file.c
src/types/decl_file.h
src/types/decl_libs.c [deleted file]
src/types/decl_libs.h [deleted file]
src/types/decl_struct.c
src/types/decl_struct.h
src/types/decl_struct_layout.c [deleted file]
src/types/decl_struct_layout.h [deleted file]
src/types/decl_structs.c [deleted file]
src/types/decl_structs.h [deleted file]
src/types/decl_type.c
src/types/decl_type.h
src/types/decl_typedefs.c [deleted file]
src/types/decl_typedefs.h [deleted file]
src/types/decl_union.c
src/types/decl_union.h
src/types/decl_unions.c [deleted file]
src/types/decl_unions.h [deleted file]
src/types/decl_var.c
src/types/decl_var.h
src/types/decl_vars.c [deleted file]
src/types/decl_vars.h [deleted file]
src/types/decls.c [deleted file]
src/types/decls.h [deleted file]
src/types/free_call.c [deleted file]
src/types/free_call.h [deleted file]
src/types/free_calls.c [deleted file]
src/types/free_calls.h [deleted file]
src/types/free_exp.c [new file with mode: 0644]
src/types/free_exp.h [new file with mode: 0644]
src/types/free_stmt.c
src/types/free_stmt.h
src/types/impl.c
src/types/impl.h
src/types/impl_arg.c
src/types/impl_arg.h
src/types/impl_args.c [deleted file]
src/types/impl_args.h [deleted file]
src/types/impl_def_val.c
src/types/impl_def_val.h
src/types/impl_func.c
src/types/impl_func.h
src/types/impl_stmt.c [deleted file]
src/types/impl_stmt.h [deleted file]
src/types/impl_stmts.c [deleted file]
src/types/impl_stmts.h [deleted file]
src/types/impl_type.c
src/types/impl_type.h
src/types/impl_val.h
src/types/impl_var.c
src/types/impl_var.h
src/types/impls.c [deleted file]
src/types/impls.h [deleted file]
src/types/layout.c [new file with mode: 0644]
src/types/layout.h [new file with mode: 0644]
src/types/let_callback.c
src/types/let_callback.h
src/types/let_calloc.c
src/types/let_calloc.h
src/types/let_exp.c [new file with mode: 0644]
src/types/let_exp.h [new file with mode: 0644]
src/types/let_func.c
src/types/let_func.h
src/types/let_stmt.c
src/types/let_stmt.h
src/types/let_val.c [deleted file]
src/types/let_val.h [deleted file]
src/types/let_vals.c [deleted file]
src/types/let_vals.h [deleted file]
src/types/num_exp.c
src/types/num_exp.h
src/types/return_stmt.c
src/types/return_stmt.h
src/types/set_exp.c [new file with mode: 0644]
src/types/set_exp.h [new file with mode: 0644]
src/types/set_func.c
src/types/set_func.h
src/types/set_stmt.c
src/types/set_stmt.h
src/types/set_value.c [deleted file]
src/types/set_value.h [deleted file]
src/types/set_values.c [deleted file]
src/types/set_values.h [deleted file]
tests/getopt/getopt001.phpt
tests/glob/glob001.phpt
tests/glob/glob003.phpt
tests/ndbm/ndbm.psi
tests/parser/dump/dump001.phpt
tests/parser/validate001.phpt
tests/pipe/pipe.psi
tests/sqlite/sqlite.psi
tests/sqlite/sqlite001.phpt
tests/time/asc_gmtime001.phpt
tests/time/times001.phpt

diff --git a/TODO b/TODO
index ffda07a..2e6e0a9 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,9 +1,7 @@
-* move numbers to the lexer
 * avoid allocs inside structures by reallocating the whole structure
 * let the various list types be hashtables where appropriate
 * check out jit-dynamic
 * fix arginfo with nullable types
 * pemalloc
-* unions
-* callbacks and function pointers
-* let impl_Var point to impl_arg, just like decl_var?
\ No newline at end of file
+* CPP style #if(def(ined)) support in parser.re with a HashTable
+* think about a better system for EXTVARs, separate \set and \get functions are clunky
\ No newline at end of file
index 6895acf..ac266ac 100644 (file)
@@ -163,7 +163,7 @@ PSI_CHECK_SIGNAL() {
        ])
        
        PSI_DECL(int raise, [(int sig)])
-       PSI_DECL(int sigaction, [(int sig, const struct sigaction *act, struct sigaction *oact)])
+       PSI_DECL(int sigaction, [(int sig, struct sigaction *act, struct sigaction *oact)])
        PSI_DECL(int sigaddset, [(sigset_t * set, int signum)])
        PSI_DECL(int sigaltstack, [(const stack_t *ss, stack_t *oss)])
        PSI_DECL(int sigdelset, [(sigset_t *set, int signum)])
index fde0fe9..0da8665 100644 (file)
@@ -1,6 +1,6 @@
 PSI_CHECK_UNISTD() {
        PSI_CONFIG_POSIX(unistd, unistd.h)
-       
+
        PSI_CONST(F_LOCK, int)
        PSI_CONST(F_TEST, int)
        PSI_CONST(F_TLOCK, int)
@@ -277,12 +277,13 @@ PSI_CHECK_UNISTD() {
        PSI_CONST(_XOPEN_UNIX, int)
        PSI_CONST(_XOPEN_UUCP, int)
        PSI_CONST(_XOPEN_VERSION, int)
-       
+
        PSI_EXTVAR(char *optarg)
        PSI_EXTVAR(int opterr)
        PSI_EXTVAR(int optind)
        PSI_EXTVAR(int optopt)
-       
+       PSI_EXTVAR(int optreset)
+
        PSI_DECL(int access, [(const char *path, int amode)])
        PSI_DECL(unsigned alarm, [(unsigned seconds)])
        PSI_DECL(int chdir, [(const char *path)])
@@ -367,4 +368,4 @@ PSI_CHECK_UNISTD() {
        PSI_DECL(ssize_t write, [(int fildes, const void *buf, size_t nbyte)])
 
 
-}
\ No newline at end of file
+}
index ff112d7..96c648e 100644 (file)
@@ -106,8 +106,22 @@ dnl Finish the headers with the pre-defined types etc.
 AC_DEFUN(PSI_CONFIG_DONE, [
        cat >$PSI_STDINC <<EOF
 /* generated by configure */
-#ifndef _PSI_STDINC
-# define _PSI_STDINC
+#ifndef PSI_STDINC_H
+#define PSI_STDINC_H
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#else
+# include "php_config.h"
+#endif
+
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
+#ifndef _REENTRANT
+# define _REENTRANT
+#endif
+
 PSI_INCLUDES
 #endif
 EOF
@@ -185,6 +199,21 @@ AC_DEFUN(PSI_INCLUDES, [#define PSI_INCLUDES
 # define _REENTRANT
 #endif
 AC_INCLUDES_DEFAULT()
+#ifdef HAVE_STDBOOL_H
+# include <stdbool.h>
+#else
+# ifndef HAVE__BOOL
+#  ifdef __cplusplus
+typedef bool _Bool;
+#  else
+#   define _Bool signed char
+#  endif
+# endif
+# define bool _Bool
+# define false 0
+# define true 1
+# define __bool_true_false_are_defined 1
+#endif
 #ifdef HAVE_ERRNO_H
 # include <errno.h>
 #endif
@@ -407,6 +436,7 @@ AC_DEFUN(PSI_CHECK_LIBFFI, [
                PHP_EVAL_INCLINE(`$PKG_CONFIG --cflags libffi`)
                PHP_EVAL_LIBLINE(`$PKG_CONFIG --libs libffi`, PSI_SHARED_LIBADD)
                AC_DEFINE(HAVE_LIBFFI, 1, Have libffi)
+               AC_DEFINE_UNQUOTED([PHP_PSI_LIBFFI_VERSION], ["`$PKG_CONFIG --modversion libffi`"], [libffi version])
        else
                AC_CACHE_CHECK(for libffi, psi_cv_libffi_dir, [
                for psi_cv_libffi_dir in $PHP_PSI_LIBFFI {/usr{,/local},/opt}{,/libffi}
index 826ae7e..b5fe39f 100644 (file)
@@ -2,13 +2,13 @@
 # Add a pre-defined type to $PSI_TYPES.
 psi_add_type() {
        cat >>$PSI_TYPES <<EOF
-       $1, 
+       $1,
 EOF
 }
 
 psi_add_stdtype() {
        cat >>$PSI_STDTYPES <<EOF
-       $1, 
+       $1,
 EOF
 }
 
@@ -18,6 +18,9 @@ EOF
 psi_type_pair() {
        local psi_type_name=`printf "%s" "$1" | tr -cd A-Za-z0-9_`
        local psi_type_lower=`printf "%s" "$1" | tr A-Z a-z`
+       while expr "$psi_type_lower" : const >/dev/null; do
+               psi_type_lower=`printf "%s" "$psi_type_lower" | cut -d " " -f2-`
+       done
        case $psi_type_lower in
        int*|uint*)
                local psi_type_upper=`printf "%s" "$psi_type_name" | tr a-z A-Z`
@@ -42,7 +45,7 @@ psi_type_pair() {
 dnl PSI_TYPE(type name, basic type)
 dnl Check for a specific type, optionally referring to a basic type.
 dnl Calls AC_TYPE_<TYPE> (if defined) and PSI_CHECK_SIZEOF.
-dnl If the basic type is just specified as "int" (in contrast to "sint" or 
+dnl If the basic type is just specified as "int" (in contrast to "sint" or
 dnl "uint"), AX_CHECK_SIGN is used to discover signedness of the type.
 dnl Defines a pre-defined type in $PSI_TYPES.
 AC_DEFUN(PSI_TYPE, [
@@ -68,6 +71,7 @@ AC_DEFUN(PSI_STDTYPE, [
        PSI_CHECK_SIZEOF($1)
        if PSI_SH_TEST_SIZEOF($1); then
                m4_case([$1],
+               [bool],[psi_add_stdtype "{PSI_T_BOOL, \"bool\", NULL}"],
                [float],[psi_add_stdtype "{PSI_T_FLOAT, \"float\", NULL}"],
                [double],[psi_add_stdtype "{PSI_T_DOUBLE, \"double\", NULL}"],
                [long double],[psi_add_stdtype "{PSI_T_LONG_DOUBLE, \"long double\", NULL}"],
@@ -187,9 +191,10 @@ AC_DEFUN(PSI_TYPE_PAIR, [m4_case(m4_bregexp([$1], [^\w+], [\&]),
        [PSI_T_NAME, \"m4_bregexp([$1], [^\(\w+ \)*\w+], [\&])\"])])
 
 dnl PSI_CHECK_STD_TYPES()
-dnl Checks for standard ANSI-C and stdint types.
+dnl Checks for standard ANSI-C, stdint and stdbool types.
 AC_DEFUN(PSI_CHECK_STD_TYPES, [
        AC_CHECK_HEADERS(stdint.h)
+       AC_HEADER_STDBOOL
 
        AC_TYPE_INT8_T
        PSI_CHECK_SIZEOF(int8_t)
@@ -215,7 +220,7 @@ AC_DEFUN(PSI_CHECK_STD_TYPES, [
        AC_TYPE_UINT64_T
        PSI_CHECK_SIZEOF(uint64_t)
        AC_CHECK_ALIGNOF(uint64_t)
-       
+
        PSI_CHECK_SIZEOF(void *)
        AC_CHECK_ALIGNOF(void *)
 
@@ -226,6 +231,9 @@ AC_DEFUN(PSI_CHECK_STD_TYPES, [
        PSI_STDTYPE(long double)
        AC_CHECK_ALIGNOF(long double)
 
+       PSI_STDTYPE(bool)
+       AC_CHECK_ALIGNOF(bool, PSI_INCLUDES)
+
        PSI_STDTYPE(char, int)
        AC_CHECK_ALIGNOF(char)
        PSI_STDTYPE(signed char, int)
@@ -255,6 +263,6 @@ AC_DEFUN(PSI_CHECK_STD_TYPES, [
        PSI_STDTYPE(signed long long int, int)
        PSI_STDTYPE(unsigned long long, uint)
        PSI_STDTYPE(unsigned long long int, uint)
-       dnl this must come after the check fo "unsigned long long int"; autoconf, wth?
+       dnl this must come after the check for "unsigned long long int"; autoconf, wth?
        PSI_STDTYPE(long long int, int)
 ])
index 20e16de..e7db772 100644 (file)
@@ -164,8 +164,8 @@ and system interfaces of POSIX.1-2008 (http://pubs.opengroup.org/onlinepubs/9699
      <file role="src" name="let_func.h"/>
      <file role="src" name="let_stmt.c"/>
      <file role="src" name="let_stmt.h"/>
-     <file role="src" name="let_val.c"/>
-     <file role="src" name="let_val.h"/>
+     <file role="src" name="let_exp.c"/>
+     <file role="src" name="let_exp.h"/>
      <file role="src" name="let_vals.c"/>
      <file role="src" name="let_vals.h"/>
      <file role="src" name="num_exp.c"/>
index 3dedff2..1609700 100644 (file)
--- a/php_psi.h
+++ b/php_psi.h
@@ -1,3 +1,28 @@
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+     * Redistributions of source code must retain the above copyright notice,
+       this list of conditions and the following disclaimer.
+     * Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
 #ifndef PHP_PSI_H
 #define PHP_PSI_H
 
@@ -18,8 +43,6 @@ extern zend_module_entry psi_module_entry;
 #include "TSRM.h"
 #endif
 
-#include "context.h"
-
 static inline int psi_check_env(const char *var) {
        char *set = getenv(var);
        return (set && *set && '0' != *set);
@@ -27,6 +50,7 @@ static inline int psi_check_env(const char *var) {
 
 typedef struct psi_object {
        void *data;
+       void (*dtor)(void *data);
        size_t size;
        zend_object std;
 } psi_object;
@@ -38,12 +62,14 @@ static inline psi_object *PSI_OBJ(zval *zv, zend_object *zo) {
        return (void *) (((char *) zo) - zo->handlers->offset);
 }
 
+PHP_PSI_API zend_object *psi_object_init(zend_class_entry *ce);
+PHP_PSI_API zend_object *psi_object_init_ex(zend_class_entry *ce, void *data, void (*dtor)(void *));
 PHP_PSI_API zend_class_entry *psi_object_get_class_entry();
 
 ZEND_BEGIN_MODULE_GLOBALS(psi)
        char *engine;
        char *directory;
-       struct psi_context context;
+       struct psi_context *context;
 ZEND_END_MODULE_GLOBALS(psi);
 
 ZEND_EXTERN_MODULE_GLOBALS(psi);
index 5e1e427..fcf1db7 100644 (file)
@@ -2,8 +2,12 @@ function psi\opterr(int $value) : void {
        let _v = intval($value);
        return void(opterr_set);
 }
-function psi\optind() : int {
-       return to_int(optind);
+function psi\optind\get() : int {
+       return to_int(optind_get);
+}
+function psi\optind\set(int $v) : void {
+       let _v = intval($v);
+       return void(optind_set);
 }
 function psi\optopt() : int {
        return to_int(optopt);
@@ -11,15 +15,22 @@ function psi\optopt() : int {
 function psi\optarg() : string {
        return to_string(optarg);
 }
-
-function psi\getopt(array &$argv, string $options) : int {
+/* OSX
+function psi\optreset() : void {
+       let _v = 1;
+       return void(optreset_set);
+}
+*/
+static 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)
+       return to_int(getopt);
+       set $argv = to_array(
+               *argv,
+               argc,
+               to_string(*argv)
        );
 }
index 19aa6cb..f4a762a 100644 (file)
@@ -5,14 +5,22 @@ function psi\glob(string $pattern, int $flags, array &$glob = NULL, callable $er
                to_string(epath),
                to_int(eerrno)
        ));
-       let buf = &arrval($glob);
+       let buf = &arrval($glob,
+               intval($gl_matchc),
+               intval($gl_pathc),
+               intval($gl_offs),
+               intval($gl_flags),
+               &arrval($gl_pathv, 
+                       strval($gl_pathv)
+               )
+       );
        return to_int(glob);
        set $glob = to_array(*buf,
                to_int(gl_matchc),
                to_int(gl_pathc),
                to_int(gl_offs),
                to_int(gl_flags),
-               to_array(gl_pathv, gl_pathc + gl_offs, to_string(gl_pathv))
+               to_array(*gl_pathv, gl_pathc + gl_offs, to_string(*gl_pathv))
        );
        free globfree(buf);
 }
index 3eca291..f37476d 100644 (file)
@@ -44,10 +44,15 @@ function psi\gai_strerror(int $errcode) : string {
 }
 
 // extern int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res)
-function psi\getaddrinfo(string $node, string $service, array $hints, object &$res = NULL) : int {
+function psi\getaddrinfo(string $node, string $service, array $hints = NULL, object &$res = NULL) : int {
        let node = strval($node);
        let service = strval($service);
-       let hints = &arrval($hints);
+       let hints = &arrval($hints,
+               intval($ai_flags),
+               intval($ai_family),
+               intval($ai_socktype),
+               intval($ai_protocol)
+       );
        let res = &NULL;
        return to_int(getaddrinfo);
        set $res = to_array(**res,
index 9302b13..25bc4e8 100644 (file)
@@ -18,14 +18,34 @@ function psi\gettimeofday(array &$tv = NULL, array &$tz = NULL) : int {
 }
 
 // extern char *asctime(struct tm *tm);
-function psi\asctime(array $tm = NULL) : string {
-       let tm = &arrval($tm);
+function psi\asctime(array $tm) : string {
+       let tm = &arrval($tm,
+               intval($tm_sec),
+               intval($tm_min),
+               intval($tm_hour),
+               intval($tm_mday),
+               intval($tm_mon),
+               intval($tm_year),
+               intval($tm_wday),
+               intval($tm_yday),
+               intval($tm_isdst)
+       );
        return to_string(asctime);
 }
 
 // extern char *asctime_r(struct tm *tm, char *buf);
-function psi\asctime_r(array $tm = NULL) : string {
-       let tm = &arrval($tm);
+function psi\asctime_r(array $tm) : string {
+       let tm = &arrval($tm,
+               intval($tm_sec),
+               intval($tm_min),
+               intval($tm_hour),
+               intval($tm_mday),
+               intval($tm_mon),
+               intval($tm_year),
+               intval($tm_wday),
+               intval($tm_yday),
+               intval($tm_isdst)
+       );
        let buf = calloc(32, psi\SIZEOF_CHAR);
        return to_string(asctime_r);
 }
@@ -65,7 +85,10 @@ function psi\gmtime_r(int $ts) : array {
 
 // extern int nanosleep(struct timespec *rqts, struct timespec *rmts);
 function psi\nanosleep(array $rq = NULL, array &$rm = NULL) : int {
-       let rqts = &arrval($rq);
+       let rqts = &arrval($rq,
+               intval($tv_sec),
+               intval($tv_nsec)
+       );
        let rmts = calloc(1, psi\SIZEOF_STRUCT_TIMESPEC);
        return to_int(nanosleep);
        set $rm = to_array(*rmts,
index 0e21ec5..b1b3a74 100644 (file)
@@ -1,97 +1,33 @@
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#else
-# include "php_config.h"
-#endif
-
-#include "php.h"
-#include "php_psi.h"
-#include "parser.h"
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+     * Redistributions of source code must retain the above copyright notice,
+       this list of conditions and the following disclaimer.
+     * Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#include "php_psi_stdinc.h"
+
+#include "token.h"
 #include "calc.h"
 
-static inline int psi_calc_num_exp_value(num_exp *exp, impl_val *strct, impl_val *res) {
-       impl_val *ref, *tmp = NULL;
-
-       switch (exp->t) {
-       case PSI_T_NUMBER:
-               switch (is_numeric_string(exp->u.numb, strlen(exp->u.numb), (zend_long *) res, (double *) res, 0)) {
-               case IS_LONG:
-                       return PSI_T_INT64;
-               case IS_DOUBLE:
-                       return PSI_T_DOUBLE;
-               }
-               break;
-
-       case PSI_T_NSNAME:
-               switch (exp->u.cnst->type->type) {
-               case PSI_T_INT:
-                       res->i64 = zend_get_constant_str(exp->u.cnst->name, strlen(exp->u.cnst->name))->value.lval;
-                       return PSI_T_INT64;
-               case PSI_T_FLOAT:
-                       res->dval = zend_get_constant_str(exp->u.cnst->name, strlen(exp->u.cnst->name))->value.dval;
-                       return PSI_T_DOUBLE;
-               default:
-                       return 0;
-               }
-               break;
-
-       case PSI_T_ENUM:
-               return psi_calc_num_exp(exp->u.enm->num ?: &exp->u.enm->inc, NULL, res);
-               break;
-
-       case PSI_T_NAME:
-               if (strct) {
-                       ref = struct_member_ref(exp->u.dvar->arg, strct, &tmp);
-               } else {
-                       ref = exp->u.dvar->arg->let;
-               }
-               switch (real_decl_type(exp->u.dvar->arg->type)->type) {
-               case PSI_T_INT8:
-               case PSI_T_UINT8:
-               case PSI_T_INT16:
-               case PSI_T_UINT16:
-               case PSI_T_INT32:
-               case PSI_T_UINT32:
-               case PSI_T_INT64:
-               case PSI_T_UINT64:
-                       memcpy(res, deref_impl_val(ref, exp->u.dvar), sizeof(*res));
-                       if (tmp) {
-                               free(tmp);
-                       }
-                       return real_decl_type(exp->u.dvar->arg->type)->type;
-
-               case PSI_T_FLOAT:
-               case PSI_T_DOUBLE:
-                       memcpy(res, deref_impl_val(ref, exp->u.dvar), sizeof(*res));
-                       if (tmp) {
-                               free(tmp);
-                       }
-                       return real_decl_type(exp->u.dvar->arg->type)->type;
-
-               EMPTY_SWITCH_DEFAULT_CASE();
-               }
-               break;
-
-       EMPTY_SWITCH_DEFAULT_CASE();
-       }
-       return  0;
-}
-
-int psi_calc_num_exp(num_exp *exp, impl_val *strct, impl_val *res) {
-       impl_val num = {0};
-       int num_type = psi_calc_num_exp_value(exp, strct, &num);
-
-       if (exp->operand) {
-               impl_val tmp = {0};
-               int tmp_type = psi_calc_num_exp(exp->operand, strct, &tmp);
-
-               return exp->calculator(num_type, &num, tmp_type, &tmp, res);
-       }
-
-       memcpy(res, &num, sizeof(*res));
-       return num_type;
-}
-
 #define PRIfval "f"
 #define PRIdval "lf"
 #define PRIldval "Lf"
@@ -108,18 +44,18 @@ int psi_calc_num_exp(num_exp *exp, impl_val *strct, impl_val *res) {
 } while(0)
 
 #ifdef HAVE_LONG_DOUBLE
-#define PSI_CALC_NO_LD
-#define PSI_CALC_OP_LD PSI_CALC_OP(ldval)
-#define PSI_CALC_OP2_LD2(var1) PSI_CALC_OP2(ldval, var1, ldval)
-#define PSI_CALC_OP2_LD1(var2) PSI_CALC_OP2(ldval, ldval, var2)
+# define PSI_CALC_NO_LD
+# define PSI_CALC_OP_LD PSI_CALC_OP(ldval)
+# define PSI_CALC_OP2_LD2(var1) PSI_CALC_OP2(ldval, var1, ldval)
+# define PSI_CALC_OP2_LD1(var2) PSI_CALC_OP2(ldval, ldval, var2)
 #else
-#define PSI_CALC_NO_LD abort()
-#define PSI_CALC_OP_LD PSI_CALC_NO_LD
-#define PSI_CALC_OP2_LD2(var) PSI_CALC_NO_LD
-#define PSI_CALC_OP2_LD1(var) PSI_CALC_NO_LD
+# define PSI_CALC_NO_LD abort()
+# define PSI_CALC_OP_LD PSI_CALC_NO_LD
+# define PSI_CALC_OP2_LD2(var) PSI_CALC_NO_LD
+# define PSI_CALC_OP2_LD1(var) PSI_CALC_NO_LD
 #endif
 
-#define PSI_CALC_FN(op) int psi_calc_##op(int t1, impl_val *v1, int t2, impl_val *v2, impl_val *res) \
+#define PSI_CALC_FN(op) token_t psi_calc_##op(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res) \
 { \
        if (t1 == t2) { \
                switch (t1) { \
index db8fd7c..d294cfb 100644 (file)
@@ -1,33 +1,37 @@
-#ifndef _PSI_CALC_H
-#define _PSI_CALC_H
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
 
-#include "num_exp.h"
-#include "impl_val.h"
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+     * Redistributions of source code must retain the above copyright notice,
+       this list of conditions and the following disclaimer.
+     * Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
 
-int psi_calc_num_exp(num_exp *exp, impl_val *strct, impl_val *res);
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
 
-static inline zend_long psi_long_num_exp(num_exp *exp, impl_val *strct) {
-       impl_val val = {0};
+#ifndef PSI_CALC_H
+#define PSI_CALC_H
 
-       switch (psi_calc_num_exp(exp, strct, &val)) {
-       case PSI_T_UINT8:       return val.u8;
-       case PSI_T_UINT16:      return val.u16;
-       case PSI_T_UINT32:      return val.u32;
-       case PSI_T_UINT64:      return val.u64; /* FIXME */
-       case PSI_T_INT8:        return val.i8;
-       case PSI_T_INT16:       return val.i16;
-       case PSI_T_INT32:       return val.i32;
-       case PSI_T_INT64:       return val.i64;
-       case PSI_T_FLOAT:       return val.fval;
-       case PSI_T_DOUBLE:      return val.dval;
-       EMPTY_SWITCH_DEFAULT_CASE();
-       }
-       return 0;
-}
+#include "token.h"
+#include "impl_val.h"
 
-int psi_calc_add(int t1, impl_val *v1, int t2, impl_val *v2, impl_val *res);
-int psi_calc_sub(int t1, impl_val *v1, int t2, impl_val *v2, impl_val *res);
-int psi_calc_mul(int t1, impl_val *v1, int t2, impl_val *v2, impl_val *res);
-int psi_calc_div(int t1, impl_val *v1, int t2, impl_val *v2, impl_val *res);
+token_t psi_calc_add(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
+token_t psi_calc_sub(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
+token_t psi_calc_mul(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
+token_t psi_calc_div(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res);
 
 #endif
diff --git a/src/call.c b/src/call.c
new file mode 100644 (file)
index 0000000..46a1dde
--- /dev/null
@@ -0,0 +1,545 @@
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+     * Redistributions of source code must retain the above copyright notice,
+       this list of conditions and the following disclaimer.
+     * Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#include "php_psi_stdinc.h"
+#include "context.h"
+#include "data.h"
+#include "call.h"
+
+#include "php.h"
+#include "zend_exceptions.h"
+
+struct psi_call_frame_argument *psi_call_frame_argument_init(struct psi_impl_arg *spec,
+               impl_val *ival, zval *zptr, int is_vararg) {
+       struct psi_call_frame_argument *frame_arg = ecalloc(1, sizeof(*frame_arg));
+
+
+       if ((frame_arg->zval_ptr = zptr)) {
+               ZVAL_DEREF(frame_arg->zval_ptr);
+
+               /* use userland type if the declared type of the vararg is mixed */
+               if (is_vararg) {
+                       if (spec->type->type == PSI_T_MIXED) {
+                               switch (Z_TYPE_P(zptr)) {
+                               case IS_TRUE:
+                                       frame_arg->va_type = PSI_T_BOOL;
+                                       ival->zend.bval = 1;
+                                       break;
+                               case IS_FALSE:
+                                       frame_arg->va_type = PSI_T_BOOL;
+                                       ival->zend.bval = 0;
+                                       break;
+                               case IS_LONG:
+                                       frame_arg->va_type = PSI_T_INT;
+                                       ival->zend.lval = Z_LVAL_P(zptr);
+                                       break;
+                               case IS_DOUBLE:
+                                       frame_arg->va_type = PSI_T_FLOAT;
+                                       ival->dval = Z_DVAL_P(zptr);
+                                       break;
+                               default:
+                                       frame_arg->va_type = PSI_T_STRING;
+                                       ival->zend.str = zval_get_string(zptr);
+                                       break;
+                               }
+                       } else {
+                               frame_arg->va_type = spec->type->type;
+                       }
+               }
+       }
+
+       frame_arg->ival = *ival;
+       frame_arg->ival_ptr = &frame_arg->ival;
+       frame_arg->spec = spec;
+
+       return frame_arg;
+}
+
+void psi_call_frame_argument_free(struct psi_call_frame_argument *arg) {
+       switch (arg->spec->type->type) {
+       case PSI_T_STRING:
+               if (arg->ival.zend.str) {
+                       zend_string_release(arg->ival.zend.str);
+               }
+               break;
+       case PSI_T_CALLABLE:
+               if (arg->ival.zend.cb) {
+                       if (arg->ival.zend.cb->fci.size) {
+                               zend_fcall_info_args_clear(&arg->ival.zend.cb->fci, 1);
+                       }
+                       efree(arg->ival.zend.cb);
+               }
+               break;
+       default:
+               break;
+       }
+       if (arg->ival_ptr && arg->ival_ptr != &arg->temp_val && arg->ival_ptr != &arg->ival) {
+               efree(arg->ival_ptr);
+       }
+       efree(arg);
+}
+
+struct psi_call_frame_symbol *psi_call_frame_symbol_init(struct psi_decl_var *dvar) {
+       struct psi_call_frame_symbol *frame_sym;
+       size_t size = psi_decl_type_get_size(dvar->arg->type, NULL);
+
+       frame_sym = ecalloc(1, sizeof(*frame_sym) + size);
+       frame_sym->ptr = frame_sym->ival_ptr = &frame_sym->temp_val;
+
+       return frame_sym;
+}
+
+void psi_call_frame_symbol_free(struct psi_call_frame_symbol *sym) {
+       efree(sym);
+}
+
+static void psi_call_frame_free_argument(zval *zptr) {
+       psi_call_frame_argument_free(Z_PTR_P(zptr));
+}
+
+static void psi_call_frame_free_symbol(zval *zptr) {
+       psi_call_frame_symbol_free(Z_PTR_P(zptr));
+}
+
+struct psi_call_frame_auto_free {
+       void *data;
+       void (*dtor)(void *);
+};
+
+static void psi_call_frame_free_temp(void *ptr) {
+       struct psi_call_frame_auto_free *f = ptr;
+
+       if (f->data) {
+               if (f->dtor) {
+                       f->dtor(&f->data);
+               } else {
+                       efree(f->data);
+               }
+       }
+}
+
+struct psi_call_frame *psi_call_frame_init(struct psi_context *C, struct psi_decl *decl, struct psi_impl *impl) {
+       struct psi_call_frame *frame = ecalloc(1, sizeof(*frame));
+
+       frame->context = C;
+       frame->decl = decl;
+       frame->impl = impl;
+
+       zend_hash_init(&frame->arguments, 8, NULL, psi_call_frame_free_argument, 0);
+       zend_hash_init(&frame->symbols, 8, NULL, psi_call_frame_free_symbol, 0);
+       zend_llist_init(&frame->temp, sizeof(struct psi_call_frame_auto_free), psi_call_frame_free_temp, 0);
+
+       return frame;
+}
+
+struct psi_call_frame_symbol *psi_call_frame_fetch_symbol(
+               struct psi_call_frame *frame, struct psi_decl_var *dvar) {
+       struct psi_call_frame_symbol *frame_sym;
+
+       frame_sym = zend_hash_str_find_ptr(&frame->symbols, dvar->fqn, strlen(dvar->fqn));
+       if (!frame_sym) {
+               frame_sym = zend_hash_str_add_ptr(&frame->symbols, dvar->fqn, strlen(dvar->fqn),
+                               psi_call_frame_symbol_init(dvar));
+       }
+       return frame_sym;
+}
+
+zval *psi_call_frame_new_argument(struct psi_call_frame *frame,
+               struct psi_call_frame_argument *frame_arg) {
+       if (frame_arg->va_type) {
+               /* varargs are just appended with numeric indices */
+               return zend_hash_next_index_insert_ptr(&frame->arguments, frame_arg);
+       } else {
+               return zend_hash_str_add_ptr(&frame->arguments,
+                               frame_arg->spec->var->name, strlen(frame_arg->spec->var->name),
+                               frame_arg);
+       }
+}
+
+zval *psi_call_frame_sub_argument(struct psi_call_frame *frame,
+               struct psi_impl_var *inner_var, zval *outer_zval, const char *name) {
+       struct psi_call_frame_argument *iarg;
+       zval *inner_zval = zend_symtable_str_find(Z_ARRVAL_P(outer_zval),
+                       &inner_var->name[1], strlen(&inner_var->name[1]));
+
+       if (!inner_zval) {
+               zval empty_zval;
+
+               ZVAL_NULL(&empty_zval);
+               inner_zval = zend_symtable_str_update(Z_ARRVAL_P(outer_zval),
+                               &inner_var->name[1], strlen(&inner_var->name[1]),
+                               &empty_zval);
+       }
+
+       iarg = psi_call_frame_get_argument(frame, name);
+
+       if (!iarg) {
+               struct psi_call_frame_argument *frame_arg;
+               impl_val empty_val = {0};
+               struct psi_impl_arg *carg_spec = psi_impl_arg_init(
+                               psi_impl_type_init(PSI_T_MIXED, "mixed"),
+                               psi_impl_var_copy(inner_var), NULL);
+
+               psi_call_frame_push_auto_ex(frame, carg_spec, (void(*)(void*)) psi_impl_arg_free);
+               frame_arg = psi_call_frame_argument_init(carg_spec, &empty_val, inner_zval, 0);
+               zend_hash_str_add_ptr(&frame->arguments, name, strlen(name), frame_arg);
+       }
+
+       return inner_zval;
+}
+
+struct psi_call_frame_argument *psi_call_frame_get_argument(
+               struct psi_call_frame *frame, const char *name) {
+       return zend_hash_str_find_ptr(&frame->arguments, name, strlen(name));
+}
+
+size_t psi_call_frame_num_var_args(struct psi_call_frame *frame) {
+       return zend_hash_next_free_element(&frame->arguments);
+}
+
+size_t psi_call_frame_num_fixed_args(struct psi_call_frame *frame) {
+       return psi_plist_count(frame->decl->args);
+}
+
+struct psi_call_frame_argument *psi_call_frame_get_var_argument(
+               struct psi_call_frame *frame, zend_long index) {
+       return zend_hash_index_find_ptr(&frame->arguments, index);
+}
+
+void **psi_call_frame_get_arg_pointers(struct psi_call_frame *frame) {
+       return frame->pointers;
+}
+
+ZEND_RESULT_CODE psi_call_frame_parse_args(struct psi_call_frame *frame,
+               zend_execute_data *execute_data) {
+       size_t i, argc = psi_plist_count(frame->impl->func->args);
+       zend_error_handling zeh;
+
+       zend_replace_error_handling(EH_THROW, zend_exception_get_default(), &zeh);
+
+       if (!argc) {
+               ZEND_RESULT_CODE rv;
+
+               rv = zend_parse_parameters_none();
+               zend_restore_error_handling(&zeh);
+               return rv;
+       }
+
+       ZEND_PARSE_PARAMETERS_START(
+                       psi_impl_num_min_args(frame->impl),
+                       frame->impl->func->vararg ? -1 : argc
+       )
+       nextarg: {
+
+               struct psi_impl_arg *iarg;
+               impl_val ival = {0};
+
+               if (frame->impl->func->vararg && _i >= argc) {
+                       iarg = frame->impl->func->vararg;
+                       Z_PARAM_OPTIONAL;
+               } else {
+                       psi_plist_get(frame->impl->func->args, _i, &iarg);
+                       if (iarg->def) {
+                               Z_PARAM_OPTIONAL;
+                       }
+               }
+
+               if (PSI_T_BOOL == iarg->type->type) {
+                       Z_PARAM_BOOL(ival.zend.bval);
+               } else if (PSI_T_INT == iarg->type->type) {
+                       Z_PARAM_LONG(ival.zend.lval);
+               } else if (PSI_T_FLOAT == iarg->type->type || PSI_T_DOUBLE == iarg->type->type) {
+                       Z_PARAM_DOUBLE(ival.dval);
+               } else if (PSI_T_STRING == iarg->type->type) {
+                       Z_PARAM_STR_EX(ival.zend.str, 1, iarg->var->reference);
+                       if (ival.zend.str) {
+                               zend_string_addref(ival.zend.str);
+                       }
+               } else if (PSI_T_ARRAY == iarg->type->type) {
+                       zval *tmp;
+                       Z_PARAM_ARRAY_EX(tmp, _optional || iarg->var->reference,
+                                       iarg->var->reference);
+               } else if (PSI_T_OBJECT == iarg->type->type) {
+                       Z_PARAM_PROLOGUE(0);
+               } else if (PSI_T_MIXED == iarg->type->type) {
+                       Z_PARAM_PROLOGUE(0);
+               } else if (PSI_T_CALLABLE == iarg->type->type) {
+                       zend_fcall_info fci;
+                       zend_fcall_info_cache fcc;
+
+                       Z_PARAM_FUNC_EX(fci, fcc, 1, 0);
+
+                       if (fci.size) {
+                               ival.zend.cb = ecalloc(1, sizeof(zend_fcall));
+                               ival.zend.cb->fci = fci;
+                               ival.zend.cb->fcc = fcc;
+                       }
+               } else {
+                       error_code = ZPP_ERROR_FAILURE;
+                       break;
+               }
+
+               psi_call_frame_new_argument(frame,
+                               psi_call_frame_argument_init(iarg, &ival, _arg, _i > argc));
+
+               if (_i < _num_args) {
+                       goto nextarg;
+               }
+       }
+       ZEND_PARSE_PARAMETERS_END_EX(
+               zend_restore_error_handling(&zeh);
+               return FAILURE;
+       );
+
+       /* set up defaults */
+       for (i = EX_NUM_ARGS(); i < argc; ++i) {
+               struct psi_impl_arg *iarg;
+
+               psi_plist_get(frame->impl->func->args, i, &iarg);
+
+               assert(iarg->def);
+               psi_call_frame_new_argument(frame, psi_call_frame_argument_init(iarg,
+                               &iarg->def->ival, NULL, 0));
+       }
+
+       zend_restore_error_handling(&zeh);
+       return SUCCESS;
+}
+
+void psi_call_frame_enter(struct psi_call_frame *frame) {
+       size_t argc = psi_call_frame_num_fixed_args(frame);
+       size_t va_count = psi_call_frame_num_var_args(frame);
+       size_t rsize = psi_decl_arg_get_size(frame->decl->func);
+       struct psi_call_frame_symbol *rv_sym;
+
+       /* initialize ffi argument array */
+       frame->pointers = ecalloc(argc + va_count + 1, sizeof(void *));
+
+       /* initialize return value symbol */
+       rv_sym = psi_call_frame_fetch_symbol(frame, frame->decl->func->var);
+       if (rsize > sizeof(impl_val)) {
+               rv_sym->ival_ptr = ecalloc(1, rsize);
+       } else {
+               rv_sym->ival_ptr = &rv_sym->temp_val;
+       }
+       frame->rpointer = rv_sym->ptr = rv_sym->ival_ptr;
+}
+
+ZEND_RESULT_CODE psi_call_frame_do_let(struct psi_call_frame *frame) {
+       size_t i;
+       struct psi_let_stmt *let;
+       struct psi_decl_arg *arg;
+       size_t argc = psi_call_frame_num_fixed_args(frame);
+       size_t va_count = psi_call_frame_num_var_args(frame);
+
+       for (i = 0; psi_plist_get(frame->impl->stmts.let, i, &let); ++i) {
+               psi_let_stmt_exec(let, frame);
+       }
+       for (i = 0; psi_plist_get(frame->decl->args, i, &arg); ++i) {
+               struct psi_let_stmt *let;
+               struct psi_call_frame_symbol *frame_sym;
+
+               let = psi_impl_get_let(frame->impl, arg->var);
+               frame_sym = psi_call_frame_fetch_symbol(frame, let->exp->var);
+               frame->pointers[i] = frame_sym->ptr;
+       }
+       /* varargs */
+       if (va_count) {
+               for (i = 0; i < va_count; ++i) {
+                       struct psi_call_frame_argument *frame_arg;
+                       psi_marshal_let let_fn;
+                       void *temp = NULL;
+
+                       frame_arg = psi_call_frame_get_var_argument(frame, i);
+                       switch (frame_arg->va_type) {
+                       case PSI_T_BOOL:        let_fn = psi_let_boolval;       break;
+                       case PSI_T_INT:         let_fn = psi_let_intval;        break;
+                       case PSI_T_FLOAT:
+                       case PSI_T_DOUBLE:      let_fn = psi_let_floatval;      break;
+                       case PSI_T_STRING:      let_fn = psi_let_strval;        break;
+                       default:
+                               assert(0);
+                       }
+
+                       frame_arg->ival_ptr = let_fn(&frame_arg->temp_val, NULL, frame_arg->va_type,
+                                       &frame_arg->ival, frame_arg->zval_ptr, &temp);
+                       if (temp) {
+                               psi_call_frame_push_auto(frame, temp);
+                       }
+
+                       frame->pointers[argc + i] = frame_arg->ival_ptr;
+               }
+       }
+
+       return SUCCESS;
+}
+
+void psi_call_frame_do_call(struct psi_call_frame *frame) {
+       size_t va_count = psi_call_frame_num_var_args(frame);
+
+       if (va_count) {
+               void **va_types = ecalloc(va_count, sizeof(void *));
+               size_t i;
+
+               for (i = 0; i < va_count; ++i) {
+                       struct psi_call_frame_argument *frame_arg;
+
+                       frame_arg = psi_call_frame_get_var_argument(frame, i);
+                       va_types[i] = frame->context->ops->query(frame->context,
+                                       PSI_CONTEXT_QUERY_TYPE, &frame_arg->va_type);
+               }
+
+               frame->context->ops->call_va(frame->context,
+                               frame,
+                               frame->decl,
+                               frame->rpointer,
+                               frame->pointers,
+                               va_count,
+                               va_types);
+
+               efree(va_types);
+       } else {
+               frame->context->ops->call(frame->context,
+                               frame,
+                               frame->decl,
+                               frame->rpointer,
+                               frame->pointers);
+       }
+}
+
+void psi_call_frame_do_callback(struct psi_call_frame *frame, struct psi_call_frame_callback *cbdata)
+{
+       size_t i;
+       void *retptr;
+       ZEND_RESULT_CODE rc;
+       struct psi_let_callback *cb = cbdata->cb->data.callback;
+       zval return_value, *zargv = ecalloc(cbdata->argc, sizeof(*zargv));
+       struct psi_call_frame_argument *frame_arg;
+
+       assert(cbdata->argc == psi_plist_count(cb->decl->args));
+
+       /* prepare args for the userland call */
+       for (i = 0; i < cbdata->argc; ++i) {
+               struct psi_set_exp *set_exp;
+               struct psi_decl_var *set_var;
+               struct psi_call_frame_symbol *set_sym;
+
+               psi_plist_get(cb->args, i, &set_exp);
+               set_var = psi_set_exp_get_decl_var(set_exp);
+               set_sym = psi_call_frame_fetch_symbol(frame, set_var);
+
+               set_sym->ptr = cbdata->argv[i];
+               psi_set_exp_exec_ex(set_exp, &zargv[i], set_sym->ptr, frame);
+       }
+
+       frame_arg = psi_call_frame_get_argument(frame, cb->func->var->fqn);
+
+       /* callback into userland */
+       ZVAL_UNDEF(&return_value);
+       zend_fcall_info_argp(&frame_arg->ival_ptr->zend.cb->fci, cbdata->argc, zargv);
+       rc = zend_fcall_info_call(&frame_arg->ival_ptr->zend.cb->fci,
+                       &frame_arg->ival_ptr->zend.cb->fcc,     &return_value, NULL);
+       assert(rc == SUCCESS);
+
+       /* marshal return value of the userland call */
+       frame_arg->zval_ptr = &return_value;
+       retptr = psi_let_func_exec(cbdata->cb, cb->func, cb->decl->func, frame);
+       memcpy(cbdata->rval, retptr, psi_decl_arg_get_size(cb->decl->func));
+
+       /* cleanup */
+       zend_fcall_info_args_clear(&frame_arg->ival_ptr->zend.cb->fci, 0);
+       for (i = 0; i < cbdata->argc; ++i) {
+               zval_ptr_dtor(&zargv[i]);
+       }
+       efree(zargv);
+}
+
+void psi_call_frame_do_return(struct psi_call_frame *frame, zval *return_value) {
+       struct psi_return_stmt *ret;
+
+       psi_plist_get(frame->impl->stmts.ret, 0, &ret);
+       psi_return_stmt_exec(ret, return_value, frame);
+}
+
+void psi_call_frame_do_set(struct psi_call_frame *frame) {
+       size_t i = 0;
+       struct psi_set_stmt *set;
+
+       while (psi_plist_get(frame->impl->stmts.set, i++, &set)) {
+               psi_set_stmt_exec(set, frame);
+       }
+}
+
+void psi_call_frame_do_free(struct psi_call_frame *frame) {
+       size_t i = 0;
+       struct psi_free_stmt *fre;
+
+       while (psi_plist_get(frame->impl->stmts.fre, i++, &fre)) {
+               psi_free_stmt_exec(fre, frame);
+       }
+}
+
+void **psi_call_frame_push_auto_ex(struct psi_call_frame *frame, void *auto_free, void (*dtor)(void*)) {
+       struct psi_call_frame_auto_free f;
+
+       f.data = auto_free;
+       f.dtor = dtor;
+
+       zend_llist_add_element(&frame->temp, &f);
+       return &((struct psi_call_frame_auto_free *) zend_llist_get_last(&frame->temp))->data;
+}
+
+void **psi_call_frame_push_auto(struct psi_call_frame *frame, void *auto_free) {
+       return psi_call_frame_push_auto_ex(frame, auto_free, NULL);
+}
+
+static void psi_call_frame_local_auto_dtor(void *auto_list)
+{
+       zend_llist_destroy(auto_list);
+       efree(auto_list);
+}
+
+#include "php_psi.h"
+
+void psi_call_frame_free(struct psi_call_frame *frame) {
+       zend_hash_destroy(&frame->arguments);
+       zend_hash_destroy(&frame->symbols);
+       if (frame->impl && frame->impl->func->static_memory) {
+               zend_llist *temp = emalloc(sizeof(*temp));
+               zval zlocal;
+
+               memcpy(temp, &frame->temp, sizeof(*temp));
+               ZVAL_OBJ(&zlocal, psi_object_init_ex(NULL, temp, psi_call_frame_local_auto_dtor));
+               zend_set_local_var_str(frame->impl->func->name,
+                               strlen(frame->impl->func->name), &zlocal, /* force */ 1);
+       } else {
+               zend_llist_destroy(&frame->temp);
+       }
+       efree(frame->pointers);
+       efree(frame);
+}
+
+
+
diff --git a/src/call.h b/src/call.h
new file mode 100644 (file)
index 0000000..01e6ead
--- /dev/null
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+     * Redistributions of source code must retain the above copyright notice,
+       this list of conditions and the following disclaimer.
+     * Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#ifndef PSI_CALL_H
+#define PSI_CALL_H
+
+#include "Zend/zend_types.h"
+
+#include "data.h"
+
+struct psi_call_frame_symbol {
+       impl_val *ival_ptr; /* marshaled */
+       void *ptr; /* possibly indirect (pointer to ival_ptr) */
+       impl_val temp_val;
+};
+
+struct psi_call_frame_argument {
+       impl_val ival; /* input */
+       impl_val temp_val; /* va */
+       impl_val *ival_ptr; /* marshaled, pointer to ival or temp_val */
+       zval *zval_ptr; /* input */
+       struct psi_impl_arg *spec;
+       token_t va_type;
+};
+
+struct psi_call_frame_callback {
+       struct psi_let_exp *cb;
+       size_t argc;
+       void **argv;
+       void *rval;
+};
+
+struct psi_call_frame_argument *psi_call_frame_argument_init(struct psi_impl_arg *spec, impl_val *ival, zval *zptr, int is_vararg);
+void psi_call_frame_argument_free(struct psi_call_frame_argument *arg);
+
+struct psi_call_frame_symbol *psi_call_frame_symbol_init();
+void psi_call_frame_symbol_free(struct psi_call_frame_symbol *arg);
+
+struct psi_call_frame {
+       struct psi_context *context;
+       struct psi_decl *decl;
+       struct psi_impl *impl;
+       HashTable arguments;
+       HashTable symbols;
+       void **pointers;
+       void *rpointer;
+       zend_llist temp;
+};
+
+struct psi_call_frame *psi_call_frame_init(struct psi_context *context, struct psi_decl *decl, struct psi_impl *impl);
+
+ZEND_RESULT_CODE psi_call_frame_parse_args(struct psi_call_frame *frame, zend_execute_data *execute_data);
+
+size_t psi_call_frame_num_var_args(struct psi_call_frame *frame);
+size_t psi_call_frame_num_fixed_args(struct psi_call_frame *frame);
+
+zval *psi_call_frame_new_argument(struct psi_call_frame *frame, struct psi_call_frame_argument *frame_arg);
+zval *psi_call_frame_sub_argument(struct psi_call_frame *frame, struct psi_impl_var *inner_var, zval *outer_zval, const char *name);
+
+struct psi_call_frame_argument *psi_call_frame_get_argument(struct psi_call_frame *frame, const char *name);
+struct psi_call_frame_argument *psi_call_frame_get_var_argument(struct psi_call_frame *frame, zend_long index);
+
+struct psi_call_frame_symbol *psi_call_frame_fetch_symbol(struct psi_call_frame *frame, struct psi_decl_var *dvar);
+
+void psi_call_frame_enter(struct psi_call_frame *frame);
+
+void **psi_call_frame_get_arg_pointers(struct psi_call_frame *frame);
+
+ZEND_RESULT_CODE psi_call_frame_do_let(struct psi_call_frame *frame);
+void psi_call_frame_do_call(struct psi_call_frame *frame);
+void psi_call_frame_do_callback(struct psi_call_frame *frame, struct psi_call_frame_callback *cb);
+void psi_call_frame_do_return(struct psi_call_frame *frame, zval *return_value);
+void psi_call_frame_do_set(struct psi_call_frame *frame);
+void psi_call_frame_do_free(struct psi_call_frame *frame);
+
+void **psi_call_frame_push_auto_ex(struct psi_call_frame *frame, void *auto_free, void (*dtor)(void*));
+void **psi_call_frame_push_auto(struct psi_call_frame *frame, void *auto_free);
+
+void psi_call_frame_free(struct psi_call_frame *frame);
+
+
+#endif
index b7ae46f..3ac26c7 100644 (file)
@@ -1,8 +1,27 @@
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#else
-# include "php_config.h"
-#endif
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+     * Redistributions of source code must retain the above copyright notice,
+       this list of conditions and the following disclaimer.
+     * Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
 
 #include "php_psi_stdinc.h"
 
@@ -30,6 +49,7 @@
 #include "php_scandir.h"
 #include "php_psi.h"
 #include "calc.h"
+#include "call.h"
 #include "libjit.h"
 #include "libffi.h"
 
@@ -58,8 +78,7 @@ struct psi_context *psi_context_init(struct psi_context *C, struct psi_context_o
        }
        memset(C, 0, sizeof(*C));
 
-       C->error = error;
-       C->flags = flags;
+       psi_data_ctor(PSI_DATA(C), error, flags);
        C->ops = ops;
 
        if (ops->init) {
@@ -71,133 +90,129 @@ struct psi_context *psi_context_init(struct psi_context *C, struct psi_context_o
 
        /* build up predefs in a temporary PSI_Data for validation */
        memset(&T, 0, sizeof(T));
-       T.error = error;
+       psi_data_ctor_with_dtors(&T, error, flags);
 
        for (predef_type = &psi_predef_types[0]; predef_type->type_tag; ++predef_type) {
-               decl_type *type = init_decl_type(predef_type->type_tag, predef_type->type_name);
-               decl_var *var = init_decl_var(predef_type->alias, 0, 0); /* FIXME: indirection */
-               decl_arg *def = init_decl_arg(type, var);
+               struct psi_decl_type *type = psi_decl_type_init(predef_type->type_tag, predef_type->type_name);
+               struct psi_decl_var *var = psi_decl_var_init(predef_type->alias, 0, 0); /* FIXME: indirection */
+               struct psi_decl_arg *def = psi_decl_arg_init(type, var);
 
-               T.defs = add_decl_typedef(T.defs, def);
+               T.types = psi_plist_add(T.types, &def);
        }
        for (predef_const = &psi_predef_consts[0]; predef_const->type_tag; ++predef_const) {
-               impl_def_val *val = init_impl_def_val(predef_const->val_type_tag, predef_const->val_text);
-               const_type *type = init_const_type(predef_const->type_tag, predef_const->type_name);
-               constant *constant = init_constant(type, predef_const->var_name, val);
+               struct psi_impl_def_val *val = psi_impl_def_val_init(predef_const->val_type_tag, predef_const->val_text);
+               struct psi_const_type *type = psi_const_type_init(predef_const->type_tag, predef_const->type_name);
+               struct psi_const *constant = psi_const_init(type, predef_const->var_name, val);
 
-               T.consts = add_constant(T.consts, constant);
+               T.consts = psi_plist_add(T.consts, &constant);
        }
        for (predef_struct = &psi_predef_structs[0]; predef_struct->type_tag; ++predef_struct) {
                struct psi_predef_struct *member;
-               decl_args *dargs = init_decl_args(NULL);
-               decl_struct *dstruct = init_decl_struct(predef_struct->var_name, dargs);
+               struct psi_plist *dargs = psi_plist_init((psi_plist_dtor) psi_decl_arg_free);
+               struct psi_decl_struct *dstruct = psi_decl_struct_init(predef_struct->var_name, dargs);
 
                dstruct->size = predef_struct->size;
                dstruct->align = predef_struct->offset;
                for (member = &predef_struct[1]; member->type_tag; ++member) {
-                       decl_type *type;
-                       decl_var *dvar;
-                       decl_arg *darg;
-
-                       type = init_decl_type(member->type_tag, member->type_name);
-                       dvar = init_decl_var(member->var_name, member->pointer_level, member->array_size);
-                       darg = init_decl_arg(type, dvar);
-                       darg->layout = init_decl_struct_layout(member->offset, member->size);
-                       dargs = add_decl_arg(dargs, darg);
+                       struct psi_decl_type *type;
+                       struct psi_decl_var *dvar;
+                       struct psi_decl_arg *darg;
+
+                       type = psi_decl_type_init(member->type_tag, member->type_name);
+                       dvar = psi_decl_var_init(member->var_name, member->pointer_level, member->array_size);
+                       darg = psi_decl_arg_init(type, dvar);
+                       darg->layout = psi_layout_init(member->offset, member->size);
+                       dstruct->args = psi_plist_add(dstruct->args, &darg);
                }
 
-               T.structs = add_decl_struct(T.structs, dstruct);
+               T.structs = psi_plist_add(T.structs, &dstruct);
                predef_struct = member;
        }
        for (predef_union = &psi_predef_unions[0]; predef_union->type_tag; ++predef_union) {
                struct psi_predef_union *member;
-               decl_args *dargs = init_decl_args(NULL);
-               decl_union *dunion = init_decl_union(predef_union->var_name, dargs);
+               struct psi_plist *dargs = psi_plist_init((psi_plist_dtor) psi_decl_arg_free);
+               struct psi_decl_union *dunion = psi_decl_union_init(predef_union->var_name, dargs);
 
                dunion->size = predef_union->size;
                dunion->align = predef_union->offset;
                for (member = &predef_union[1]; member->type_tag; ++member) {
-                       decl_type *type;
-                       decl_var *dvar;
-                       decl_arg *darg;
-
-                       type = init_decl_type(member->type_tag, member->type_name);
-                       dvar = init_decl_var(member->var_name, member->pointer_level, member->array_size);
-                       darg = init_decl_arg(type, dvar);
-                       darg->layout = init_decl_struct_layout(member->offset, member->size);
-                       dargs = add_decl_arg(dargs, darg);
+                       struct psi_decl_type *type;
+                       struct psi_decl_var *dvar;
+                       struct psi_decl_arg *darg;
+
+                       type = psi_decl_type_init(member->type_tag, member->type_name);
+                       dvar = psi_decl_var_init(member->var_name, member->pointer_level, member->array_size);
+                       darg = psi_decl_arg_init(type, dvar);
+                       darg->layout = psi_layout_init(member->offset, member->size);
+                       dunion->args = psi_plist_add(dunion->args, &darg);
                }
 
-               T.unions = add_decl_union(T.unions, dunion);
+               T.unions = psi_plist_add(T.unions, &dunion);
                predef_union = member;
        }
        for (predef_decl = &psi_predef_decls[0]; predef_decl->type_tag; ++predef_decl) {
                struct psi_predef_decl *farg;
-               decl_type *ftype = init_decl_type(predef_decl->type_tag, predef_decl->type_name);
-               decl_var *fname = init_decl_var(predef_decl->var_name, predef_decl->pointer_level, predef_decl->array_size);
-               decl_arg *func = init_decl_arg(ftype, fname);
-               decl_args *args = init_decl_args(NULL);
-               decl *decl = init_decl(init_decl_abi("default"), func, args);
+               struct psi_decl_type *ftype = psi_decl_type_init(predef_decl->type_tag, predef_decl->type_name);
+               struct psi_decl_var *fname = psi_decl_var_init(predef_decl->var_name, predef_decl->pointer_level, predef_decl->array_size);
+               struct psi_decl_arg *func = psi_decl_arg_init(ftype, fname);
+               struct psi_plist *args = psi_plist_init((psi_plist_dtor) psi_decl_arg_free);
+               struct psi_decl *decl = psi_decl_init(psi_decl_abi_init("default"), func, args);
 
                for (farg = &predef_decl[1]; farg->type_tag; ++farg) {
-                       decl_type *arg_type = init_decl_type(farg->type_tag, farg->type_name);
-                       decl_var *arg_var = init_decl_var(farg->var_name, farg->pointer_level, farg->array_size);
-                       decl_arg *darg = init_decl_arg(arg_type, arg_var);
-                       args = add_decl_arg(args, darg);
+                       struct psi_decl_type *arg_type = psi_decl_type_init(farg->type_tag, farg->type_name);
+                       struct psi_decl_var *arg_var = psi_decl_var_init(farg->var_name, farg->pointer_level, farg->array_size);
+                       struct psi_decl_arg *darg = psi_decl_arg_init(arg_type, arg_var);
+                       decl->args = psi_plist_add(decl->args, &darg);
                }
 
-               T.decls = add_decl(T.decls, decl);
+               T.decls = psi_plist_add(T.decls, &decl);
                predef_decl = farg;
        }
 
        for (predef_decl = &psi_predef_vararg_decls[0]; predef_decl->type_tag; ++predef_decl) {
                struct psi_predef_decl *farg;
-               decl_type *ftype = init_decl_type(predef_decl->type_tag, predef_decl->type_name);
-               decl_var *fname = init_decl_var(predef_decl->var_name, predef_decl->pointer_level, predef_decl->array_size);
-               decl_arg *func = init_decl_arg(ftype, fname);
-               decl_args *args = init_decl_args(NULL);
-               decl *decl = init_decl(init_decl_abi("default"), func, args);
+               struct psi_decl_type *ftype = psi_decl_type_init(predef_decl->type_tag, predef_decl->type_name);
+               struct psi_decl_var *fname = psi_decl_var_init(predef_decl->var_name, predef_decl->pointer_level, predef_decl->array_size);
+               struct psi_decl_arg *func = psi_decl_arg_init(ftype, fname);
+               struct psi_plist *args = psi_plist_init((psi_plist_dtor) psi_decl_arg_free);
+               struct psi_decl *decl = psi_decl_init(psi_decl_abi_init("default"), func, args);
 
                for (farg = &predef_decl[1]; farg->type_tag; ++farg) {
-                       decl_type *arg_type = init_decl_type(farg->type_tag, farg->type_name);
-                       decl_var *arg_var = init_decl_var(farg->var_name, farg->pointer_level, farg->array_size);
-                       decl_arg *darg = init_decl_arg(arg_type, arg_var);
-                       args = add_decl_arg(args, darg);
+                       struct psi_decl_type *arg_type = psi_decl_type_init(farg->type_tag, farg->type_name);
+                       struct psi_decl_var *arg_var = psi_decl_var_init(farg->var_name, farg->pointer_level, farg->array_size);
+                       struct psi_decl_arg *darg = psi_decl_arg_init(arg_type, arg_var);
+                       decl->args = psi_plist_add(decl->args, &darg);
                }
-               args->varargs = 1;
+               decl->varargs = 1;
 
-               T.decls = add_decl(T.decls, decl);
+               T.decls = psi_plist_add(T.decls, &decl);
                predef_decl = farg;
        }
 
        for (predef_decl = &psi_predef_functor_decls[0]; predef_decl->type_tag; ++predef_decl) {
                struct psi_predef_decl *farg;
-               decl_type *dtype, *ftype = init_decl_type(predef_decl->type_tag, predef_decl->type_name);
-               decl_var *fname = init_decl_var(predef_decl->var_name, predef_decl->pointer_level, predef_decl->array_size);
-               decl_arg *tdef, *func = init_decl_arg(ftype, fname);
-               decl_args *args = init_decl_args(NULL);
-               decl *decl = init_decl(init_decl_abi("default"), func, args);
+               struct psi_decl_type *dtype, *ftype = psi_decl_type_init(predef_decl->type_tag, predef_decl->type_name);
+               struct psi_decl_var *fname = psi_decl_var_init(predef_decl->var_name, predef_decl->pointer_level, predef_decl->array_size);
+               struct psi_decl_arg *tdef, *func = psi_decl_arg_init(ftype, fname);
+               struct psi_plist *args = psi_plist_init((psi_plist_dtor) psi_decl_arg_free);
+               struct psi_decl *decl = psi_decl_init(psi_decl_abi_init("default"), func, args);
 
                for (farg = &predef_decl[1]; farg->type_tag; ++farg) {
-                       decl_type *arg_type = init_decl_type(farg->type_tag, farg->type_name);
-                       decl_var *arg_var = init_decl_var(farg->var_name, farg->pointer_level, farg->array_size);
-                       decl_arg *darg = init_decl_arg(arg_type, arg_var);
-                       args = add_decl_arg(args, darg);
+                       struct psi_decl_type *arg_type = psi_decl_type_init(farg->type_tag, farg->type_name);
+                       struct psi_decl_var *arg_var = psi_decl_var_init(farg->var_name, farg->pointer_level, farg->array_size);
+                       struct psi_decl_arg *darg = psi_decl_arg_init(arg_type, arg_var);
+                       decl->args = psi_plist_add(decl->args, &darg);
                }
 
-               dtype = init_decl_type(PSI_T_FUNCTION, fname->name);
+               dtype = psi_decl_type_init(PSI_T_FUNCTION, fname->name);
                dtype->real.func = decl;
-               tdef = init_decl_arg(dtype, copy_decl_var(fname));
-               T.defs = add_decl_typedef(T.defs, tdef);
+               tdef = psi_decl_arg_init(dtype, psi_decl_var_copy(fname));
+               T.types = psi_plist_add(T.types, &tdef);
 
                predef_decl = farg;
        }
 
-       psi_context_validate_data(PSI_DATA(C), &T);
-
-       C->count = 1;
-       C->data = malloc(sizeof(*C->data));
-       psi_data_exchange(C->data, &T);
+       psi_context_add_data(C, &T);
 
        return C;
 }
@@ -205,7 +220,7 @@ struct psi_context *psi_context_init(struct psi_context *C, struct psi_context_o
 static int psi_select_dirent(const struct dirent *entry)
 {
 #ifndef FNM_CASEFOLD
-#define FNM_CASEFOLD 0
+# define FNM_CASEFOLD 0
 #endif
        return 0 == fnmatch("*.psi", entry->d_name, FNM_CASEFOLD);
 }
@@ -232,11 +247,11 @@ void psi_context_build(struct psi_context *C, const char *paths)
                                struct psi_parser P;
 
                                if (MAXPATHLEN <= slprintf(psi, MAXPATHLEN, "%s/%s", ptr, entries[i]->d_name)) {
-                                       C->error(C, NULL, PSI_WARNING, "Path to PSI file too long: %s/%s",
+                                       C->error(PSI_DATA(C), NULL, PSI_WARNING, "Path to PSI file too long: %s/%s",
                                                ptr, entries[i]->d_name);
                                }
                                if (!psi_parser_init(&P, psi, C->error, C->flags)) {
-                                       C->error(C, NULL, PSI_WARNING, "Failed to init PSI parser (%s): %s",
+                                       C->error(PSI_DATA(C), NULL, PSI_WARNING, "Failed to init PSI parser (%s): %s",
                                                psi, strerror(errno));
                                        continue;
                                }
@@ -249,7 +264,7 @@ void psi_context_build(struct psi_context *C, const char *paths)
                                }
 
                                psi_parser_parse(&P, NULL);
-                               psi_context_validate(C, &P);
+                               psi_context_add_data(C, PSI_DATA(&P));
                                psi_parser_dtor(&P);
                        }
                }
@@ -266,25 +281,24 @@ void psi_context_build(struct psi_context *C, const char *paths)
 
 
        if (psi_context_compile(C) && SUCCESS != zend_register_functions(NULL, C->closures, NULL, MODULE_PERSISTENT)) {
-               C->error(C, NULL, PSI_WARNING, "Failed to register functions!");
+               C->error(PSI_DATA(C), NULL, PSI_WARNING, "Failed to register functions!");
        }
 
        free(cpy);
-
 }
 
 zend_function_entry *psi_context_compile(struct psi_context *C)
 {
-       size_t i;
        zend_constant zc;
 
        zc.flags = CONST_PERSISTENT|CONST_CS;
        zc.module_number = EG(current_module)->module_number;
 
        if (C->consts) {
-               for (i = 0; i < C->consts->count; ++i) {
-                       constant *c = C->consts->list[i];
+               size_t i = 0;
+               struct psi_const *c;
 
+               while (psi_plist_get(C->consts, i++, &c)) {
                        zc.name = zend_string_init(c->name + (c->name[0] == '\\'), strlen(c->name) - (c->name[0] == '\\'), 1);
                        ZVAL_NEW_STR(&zc.value, zend_string_init(c->val->text, strlen(c->val->text), 1));
 
@@ -308,16 +322,18 @@ zend_function_entry *psi_context_compile(struct psi_context *C)
                }
        }
        if (C->enums) {
-               for (i = 0; i < C->enums->count; ++i) {
-                       decl_enum *e = C->enums->list[i];
-                       size_t j;
+               size_t i = 0;
+               struct psi_decl_enum *e;
+
+               while (psi_plist_get(C->enums, i++, &e)) {
+                       size_t j = 0;
+                       struct psi_decl_enum_item *item;
 
-                       for (j = 0; j < e->items->count; ++j) {
-                               decl_enum_item *i = e->items->list[j];
-                               zend_string *name = strpprintf(0, "psi\\%s\\%s", e->name, i->name);
+                       while (psi_plist_get(e->items, j++, &item)) {
+                               zend_string *name = strpprintf(0, "psi\\%s\\%s", e->name, item->name);
 
                                zc.name = zend_string_dup(name, 1);
-                               ZVAL_LONG(&zc.value, psi_long_num_exp(i->num, NULL));
+                               ZVAL_LONG(&zc.value, psi_long_num_exp(item->num, NULL));
                                zend_register_constant(&zc);
                                zend_string_release(name);
                        }
@@ -328,9 +344,34 @@ zend_function_entry *psi_context_compile(struct psi_context *C)
 }
 
 
-void psi_context_call(struct psi_context *C, struct decl_callinfo *decl_call, struct impl_vararg *va)
+ZEND_RESULT_CODE psi_context_call(struct psi_context *C, zend_execute_data *execute_data, zval *return_value, struct psi_impl *impl)
 {
-       C->ops->call(C, decl_call, va);
+       struct psi_call_frame *frame;
+
+       frame = psi_call_frame_init(C, impl->decl, impl);
+
+       if (SUCCESS != psi_call_frame_parse_args(frame, execute_data)) {
+               psi_call_frame_free(frame);
+
+               return FAILURE;
+       }
+
+       psi_call_frame_enter(frame);
+
+       if (SUCCESS != psi_call_frame_do_let(frame)) {
+               psi_call_frame_do_return(frame, return_value);
+               psi_call_frame_free(frame);
+
+               return FAILURE;
+       }
+
+       psi_call_frame_do_call(frame);
+       psi_call_frame_do_return(frame, return_value);
+       psi_call_frame_do_set(frame);
+       psi_call_frame_do_free(frame);
+       psi_call_frame_free(frame);
+
+       return SUCCESS;
 }
 
 
@@ -343,7 +384,7 @@ void psi_context_dtor(struct psi_context *C)
                C->ops->dtor(C);
        }
 
-       free_decl_libs(&C->psi.libs);
+       psi_data_dtor(PSI_DATA(C));
 
        if (C->data) {
                for (i = 0; i < C->count; ++i) {
@@ -358,51 +399,6 @@ void psi_context_dtor(struct psi_context *C)
                }
                free(C->closures);
        }
-
-       if (C->consts) {
-               if (C->consts->list) {
-                       free(C->consts->list);
-               }
-               free(C->consts);
-       }
-       if (C->defs) {
-               if (C->defs->list) {
-                       free(C->defs->list);
-               }
-               free(C->defs);
-       }
-       if (C->structs) {
-               if (C->structs->list) {
-                       free(C->structs->list);
-               }
-               free(C->structs);
-       }
-       if (C->unions) {
-               if (C->unions->list) {
-                       free(C->unions->list);
-               }
-               free(C->unions);
-       }
-       if (C->enums) {
-               if (C->enums->list) {
-                       free(C->enums->list);
-               }
-               free(C->enums);
-       }
-       if (C->decls) {
-               if (C->decls->list) {
-                       free(C->decls->list);
-               }
-               free(C->decls);
-       }
-       if (C->impls) {
-               if (C->impls->list) {
-                       free(C->impls->list);
-               }
-               free(C->impls);
-       }
-
-       memset(C, 0, sizeof(*C));
 }
 
 void psi_context_free(struct psi_context **C)
@@ -414,264 +410,29 @@ void psi_context_free(struct psi_context **C)
        }
 }
 
-int psi_context_validate(struct psi_context *C, struct psi_parser *P)
+bool psi_context_add_data(struct psi_context *C, struct psi_data *P)
 {
        struct psi_data *D;
-       void *dlopened = NULL;
-       size_t i, count = C->count++, check_round, check_count;
-       decl_typedefs *check_defs = P->defs;
-       decl_structs *check_structs = P->structs;
-       decl_unions *check_unions = P->unions;
-       decl_enums *check_enums = P->enums;
-       unsigned flags = C->flags;
-
-       C->data = realloc(C->data, C->count * sizeof(*C->data));
-       D = psi_data_exchange(&C->data[count], PSI_DATA(P));
-
-#define REVALIDATE(what) do { \
-               if (check_round && check_ ##what) { \
-                       free(check_ ##what->list); \
-                       free(check_ ##what); \
-               } \
-               check_ ##what = recheck_ ##what; \
-} while (0)
-#define CHECK_TOTAL (CHECK_COUNT(defs) + CHECK_COUNT(structs) + CHECK_COUNT(enums))
-#define CHECK_COUNT(of) (check_ ##of ? check_ ##of->count : 0)
-
-       if (!(flags & PSI_PARSER_SILENT)) {
-               /* no warnings on first round */
-               C->flags |= PSI_PARSER_SILENT;
-       }
-       for (check_round = 0, check_count = 0; CHECK_TOTAL && check_count != CHECK_TOTAL; ++check_round) {
-               decl_typedefs *recheck_defs = NULL;
-               decl_structs *recheck_structs = NULL;
-               decl_unions *recheck_unions = NULL;
-               decl_enums *recheck_enums = NULL;
-
-               check_count = CHECK_TOTAL;
-
-               for (i = 0; i < CHECK_COUNT(defs); ++i) {
-                       if (validate_decl_typedef(PSI_DATA(C), check_defs->list[i])) {
-                               C->defs = add_decl_typedef(C->defs, check_defs->list[i]);
-                       } else {
-                               recheck_defs = add_decl_typedef(recheck_defs, check_defs->list[i]);
-                       }
-               }
-               for (i = 0; i < CHECK_COUNT(structs); ++i) {
-                       if (validate_decl_struct(PSI_DATA(C), check_structs->list[i])) {
-                               C->structs = add_decl_struct(C->structs, check_structs->list[i]);
-                       } else {
-                               recheck_structs = add_decl_struct(recheck_structs, check_structs->list[i]);
-                       }
-               }
-               for (i = 0; i < CHECK_COUNT(unions); ++i) {
-                       if (validate_decl_union(PSI_DATA(C), check_unions->list[i])) {
-                               C->unions = add_decl_union(C->unions, check_unions->list[i]);
-                       } else {
-                               recheck_unions = add_decl_union(recheck_unions, check_unions->list[i]);
-                       }
-               }
-               for (i = 0; i < CHECK_COUNT(enums); ++i) {
-                       if (validate_decl_enum(PSI_DATA(C), check_enums->list[i])) {
-                               C->enums = add_decl_enum(C->enums, check_enums->list[i]);
-                       } else {
-                               recheck_enums = add_decl_enum(recheck_enums, check_enums->list[i]);
-                       }
-               }
-
-               REVALIDATE(defs);
-               REVALIDATE(structs);
-               REVALIDATE(unions);
-               REVALIDATE(enums);
-
-               if (check_round == 0 && !(flags & PSI_PARSER_SILENT)) {
-                       C->flags ^= PSI_PARSER_SILENT;
-               }
-       }
-
-       C->flags = flags;
-
-       if (D->consts) {
-               for (i = 0; i < D->consts->count; ++i) {
-                       if (validate_constant(PSI_DATA(C), D->consts->list[i])) {
-                               C->consts = add_constant(C->consts, D->consts->list[i]);
-                       }
-               }
-       }
-
-       if (!validate_file(D, &dlopened)) {
-               return 0;
-       }
-
-       add_decl_lib(&C->psi.libs, dlopened);
-
-       if (D->decls) {
-               for (i = 0; i < D->decls->count; ++i) {
-                       if (validate_decl(PSI_DATA(C), dlopened, D->decls->list[i])) {
-                               C->decls = add_decl(C->decls, D->decls->list[i]);
-                       }
-               }
-       }
-       if (D->impls) {
-               for (i = 0; i < D->impls->count; ++i) {
-                       if (validate_impl(PSI_DATA(C), D->impls->list[i])) {
-                               C->impls = add_impl(C->impls, D->impls->list[i]);
-                       }
-               }
-       }
-
-       return 1;
-}
-
-int psi_context_validate_data(struct psi_data *dest, struct psi_data *source)
-{
-       size_t i;
-       int errors = 0;
-
-       if (source->defs) for (i = 0; i < source->defs->count; ++i) {
-               decl_arg *def = source->defs->list[i];
-
-               if (validate_decl_typedef(source, def)) {
-                       if (dest) {
-                               dest->defs = add_decl_typedef(dest->defs, def);
-                       }
-               } else {
-                       ++errors;
-               }
-       }
 
-       if (source->consts) for (i = 0; i < source->consts->count; ++i) {
-               constant *constant = source->consts->list[i];
+       C->data = realloc(C->data, (C->count + 1) * sizeof(*C->data));
+       D = psi_data_exchange(&C->data[C->count++], P);
 
-               if (validate_constant(source, constant)) {
-                       if (dest) {
-                               dest->consts = add_constant(dest->consts, constant);
-                       }
-               } else {
-                       ++errors;
-               }
-       }
-
-       if (source->structs) for (i = 0; i < source->structs->count; ++i) {
-               decl_struct *dstruct = source->structs->list[i];
-
-               if (validate_decl_struct(source, dstruct)) {
-                       if (dest) {
-                               dest->structs = add_decl_struct(dest->structs, dstruct);
-                       }
-               } else {
-                       ++errors;
-               }
-       }
-
-       if (source->unions) for (i = 0; i < source->unions->count; ++i) {
-               decl_union *dunion = source->unions->list[i];
-
-               if (validate_decl_union(source, dunion)) {
-                       if (dest) {
-                               dest->unions = add_decl_union(dest->unions, dunion);
-                       }
-               } else {
-                       ++errors;
-               }
-       }
-
-       if (source->enums) for (i = 0; i < source->enums->count; ++i) {
-               decl_enum *denum = source->enums->list[i];
-
-               if (validate_decl_enum(source, denum)) {
-                       if (dest) {
-                               dest->enums = add_decl_enum(dest->enums, denum);
-                       }
-               } else {
-                       ++errors;
-               }
-       }
-
-       if (source->decls) for (i = 0; i < source->decls->count; ++i) {
-               decl *decl = source->decls->list[i];
-
-               if (validate_decl(source, NULL, decl)) {
-                       if (dest) {
-                               dest->decls = add_decl(dest->decls, decl);
-                       }
-               } else {
-                       ++errors;
-               }
-       }
-
-       if (source->impls) for (i = 0; i < source->impls->count; ++i) {
-               impl *impl = source->impls->list[i];
-
-               if (validate_impl(source, impl)) {
-                       if (dest) {
-                               dest->impls = add_impl(dest->impls, impl);
-                       }
-               } else {
-                       ++errors;
-               }
-       }
-
-       return errors;
-}
-
-static inline void dump_data(int fd, struct psi_data *D) {
-       if (D->psi.file.fn) {
-               dprintf(fd, "// psi.filename=%s\n", D->psi.file.fn);
-               if (D->psi.file.ln) {
-                       dprintf(fd, "lib \"%s\";\n", D->psi.file.ln);
-               }
-       } else {
-               dprintf(fd, "// builtin predef\n");
-       }
-       if (D->defs) {
-               dump_decl_typedefs(fd, D->defs);
-               dprintf(fd, "\n");
-       }
-       if (D->unions) {
-               dump_decl_unions(fd, D->unions);
-               dprintf(fd, "\n");
-       }
-       if (D->structs) {
-               dump_decl_structs(fd, D->structs);
-               dprintf(fd, "\n");
-       }
-       if (D->enums) {
-               dump_decl_enums(fd, D->enums);
-               dprintf(fd, "\n");
-       }
-       if (D->consts) {
-               dump_constants(fd, D->consts);
-               dprintf(fd, "\n");
-       }
-       if (D->decls) {
-               dump_decls(fd, D->decls);
-               dprintf(fd, "\n");
-       }
-       if (D->impls) {
-               dump_impls(fd, D->impls);
-               dprintf(fd, "\n");
-       }
+       return psi_data_validate(PSI_DATA(C), D);
 }
 
 void psi_context_dump(struct psi_context *C, int fd)
 {
-       size_t i;
 
-#ifdef HAVE_LIBJIT
-       if (C->ops == psi_libjit_ops()) {
-               dprintf(fd, "// psi.engine=jit\n");
-       }
-#endif
-#ifdef HAVE_LIBFFI
-       if (C->ops == psi_libffi_ops()) {
-               dprintf(fd, "// psi.engine=ffi\n");
-       }
-#endif
-       dprintf(fd, "\n");
+       dprintf(fd, "// psi.engine=%s\n",
+                       (char *) C->ops->query(C, PSI_CONTEXT_QUERY_SELF, NULL));
 
-       for (i = 0; i < C->count; ++i) {
-               dump_data(fd, &C->data[i]);
-       }
+       psi_data_dump(fd, PSI_DATA(C));
+
+//     size_t i;
+//     dprintf(fd, "/* parsed\n");
+//     for (i = 0; i < C->count; ++i) {
+//             psi_data_dump(fd, &C->data[i]);
+//     }
+//     dprintf(fd, "*/\n");
 
 }
index d132256..dc350fb 100644 (file)
@@ -1,17 +1,54 @@
-#ifndef _PSI_CONTEXT_H
-#define _PSI_CONTEXT_H
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+     * Redistributions of source code must retain the above copyright notice,
+       this list of conditions and the following disclaimer.
+     * Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#ifndef PSI_CONTEXT_H
+#define PSI_CONTEXT_H
+
+/* zend_function_entry */
+#include "Zend/zend_API.h"
 
 struct psi_context;
 struct psi_token;
 struct psi_parser;
-struct decl_callinfo;
+struct psi_call_frame;
 struct impl_vararg;
+struct psi_decl;
+struct psi_impl;
+
+enum psi_context_query {
+       PSI_CONTEXT_QUERY_SELF, /* ffi/jit */
+       PSI_CONTEXT_QUERY_TYPE, /* impl type token_t to native ffi_type/jit_type */
+};
 
 struct psi_context_ops {
        void (*init)(struct psi_context *C);
        void (*dtor)(struct psi_context *C);
        zend_function_entry *(*compile)(struct psi_context *C);
-       void (*call)(struct psi_context *C, struct decl_callinfo *decl_call, struct impl_vararg *va);
+       void (*call)(struct psi_context *C, struct psi_call_frame *frame, struct psi_decl *psi_decl, void *rval, void **args);
+       void (*call_va)(struct psi_context *C, struct psi_call_frame *frame, struct psi_decl *psi_decl, void *rval, void **args, size_t va_count, void **va_types);
+       void *(*query)(struct psi_context *C, enum psi_context_query q, void *arg);
 };
 
 #include "data.h"
@@ -25,12 +62,19 @@ struct psi_context {
        size_t count;
 };
 
+struct psi_context_call_data {
+       struct psi_context *context;
+       union {
+               struct psi_impl *fn;
+               struct psi_let_callback *cb;
+       } impl;
+};
+
 struct psi_context *psi_context_init(struct psi_context *C, struct psi_context_ops *ops, psi_error_cb error, unsigned flags);
 void psi_context_build(struct psi_context *C, const char *path);
-int psi_context_validate(struct psi_context *C, struct psi_parser *P);
-int psi_context_validate_data(struct psi_data *C, struct psi_data *D);
+bool psi_context_add_data(struct psi_context *C, struct psi_data *P);
 zend_function_entry *psi_context_compile(struct psi_context *C);
-void psi_context_call(struct psi_context *C, struct decl_callinfo *decl_call, struct impl_vararg *va);
+ZEND_RESULT_CODE psi_context_call(struct psi_context *C, zend_execute_data *execute_data, zval *return_value, struct psi_impl *impl);
 void psi_context_dump(struct psi_context *C, int fd);
 void psi_context_dtor(struct psi_context *C);
 void psi_context_free(struct psi_context **C);
index 860387d..9c2cefb 100644 (file)
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#else
-# include "php_config.h"
-#endif
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
 
-#include <string.h>
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
 
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *******************************************************************************/
+
+#include "php_psi_stdinc.h"
 #include "data.h"
 
-struct psi_data *psi_data_exchange(struct psi_data *dest, struct psi_data *src) {
+#include "php_globals.h"
+
+#include <dlfcn.h>
+
+struct psi_data *psi_data_ctor_with_dtors(struct psi_data *data,
+               psi_error_cb error, unsigned flags)
+{
+       if (!data) {
+               data = calloc(1, sizeof(*data));
+       }
+
+       data->error = error;
+       data->flags = flags;
+
+       if (!data->consts) {
+               data->consts = psi_plist_init((psi_plist_dtor) psi_const_free);
+       }
+       if (!data->types) {
+               data->types = psi_plist_init((psi_plist_dtor) psi_decl_arg_free);
+       }
+       if (!data->structs) {
+               data->structs = psi_plist_init((psi_plist_dtor) psi_decl_struct_free);
+       }
+       if (!data->unions) {
+               data->unions = psi_plist_init((psi_plist_dtor) psi_decl_union_free);
+       }
+       if (!data->enums) {
+               data->enums = psi_plist_init((psi_plist_dtor) psi_decl_enum_free);
+       }
+       if (!data->decls) {
+               data->decls = psi_plist_init((psi_plist_dtor) psi_decl_free);
+       }
+       if (!data->impls) {
+               data->impls = psi_plist_init((psi_plist_dtor) psi_impl_free);
+       }
+       if (!data->libs) {
+               data->libs = psi_plist_init((psi_plist_dtor) psi_libs_free);
+       }
+       return data;
+}
+
+struct psi_data *psi_data_ctor(struct psi_data *data, psi_error_cb error,
+               unsigned flags)
+{
+       if (!data) {
+               data = calloc(1, sizeof(*data));
+       }
+
+       data->error = error;
+       data->flags = flags;
+
+       if (!data->consts) {
+               data->consts = psi_plist_init(NULL);
+       }
+       if (!data->types) {
+               data->types = psi_plist_init(NULL);
+       }
+       if (!data->structs) {
+               data->structs = psi_plist_init(NULL);
+       }
+       if (!data->unions) {
+               data->unions = psi_plist_init(NULL);
+       }
+       if (!data->enums) {
+               data->enums = psi_plist_init(NULL);
+       }
+       if (!data->decls) {
+               data->decls = psi_plist_init(NULL);
+       }
+       if (!data->impls) {
+               data->impls = psi_plist_init(NULL);
+       }
+       if (!data->libs) {
+               data->libs = psi_plist_init(NULL);
+       }
+       return data;
+}
+
+struct psi_data *psi_data_exchange(struct psi_data *dest, struct psi_data *src)
+{
        if (!dest) {
                dest = malloc(sizeof(*dest));
        }
-       memcpy(dest, src, sizeof(*dest));
+       *dest = *src;
        memset(src, 0, sizeof(*src));
        return dest;
 }
 
-void psi_data_dtor(struct psi_data *data) {
+void psi_data_dtor(struct psi_data *data)
+{
        if (data->consts) {
-               free_constants(data->consts);
+               psi_plist_free(data->consts);
        }
-       if (data->defs) {
-               free_decl_typedefs(data->defs);
+       if (data->types) {
+               psi_plist_free(data->types);
        }
        if (data->structs) {
-               free_decl_structs(data->structs);
+               psi_plist_free(data->structs);
        }
        if (data->unions) {
-               free_decl_unions(data->unions);
+               psi_plist_free(data->unions);
        }
        if (data->enums) {
-               free_decl_enums(data->enums);
+               psi_plist_free(data->enums);
        }
        if (data->decls) {
-               free_decls(data->decls);
+               psi_plist_free(data->decls);
        }
        if (data->impls) {
-               free_impls(data->impls);
+               psi_plist_free(data->impls);
+       }
+       if (data->libs) {
+               psi_plist_free(data->libs);
+       }
+
+       psi_decl_file_dtor(&data->file);
+}
+
+void psi_data_dump(int fd, struct psi_data *D)
+{
+       if (D->file.fn) {
+               dprintf(fd, "// filename=%s (%u errors)\n", D->file.fn, D->errors);
+               if (D->file.ln) {
+                       dprintf(fd, "lib \"%s\";\n", D->file.ln);
+               }
+       } else {
+               dprintf(fd, "// builtin predef\n");
+       }
+       if (psi_plist_count(D->types)) {
+               size_t i = 0;
+               struct psi_decl_arg *def;
+
+               while (psi_plist_get(D->types, i++, &def)) {
+                       dprintf(fd, "typedef ");
+                       psi_decl_arg_dump(fd, def, 0);
+                       dprintf(fd, ";\n");
+               }
+               dprintf(fd, "\n");
+       }
+       if (psi_plist_count(D->unions)) {
+               size_t i = 0;
+               struct psi_decl_union *unn;
+
+               while (psi_plist_get(D->unions, i++, &unn)) {
+                       if (!psi_decl_type_is_anon(unn->name, "union")) {
+                               psi_decl_union_dump(fd, unn);
+                               dprintf(fd, "\n");
+                       }
+               }
+               dprintf(fd, "\n");
        }
-       free_decl_file(&data->psi.file);
+       if (psi_plist_count(D->structs)) {
+               size_t i = 0;
+               struct psi_decl_struct *strct;
+
+               while (psi_plist_get(D->structs, i++, &strct)) {
+                       if (!psi_decl_type_is_anon(strct->name, "struct")) {
+                               psi_decl_struct_dump(fd, strct);
+                               dprintf(fd, "\n");
+                       }
+               }
+               dprintf(fd, "\n");
+       }
+       if (psi_plist_count(D->enums)) {
+               size_t i = 0;
+               struct psi_decl_enum *enm;
+
+               while (psi_plist_get(D->enums, i++, &enm)) {
+                       if (!psi_decl_type_is_anon(enm->name, "enum")) {
+                               psi_decl_enum_dump(fd, enm, 0);
+                               dprintf(fd, "\n");
+                       }
+               }
+               dprintf(fd, "\n");
+       }
+       if (psi_plist_count(D->consts)) {
+               size_t i = 0;
+               struct psi_const *c;
+
+               while (psi_plist_get(D->consts, i++, &c)) {
+                       psi_const_dump(fd, c);
+                       dprintf(fd, "\n");
+               }
+               dprintf(fd, "\n");
+       }
+       if (psi_plist_count(D->decls)) {
+               size_t i = 0;
+               struct psi_decl *decl;
+
+               while (psi_plist_get(D->decls, i++, &decl)) {
+                       psi_decl_dump(fd, decl);
+                       dprintf(fd, "\n");
+               }
+               dprintf(fd, "\n");
+       }
+       if (psi_plist_count(D->impls)) {
+               size_t i = 0;
+               struct psi_impl *impl;
+
+               while (psi_plist_get(D->impls, i++, &impl)) {
+                       psi_impl_dump(fd, impl);
+                       dprintf(fd, "\n");
+               }
+               dprintf(fd, "\n");
+       }
+}
+
+bool psi_data_validate(struct psi_data *dst, struct psi_data *src)
+{
+       void *dlopened = NULL;
+       size_t check_count = ~0;
+       struct psi_plist *check_types = src->types;
+       struct psi_plist *check_structs = src->structs;
+       struct psi_plist *check_unions = src->unions;
+       struct psi_plist *check_enums = src->enums;
+       unsigned flags = dst->flags;
+       unsigned errors = src->errors;
+
+       /* fail early if library is not found */
+       if (!psi_decl_file_validate(dst, src, &dlopened)) {
+               return false;
+       }
+
+       dst->flags |= PSI_SILENT;
+
+       while (check_count) {
+               struct psi_plist *recheck_types;
+               struct psi_plist *recheck_structs;
+               struct psi_plist *recheck_unions;
+               struct psi_plist *recheck_enums;
+               size_t count_types = psi_plist_count(check_types);
+               size_t count_structs = psi_plist_count(check_structs);
+               size_t count_unions = psi_plist_count(check_unions);
+               size_t count_enums = psi_plist_count(check_enums);
+               size_t count_all = count_types + count_structs + count_unions
+                               + count_enums;
+
+               if (check_count == count_all) {
+                       /* nothing changed; bail out */
+                       if (count_all && (dst->flags & PSI_SILENT) && !(flags & PSI_SILENT)) {
+                               /* one last error-spitting round, if not explicitly suppressed */
+                               dst->flags ^= PSI_SILENT;
+                               check_count = ~0;
+
+                               PSI_DEBUG_PRINT(dst, "PSI: validation bail out with %zu"
+                                               " type checks remaining, errors follow\n", count_all);
+                               continue;
+                       }
+                       check_count = 0;
+               } else {
+                       recheck_types = count_types ? psi_plist_init(NULL) : NULL;
+                       recheck_structs = count_structs ? psi_plist_init(NULL) : NULL;
+                       recheck_unions = count_unions ? psi_plist_init(NULL) : NULL;
+                       recheck_enums = count_enums ? psi_plist_init(NULL) : NULL;
+
+                       check_count = count_all;
+                       src->errors = errors + check_count;
+
+                       PSI_DEBUG_PRINT(dst, "PSI: validate data(%p) %zu type checks remaining\n",
+                                       src, check_count);
+
+                       if (count_types) {
+                               size_t i = 0;
+                               struct psi_decl_arg *def;
+
+                               while (psi_plist_get(check_types, i++, &def)) {
+                                       *dst->last_error = 0;
+                                       PSI_DEBUG_PRINT(dst, "PSI: validate typedef %s ", def->var->name);
+                                       if (psi_decl_arg_validate_typedef(PSI_DATA(dst), def)) {
+                                               PSI_DEBUG_PRINT(dst, "%s\n", "✔");
+                                               dst->types = psi_plist_add(dst->types, &def);
+                                       } else {
+                                               PSI_DEBUG_PRINT(dst, "%s (%s)\n", "✘", dst->last_error);
+                                               recheck_types = psi_plist_add(recheck_types, &def);
+                                       }
+                               }
+                       }
+                       if (count_structs) {
+                               size_t i = 0;
+                               struct psi_decl_struct *str;
+
+                               while (psi_plist_get(check_structs, i++, &str)) {
+                                       *dst->last_error = 0;
+                                       dst->structs = psi_plist_add(dst->structs, &str);
+                                       PSI_DEBUG_PRINT(dst, "PSI: validate struct %s ", str->name);
+                                       if (psi_decl_struct_validate(PSI_DATA(dst), str)) {
+                                               PSI_DEBUG_PRINT(dst, "%s ::(%zu, %zu)\n", "✔", str->align, str->size);
+                                       } else {
+                                               PSI_DEBUG_PRINT(dst, "%s (%s)\n", "✘", dst->last_error);
+                                               recheck_structs = psi_plist_add(recheck_structs, &str);
+                                               psi_plist_pop(dst->structs, NULL);
+                                       }
+                               }
+                       }
+                       if (count_unions) {
+                               size_t i = 0;
+                               struct psi_decl_union *unn;
+
+                               while (psi_plist_get(check_unions, i++, &unn)) {
+                                       *dst->last_error = 0;
+                                       dst->unions = psi_plist_add(dst->unions, &unn);
+                                       PSI_DEBUG_PRINT(dst, "PSI: validate union %s ", unn->name);
+                                       if (psi_decl_union_validate(PSI_DATA(dst), unn)) {
+                                               PSI_DEBUG_PRINT(dst, "%s ::(%zu, %zu)\n", "✔", unn->align, unn->size);
+
+                                       } else {
+                                               PSI_DEBUG_PRINT(dst, "%s (%s)\n", "✘", dst->last_error);
+                                               recheck_unions = psi_plist_add(recheck_unions, &unn);
+                                               psi_plist_pop(dst->unions, NULL);
+                                       }
+                               }
+                       }
+                       if (count_enums) {
+                               size_t i = 0;
+                               struct psi_decl_enum *enm;
+
+                               while (psi_plist_get(check_enums, i++, &enm)) {
+                                       *dst->last_error = 0;
+                                       PSI_DEBUG_PRINT(dst, "PSI: validate enum %s ", enm->name);
+                                       if (psi_decl_enum_validate(PSI_DATA(dst), enm)) {
+                                               PSI_DEBUG_PRINT(dst, "%s\n", "✔");
+                                               dst->enums = psi_plist_add(dst->enums, &enm);
+                                       } else {
+                                               PSI_DEBUG_PRINT(dst, "%s (%s)\n", "✘", dst->last_error);
+                                               recheck_enums = psi_plist_add(recheck_enums, &enm);
+                                       }
+                               }
+                       }
+               }
+
+               if (check_types && check_types != src->types) {
+                       psi_plist_free(check_types);
+               }
+               check_types = recheck_types;
+               if (check_structs && check_structs != src->structs) {
+                       psi_plist_free(check_structs);
+               }
+               check_structs = recheck_structs;
+               if (check_unions && check_unions != src->unions) {
+                       psi_plist_free(check_unions);
+               }
+               check_unions = recheck_unions;
+               if (check_enums && check_enums != src->enums) {
+                       psi_plist_free(check_enums);
+               }
+               check_enums = recheck_enums;
+       }
+
+       /* reset original flags */
+       dst->flags = flags;
+
+       if (src->consts) {
+               size_t i = 0;
+               struct psi_const *cnst;
+
+               while (psi_plist_get(src->consts, i++, &cnst)) {
+                       *dst->last_error = 0;
+                       PSI_DEBUG_PRINT(dst, "PSI: validate const %s ", cnst->name);
+                       if (psi_const_validate(PSI_DATA(dst), cnst)) {
+                               PSI_DEBUG_PRINT(dst, "%s\n", "✔");
+                               dst->consts = psi_plist_add(dst->consts, &cnst);
+                       } else {
+                               PSI_DEBUG_PRINT(dst, "%s (%s)\n", "✘", dst->last_error);
+                               ++src->errors;
+                       }
+               }
+       }
+
+       if (src->decls) {
+               size_t i = 0;
+               struct psi_decl *decl;
+
+               while (psi_plist_get(src->decls, i++, &decl)) {
+                       *dst->last_error = 0;
+                       PSI_DEBUG_PRINT(dst, "PSI: validate decl %s ", decl->func->var->name);
+                       if (psi_decl_validate(PSI_DATA(dst), decl, dlopened)) {
+                               PSI_DEBUG_PRINT(dst, "%s\n", "✔");
+                               dst->decls = psi_plist_add(dst->decls, &decl);
+                       } else {
+                               PSI_DEBUG_PRINT(dst, "%s (%s)\n", "✘", dst->last_error);
+                               ++src->errors;
+                       }
+               }
+       }
+
+       if (src->impls) {
+               size_t i = 0;
+               struct psi_impl *impl;
+
+               while (psi_plist_get(src->impls, i++, &impl)) {
+                       *dst->last_error = 0;
+                       PSI_DEBUG_PRINT(dst, "PSI: validate impl %s ", impl->func->name);
+                       if (psi_impl_validate(PSI_DATA(dst), impl)) {
+                               PSI_DEBUG_PRINT(dst, "%s\n", "✔");
+                               dst->impls = psi_plist_add(dst->impls, &impl);
+                       } else {
+                               PSI_DEBUG_PRINT(dst, "%s (%s)\n", "✘", dst->last_error);
+                               ++src->errors;
+                       }
+               }
+       }
+
+       return true;
 }
 
index c31269c..3c48716 100644 (file)
@@ -1,24 +1,61 @@
-#ifndef _PSI_DATA_H
-#define _PSI_DATA_H
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+     * Redistributions of source code must retain the above copyright notice,
+       this list of conditions and the following disclaimer.
+     * Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#ifndef PSI_DATA_H
+#define PSI_DATA_H
 
 #include "types.h"
 #include "error.h"
+#include "plist.h"
+
+#define PSI_DEBUG 0x1
+#define PSI_SILENT 0x2
+
+#include <stdarg.h>
+
+#define PSI_DEBUG_PRINT(ctx, msg, ...) do { \
+       if (PSI_DATA(ctx)->flags & PSI_DEBUG) { \
+               fprintf(stderr, msg, __VA_ARGS__); \
+       } \
+} while(0)
+
 
 #define PSI_DATA(D) ((struct psi_data *) (D))
 
 #define PSI_DATA_MEMBERS \
-       constants *consts; \
-       decl_typedefs *defs; \
-       decl_structs *structs; \
-       decl_unions *unions; \
-       decl_enums *enums; \
-       decls *decls; \
-       impls *impls; \
-       union { \
-               decl_file file; \
-               decl_libs libs; \
-       } psi; \
+       struct psi_decl_file file; \
+       struct psi_plist *consts; \
+       struct psi_plist *types; \
+       struct psi_plist *structs; \
+       struct psi_plist *unions; \
+       struct psi_plist *enums; \
+       struct psi_plist *decls; \
+       struct psi_plist *impls; \
+       struct psi_plist *libs; \
        psi_error_cb error; \
+       char last_error[0x1000]; \
        unsigned errors; \
        unsigned flags
 
@@ -26,7 +63,11 @@ struct psi_data {
        PSI_DATA_MEMBERS;
 };
 
+struct psi_data *psi_data_ctor(struct psi_data *data, psi_error_cb error, unsigned flags);
+struct psi_data *psi_data_ctor_with_dtors(struct psi_data *data, psi_error_cb error, unsigned flags);
 struct psi_data *psi_data_exchange(struct psi_data *dest, struct psi_data *src);
+bool psi_data_validate(struct psi_data *dst, struct psi_data *src);
 void psi_data_dtor(struct psi_data *data);
+void psi_data_dump(int fd, struct psi_data *data);
 
 #endif
diff --git a/src/engine.c b/src/engine.c
deleted file mode 100644 (file)
index 6fba400..0000000
+++ /dev/null
@@ -1,769 +0,0 @@
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#else
-# include "php_config.h"
-#endif
-
-#include "php.h"
-#include "php_psi.h"
-
-#include "zend_exceptions.h"
-#include "zend_interfaces.h"
-#include "ext/spl/spl_iterators.h"
-
-#include "parser.h"
-#include "engine.h"
-#include "calc.h"
-#include "marshal.h"
-
-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);
-}
-
-int psi_internal_type(impl_type *type)
-{
-       switch (type->type) {
-       case PSI_T_BOOL:
-               return _IS_BOOL;
-       case PSI_T_INT:
-               return IS_LONG;
-       case PSI_T_FLOAT:
-       case PSI_T_DOUBLE:
-               return IS_DOUBLE;
-       case PSI_T_STRING:
-               return IS_STRING;
-       case PSI_T_ARRAY:
-               return IS_ARRAY;
-       default:
-               return 0;
-       }
-}
-
-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;
-       zend_internal_arg_info *aip;
-       zend_internal_function_info *fi;
-
-       aip = calloc(impl->func->args->count + 1 + !!impl->func->args->vararg.name, sizeof(*aip));
-
-       fi = (zend_internal_function_info *) &aip[0];
-       fi->allow_null = 1;
-       fi->required_num_args = psi_num_min_args(impl);
-       fi->return_reference = impl->func->return_reference;
-       fi->type_hint = psi_internal_type(impl->func->return_type);
-
-       if (impl->func->args->vararg.name) {
-               impl_arg *vararg = impl->func->args->vararg.name;
-               zend_internal_arg_info *ai = &aip[impl->func->args->count];
-
-               ai->name = vararg->var->name;
-               ai->allow_null = 1;
-               ai->type_hint = psi_internal_type(vararg->type);
-               if (vararg->var->reference) {
-                       ai->pass_by_reference = 1;
-               }
-               ai->is_variadic = 1;
-       }
-
-       for (i = 0; i < impl->func->args->count; ++i) {
-               impl_arg *iarg = impl->func->args->args[i];
-               zend_internal_arg_info *ai = &aip[i+1];
-
-               ai->name = iarg->var->name;
-               ai->type_hint = psi_internal_type(iarg->type);
-               if (iarg->var->reference) {
-                       ai->pass_by_reference = 1;
-               }
-               //if (iarg->var->reference || (iarg->def && iarg->def->type == PSI_T_NULL)) {
-                       ai->allow_null = 1;
-               //}
-       }
-
-       return aip;
-}
-
-size_t psi_num_min_args(impl *impl)
-{
-       size_t i, n = impl->func->args->count;
-
-       for (i = 0; i < impl->func->args->count; ++i) {
-               if (impl->func->args->args[i]->def) {
-                       --n;
-               }
-       }
-       return n;
-}
-
-
-static inline ZEND_RESULT_CODE psi_parse_args(zend_execute_data *execute_data, impl *impl)
-{
-       size_t i;
-       impl_arg *iarg;
-       zend_error_handling zeh;
-
-       zend_replace_error_handling(EH_THROW, zend_exception_get_default(), &zeh);
-
-       if (!impl->func->args->count) {
-               ZEND_RESULT_CODE rv;
-
-               rv = zend_parse_parameters_none();
-               zend_restore_error_handling(&zeh);
-               return rv;
-       }
-
-       ZEND_PARSE_PARAMETERS_START(psi_num_min_args(impl), impl->func->args->vararg.name ? -1 : impl->func->args->count)
-       nextarg:
-               if (impl->func->args->vararg.name && _i >= impl->func->args->count) {
-                       impl_arg *varg = impl->func->args->vararg.name;
-                       iarg = init_impl_arg(
-                                       init_impl_type(varg->type->type, varg->type->name),
-                                       init_impl_var(varg->var->name, varg->var->reference),
-                                       NULL);
-
-                       Z_PARAM_OPTIONAL;
-                       if (_i == impl->func->args->count) {
-                               impl->func->args->vararg.args = init_impl_args(iarg);
-                       } else {
-                               add_impl_arg(impl->func->args->vararg.args, iarg);
-                       }
-               } else {
-                       iarg = impl->func->args->args[_i];
-                       if (iarg->def) {
-                               Z_PARAM_OPTIONAL;
-                       }
-               }
-               if (PSI_T_BOOL == iarg->type->type) {
-                       Z_PARAM_BOOL(iarg->val.zend.bval);
-               } else if (PSI_T_INT == iarg->type->type) {
-                       Z_PARAM_LONG(iarg->val.zend.lval);
-               } else if (PSI_T_FLOAT == iarg->type->type || PSI_T_DOUBLE == iarg->type->type) {
-                       Z_PARAM_DOUBLE(iarg->val.dval);
-               } else if (PSI_T_STRING == iarg->type->type) {
-                       Z_PARAM_STR_EX(iarg->val.zend.str, 1, iarg->var->reference);
-                       if (iarg->val.zend.str) {
-                               zend_string_addref(iarg->val.zend.str);
-                       }
-               } else if (PSI_T_ARRAY == iarg->type->type) {
-                       Z_PARAM_PROLOGUE(0);
-               } else if (PSI_T_OBJECT == iarg->type->type) {
-                       Z_PARAM_PROLOGUE(0);
-               } else if (PSI_T_MIXED == iarg->type->type) {
-                       Z_PARAM_PROLOGUE(0);
-               } else if (PSI_T_CALLABLE == iarg->type->type) {
-                       zend_fcall_info fci;
-                       zend_fcall_info_cache fcc;
-
-                       Z_PARAM_FUNC_EX(fci, fcc, 1, 0);
-
-                       if (fci.size) {
-                               iarg->val.zend.cb = ecalloc(1, sizeof(zend_fcall));
-                               iarg->val.zend.cb->fci = fci;
-                               iarg->val.zend.cb->fcc = fcc;
-                       }
-               } else {
-                       error_code = ZPP_ERROR_FAILURE;
-                       break;
-               }
-               iarg->_zv = _arg;
-               ZVAL_DEREF(iarg->_zv);
-               if (_i < _num_args) {
-                       goto nextarg;
-               }
-       ZEND_PARSE_PARAMETERS_END_EX(
-               zend_restore_error_handling(&zeh);
-               return FAILURE
-       );
-
-       /* set up defaults */
-       for (i = 0; i < impl->func->args->count; ++i) {
-               if (i >= EX_NUM_ARGS() && iarg->def) {
-                       iarg = impl->func->args->args[i];
-
-                       switch (iarg->type->type) {
-                       case PSI_T_BOOL:
-                               iarg->val.zend.bval = iarg->def->type == PSI_T_TRUE ? 1 : 0;
-                               break;
-                       case PSI_T_INT:
-                               iarg->val.zend.lval = zend_atol(iarg->def->text, strlen(iarg->def->text));
-                               break;
-                       case PSI_T_FLOAT:
-                       case PSI_T_DOUBLE:
-                               iarg->val.dval = zend_strtod(iarg->def->text, NULL);
-                               break;
-                       case PSI_T_STRING:
-                               /* FIXME */
-                               iarg->val.zend.str = zend_string_init(&iarg->def->text[1], strlen(iarg->def->text) - 2, 0);
-                               break;
-                       }
-               }
-       }
-
-       zend_restore_error_handling(&zeh);
-       return SUCCESS;
-}
-
-static inline void *psi_do_calloc(let_calloc *alloc)
-{
-       zend_long n = psi_long_num_exp(alloc->nmemb, NULL), s = psi_long_num_exp(alloc->size, NULL);
-       void *mem = safe_emalloc(n, s, sizeof(void *));
-       memset(mem, 0, n * s + sizeof(void *));
-#if 0
-       fprintf(stderr, "calloc: %p\n", mem);
-#endif
-       return mem;
-}
-
-static inline impl_val *psi_let_func(let_func *func, decl_arg *darg);
-
-static inline void *psi_let_val(let_val *val, decl_arg *darg)
-{
-       ZEND_ASSERT(darg);
-
-       switch (val ? val->kind : PSI_LET_NULL) {
-       case PSI_LET_TMP:
-               memcpy(darg->ptr, deref_impl_val(val->data.var->arg->let, val->data.var), sizeof(impl_val));
-               break;
-       case PSI_LET_NULL:
-               if (darg->var->array_size) {
-                       darg->val.ptr = ecalloc(darg->var->array_size, sizeof(impl_val));
-                       darg->mem = darg->val.ptr;
-               } else {
-                       memset(&darg->val, 0, sizeof(impl_val));
-               }
-               break;
-       case PSI_LET_CALLOC:
-               darg->val.ptr = psi_do_calloc(val->data.alloc);
-               darg->mem = darg->val.ptr;
-               break;
-       case PSI_LET_NUMEXP:
-               darg->val.zend.lval = psi_long_num_exp(val->data.num, NULL);
-               break;
-       case PSI_LET_CALLBACK:
-               darg->val.ptr = val->data.callback->decl->call.sym;
-               break;
-       case PSI_LET_FUNC:
-               if (!psi_let_func(val->data.func, darg)) {
-                       return NULL;
-               }
-               break;
-       }
-
-       if (val && val->is_reference) {
-               return darg->let = &darg->ptr;
-       } else {
-               return darg->let = darg->ptr;
-       }
-}
-
-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);
-       case PSI_T_INTVAL:
-               return psi_let_intval(dptr, dtype, itype, ival, zvalue, to_free);
-       case PSI_T_FLOATVAL:
-               return psi_let_floatval(dptr, dtype, itype, ival, zvalue, to_free);
-       case PSI_T_STRVAL:
-               return psi_let_strval(dptr, dtype, itype, ival, zvalue, to_free);
-       case PSI_T_STRLEN:
-               return psi_let_strlen(dptr, dtype, itype, ival, zvalue, to_free);
-       case PSI_T_PATHVAL:
-               return psi_let_pathval(dptr, dtype, itype, ival, zvalue, to_free);
-       case PSI_T_OBJVAL:
-               return psi_let_objval(dptr, dtype, itype, ival, zvalue, to_free);
-       case PSI_T_ZVAL:
-               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);
-       case PSI_T_COUNT:
-               return psi_let_count(dptr, dtype, itype, ival, zvalue, to_free);
-       case PSI_T_ARRVAL:
-               if (func->inner) {
-                       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);
-                       }
-
-                       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, dvar, itype, ival, zvalue, to_free);
-               }
-               break;
-       default:
-               assert(0);
-       }
-       return NULL;
-}
-
-static inline impl_val *psi_let_func(let_func *func, decl_arg *darg) {
-
-       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;
-
-                       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;
-       }
-
-}
-
-static inline void *psi_do_let(let_stmt *let)
-{
-       return psi_let_val(let->val, let->val->var->arg);
-}
-
-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);
-}
-
-static inline void psi_do_free(free_stmt *fre)
-{
-       size_t i, j;
-
-       for (i = 0; i < fre->calls->count; ++i) {
-               free_call *f = fre->calls->list[i];
-
-               for (j = 0; j < f->vars->count; ++j) {
-                       decl_var *dvar = f->vars->vars[j];
-                       decl_arg *darg = dvar->arg;
-                       impl_val *fval = darg->let;
-
-                       f->decl->call.args[j] = deref_impl_val(fval, dvar);
-               }
-
-               /* FIXME: check in validate_* that free functions return scalar */
-               psi_context_call(&PSI_G(context), &f->decl->call, NULL);
-       }
-}
-
-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);
-
-               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;
-               } 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;
-               }
-#if 0
-               if (args && val->data.func->inner) {
-                       size_t i;
-
-                       for (i = 0; i < val->data.func->inner->count; ++i) {
-                               let_val *inner = val->data.func->inner->vals[i];
-                               decl_var *refvar = locate_let_val_inner_ref(inner)->var;
-                               decl_arg *subarg = locate_decl_arg(args, refvar->name);
-
-                               if (subarg) {
-                                       psi_clean_array_struct(val->data.func->inner->vals[i], subarg);
-                                       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;
-               }
-       }
-}
-
-static inline void psi_do_clean(impl *impl)
-{
-       size_t i;
-
-       if (impl->decl->func->ptr != &impl->decl->func->val) {
-               efree(impl->decl->func->ptr);
-               impl->decl->func->ptr = &impl->decl->func->val;
-       }
-
-       for (i = 0; i < impl->func->args->count; ++i ) {
-               impl_arg *iarg = impl->func->args->args[i];
-
-               switch (iarg->type->type) {
-               case PSI_T_STRING:
-                       if (iarg->val.zend.str) {
-                               zend_string_release(iarg->val.zend.str);
-                       }
-                       break;
-               case PSI_T_CALLABLE:
-                       if (iarg->val.zend.cb) {
-                               if (iarg->val.zend.cb->fci.size) {
-                                       zend_fcall_info_args_clear(&iarg->val.zend.cb->fci, 1);
-                               }
-                               efree(iarg->val.zend.cb);
-                       }
-                       break;
-               }
-       }
-
-       for (i = 0; i < impl->stmts->let.count; ++i) {
-               let_stmt *let = impl->stmts->let.list[i];
-               psi_clean_let_val(let->val);
-       }
-
-       if (impl->func->args->vararg.args) {
-               free_impl_args(impl->func->args->vararg.args);
-               impl->func->args->vararg.args = NULL;
-       }
-       if (impl->func->args->vararg.types) {
-               efree(impl->func->args->vararg.types);
-               impl->func->args->vararg.types = NULL;
-       }
-       if (impl->func->args->vararg.values) {
-               efree(impl->func->args->vararg.values);
-               impl->func->args->vararg.values = NULL;
-       }
-       if (impl->func->args->vararg.free_list) {
-               void **list = impl->func->args->vararg.free_list;
-
-               while (*list) {
-                       efree(*list++);
-               }
-
-               efree(impl->func->args->vararg.free_list);
-               impl->func->args->vararg.free_list = NULL;
-       }
-}
-
-
-static inline void psi_do_args(impl *impl) {
-       size_t i;
-
-       for (i = 0; i < impl->decl->args->count; ++i) {
-               impl->decl->call.args[i] = impl->decl->args->args[i]->let;
-       }
-
-       if (!impl->decl->func->var->pointer_level) {
-               decl_type *real;
-               decl_args *args = extract_decl_type_args(impl->decl->func->type, &real);
-
-               switch (real->type) {
-               case PSI_T_STRUCT:
-               case PSI_T_UNION:
-                       impl->decl->func->ptr = ecalloc(1,
-                                       extract_decl_type_size(real, NULL) + args->count * sizeof(void*));
-                       break;
-               default:
-                       break;
-               }
-       }
-}
-
-static inline impl_vararg *psi_do_varargs(impl *impl) {
-       size_t i, j;
-       impl_vararg *va = &impl->func->args->vararg;
-       size_t vacount = va->args->count;
-
-
-       if (!vacount) {
-               return NULL;
-       }
-
-       va->types = ecalloc(vacount, sizeof(*va->types));
-       va->values = ecalloc(vacount, sizeof(*va->values));
-
-       for (i = 0, j = 0; i < vacount; ++i) {
-               impl_arg *vaarg = va->args->args[i];
-               void *to_free = NULL;
-               token_t vatype = va->name->type->type;
-               psi_marshal_let let_fn;
-
-               if (vatype == PSI_T_MIXED) {
-                       switch (Z_TYPE_P(vaarg->_zv)) {
-                       case IS_TRUE:
-                       case IS_FALSE:  vatype = PSI_T_BOOL;    break;
-                       case IS_LONG:   vatype = PSI_T_INT;             break;
-                       case IS_DOUBLE: vatype = PSI_T_FLOAT;   break;
-                       default:                vatype = PSI_T_STRING;  break;
-                       }
-               }
-
-
-               switch (vatype) {
-               case PSI_T_BOOL:        let_fn = psi_let_boolval;       break;
-               case PSI_T_INT:         let_fn = psi_let_intval;        break;
-               case PSI_T_FLOAT:
-               case PSI_T_DOUBLE:      let_fn = psi_let_floatval;      break;
-               case PSI_T_STRING:      let_fn = psi_let_strval;        break;
-               EMPTY_SWITCH_DEFAULT_CASE();
-               }
-
-               va->types[i] = vatype;
-
-               /* FIXME: varargs with struct-by-value :) */
-               //if (!psi_let_val(let_fn, vaarg, &va->values[i], NULL, &to_free)) {
-               if (!let_fn(&va->values[i], NULL, vaarg->type->type, &vaarg->val, vaarg->_zv, &to_free)) {
-                       return NULL;
-               }
-
-               if (to_free) {
-                       if (!va->free_list) {
-                               va->free_list = ecalloc(vacount - i + 1, sizeof(*va->free_list));
-                       }
-                       va->free_list[j++] = to_free;
-               }
-       }
-
-       return va;
-}
-
-ZEND_RESULT_CODE psi_call(zend_execute_data *execute_data, zval *return_value, impl *impl)
-{
-       size_t i;
-       impl_vararg *va = NULL;
-
-       memset(impl->decl->func->ptr, 0, sizeof(impl_val));
-
-       if (SUCCESS != psi_parse_args(execute_data, impl)) {
-               return FAILURE;
-       }
-
-       for (i = 0; i < impl->stmts->let.count; ++i) {
-               let_stmt *let = impl->stmts->let.list[i];
-
-               if (!psi_do_let(let)) {
-                       psi_do_return(return_value, impl->stmts->ret.list[0]);
-                       psi_do_clean(impl);
-                       return FAILURE;
-               }
-       }
-
-       if (impl->decl->args) {
-               psi_do_args(impl);
-
-               if (impl->func->args->vararg.args) {
-                       va = psi_do_varargs(impl);
-               }
-       }
-
-       psi_context_call(&PSI_G(context), &impl->decl->call, va);
-       psi_do_return(return_value, impl->stmts->ret.list[0]);
-
-       for (i = 0; i < impl->stmts->set.count; ++i) {
-               set_stmt *set = impl->stmts->set.list[i];
-
-               if (set->arg->_zv) {
-                       psi_do_set(set->arg->_zv, set->val);
-               }
-       }
-
-       for (i = 0; i < impl->stmts->fre.count; ++i) {
-               free_stmt *fre = impl->stmts->fre.list[i];
-
-               psi_do_free(fre);
-       }
-       psi_do_clean(impl);
-
-       return SUCCESS;
-}
-
-ZEND_RESULT_CODE psi_callback(let_callback *cb, void *retval, unsigned argc, void **argv)
-{
-       size_t i;
-       decl *decl_cb = cb->decl;
-       impl_arg *iarg = cb->func->var->arg;
-       zval return_value, *zargv = calloc(argc, sizeof(*zargv));
-       void *result, *to_free = NULL;
-
-       ZEND_ASSERT(argc == cb->decl->args->count);
-
-       /* prepare args for the userland call */
-       for (i = 0; i < argc; ++i) {
-               cb->decl->args->args[i]->let = argv[i];
-       }
-       for (i = 0; i < cb->args->count; ++i) {
-               psi_do_set(&zargv[i], cb->args->vals[i]);
-       }
-       zend_fcall_info_argp(&iarg->val.zend.cb->fci, cb->args->count, zargv);
-
-       /* callback into userland */
-       ZVAL_UNDEF(&return_value);
-       iarg->_zv = &return_value;
-       zend_fcall_info_call(&iarg->val.zend.cb->fci, &iarg->val.zend.cb->fcc, iarg->_zv, NULL);
-
-       /* marshal return value of the userland call
-       switch (iarg->type->type) {
-       case PSI_T_BOOL:        zend_parse_arg_bool(iarg->_zv, &iarg->val.zend.bval, NULL, 0);          break;
-       case PSI_T_LONG:        zend_parse_arg_long(iarg->_zv, &iarg->val.zend.lval, NULL, 0, 1);       break;
-       case PSI_T_FLOAT:
-       case PSI_T_DOUBLE:      zend_parse_arg_double(iarg->_zv, &iarg->val.dval, NULL, 0);                     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, 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) {
-               *(void **)retval = result;
-       }
-
-       zend_fcall_info_args_clear(&iarg->val.zend.cb->fci, 0);
-       for (i = 0; i < cb->args->count; ++i) {
-               zval_ptr_dtor(&zargv[i]);
-       }
-       free(zargv);
-
-       return SUCCESS;
-
-}
diff --git a/src/engine.h b/src/engine.h
deleted file mode 100644 (file)
index 624ddfb..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef _PSI_ENGINE_H
-#define _PSI_ENGINE_H
-
-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);
-
-#endif
index 2d764bc..c92b847 100644 (file)
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *******************************************************************************/
 
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#else
-# include "php_config.h"
-#endif
+#include "php_psi_stdinc.h"
+#include "data.h"
 
-#include <stdlib.h>
-#include <stdio.h>
+/* zend_error_cb */
+#include "Zend/zend.h"
+/* is executing/compiling query API */
+#include "Zend/zend_compile.h"
+#include "Zend/zend_execute.h"
 
-#include "error.h"
+/* PG(), strlcpy, vslprintf */
+#include "php.h"
 
+void psi_error_wrapper(struct psi_data *context, struct psi_token *t, int type, const char *msg, ...)
+{
+       va_list argv;
+       const char *fn = NULL;
+       unsigned ln = 0;
+
+       if (context) {
+               if (context->flags & PSI_SILENT) {
+                       /* context->last_error may be an argument to print */
+                       char error[sizeof(context->last_error)];
+
+                       va_start(argv, msg);
+                       vslprintf(error, sizeof(error), msg, argv);
+                       va_end(argv);
+
+                       memcpy(context->last_error, error,
+                                       sizeof(context->last_error));
+                       return;
+               }
+       }
+
+       if (t) {
+               fn = t->file;
+               ln = t->line;
+       } else if (zend_is_executing()) {
+               fn = zend_get_executed_filename();
+               ln = zend_get_executed_lineno();
+       } else if (zend_is_compiling()) {
+               fn = zend_get_compiled_filename()->val;
+               ln = zend_get_compiled_lineno();
+       } else {
+               fn = "PSI module startup";
+       }
+
+       va_start(argv, msg);
+       psi_verror(type, fn, ln, msg, argv);
+       va_end(argv);
+
+       if (context) {
+               strlcpy(context->last_error, PG(last_error_message),
+                               sizeof(context->last_error));
+       }
+}
+
+void psi_error(int type, const char *fn, unsigned ln, const char *msg, ...)
+{
+       va_list argv;
+
+       va_start(argv, msg);
+       psi_verror(type, fn, ln, msg, argv);
+       va_end(argv);
+}
+
+void psi_verror(int type, const char *fn, unsigned ln, const char *msg, va_list argv)
+{
+       zend_error_cb(type, fn, ln, msg, argv);
+}
index 2c66d88..3f64f1f 100644 (file)
 
 #include <stdarg.h>
 
-#include "token.h"
-
 #define PSI_ERROR 16
 #define PSI_WARNING 32
 
-typedef void (*psi_error_cb)(void *context, struct psi_token *token, int type, const char *msg, ...);
+struct psi_data;
+struct psi_token;
+
+typedef void (*psi_error_cb)(struct psi_data *context, struct psi_token *token, int type, const char *msg, ...);
 
-void psi_error_wrapper(void *context, struct psi_token *t, int type, const char *msg, ...);
+void psi_error_wrapper(struct psi_data *context, struct psi_token *t, int type, const char *msg, ...);
 void psi_error(int type, const char *fn, unsigned ln, const char *msg, ...);
 void psi_verror(int type, const char *fn, unsigned ln, const char *msg, va_list argv);
 
-#endif /* EXT_PSI_SRC_ERROR_H */
+#endif /* PSI_ERROR_H */
index 8cf29dd..aea1cfa 100644 (file)
@@ -1,16 +1,35 @@
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#else
-# include "php_config.h"
-#endif
-
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+     * Redistributions of source code must retain the above copyright notice,
+       this list of conditions and the following disclaimer.
+     * Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#include "php_psi_stdinc.h"
+#include "context.h"
+#include "call.h"
 #include "php.h"
 
 #ifdef HAVE_LIBFFI
 
-#include "php_psi.h"
-#include "engine.h"
-
 #undef PACKAGE
 #undef PACKAGE_BUGREPORT
 #undef PACKAGE_NAME
@@ -60,7 +79,6 @@ static ffi_status psi_ffi_prep_closure(ffi_closure **closure, void **code, ffi_c
 #else
 # error "Neither ffi_prep_closure() nor ffi_prep_closure_loc() is available"
 #endif
-
 }
 
 static void psi_ffi_closure_free(void *c)
@@ -72,17 +90,22 @@ static void psi_ffi_closure_free(void *c)
 #endif
 }
 
-static void psi_ffi_handler(ffi_cif *_sig, void *_result, void **_args, void *_data)
-{
-       psi_call(*(zend_execute_data **)_args[0], *(zval **)_args[1], _data);
-}
+static void psi_ffi_prep_va(ffi_cif *base, ffi_cif *signature, size_t argc, size_t va_count,
+               ffi_type **param_types) {
+       ffi_status rc;
 
-static void psi_ffi_callback(ffi_cif *_sig, void *_result, void **_args, void *_data)
-{
-       psi_callback(_data, _result, _sig->nargs, _args);
+#ifdef PSI_HAVE_FFI_PREP_CIF_VAR
+       rc = ffi_prep_cif_var(signature, base->abi, argc, argc + va_count,
+                       base->rtype, param_types);
+#else
+       /* FIXME: test in config.m4; assume we can just call anyway */
+       rc = ffi_prep_cif(signature, base->abi, argc + va_count, base->rtype, param_types);
+#endif
+
+       ZEND_ASSERT(FFI_OK == rc);
 }
 
-static inline ffi_type *psi_ffi_decl_arg_type(decl_arg *darg);
+static inline ffi_type *psi_ffi_decl_arg_type(struct psi_decl_arg *darg);
 
 struct psi_ffi_context {
        ffi_cif signature;
@@ -90,46 +113,86 @@ struct psi_ffi_context {
 };
 
 struct psi_ffi_call {
+       struct psi_context *context;
+       union {
+               struct {
+                       struct psi_impl *impl;
+                       struct psi_call_frame *frame;
+               } fn;
+               struct  {
+                       struct psi_let_exp *let_exp;
+                       struct psi_ffi_call *impl_call;
+               } cb;
+       } impl;
        void *code;
        ffi_closure *closure;
        ffi_cif signature;
-       void *params[1]; /* [type1, type2, NULL, arg1, arg2] ... */
+       ffi_type *params[1]; /* [type1, type2, ... ] */
 };
 
+static void psi_ffi_handler(ffi_cif *sig, void *result, void **args, void *data)
+{
+       struct psi_ffi_call *call = data;
+
+       psi_context_call(call->context, *(zend_execute_data **)args[0], *(zval **)args[1], call->impl.fn.impl);
+}
+
+static void psi_ffi_callback(ffi_cif *sig, void *result, void **args, void *data)
+{
+       struct psi_ffi_call *call = data, *impl_call = call->impl.cb.impl_call;
+
+       if (impl_call->impl.fn.frame) {
+               struct psi_call_frame_callback cbdata;
+
+               cbdata.cb = call->impl.cb.let_exp;
+               cbdata.argc = sig->nargs;
+               cbdata.argv = args;
+               cbdata.rval = result;
+
+               psi_call_frame_do_callback(impl_call->impl.fn.frame, &cbdata);
+       } else {
+               assert(0);
+       }
+}
+
 static inline ffi_abi psi_ffi_abi(const char *convention) {
        return FFI_DEFAULT_ABI;
 }
 
-static inline struct psi_ffi_call *psi_ffi_call_alloc(struct psi_context *C, decl *decl) {
+static inline struct psi_ffi_call *psi_ffi_call_alloc(struct psi_context *C, struct psi_decl *decl) {
        int rc;
-       size_t i, c = decl->args ? decl->args->count : 0;
+       size_t i, c = psi_plist_count(decl->args);
        struct psi_ffi_call *call = calloc(1, sizeof(*call) + 2 * c * sizeof(void *));
+       struct psi_decl_arg *arg;
 
-       for (i = 0; i < c; ++i) {
-               call->params[i] = psi_ffi_decl_arg_type(decl->args->args[i]);
+       decl->info = call;
+       call->context = C;
+
+       for (i = 0; psi_plist_get(decl->args, i, &arg); ++i) {
+               call->params[i] = psi_ffi_decl_arg_type(arg);
        }
        call->params[c] = NULL;
 
-       decl->call.info = call;
-       decl->call.rval = &decl->func->ptr;
-       decl->call.argc = c;
-       decl->call.args = (void **) &call->params[c+1];
-
        rc = ffi_prep_cif(&call->signature, psi_ffi_abi(decl->abi->convention),
-                       c, psi_ffi_decl_arg_type(decl->func), (ffi_type **) call->params);
+                       c, psi_ffi_decl_arg_type(decl->func), call->params);
        ZEND_ASSERT(FFI_OK == rc);
 
        return call;
 }
 
-static inline ffi_status psi_ffi_call_init_closure(struct psi_context *C, struct psi_ffi_call *call, impl *impl) {
+static inline ffi_status psi_ffi_call_init_closure(struct psi_context *C, struct psi_ffi_call *call, struct psi_impl *impl) {
        struct psi_ffi_context *context = C->context;
 
-       return psi_ffi_prep_closure(&call->closure, &call->code, &context->signature, psi_ffi_handler, impl);
+       call->impl.fn.impl = impl;
+       return psi_ffi_prep_closure(&call->closure, &call->code, &context->signature, psi_ffi_handler, call);
 }
 
-static inline ffi_status psi_ffi_call_init_callback_closure(struct psi_context *C, struct psi_ffi_call *call, let_callback *cb) {
-       return psi_ffi_prep_closure(&call->closure, &call->code, &call->signature, psi_ffi_callback, cb);
+static inline ffi_status psi_ffi_call_init_callback_closure(struct psi_context *C,
+               struct psi_ffi_call *call, struct psi_ffi_call *impl_call,
+               struct psi_let_exp *cb) {
+       call->impl.cb.let_exp = cb;
+       call->impl.cb.impl_call = impl_call;
+       return psi_ffi_prep_closure(&call->closure, &call->code, &call->signature, psi_ffi_callback, call);
 }
 
 static inline void psi_ffi_call_free(struct psi_ffi_call *call) {
@@ -224,23 +287,22 @@ static size_t psi_ffi_struct_type_pad(ffi_type **els, size_t padding) {
        return padding;
 }
 
-static ffi_type **psi_ffi_struct_type_elements(decl_struct *strct) {
-       size_t i, argc = strct->args->count, nels = 0, offset = 0, maxalign = 0;
+static ffi_type **psi_ffi_struct_type_elements(struct psi_decl_struct *strct) {
+       size_t i = 0, argc = psi_plist_count(strct->args), nels = 0, offset = 0, maxalign = 0;
        ffi_type **els = calloc(argc + 1, sizeof(*els));
+       struct psi_decl_arg *darg;
 
-       for (i = 0; i < strct->args->count; ++i) {
-               decl_arg *darg = strct->args->args[i];
+       while (psi_plist_get(strct->args, i++, &darg)) {
                ffi_type *type = malloc(sizeof(*type));
                size_t padding;
 
-               memcpy(type, psi_ffi_decl_arg_type(darg), sizeof(*type));
-
-               ZEND_ASSERT(type->size == darg->layout->len);
+               *type = *psi_ffi_decl_arg_type(darg);
 
                if (type->alignment > maxalign) {
                        maxalign = type->alignment;
                }
 
+               assert(type->size == darg->layout->len);
                if ((padding = psi_offset_padding(darg->layout->pos - offset, type->alignment))) {
                        if (nels + padding + 1 > argc) {
                                argc += padding;
@@ -251,7 +313,7 @@ static ffi_type **psi_ffi_struct_type_elements(decl_struct *strct) {
                        nels += padding;
                        offset += padding;
                }
-               ZEND_ASSERT(offset == darg->layout->pos);
+               assert(offset == darg->layout->pos);
 
                offset = (offset + darg->layout->len + type->alignment - 1) & ~(type->alignment - 1);
                els[nels++] = type;
@@ -260,15 +322,15 @@ static ffi_type **psi_ffi_struct_type_elements(decl_struct *strct) {
        /* apply struct alignment padding */
        offset = (offset + maxalign - 1) & ~(maxalign - 1);
 
-       ZEND_ASSERT(offset <= strct->size);
+       assert(offset <= strct->size);
        if (offset < strct->size) {
                psi_ffi_struct_type_pad(&els[nels], strct->size - offset);
        }
 
        return els;
 }
-static inline ffi_type *psi_ffi_decl_type(decl_type *type) {
-       decl_type *real = real_decl_type(type);
+static inline ffi_type *psi_ffi_decl_type(struct psi_decl_type *type) {
+       struct psi_decl_type *real = psi_decl_type_get_real(type);
 
        switch (real->type) {
        case PSI_T_STRUCT:
@@ -286,13 +348,17 @@ static inline ffi_type *psi_ffi_decl_type(decl_type *type) {
                return real->real.strct->engine.type;
 
        case PSI_T_UNION:
-               return psi_ffi_decl_arg_type(real->real.unn->args->args[0]);
+               {
+                       struct psi_decl_arg *arg;
+                       psi_plist_get(real->real.unn->args, 0, &arg);
+                       return psi_ffi_decl_arg_type(arg);
+               }
 
        default:
                return psi_ffi_token_type(real->type);
        }
 }
-static inline ffi_type *psi_ffi_decl_arg_type(decl_arg *darg) {
+static inline ffi_type *psi_ffi_decl_arg_type(struct psi_decl_arg *darg) {
        if (darg->var->pointer_level) {
                return &ffi_type_pointer;
        } else {
@@ -329,29 +395,30 @@ static void psi_ffi_init(struct psi_context *C)
        C->context = psi_ffi_context_init(NULL);
 }
 
-static inline void psi_ffi_destroy_callbacks(struct psi_context *C, let_val *let_val) {
-       let_callback *cb;
-       let_func *fn = NULL;
+static inline void psi_ffi_destroy_callbacks(struct psi_context *C, struct psi_let_exp *let_exp) {
+       struct psi_let_callback *cb;
+       struct psi_let_func *fn = NULL;
 
-       switch (let_val->kind) {
+       switch (let_exp->kind) {
        case PSI_LET_CALLBACK:
-               cb = let_val->data.callback;
+               cb = let_exp->data.callback;
 
-               if (cb->decl && cb->decl->call.info) {
-                       psi_ffi_call_free(cb->decl->call.info);
+               if (cb->decl && cb->decl->info) {
+                       psi_ffi_call_free(cb->decl->info);
                }
                fn = cb->func;
                /* no break */
        case PSI_LET_FUNC:
                if (!fn) {
-                       fn = let_val->data.func;
+                       fn = let_exp->data.func;
                }
 
                if (fn->inner) {
-                       size_t i;
+                       size_t i = 0;
+                       struct psi_let_exp *cb;
 
-                       for (i = 0; i < fn->inner->count; ++i) {
-                               psi_ffi_destroy_callbacks(C, fn->inner->vals[i]);
+                       while (psi_plist_get(fn->inner, i++, &cb)) {
+                               psi_ffi_destroy_callbacks(C, cb);
                        }
                }
                break;
@@ -363,66 +430,61 @@ static inline void psi_ffi_destroy_callbacks(struct psi_context *C, let_val *let
 static void psi_ffi_dtor(struct psi_context *C)
 {
        if (C->decls) {
-               size_t i;
-
-               for (i = 0; i < C->decls->count; ++i) {
-                       decl *decl = C->decls->list[i];
+               size_t i = 0;
+               struct psi_decl *decl;
 
-                       if (decl->call.info) {
-                               psi_ffi_call_free(decl->call.info);
+               while (psi_plist_get(C->decls, i++, &decl)) {
+                       if (decl->info) {
+                               psi_ffi_call_free(decl->info);
                        }
                }
 
        }
        if (C->impls) {
-               size_t i, j;
-
-               for (i = 0; i < C->impls->count; ++i) {
-                       impl *impl = C->impls->list[i];
+               size_t i = 0;
+               struct psi_impl *impl;
 
-                       for (j = 0; j < impl->stmts->let.count; ++j) {
-                               let_stmt *let = impl->stmts->let.list[j];
+               while (psi_plist_get(C->impls, i++, &impl)) {
+                       size_t j = 0;
+                       struct psi_let_stmt *let;
 
-                               if (let->val && let->val->kind == PSI_LET_CALLBACK) {
-                                       let_callback *cb = let->val->data.callback;
-
-                                       if (cb->decl && cb->decl->call.info) {
-                                               psi_ffi_call_free(cb->decl->call.info);
-                                       }
-                               }
+                       while (psi_plist_get(impl->stmts.let, j++, &let)) {
+                               psi_ffi_destroy_callbacks(C, let->exp);
                        }
                }
        }
        psi_ffi_context_free((void *) &C->context);
 }
 
-static inline void psi_ffi_compile_callbacks(struct psi_context *C, let_val *let_val) {
+static inline void psi_ffi_compile_callbacks(struct psi_context *C,
+               struct psi_ffi_call *impl_call, struct psi_let_exp *let_exp) {
        struct psi_ffi_call *call;
-       let_callback *cb;
-       let_func *fn = NULL;
+       struct psi_let_callback *cb;
+       struct psi_let_func *fn = NULL;
 
-       switch (let_val->kind) {
+       switch (let_exp->kind) {
        case PSI_LET_CALLBACK:
-               cb = let_val->data.callback;
+               cb = let_exp->data.callback;
                if ((call = psi_ffi_call_alloc(C, cb->decl))) {
-                       if (FFI_OK != psi_ffi_call_init_callback_closure(C, call, cb)) {
+                       if (FFI_OK != psi_ffi_call_init_callback_closure(C, call, impl_call, let_exp)) {
                                psi_ffi_call_free(call);
                                break;
                        }
 
-                       cb->decl->call.sym = call->code;
+                       cb->decl->sym = call->code;
                }
                fn = cb->func;
                /* no break */
        case PSI_LET_FUNC:
                if (!fn) {
-                       fn = let_val->data.func;
+                       fn = let_exp->data.func;
                }
                if (fn->inner) {
-                       size_t i;
+                       size_t i = 0;
+                       struct psi_let_exp *inner_let;
 
-                       for (i = 0; i < fn->inner->count; ++i) {
-                               psi_ffi_compile_callbacks(C, fn->inner->vals[i]);
+                       while (psi_plist_get(fn->inner, i++, &inner_let)) {
+                               psi_ffi_compile_callbacks(C, impl_call, inner_let);
                        }
                }
                break;
@@ -433,18 +495,22 @@ static inline void psi_ffi_compile_callbacks(struct psi_context *C, let_val *let
 
 static zend_function_entry *psi_ffi_compile(struct psi_context *C)
 {
-       size_t c, i, j = 0;
+       size_t i = 0, d = 0, nf = 0;
+       struct psi_impl *impl;
+       struct psi_decl *decl;
        zend_function_entry *zfe;
 
        if (!C->impls) {
                return NULL;
        }
 
-       zfe = calloc(C->impls->count + 1, sizeof(*zfe));
-       for (i = 0; i < C->impls->count; ++i) {
-               zend_function_entry *zf = &zfe[j];
+       zfe = calloc(psi_plist_count(C->impls) + 1, sizeof(*zfe));
+
+       while (psi_plist_get(C->impls, i++, &impl)) {
+               size_t l = 0;
+               struct psi_let_stmt *let;
                struct psi_ffi_call *call;
-               impl *impl = C->impls->list[i];
+               zend_function_entry *zf = &zfe[nf];
 
                if (!impl->decl) {
                        continue;
@@ -458,20 +524,18 @@ static zend_function_entry *psi_ffi_compile(struct psi_context *C)
                }
 
                zf->fname = impl->func->name + (impl->func->name[0] == '\\');
-               zf->num_args = impl->func->args->count;
                zf->handler = call->code;
+               zf->num_args = psi_plist_count(impl->func->args);
                zf->arg_info = psi_internal_arginfo(impl);
-               ++j;
+               ++nf;
 
-               for (c = 0; c < impl->stmts->let.count; ++c) {
-                       psi_ffi_compile_callbacks(C, impl->stmts->let.list[c]->val);
+               while (psi_plist_get(impl->stmts.let, l++, &let)) {
+                       psi_ffi_compile_callbacks(C, call, let->exp);
                }
        }
 
-       for (i = 0; i < C->decls->count; ++i) {
-               decl *decl = C->decls->list[i];
-
-               if (decl->call.info) {
+       while (psi_plist_get(C->decls, d++, &decl)) {
+               if (decl->info) {
                        continue;
                }
 
@@ -481,38 +545,41 @@ static zend_function_entry *psi_ffi_compile(struct psi_context *C)
        return zfe;
 }
 
-static void psi_ffi_call(struct psi_context *C, decl_callinfo *decl_call, impl_vararg *va) {
-       struct psi_ffi_call *call = decl_call->info;
+static void psi_ffi_call(struct psi_context *C, struct psi_call_frame *frame, struct psi_decl *decl, void *rval, void **args) {
+       struct psi_ffi_call *info = decl->info;
+       struct psi_call_frame *prev = info->impl.fn.frame;
 
-       if (va) {
-               ffi_status rc;
-               ffi_cif signature;
-               size_t i, nfixedargs = decl_call->argc, ntotalargs = nfixedargs + va->args->count;
-               void **params = calloc(2 * ntotalargs + 2, sizeof(void *));
+       info->impl.fn.frame = frame;
+       ffi_call(&info->signature, FFI_FN(decl->sym), rval, args);
+       info->impl.fn.frame = prev;
+}
 
-               for (i = 0; i < nfixedargs; ++i) {
-                       params[i] = call->params[i];
-                       params[i + ntotalargs + 1] = call->params[i + nfixedargs + 1];
-               }
-               for (i = 0; i < va->args->count; ++i) {
-                       params[nfixedargs + i] = psi_ffi_impl_type(va->types[i]);
-                       params[nfixedargs + i + ntotalargs + 1] = &va->values[i];
-               }
-#ifdef PSI_HAVE_FFI_PREP_CIF_VAR
-               rc = ffi_prep_cif_var(&signature, call->signature.abi,
-                               nfixedargs, ntotalargs,
-                               call->signature.rtype, (ffi_type **) params);
-#else
-               /* FIXME: test in config.m4; assume we can just call anyway */
-               rc = ffi_prep_cif(&signature, call->signature.abi, ntotalargs,
-                               call->signature.rtype, (ffi_type **) params);
-#endif
-               ZEND_ASSERT(FFI_OK == rc);
-               ffi_call(&signature, FFI_FN(decl_call->sym), *decl_call->rval, &params[ntotalargs + 1]);
-               free(params);
-       } else {
-               ffi_call(&call->signature, FFI_FN(decl_call->sym), *decl_call->rval, decl_call->args);
+static void psi_ffi_call_va(struct psi_context *C, struct psi_call_frame *frame, struct psi_decl *decl, void *rval, void **args,
+       size_t va_count, void **va_types) {
+       ffi_cif signature;
+       struct psi_ffi_call *info = decl->info;
+       struct psi_call_frame *prev = info->impl.fn.frame;
+       size_t argc = psi_plist_count(decl->args);
+       ffi_type **param_types = ecalloc(argc + va_count + 1, sizeof(ffi_type *));
+
+       memcpy(param_types, info->params, argc * sizeof(ffi_type *));
+       memcpy(param_types + argc, va_types, va_count * sizeof(ffi_type *));
+
+       psi_ffi_prep_va(&info->signature, &signature, argc, va_count, param_types);
+       info->impl.fn.frame = frame;
+       ffi_call(&signature, FFI_FN(decl->sym), rval, args);
+       info->impl.fn.frame = prev;
+       efree(param_types);
+}
+
+static void *psi_ffi_query(struct psi_context *C, enum psi_context_query q, void *arg) {
+       switch (q) {
+       case PSI_CONTEXT_QUERY_SELF:
+               return "ffi";
+       case PSI_CONTEXT_QUERY_TYPE:
+               return psi_ffi_impl_type(*(token_t *) arg);
        }
+       return NULL;
 }
 
 static struct psi_context_ops ops = {
@@ -520,6 +587,8 @@ static struct psi_context_ops ops = {
        psi_ffi_dtor,
        psi_ffi_compile,
        psi_ffi_call,
+       psi_ffi_call_va,
+       psi_ffi_query,
 };
 
 struct psi_context_ops *psi_libffi_ops(void)
index 8db73ee..df7865a 100644 (file)
@@ -1,5 +1,30 @@
-#ifndef _PSI_LIBFFI_H
-#define _PSI_LIBFFI_H
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+     * Redistributions of source code must retain the above copyright notice,
+       this list of conditions and the following disclaimer.
+     * Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#ifndef PSI_LIBFFI_H
+#define PSI_LIBFFI_H
 
 #include "context.h"
 
index 23d53c1..da8f25e 100644 (file)
@@ -1,35 +1,45 @@
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#else
-# include "php_config.h"
-#endif
-
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *******************************************************************************/
+
+#include "php_psi_stdinc.h"
+#include "context.h"
+#include "call.h"
 #include "php.h"
 
 #ifdef HAVE_LIBJIT
 
-#include "php_psi.h"
-#include "libjit.h"
-#include "engine.h"
-
 #include <jit/jit.h>
 
-static void psi_jit_handler(jit_type_t _sig, void *_result, void **_args, void *_data)
-{
-       psi_call(*(zend_execute_data **)_args[0], *(zval **)_args[1], _data);
-}
+static inline jit_type_t psi_jit_decl_arg_type(struct psi_decl_arg *darg);
 
-static void psi_jit_callback(jit_type_t _sig, void *_result, void **_args, void *_data)
+static inline jit_abi_t psi_jit_abi(const char *convention)
 {
-       psi_callback(_data, _result, jit_type_num_params(_sig), _args);
-}
-
-static inline jit_type_t psi_jit_decl_arg_type(decl_arg *darg);
-
-static inline jit_abi_t psi_jit_abi(const char *convention) {
        return jit_abi_cdecl;
 }
-static inline jit_type_t psi_jit_token_type(token_t t) {
+static inline jit_type_t psi_jit_token_type(token_t t)
+{
        switch (t) {
        default:
                ZEND_ASSERT(0);
@@ -72,7 +82,8 @@ static inline jit_type_t psi_jit_token_type(token_t t) {
                return jit_type_void_ptr;
        }
 }
-static inline jit_type_t psi_jit_impl_type(token_t impl_type) {
+static inline jit_type_t psi_jit_impl_type(token_t impl_type)
+{
        switch (impl_type) {
        case PSI_T_BOOL:
                return jit_type_sbyte;
@@ -83,18 +94,21 @@ static inline jit_type_t psi_jit_impl_type(token_t impl_type) {
        case PSI_T_FLOAT:
        case PSI_T_DOUBLE:
                return jit_type_sys_double;
-       EMPTY_SWITCH_DEFAULT_CASE();
+       EMPTY_SWITCH_DEFAULT_CASE()
+               ;
        }
        return NULL;
 }
 
-static void psi_jit_struct_type_dtor(void *type) {
+static void psi_jit_struct_type_dtor(void *type)
+{
        jit_type_t strct = type;
 
        jit_type_free(strct);
 }
 
-static size_t psi_jit_struct_type_pad(jit_type_t *els, size_t padding) {
+static size_t psi_jit_struct_type_pad(jit_type_t *els, size_t padding)
+{
        size_t i;
 
        for (i = 0; i < padding; ++i) {
@@ -104,21 +118,24 @@ static size_t psi_jit_struct_type_pad(jit_type_t *els, size_t padding) {
        return padding;
 }
 
-static unsigned psi_jit_struct_type_elements(decl_struct *strct, jit_type_t **fields) {
-       size_t i, argc = strct->args->count, nels = 0, offset = 0, maxalign;
+static unsigned psi_jit_struct_type_elements(struct psi_decl_struct *strct,
+               jit_type_t **fields)
+{
+       size_t i = 0, argc = psi_plist_count(strct->args), nels = 0, offset = 0,
+                       maxalign;
+       struct psi_decl_arg *darg;
+
        *fields = calloc(argc + 1, sizeof(*fields));
 
-       for (i = 0; i < strct->args->count; ++i) {
-               decl_arg *darg = strct->args->args[i];
+       while (psi_plist_get(strct->args, i++, &darg)) {
                jit_type_t type = jit_type_copy(psi_jit_decl_arg_type(darg));
                size_t padding, alignment;
 
-               ZEND_ASSERT(jit_type_get_size(type) == darg->layout->len);
-
                if ((alignment = jit_type_get_alignment(type)) > maxalign) {
                        maxalign = alignment;
                }
 
+               assert(jit_type_get_size(type) == darg->layout->len);
                if ((padding = psi_offset_padding(darg->layout->pos - offset, alignment))) {
                        if (nels + padding > argc) {
                                argc += padding;
@@ -128,9 +145,10 @@ static unsigned psi_jit_struct_type_elements(decl_struct *strct, jit_type_t **fi
                        nels += padding;
                        offset += padding;
                }
-               ZEND_ASSERT(offset == darg->layout->pos);
+               assert(offset == darg->layout->pos);
 
-               offset = (offset + darg->layout->len + alignment - 1) & ~(alignment - 1);
+               offset = (offset + darg->layout->len + alignment - 1)
+                               & ~(alignment - 1);
                (*fields)[nels++] = type;
        }
 
@@ -144,8 +162,9 @@ static unsigned psi_jit_struct_type_elements(decl_struct *strct, jit_type_t **fi
 
        return nels;
 }
-static inline jit_type_t psi_jit_decl_type(decl_type *type) {
-       decl_type *real = real_decl_type(type);
+static inline jit_type_t psi_jit_decl_type(struct psi_decl_type *type)
+{
+       struct psi_decl_type *real = psi_decl_type_get_real(type);
 
        switch (real->type) {
        case PSI_T_STRUCT:
@@ -163,13 +182,18 @@ static inline jit_type_t psi_jit_decl_type(decl_type *type) {
                return real->real.strct->engine.type;
 
        case PSI_T_UNION:
-               return psi_jit_decl_arg_type(real->real.unn->args->args[0]);
+               {
+                       struct psi_decl_arg *arg;
+                       psi_plist_get(real->real.unn->args, 0, &arg);
+                       return psi_jit_decl_arg_type(arg);
+               }
 
        default:
                return psi_jit_token_type(real->type);
        }
 }
-static inline jit_type_t psi_jit_decl_arg_type(decl_arg *darg) {
+static inline jit_type_t psi_jit_decl_arg_type(struct psi_decl_arg *darg)
+{
        if (darg->var->pointer_level) {
                return jit_type_void_ptr;
        } else {
@@ -183,56 +207,100 @@ struct psi_jit_context {
 };
 
 struct psi_jit_call {
+       struct psi_context *context;
+       union {
+               struct {
+                       struct psi_impl *impl;
+                       struct psi_call_frame *frame;
+               } fn;
+               struct {
+                       struct psi_let_exp *let_exp;
+                       struct psi_jit_call *impl_call;
+               } cb;
+       } impl;
        void *closure;
        jit_type_t signature;
-       void *params[1]; /* [type1, type2, NULL, arg1, arg2] ... */
+       void *params[1]; /* [type1, type2, ... ] */
 };
 
-static inline struct psi_jit_call *psi_jit_call_alloc(struct psi_context *C, decl *decl) {
-       size_t i, c = decl->args ? decl->args->count : 0;
+static void psi_jit_handler(jit_type_t sig, void *result, void **args, void *data)
+{
+       struct psi_jit_call *call = data;
+
+       psi_context_call(call->context, *(zend_execute_data **)args[0], *(zval **) args[1], call->impl.fn.impl);
+}
+
+static void psi_jit_callback(jit_type_t sig, void *result, void **args,
+               void *data)
+{
+       struct psi_jit_call *call = data, *impl_call = call->impl.cb.impl_call;
+       struct psi_call_frame_callback cbdata;
+
+       cbdata.cb = call->impl.cb.let_exp;
+       cbdata.argc = jit_type_num_params(sig);
+       cbdata.argv = args;
+       cbdata.rval = result;
+
+       psi_call_frame_do_callback(impl_call->impl.fn.frame, &cbdata);
+}
+
+static inline struct psi_jit_call *psi_jit_call_alloc(struct psi_context *C,
+               struct psi_decl *decl)
+{
+       size_t i, c = psi_plist_count(decl->args);
        struct psi_jit_call *call = calloc(1, sizeof(*call) + 2 * c * sizeof(void *));
+       struct psi_decl_arg *arg;
 
-       for (i = 0; i < c; ++i) {
-               call->params[i] = psi_jit_decl_arg_type(decl->args->args[i]);
+       decl->info = call;
+       call->context = C;
+       for (i = 0; psi_plist_get(decl->args, i, &arg); ++i) {
+               call->params[i] = psi_jit_decl_arg_type(arg);
        }
        call->params[c] = NULL;
 
-       decl->call.info = call;
-       decl->call.rval = &decl->func->ptr;
-       decl->call.argc = c;
-       decl->call.args = (void **) &call->params[c+1];
-
        call->signature = jit_type_create_signature(
                        psi_jit_abi(decl->abi->convention),
                        psi_jit_decl_arg_type(decl->func),
-                       (jit_type_t *) call->params, c, 1);
-       ZEND_ASSERT(call->signature);
+                       (jit_type_t *) call->params,
+                       c, 1);
+       assert(call->signature);
 
        return call;
 }
 
-static inline void *psi_jit_call_init_closure(struct psi_context *C, struct psi_jit_call *call, impl *impl) {
+static inline void *psi_jit_call_init_closure(struct psi_context *C,
+               struct psi_jit_call *call, struct psi_impl *impl)
+{
        struct psi_jit_context *context = C->context;
+
+       call->impl.fn.impl = impl;
        return call->closure = jit_closure_create(context->jit, context->signature,
-                       &psi_jit_handler, impl);
+                       &psi_jit_handler, call);
 }
 
-static inline void *psi_jit_call_init_callback_closure(struct psi_context *C, struct psi_jit_call *call, let_callback *cb) {
+static inline void *psi_jit_call_init_callback_closure(struct psi_context *C,
+               struct psi_jit_call *call, struct psi_jit_call *impl_call,
+               struct psi_let_exp *cb)
+{
        struct psi_jit_context *context = C->context;
+
+       call->impl.cb.let_exp = cb;
+       call->impl.cb.impl_call = impl_call;
+
        return call->closure = jit_closure_create(context->jit, call->signature,
-                       &psi_jit_callback, cb);
+                       &psi_jit_callback, call);
 }
 
-static inline void psi_jit_call_free(struct psi_jit_call *call) {
+static inline void psi_jit_call_free(struct psi_jit_call *call)
+{
        jit_type_free(call->signature);
        free(call);
 }
 
-static inline struct psi_jit_context *psi_jit_context_init(struct psi_jit_context *L) {
-       jit_type_t params[] = {
-               jit_type_void_ptr,
-               jit_type_void_ptr
-       };
+static inline struct psi_jit_context *psi_jit_context_init(
+               struct psi_jit_context *L)
+{
+       jit_type_t params[] = {jit_type_void_ptr, jit_type_void_ptr};
 
        if (!L) {
                L = malloc(sizeof(*L));
@@ -246,12 +314,14 @@ static inline struct psi_jit_context *psi_jit_context_init(struct psi_jit_contex
        return L;
 }
 
-static inline void psi_jit_context_dtor(struct psi_jit_context *L) {
+static inline void psi_jit_context_dtor(struct psi_jit_context *L)
+{
        jit_type_free(L->signature);
        jit_context_destroy(L->jit);
 }
 
-static inline void psi_jit_context_free(struct psi_jit_context **L) {
+static inline void psi_jit_context_free(struct psi_jit_context **L)
+{
        if (*L) {
                psi_jit_context_dtor(*L);
                free(*L);
@@ -264,29 +334,32 @@ static void psi_jit_init(struct psi_context *C)
        C->context = psi_jit_context_init(NULL);
 }
 
-static inline void psi_jit_destroy_callbacks(struct psi_context *C, let_val *let_val) {
-       let_callback *cb;
-       let_func *fn = NULL;
+static inline void psi_jit_destroy_callbacks(struct psi_context *C,
+               struct psi_let_exp *let_exp)
+{
+       struct psi_let_callback *cb;
+       struct psi_let_func *fn = NULL;
 
-       switch (let_val->kind) {
+       switch (let_exp->kind) {
        case PSI_LET_CALLBACK:
-               cb = let_val->data.callback;
+               cb = let_exp->data.callback;
 
-               if (cb->decl && cb->decl->call.info) {
-                       psi_jit_call_free(cb->decl->call.info);
+               if (cb->decl && cb->decl->info) {
+                       psi_jit_call_free(cb->decl->info);
                }
                fn = cb->func;
                /* no break */
        case PSI_LET_FUNC:
                if (!fn) {
-                       fn = let_val->data.func;
+                       fn = let_exp->data.func;
                }
 
                if (fn->inner) {
-                       size_t i;
+                       size_t i = 0;
+                       struct psi_let_exp *inner_let;
 
-                       for (i = 0; i < fn->inner->count; ++i) {
-                               psi_jit_destroy_callbacks(C, fn->inner->vals[i]);
+                       while (psi_plist_get(fn->inner, i++, &inner_let)) {
+                               psi_jit_destroy_callbacks(C, inner_let);
                        }
                }
                break;
@@ -298,57 +371,61 @@ static inline void psi_jit_destroy_callbacks(struct psi_context *C, let_val *let
 static void psi_jit_dtor(struct psi_context *C)
 {
        if (C->decls) {
-               size_t i;
+               size_t i = 0;
+               struct psi_decl *decl;
 
-               for (i = 0; i < C->decls->count; ++i) {
-                       decl *decl = C->decls->list[i];
-
-                       if (decl->call.info) {
-                               psi_jit_call_free(decl->call.info);
+               while (psi_plist_get(C->decls, i++, &decl)) {
+                       if (decl->info) {
+                               psi_jit_call_free(decl->info);
                        }
                }
        }
        if (C->impls) {
-               size_t i, j;
+               size_t i = 0;
+               struct psi_impl *impl;
 
-               for (i = 0; i < C->impls->count; ++i) {
-                       impl *impl = C->impls->list[i];
+               while (psi_plist_get(C->impls, i++, &impl)) {
+                       size_t l = 0;
+                       struct psi_let_stmt *let;
 
-                       for (j = 0; j < impl->stmts->let.count; ++j) {
-                               psi_jit_destroy_callbacks(C, impl->stmts->let.list[j]->val);
+                       while (psi_plist_get(impl->stmts.let, l++, &let)) {
+                               psi_jit_destroy_callbacks(C, let->exp);
                        }
                }
        }
        psi_jit_context_free((void *) &C->context);
 }
 
-static inline void psi_jit_compile_callbacks(struct psi_context *C, let_val *let_val) {
+static inline void psi_jit_compile_callbacks(struct psi_context *C,
+               struct psi_jit_call *impl_call, struct psi_let_exp *let_exp)
+{
        struct psi_jit_call *call;
-       let_callback *cb;
-       let_func *fn = NULL;
+       struct psi_let_callback *cb;
+       struct psi_let_func *fn = NULL;
 
-       switch (let_val->kind) {
+       switch (let_exp->kind) {
        case PSI_LET_CALLBACK:
-               cb = let_val->data.callback;
+               cb = let_exp->data.callback;
                if ((call = psi_jit_call_alloc(C, cb->decl))) {
-                       if (!psi_jit_call_init_callback_closure(C, call, cb)) {
+                       if (!psi_jit_call_init_callback_closure(C, call, impl_call, let_exp)) {
                                psi_jit_call_free(call);
                                break;
                        }
 
-                       cb->decl->call.sym = call->closure;
+                       cb->decl->sym = call->closure;
                }
                fn = cb->func;
                /* no break */
        case PSI_LET_FUNC:
                if (!fn) {
-                       fn = let_val->data.func;
+                       fn = let_exp->data.func;
                }
                if (fn->inner) {
-                       size_t i;
+                       size_t i = 0;
+                       struct psi_let_exp *inner_let;
 
-                       for (i = 0; i < fn->inner->count; ++i) {
-                               psi_jit_compile_callbacks(C, fn->inner->vals[i]);
+                       while (psi_plist_get(fn->inner, i++, &inner_let)) {
+                               psi_jit_compile_callbacks(C, impl_call, inner_let);
                        }
                }
                break;
@@ -359,7 +436,9 @@ static inline void psi_jit_compile_callbacks(struct psi_context *C, let_val *let
 
 static zend_function_entry *psi_jit_compile(struct psi_context *C)
 {
-       size_t c, i, j = 0;
+       size_t i = 0, d = 0, nf = 0;
+       struct psi_impl *impl;
+       struct psi_decl *decl;
        zend_function_entry *zfe;
        struct psi_jit_context *ctx = C->context;
 
@@ -367,13 +446,14 @@ static zend_function_entry *psi_jit_compile(struct psi_context *C)
                return NULL;
        }
 
-       zfe = calloc(C->impls->count + 1, sizeof(*zfe));
+       zfe = calloc(psi_plist_count(C->impls) + 1, sizeof(*zfe));
        jit_context_build_start(ctx->jit);
 
-       for (i = 0; i < C->impls->count; ++i) {
-               zend_function_entry *zf = &zfe[j];
+       while (psi_plist_get(C->impls, i++, &impl)) {
+               zend_function_entry *zf = &zfe[nf];
                struct psi_jit_call *call;
-               impl *impl = C->impls->list[i];
+               size_t l = 0;
+               struct psi_let_stmt *let;
 
                if (!impl->decl) {
                        continue;
@@ -387,20 +467,18 @@ static zend_function_entry *psi_jit_compile(struct psi_context *C)
                }
 
                zf->fname = impl->func->name + (impl->func->name[0] == '\\');
-               zf->num_args = impl->func->args->count;
                zf->handler = call->closure;
+               zf->num_args = psi_plist_count(impl->func->args);
                zf->arg_info = psi_internal_arginfo(impl);
-               ++j;
+               ++nf;
 
-               for (c = 0; c < impl->stmts->let.count; ++c) {
-                       psi_jit_compile_callbacks(C, impl->stmts->let.list[c]->val);
+               while (psi_plist_get(impl->stmts.let, l++, &let)) {
+                       psi_jit_compile_callbacks(C, call, let->exp);
                }
        }
 
-       for (i = 0; i < C->decls->count; ++i) {
-               decl *decl = C->decls->list[i];
-
-               if (decl->call.info) {
+       while (psi_plist_get(C->decls, d++, &decl)) {
+               if (decl->info) {
                        continue;
                }
 
@@ -412,45 +490,56 @@ static zend_function_entry *psi_jit_compile(struct psi_context *C)
        return zfe;
 }
 
-static void psi_jit_call(struct psi_context *C, decl_callinfo *decl_call, impl_vararg *va) {
-       struct psi_jit_call *call = decl_call->info;
+static void psi_jit_call(struct psi_context *C, struct psi_call_frame *frame,
+               struct psi_decl *decl, void *rval, void **args)
+{
+       struct psi_jit_call *call = decl->info;
+       struct psi_call_frame *prev = call->impl.fn.frame;
 
-       if (va) {
-               jit_type_t signature;
-               size_t i, nfixedargs = decl_call->argc, ntotalargs = nfixedargs + va->args->count;
-               void **params = calloc(2 * ntotalargs + 2, sizeof(void *));
+       call->impl.fn.frame = frame;
+       jit_apply(call->signature, decl->sym, args, psi_plist_count(decl->args), rval);
+       call->impl.fn.frame = prev;
+}
 
-               for (i = 0; i < nfixedargs; ++i) {
-                       params[i] = call->params[i];
-                       params[i + ntotalargs + 1] = call->params[i + nfixedargs + 1];
-               }
-               for (i = 0; i < va->args->count; ++i) {
-                       params[nfixedargs + i] = psi_jit_impl_type(va->types[i]);
-                       params[nfixedargs + i + ntotalargs + 1] = &va->values[i];
-               }
+static void psi_jit_call_va(struct psi_context *C, struct psi_call_frame *frame,
+               struct psi_decl *decl, void *rval, void **args, size_t va_count,
+               void **va_types)
+{
+       struct psi_jit_call *info = decl->info;
+       struct psi_call_frame *prev = info->impl.fn.frame;
+       size_t argc = psi_plist_count(decl->args);
+       jit_type_t signature;
+       jit_type_t *param_types = ecalloc(argc + va_count + 1, sizeof(jit_type_t));
 
-               signature = jit_type_create_signature(
-                               jit_type_get_abi(call->signature),
-                               jit_type_get_return(call->signature),
-                               (jit_type_t *) params, ntotalargs, 1);
-               ZEND_ASSERT(signature);
+       memcpy(param_types, info->params, argc * sizeof(jit_type_t));
+       memcpy(param_types + argc, va_types, va_count * sizeof(jit_type_t));
 
-               jit_apply(signature, decl_call->sym, &params[ntotalargs + 1],
-                                               nfixedargs, *decl_call->rval);
-               jit_type_free(signature);
-               free(params);
-       } else {
-               jit_apply(call->signature, decl_call->sym, decl_call->args,
-                               decl_call->argc, *decl_call->rval);
+       signature = jit_type_create_signature(jit_abi_vararg,
+                       jit_type_get_return(info->signature), param_types, argc + va_count,
+                       1);
+       ZEND_ASSERT(signature);
+
+       info->impl.fn.frame = frame;
+       jit_apply(signature, decl->sym, args, argc, rval);
+       info->impl.fn.frame = prev;
+       jit_type_free(signature);
+       efree(param_types);
+}
+
+static void *psi_jit_query(struct psi_context *C, enum psi_context_query q,
+               void *arg)
+{
+       switch (q) {
+       case PSI_CONTEXT_QUERY_SELF:
+               return "jit";
+       case PSI_CONTEXT_QUERY_TYPE:
+               return psi_jit_impl_type(*(token_t *) arg);
        }
+       return NULL;
 }
 
-static struct psi_context_ops ops = {
-       psi_jit_init,
-       psi_jit_dtor,
-       psi_jit_compile,
-       psi_jit_call,
-};
+static struct psi_context_ops ops = {psi_jit_init, psi_jit_dtor,
+               psi_jit_compile, psi_jit_call, psi_jit_call_va, psi_jit_query};
 
 struct psi_context_ops *psi_libjit_ops(void)
 {
index 602fc51..b4921bd 100644 (file)
@@ -1,5 +1,30 @@
-#ifndef _PSI_LIBJIT_H
-#define _PSI_LIBJIT_H
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+     * Redistributions of source code must retain the above copyright notice,
+       this list of conditions and the following disclaimer.
+     * Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#ifndef PSI_LIBJIT_H
+#define PSI_LIBJIT_H
 
 #include "context.h"
 
index 1e71a64..87abf98 100644 (file)
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#else
-# include "php_config.h"
-#endif
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+     * Redistributions of source code must retain the above copyright notice,
+       this list of conditions and the following disclaimer.
+     * Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#include "php_psi_stdinc.h"
+#include "data.h"
+#include "calc.h"
 
 #include "php.h"
 #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)
+#include "Zend/zend_interfaces.h"
+#include "ext/spl/spl_iterators.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;
+}
+
+int psi_internal_type(struct psi_impl_type *type)
+{
+       switch (type->type) {
+       case PSI_T_BOOL:
+               return _IS_BOOL;
+       case PSI_T_INT:
+               return IS_LONG;
+       case PSI_T_FLOAT:
+       case PSI_T_DOUBLE:
+               return IS_DOUBLE;
+       case PSI_T_STRING:
+               return IS_STRING;
+       case PSI_T_ARRAY:
+               return IS_ARRAY;
+       default:
+               return 0;
+       }
+}
+
+zend_internal_arg_info *psi_internal_arginfo(struct psi_impl *impl)
+{
+       size_t i = 0, argc = psi_plist_count(impl->func->args);
+       zend_internal_arg_info *aip;
+       zend_internal_function_info *fi;
+       struct psi_impl_arg *iarg;
+
+       aip = calloc(argc + 1 + !!impl->func->vararg, sizeof(*aip));
+
+       fi = (zend_internal_function_info *) &aip[0];
+       fi->allow_null = 1;
+       fi->required_num_args = psi_impl_num_min_args(impl);
+       fi->return_reference = impl->func->return_reference;
+       fi->type_hint = psi_internal_type(impl->func->return_type);
+
+       if (impl->func->vararg) {
+               struct psi_impl_arg *vararg = impl->func->vararg;
+               zend_internal_arg_info *ai = &aip[argc];
+
+               ai->name = vararg->var->name;
+               ai->allow_null = 1;
+               ai->type_hint = psi_internal_type(vararg->type);
+               if (vararg->var->reference) {
+                       ai->pass_by_reference = 1;
+               }
+               ai->is_variadic = 1;
+       }
+
+       while (psi_plist_get(impl->func->args, i++, &iarg)) {
+               zend_internal_arg_info *ai = &aip[i];
+
+               ai->name = iarg->var->name;
+               ai->type_hint = psi_internal_type(iarg->type);
+               if (iarg->var->reference) {
+                       ai->pass_by_reference = 1;
+               }
+               /* FIXME: if (iarg->var->reference || (iarg->def && iarg->def->type == PSI_T_NULL)) */
+               ai->allow_null = 1;
+       }
+
+       return aip;
+}
+
+/*
+ * return void(dvar)
+ */
+void psi_set_void(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame)
 {
        RETVAL_NULL();
 }
 
-impl_val *psi_let_void(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+/*
+ * ?
+ */
+impl_val *psi_let_void(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
 {
        return tmp;
 }
 
-void psi_to_zval(zval *return_value, set_value *set, impl_val *ret_val) {
+/*
+ * set $ivar = zval(dvar)
+ */
+void psi_set_zval(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame) {
        RETVAL_ZVAL(ret_val->ptr, 1, 0);
 }
 
-impl_val *psi_let_zval(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+/*
+ * let dvar = zval($ivar)
+ */
+impl_val *psi_let_zval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
 {
        *to_free = tmp->ptr = emalloc(sizeof(zval));
        ZVAL_COPY_VALUE(tmp->ptr, zvalue);
        return tmp;
 }
 
-void psi_to_bool(zval *return_value, set_value *set, impl_val *ret_val)
+/*
+ * return to_bool(dvar)
+ */
+void psi_set_to_bool(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame)
 {
-       psi_to_int(return_value, set, ret_val);
+       psi_set_to_int(return_value, set, ret_val, frame);
        convert_to_boolean(return_value);
 }
 
@@ -58,10 +194,13 @@ static inline impl_val *psi_val_boolval(impl_val *tmp, token_t real_type, zend_b
        return tmp;
 }
 
-impl_val *psi_let_boolval(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+/*
+ * let dvar = boolval($ivar)
+ */
+impl_val *psi_let_boolval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
 {
        zend_bool boolval;
-       token_t real_type = spec ? real_decl_type(spec)->type : PSI_T_UINT8;
+       token_t real_type = spec ? psi_decl_type_get_real(spec)->type : PSI_T_UINT8;
 
        if (ival && impl_type == PSI_T_BOOL) {
                boolval = ival->zend.bval;
@@ -80,10 +219,13 @@ impl_val *psi_let_boolval(impl_val *tmp, decl_type *spec, token_t impl_type, imp
                        RETVAL_LONG(V); \
                }
 
-void psi_to_int(zval *return_value, set_value *set, impl_val *ret_val)
+/*
+ * set $ivar = to_int(*dvar)
+ */
+void psi_set_to_int(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame)
 {
-       decl_var *var = set->vars->vars[0];
-       token_t t = real_decl_type(var->arg->type)->type;
+       struct psi_decl_var *var = psi_set_exp_get_decl_var(set);
+       token_t t = psi_decl_type_get_real(var->arg->type)->type;
        impl_val *v = deref_impl_val(ret_val, var);
 
        switch (t) {
@@ -129,10 +271,13 @@ static inline impl_val *psi_val_intval(impl_val *tmp, token_t real_type, zend_lo
        return tmp;
 }
 
-impl_val *psi_let_intval(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+/*
+ * let dvar = intval($ivar)
+ */
+impl_val *psi_let_intval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
 {
        zend_long intval;
-       token_t real_type = spec ? real_decl_type(spec)->type : PSI_T_LONG;
+       token_t real_type = spec ? psi_decl_type_get_real(spec)->type : PSI_T_LONG;
 
        if (ival && impl_type == PSI_T_INT) {
                intval = ival->zend.lval;
@@ -143,10 +288,13 @@ impl_val *psi_let_intval(impl_val *tmp, decl_type *spec, token_t impl_type, impl
        return psi_val_intval(tmp, real_type, intval);
 }
 
-void psi_to_double(zval *return_value, set_value *set, impl_val *ret_val)
+/*
+ * set $ivar = to_float(dvar)
+ */
+void psi_set_to_float(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame)
 {
-       decl_var *var = set->vars->vars[0];
-       token_t t = real_decl_type(var->arg->type)->type;
+       struct psi_decl_var *var = psi_set_exp_get_decl_var(set);
+       token_t t = psi_decl_type_get_real(var->arg->type)->type;
        impl_val *v = deref_impl_val(ret_val, var);
 
        switch (t) {
@@ -188,10 +336,13 @@ static inline impl_val *psi_val_floatval(impl_val *tmp, token_t real_type, doubl
        return tmp;
 }
 
-impl_val *psi_let_floatval(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+/*
+ * let dvar = floatval($ivar)
+ */
+impl_val *psi_let_floatval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
 {
        double floatval;
-       token_t real_type = spec ? real_decl_type(spec)->type : PSI_T_DOUBLE;
+       token_t real_type = spec ? psi_decl_type_get_real(spec)->type : PSI_T_DOUBLE;
 
        if (ival && (impl_type == PSI_T_FLOAT || impl_type == PSI_T_DOUBLE)) {
                floatval = ival->dval;
@@ -202,51 +353,53 @@ impl_val *psi_let_floatval(impl_val *tmp, decl_type *spec, token_t impl_type, im
        return psi_val_floatval(tmp, real_type, floatval);
 }
 
-void psi_to_string(zval *return_value, set_value *set, impl_val *ret_val)
+/*
+ * set $ivar = to_string(dvar)
+ */
+void psi_set_to_string(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame)
 {
+       struct psi_decl_var *var = psi_set_exp_get_decl_var(set);
+       impl_val *ptr = deref_impl_val(ret_val, var);
        char *str;
-       decl_var *var = set->vars->vars[0];
-       token_t t = real_decl_type(var->arg->type)->type;
 
-       switch (t) {
-       case PSI_T_FLOAT:               RETVAL_DOUBLE((double) deref_impl_val(ret_val, var)->fval);             break;
-       case PSI_T_DOUBLE:              RETVAL_DOUBLE(deref_impl_val(ret_val, var)->dval);                              break;
-#ifdef HAVE_LONG_DOUBLE
-       case PSI_T_LONG_DOUBLE: RETVAL_DOUBLE((double) deref_impl_val(ret_val, var)->ldval);    break;
-#endif
-       default:
-               if (!var->arg->var->pointer_level) {
-                       RETVAL_STRINGL(&ret_val->cval, 1);
-               } else {
-                       ret_val = deref_impl_val(ret_val, var);
-                       if (var->arg->var->array_size) {
-                               str = (char *) ret_val;
-                       } else {
-                               str = ret_val->ptr;
-                       }
-                       if (str) {
-                               if (set->num) {
-                                       zend_long n = psi_long_num_exp(set->num, set->outer.val);
-                                       RETVAL_STRINGL(str, n);
-                               } else {
-                                       RETVAL_STRING(str);
-                               }
-                       } else {
-                               RETVAL_EMPTY_STRING();
-                       }
-               }
-               return;
+       if (var->arg->var->array_size) {
+               str = (char *) ptr;
+       } else {
+               str = ptr->ptr;
        }
 
-       convert_to_string(return_value);
+       if (str) {
+               RETVAL_STRING(str);
+       } else {
+               RETVAL_EMPTY_STRING();
+       }
 }
 
-impl_val *psi_let_strval(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+/*
+ * set $ivar = to_string(dvar, num_exp)
+ */
+void psi_set_to_stringl(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame)
+{
+       struct psi_decl_var *var = psi_set_exp_get_decl_var(set);
+       char *str = deref_impl_val(ret_val, var)->ptr;
+
+       if (str) {
+               struct psi_set_exp *sub_exp;
+
+               psi_plist_get(set->inner, 0, &sub_exp);
+               RETVAL_STRINGL(str, psi_long_num_exp(sub_exp->data.num, frame));
+       } else {
+               RETVAL_EMPTY_STRING();
+       }
+}
+
+/*
+ * let dvar = strval($ivar)
+ */
+impl_val *psi_let_strval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
 {
        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 = ival->zend.str->val;
                } else {
                        tmp->ptr = "";
@@ -263,7 +416,10 @@ impl_val *psi_let_strval(impl_val *tmp, decl_type *spec, token_t impl_type, impl
        return tmp;
 }
 
-impl_val *psi_let_pathval(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+/*
+ * let dvar = pathval($ivar)
+ */
+impl_val *psi_let_pathval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
 {
        tmp = psi_let_strval(tmp, spec, impl_type, ival, zvalue, to_free);
        if (SUCCESS != php_check_open_basedir(tmp->ptr)) {
@@ -274,7 +430,10 @@ impl_val *psi_let_pathval(impl_val *tmp, decl_type *spec, token_t impl_type, imp
        return tmp;
 }
 
-impl_val *psi_let_strlen(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+/*
+ * let dvar = strlen($ivar)
+ */
+impl_val *psi_let_strlen(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
 {
        if (ival && impl_type == PSI_T_STRING) {
                if (ival->zend.str) {
@@ -298,278 +457,169 @@ static impl_val *iterate(impl_val *val, size_t size, unsigned i, impl_val *tmp)
        return tmp;
 }
 
-void psi_from_zval_ex(void *cb_ctx, impl_val **ptr, decl_arg *spec, token_t cast, zval *zv, void **tmp)
-{
-       decl_type *real = real_decl_type(spec->type);
-       impl_val *val = *ptr;
-
-       switch (real->type) {
-       default:
-               ZEND_ASSERT(0);
-               val->i64 = zval_get_long(zv);
-               break;
-       case PSI_T_INT8:
-               val->i8 = zval_get_long(zv);
-               break;
-       case PSI_T_UINT8:
-               val->u8 = zval_get_long(zv);
-               break;
-       case PSI_T_INT16:
-               val->i16 = zval_get_long(zv);
-               break;
-       case PSI_T_UINT16:
-               val->u16 = zval_get_long(zv);
-               break;
-       case PSI_T_INT32:
-               val->i32 = zval_get_long(zv);
-               break;
-       case PSI_T_UINT32:
-               val->u32 = zval_get_long(zv);
-               break;
-       case PSI_T_INT64:
-               val->i64 = zval_get_long(zv);
-               break;
-       case PSI_T_UINT64:
-               val->u64 = zval_get_long(zv);
-               break;
-       case PSI_T_FLOAT:
-               val->fval = zval_get_double(zv);
-               break;
-       case PSI_T_DOUBLE:
-               val->dval = zval_get_double(zv);
-               break;
-#ifdef HAVE_LONG_DOUBLE
-       case PSI_T_LONG_DOUBLE:
-               val->ldval = zval_get_double(zv);
-               break;
-#endif
-       case PSI_T_ENUM:
-               val->ival = zval_get_long(zv);
-               break;
-       case PSI_T_STRUCT:
-               *tmp = *ptr = psi_array_to_struct_ex(real->real.strct, HASH_OF(zv), psi_from_zval_ex, cb_ctx);
-               break;
-       case PSI_T_UNION:
-               *tmp = *ptr = psi_array_to_union_ex(real->real.unn, HASH_OF(zv), psi_from_zval_ex, cb_ctx);
-               break;
-       case PSI_T_FUNCTION:
-               /*FIXME*/
-               val->ptr = NULL;
-               break;
-       case PSI_T_VOID:
-               val->ptr = NULL;
-               if (Z_TYPE_P(zv) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zv), psi_object_get_class_entry())) {
-                       *ptr = PSI_OBJ(zv, NULL)->data;
-               } else {
-                       zend_string *zs = zval_get_string(zv);
-                       *tmp = val->ptr = estrndup(zs->val, zs->len);
-                       zend_string_release(zs);
-               }
-               break;
-       }
+/*
+ * set $ivar = to_array(dvar,
+ *             $foo = to_int(d_foo),
+ *             $bar = to_string(d_bar),
+ *             $baz = to_array(*d_next, ...)
+ */
+void psi_set_to_recursive(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame) {
+       set->outer->data.func->handler(return_value, set, r_val, frame);
 }
 
-void *psi_array_to_struct_ex(decl_struct *s, HashTable *arr, psi_marshal_zval cb, void *cb_ctx) {
-       size_t i, j = 0;
-       char *mem = ecalloc(1, s->size + s->args->count * sizeof(void *));
-
-       if (arr) for (i = 0; i < s->args->count; ++i) {
-               decl_arg *darg = s->args->args[i];
-               zval *entry = zend_hash_str_find_ind(arr, darg->var->name, strlen(darg->var->name));
-
-               if (entry) {
-                       impl_val val, *ptr = &val;
-                       void *tmp = NULL;
-
-                       memset(&val, 0, sizeof(val));
-                       cb(cb_ctx, &ptr, darg, /*FIXME*/0, entry, &tmp);
-                       memcpy(mem + darg->layout->pos, ptr, darg->layout->len);
-                       if (tmp) {
-                               ((void **)(mem + s->size))[j++] = tmp;
-                       }
-               }
-       }
-       return mem;
-}
-
-void *psi_array_to_struct(decl_struct *s, HashTable *arr)
+/*
+ * set $ivar = to_array(dvar, to_string(*dvar));
+ */
+void psi_set_to_array_simple(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame)
 {
-       return psi_array_to_struct_ex(s, arr, psi_from_zval_ex, NULL);
-}
+       struct psi_set_exp *sub_exp;
+       struct psi_decl_var *var;
+       impl_val *ret_val;
+       char *ptr;
+       size_t size;
 
-void *psi_array_to_union_ex(decl_union *u, HashTable *arr, psi_marshal_zval cb, void *cb_ctx) {
-       size_t i;
-       char *mem = ecalloc(1, u->size + sizeof(void *));
-
-       if (arr) for (i = 0; i < u->args->count; ++i) {
-               decl_arg *darg = u->args->args[i];
-               zval *entry = zend_hash_str_find_ind(arr, darg->var->name, strlen(darg->var->name));
-
-               if (entry) {
-                       impl_val val, *ptr = &val;
-                       void *tmp = NULL;
+       array_init(return_value);
 
-                       memset(&val, 0, sizeof(val));
-                       cb(cb_ctx, &ptr, darg, /*FIXME*/0, entry, &tmp);
-                       memcpy(mem, &val, darg->layout->len);
-                       if (tmp) {
-                               ((void **)(mem + u->size))[0] = tmp;
-                       }
-                       /* first found entry wins */
-                       break;
-               }
+       var = psi_set_exp_get_decl_var(set);
+       ret_val = deref_impl_val(r_val, var);
+       if ((intptr_t) ret_val <= (intptr_t) 0) {
+               return;
        }
 
-       return mem;
-}
+       psi_plist_get(set->inner, 0, &sub_exp);
 
-void *psi_array_to_union(decl_union *u, HashTable *arr) {
-       return psi_array_to_union_ex(u, arr, psi_from_zval_ex, NULL);
-}
+       size = psi_decl_arg_get_size(var->arg);
+       for (ptr = ret_val->ptr; *(void **) ptr; ptr += size) {
+               zval ele;
 
-void psi_to_recursive(zval *return_value, set_value *set, impl_val *r_val) {
-       set->outer.set->func->handler(return_value, set, r_val);
+               ZVAL_NULL(&ele);
+               sub_exp->data.func->handler(&ele, sub_exp, (void *) ptr, frame);
+               add_next_index_zval(return_value, &ele);
+       }
 }
 
-void psi_to_array(zval *return_value, set_value *set, impl_val *r_val)
+/*
+ * set $ivar = to_array(dvar, num_exp, to_string(*dvar));
+ */
+void psi_set_to_array_counted(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame)
 {
-       size_t i;
-       decl_var *var = set->vars->vars[0];
-       token_t t = real_decl_type(var->arg->type)->type;
-       impl_val tmp, *ret_val = deref_impl_val(r_val, var);
+       struct psi_set_exp *sub_exp;
+       struct psi_decl_var *var;
+       impl_val *ret_val;
+       char *ptr;
+       size_t size;
+       zend_long count;
+
+       array_init(return_value);
 
+       var = psi_set_exp_get_decl_var(set);
+       ret_val = deref_impl_val(r_val, var);
        if ((intptr_t) ret_val <= (intptr_t) 0) {
-               RETURN_NULL();
+               return;
        }
 
-       array_init(return_value);
+       psi_plist_get(set->inner, 0, &sub_exp);
+       count = psi_long_num_exp(sub_exp->data.num, frame);
+       psi_plist_get(set->inner, 1, &sub_exp);
 
-       if (t == PSI_T_STRUCT || t == PSI_T_UNION) {
-               // decl_struct *s = real_decl_type(var->arg->type)->strct;
+       for (ptr = (char *) ret_val; 0 < count--; ptr += size) {
+       size = psi_decl_var_get_size(psi_set_exp_get_decl_var(sub_exp));
+               zval ele;
 
-               if (set->inner && set->inner->count) {
-                       /* explicit member casts */
-                       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];
+               ZVAL_NULL(&ele);
+               sub_exp->data.func->handler(&ele, sub_exp, (void *) &ptr, frame);
+               add_next_index_zval(return_value, &ele);
+       }
+}
 
-                               sub_set->outer.val = ret_val;
+#include "call.h"
 
-                               if (sub_var->arg) {
-                                       impl_val *tmp = NULL, *val;
-                                       zval ztmp;
+/*
+ * set $ivar = to_array(dvar,
+ *             $foo = to_int(d_foo),
+ *             $bar = to_string(d_bar));
+ */
+void psi_set_to_array(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame)
+{
+       struct psi_set_exp *sub_exp;
+       struct psi_decl_var *var;
+       impl_val *ret_val;
+       size_t i = 0;
 
-                                       val = struct_member_ref(sub_var->arg, ret_val, &tmp);
-                                       sub_set->func->handler(&ztmp, sub_set, val);
-                                       add_assoc_zval(return_value, sub_var->name, &ztmp);
+       array_init(return_value);
 
-                                       if (tmp) {
-                                               free(tmp);
-                                       }
-                               }
-                       }
-                       return;
-               }
+       var = psi_set_exp_get_decl_var(set);
+       ret_val = deref_impl_val(r_val, var);
+       if ((intptr_t) ret_val <= (intptr_t) 0) {
+               return;
        }
 
-       if (var->arg->var->array_size) {
-               /* 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->ptr, size, i, &tmp);
-                       zval ele;
-
-                       switch (t) {
-                       case PSI_T_FLOAT:
-                               ZVAL_DOUBLE(&ele, (double) ptr->fval);
-                               break;
-                       case PSI_T_DOUBLE:
-                               ZVAL_DOUBLE(&ele, ptr->dval);
-                               break;
-                       default:
-                               ZVAL_LONG(&ele, ptr->lval);
-                               break;
-                       }
-
-                       add_next_index_zval(return_value, &ele);
-               }
-               return;
-       } else if (set->num) {
-               /* to_array(arr_var, num_expr, to_int(*arr_var)) */
-               zval ele;
-               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->vals[0];
-
-               sub_set->outer.val = set->outer.val;
-               for (i = 0; i < n; ++i) {
-                       ptr = (char *) ret_val->ptr + i * size;
-                       sub_set->func->handler(&ele, sub_set, (void *) ptr);
-                       add_next_index_zval(return_value, &ele);
-               }
-       } else {
-               /* to_array(arr_var, to_int(*arr_var)) */
+       while (psi_plist_get(set->inner, i++, &sub_exp)) {
                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->vals[0];
-
-               sub_set->outer.val = set->outer.val;
-               while (*(void **) ptr) {
-                       sub_set->func->handler(&ele, sub_set, (void *) ptr);
-                       add_next_index_zval(return_value, &ele);
-                       ptr += size;
-               }
-       }
-}
+               struct psi_decl_var *dvar = psi_set_exp_get_decl_var(sub_exp);
+               struct psi_impl_var *ivar = psi_set_exp_get_impl_var(sub_exp);
+               struct psi_call_frame_symbol *sym;
 
-impl_val *psi_let_arrval(impl_val *tmp, decl_type *spec, decl_var *spec_var, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
-{
-       decl_type *real = real_decl_type(spec);
-       HashTable *arr;
-       zval *zv;
-       size_t i, sz;
-       decl_arg tmp_arg = {0};
-
-       if (impl_type != PSI_T_ARRAY) {
-               SEPARATE_ARG_IF_REF(zvalue);
-               convert_to_array(zvalue);
-       }
-       arr = HASH_OF(zvalue);
+               sym = psi_call_frame_fetch_symbol(frame, dvar);
+               sym->ptr = ((char *) ret_val) + dvar->arg->layout->pos;
 
-       switch (real->type) {
-       case PSI_T_STRUCT:
-               *to_free = tmp = psi_array_to_struct(real->real.strct, arr);
-               break;
-       case PSI_T_UNION:
-               *to_free = tmp = psi_array_to_union(real->real.unn, arr);
-               break;
-       default:
-               sz = psi_t_size(real->type);
-               tmp = *to_free = ecalloc(zend_hash_num_elements(arr), sz);
-               tmp_arg.type = spec;
-               tmp_arg.var = spec_var;
-               ZEND_HASH_FOREACH_VAL_IND(arr, zv)
-               {
-                       void *ptr = ((char *) tmp) + (i++ * sz);
-                       psi_from_zval_ex(NULL, (impl_val **) &ptr, &tmp_arg, 0, zv, NULL);
-               }
-               ZEND_HASH_FOREACH_END();
+               ZVAL_NULL(&ele);
+               psi_set_exp_exec_ex(sub_exp, &ele, sym->ptr, frame);
+               add_assoc_zval(return_value, ivar->name + 1, &ele);
        }
-
-       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)
+//impl_val *psi_let_arrval(impl_val *tmp, decl_type *spec, decl_var *spec_var, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+//{
+//     decl_type *real = real_decl_type(spec);
+//     HashTable *arr;
+//     zval *zv;
+//     size_t i, sz;
+//     decl_arg tmp_arg = {0};
+//
+//     if (impl_type != PSI_T_ARRAY) {
+//             SEPARATE_ARG_IF_REF(zvalue);
+//             convert_to_array(zvalue);
+//     }
+//     arr = HASH_OF(zvalue);
+//
+//     switch (real->type) {
+//     case PSI_T_STRUCT:
+//             *to_free = tmp = psi_array_to_struct(real->real.strct, arr);
+//             break;
+//     case PSI_T_UNION:
+//             *to_free = tmp = psi_array_to_union(real->real.unn, arr);
+//             break;
+//     default:
+//             sz = psi_t_size(real->type);
+//             tmp = *to_free = ecalloc(zend_hash_num_elements(arr), sz);
+//             tmp_arg.type = spec;
+//             tmp_arg.var = spec_var;
+//             ZEND_HASH_FOREACH_VAL_IND(arr, zv)
+//             {
+//                     void *ptr = ((char *) tmp) + (i++ * sz);
+//                     psi_from_zval_ex(NULL, (impl_val **) &ptr, &tmp_arg, 0, zv, NULL);
+//             }
+//             ZEND_HASH_FOREACH_END();
+//     }
+//
+//     return tmp;
+//}
+
+/*
+ * let dvar = count($ivar)
+ */
+impl_val *psi_let_count(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
 {
-       return psi_val_intval(tmp, real_decl_type(spec)->type, psi_zval_count(zvalue));
+       return psi_val_intval(tmp, psi_decl_type_get_real(spec)->type, psi_zval_count(zvalue));
 }
 
-
-void psi_to_object(zval *return_value, set_value *set, impl_val *r_val)
+/*
+ * set $ivar = to_object(dvar)
+ */
+void psi_set_to_object(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame)
 {
-       decl_var *var = set->vars->vars[0];
+       struct psi_decl_var *var = psi_set_exp_get_decl_var(set);
        impl_val *ret_val = deref_impl_val(r_val, var);
 
        if ((intptr_t) ret_val->ptr > (intptr_t) 0) {
@@ -580,7 +630,10 @@ void psi_to_object(zval *return_value, set_value *set, impl_val *r_val)
        }
 }
 
-impl_val *psi_let_objval(impl_val *tmp, decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
+/*
+ * let dvar = objval($ivar)
+ */
+impl_val *psi_let_objval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free)
 {
        psi_object *obj;
 
index bf9267d..6fe15c6 100644 (file)
@@ -1,38 +1,70 @@
-#ifndef _PSI_MARSHAL_H
-#define _PSI_MARSHAL_H
-
-typedef void (*psi_marshal_set)(zval *return_value, set_value *set, impl_val *ret_val);
-typedef impl_val *(*psi_marshal_let)(impl_val *tmp, decl_type *decl_type, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
-
-void psi_to_void(zval *return_value, set_value *set, impl_val *ret_val);
-void psi_to_bool(zval *return_value, set_value *set, impl_val *ret_val);
-void psi_to_int(zval *return_value, set_value *set, impl_val *ret_val);
-void psi_to_double(zval *return_value, set_value *set, impl_val *ret_val);
-void psi_to_string(zval *return_value, set_value *set, impl_val *ret_val);
-void psi_to_recursive(zval *return_value, set_value *set, impl_val *r_val);
-void psi_to_array(zval *return_value, set_value *set, impl_val *ret_val);
-void psi_to_object(zval *return_value, set_value *set, impl_val *ret_val);
-void psi_to_zval(zval *return_value, set_value *set, impl_val *ret_val);
-
-void *psi_array_to_union(decl_union *u, HashTable *arr);
-void *psi_array_to_struct(decl_struct *s, HashTable *arr);
-
-typedef void (*psi_marshal_zval)(void *cb_ctx, impl_val **ptr, decl_arg *spec, token_t cast, zval *zv, void **tmp);
-
-void psi_from_zval_ex(void *cb_ctx, impl_val **ptr, decl_arg *spec, token_t cast, zval *zv, void **tmp);
-
-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 *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);
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+     * Redistributions of source code must retain the above copyright notice,
+       this list of conditions and the following disclaimer.
+     * Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#ifndef PSI_MARSHAL_H
+#define PSI_MARSHAL_H
+
+#include "impl_val.h"
+#include "Zend/zend_types.h"
+
+struct psi_let_exp;
+struct psi_set_exp;
+struct psi_decl_type;
+struct psi_call_frame;
+struct psi_impl;
+struct psi_impl_type;
+
+zend_long psi_zval_count(zval *zvalue);
+zend_internal_arg_info *psi_internal_arginfo(struct psi_impl *impl);
+int psi_internal_type(struct psi_impl_type *type);
+
+typedef void (*psi_marshal_set)(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame);
+typedef impl_val *(*psi_marshal_let)(impl_val *tmp, struct psi_decl_type *psi_decl_type, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
+
+void psi_set_void(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame);
+void psi_set_to_bool(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame);
+void psi_set_to_int(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame);
+void psi_set_to_float(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame);
+void psi_set_to_string(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame);
+void psi_set_to_stringl(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame);
+void psi_set_to_recursive(zval *return_value, struct psi_set_exp *set, impl_val *r_val, struct psi_call_frame *frame);
+void psi_set_to_array_simple(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame);
+void psi_set_to_array_counted(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame);
+void psi_set_to_array(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame);
+void psi_set_to_object(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame);
+void psi_set_zval(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame);
+
+impl_val *psi_let_void(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
+impl_val *psi_let_boolval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
+impl_val *psi_let_intval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
+impl_val *psi_let_floatval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
+impl_val *psi_let_strval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
+impl_val *psi_let_pathval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
+impl_val *psi_let_strlen(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
+impl_val *psi_let_objval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
+impl_val *psi_let_zval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free);
+impl_val *psi_let_count(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free);
+
 #endif
index a70a50a..8201d5a 100644 (file)
@@ -1,8 +1,29 @@
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#else
-# include "php_config.h"
-#endif
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+     * Redistributions of source code must retain the above copyright notice,
+       this list of conditions and the following disclaimer.
+     * Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#include "php_psi_stdinc.h"
 
 #include "php.h"
 #include "php_ini.h"
@@ -40,63 +61,31 @@ zend_class_entry *psi_object_get_class_entry()
        return psi_class_entry;
 }
 
-void psi_error_wrapper(void *context, struct psi_token *t, int type, const char *msg, ...)
-{
-       va_list argv;
-       const char *fn = NULL;
-       unsigned ln = 0;
-
-       if (context) {
-               if (PSI_DATA(context)->flags & PSI_PARSER_SILENT) {
-                       return;
-               }
-       }
-
-       if (t) {
-               fn = t->file;
-               ln = t->line;
-       } else if (zend_is_executing()) {
-               fn = zend_get_executed_filename();
-               ln = zend_get_executed_lineno();
-       } else if (zend_is_compiling()) {
-               fn = zend_get_compiled_filename()->val;
-               ln = zend_get_compiled_lineno();
-       }
-
-       va_start(argv, msg);
-       psi_verror(type, fn, ln, msg, argv);
-       va_end(argv);
-}
-
-void psi_error(int type, const char *fn, unsigned ln, const char *msg, ...)
-{
-       va_list argv;
-
-       va_start(argv, msg);
-       psi_verror(type, fn, ln, msg, argv);
-       va_end(argv);
-}
-
-void psi_verror(int type, const char *fn, unsigned ln, const char *msg, va_list argv)
-{
-       zend_error_cb(type, fn, ln, msg, argv);
-}
-
 static void psi_object_free(zend_object *o)
 {
        psi_object *obj = PSI_OBJ(NULL, o);
 
        if (obj->data) {
-               /* FIXME: how about registering a destructor?
-               // free(obj->data); */
+               if (obj->dtor) {
+                       obj->dtor(obj->data);
+               }
                obj->data = NULL;
        }
        zend_object_std_dtor(o);
 }
 
-static zend_object *psi_object_init(zend_class_entry *ce)
+zend_object *psi_object_init_ex(zend_class_entry *ce, void *data, void (*dtor)(void *))
 {
-       psi_object *o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce));
+       psi_object *o;
+
+       if (!ce) {
+               ce = psi_class_entry;
+       }
+
+       o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce));
+
+       o->data = data;
+       o->dtor = dtor;
 
        zend_object_std_init(&o->std, ce);
        object_properties_init(&o->std, ce);
@@ -104,6 +93,11 @@ static zend_object *psi_object_init(zend_class_entry *ce)
        return &o->std;
 }
 
+zend_object *psi_object_init(zend_class_entry *ce)
+{
+       return psi_object_init_ex(ce, NULL, NULL);
+}
+
 ZEND_BEGIN_ARG_INFO_EX(ai_psi_dump, 0, 0, 0)
        ZEND_ARG_INFO(0, stream)
 ZEND_END_ARG_INFO();
@@ -122,7 +116,7 @@ static PHP_FUNCTION(psi_dump) {
                        RETURN_FALSE;
                }
        }
-       psi_context_dump(&PSI_G(context), fd);
+       psi_context_dump(PSI_G(context), fd);
 }
 
 ZEND_BEGIN_ARG_INFO_EX(ai_psi_validate, 0, 0, 1)
@@ -131,6 +125,7 @@ ZEND_END_ARG_INFO();
 static PHP_FUNCTION(psi_validate) {
        zend_string *file;
        struct psi_parser P;
+       struct psi_data D = {0};
 
        if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "P", &file)) {
                return;
@@ -148,11 +143,10 @@ static PHP_FUNCTION(psi_validate) {
        }
        psi_parser_parse(&P, NULL);
 
-       if (0 == psi_context_validate_data(NULL, PSI_DATA(&P)) && !P.errors) {
-               RETVAL_TRUE;
-       } else {
-               RETVAL_FALSE;
-       }
+       psi_data_ctor(&D, P.error, P.flags);
+       RETVAL_BOOL(psi_data_validate(&D, PSI_DATA(&P)) && !P.errors);
+       psi_data_dtor(&D);
+
        psi_parser_dtor(&P);
 }
 
@@ -160,8 +154,14 @@ static PHP_MINIT_FUNCTION(psi)
 {
        struct psi_context_ops *ops = NULL;
        zend_class_entry ce = {0};
-       unsigned flags = psi_check_env("PSI_DEBUG") ? PSI_PARSER_DEBUG : (
-                       psi_check_env("PSI_SILENT") ? PSI_PARSER_SILENT : 0);
+       unsigned flags = 0;
+
+       if (psi_check_env("PSI_DEBUG")) {
+               flags |= PSI_DEBUG;
+       }
+       if (psi_check_env("PSI_SILENT")) {
+               flags |= PSI_SILENT;
+       }
 
        REGISTER_INI_ENTRIES();
 
@@ -188,11 +188,11 @@ static PHP_MINIT_FUNCTION(psi)
                return FAILURE;
        }
 
-       psi_context_init(&PSI_G(context), ops, psi_error_wrapper, flags);
-       psi_context_build(&PSI_G(context), PSI_G(directory));
+       PSI_G(context) = psi_context_init(NULL, ops, psi_error_wrapper, flags);
+       psi_context_build(PSI_G(context), PSI_G(directory));
 
        if (psi_check_env("PSI_DUMP")) {
-               psi_context_dump(&PSI_G(context), STDOUT_FILENO);
+               psi_context_dump(PSI_G(context), STDOUT_FILENO);
        }
 
        return SUCCESS;
@@ -200,7 +200,7 @@ static PHP_MINIT_FUNCTION(psi)
 
 static PHP_MSHUTDOWN_FUNCTION(psi)
 {
-       psi_context_dtor(&PSI_G(context));
+       psi_context_free(&PSI_G(context));
 
        UNREGISTER_INI_ENTRIES();
 
@@ -218,8 +218,28 @@ static PHP_RINIT_FUNCTION(psi)
 static PHP_MINFO_FUNCTION(psi)
 {
        php_info_print_table_start();
-       php_info_print_table_header(2, "psi support", "enabled");
+       php_info_print_table_header(2, "PSI Support", "enabled");
+       php_info_print_table_row(2, "Extension Version", PHP_PSI_VERSION);
        php_info_print_table_end();
+       php_info_print_table_start();
+       php_info_print_table_header(3, "Used Library", "Compiled", "Linked");
+       php_info_print_table_row(3, "libffi",
+#ifndef PHP_PSI_LIBFFI_VERSION
+# define PHP_PSI_LIBFFI_VERSION "unknown"
+#endif
+#ifdef HAVE_LIBFFI
+                       PHP_PSI_LIBFFI_VERSION, "unknown"
+#else
+                       "disabled", "disabled"
+#endif
+       );
+       php_info_print_table_row(3, "libjit",
+#ifdef HAVE_LIBJIT
+                       "unknown", "unknown"
+#else
+                       "disabled", "disabled"
+#endif
+       );
 
        DISPLAY_INI_ENTRIES();
 }
index b5ec9f5..7c64b25 100644 (file)
@@ -1,12 +1,32 @@
-#ifndef _PSI_PARSER_H
-#define _PSI_PARSER_H
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+     * Redistributions of source code must retain the above copyright notice,
+       this list of conditions and the following disclaimer.
+     * Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#ifndef PSI_PARSER_H
+#define PSI_PARSER_H
 
-#include <stdio.h>
-#include <stdlib.h>
 #include <stdarg.h>
-#include <string.h>
-
-#include "parser_proc.h"
 
 #define BSIZE 256
 
@@ -23,9 +43,6 @@ struct psi_parser {
        char *cur, *tok, *lim, *eof, *ctx, *mrk, buf[BSIZE];
 };
 
-#define PSI_PARSER_DEBUG 0x1
-#define PSI_PARSER_SILENT 0x2
-
 struct psi_parser *psi_parser_init(struct psi_parser *P, const char *filename, psi_error_cb error, unsigned flags);
 void psi_parser_syntax_error(struct psi_parser *P, const char *fn, size_t ln, const char *msg, ...);
 ssize_t psi_parser_fill(struct psi_parser *P, size_t n);
index 48e90ed..d2edd5e 100644 (file)
@@ -1,16 +1,5 @@
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#else
-# include "php_config.h"
-#endif
-
-#include <stddef.h>
-#include <stdio.h>
+#include "php_psi_stdinc.h"
 #include <assert.h>
-#include <errno.h>
-#include <string.h>
-
-#include "parser_proc.h"
 
 #include "parser.h"
 
@@ -26,7 +15,7 @@ struct psi_parser *psi_parser_init(struct psi_parser *P, const char *filename, p
        fp = fopen(filename, "r");
 
        if (!fp) {
-               if (!(flags & PSI_PARSER_SILENT)) {
+               if (!(flags & PSI_SILENT)) {
                        error(NULL, NULL, PSI_WARNING, "Could not open '%s' for reading: %s",
                                        filename, strerror(errno));
                }
@@ -38,15 +27,14 @@ struct psi_parser *psi_parser_init(struct psi_parser *P, const char *filename, p
        }
        memset(P, 0, sizeof(*P));
 
-       P->psi.file.fn = strdup(filename);
+       psi_data_ctor_with_dtors(PSI_DATA(P), error, flags);
+       P->file.fn = strdup(filename);
        P->fp = fp;
        P->col = 1;
        P->line = 1;
-       P->error = error;
-       P->flags = flags;
        P->proc = psi_parser_proc_Alloc(malloc);
 
-       if (flags & PSI_PARSER_DEBUG) {
+       if (flags & PSI_DEBUG) {
                psi_parser_proc_Trace(stderr, "PSI> ");
        }
 
@@ -57,7 +45,7 @@ struct psi_parser *psi_parser_init(struct psi_parser *P, const char *filename, p
 
 ssize_t psi_parser_fill(struct psi_parser *P, size_t n)
 {
-       if (P->flags & PSI_PARSER_DEBUG) {
+       if (P->flags & PSI_DEBUG) {
                fprintf(stderr, "PSI> Fill: n=%zu\n", n);
        }
        if (!n) {
@@ -85,12 +73,12 @@ ssize_t psi_parser_fill(struct psi_parser *P, size_t n)
                        P->eof = P->lim;
                }
 
-               if (P->flags & PSI_PARSER_DEBUG) {
+               if (P->flags & PSI_DEBUG) {
                        fprintf(stderr, "PSI> Fill: consumed=%zu reserved=%zu available=%zu didread=%zu\n",
                                consumed, reserved, available, didread);
                }
        }
-       if (P->flags & PSI_PARSER_DEBUG) {
+       if (P->flags & PSI_DEBUG) {
                fprintf(stderr, "PSI> Fill: avail=%td\n", P->lim - P->cur);
        }
        return P->lim - P->cur;
@@ -136,10 +124,10 @@ void psi_parser_free(struct psi_parser **P)
 
 #define RETURN(t) do { \
        P->num = t; \
-       if (P->flags & PSI_PARSER_DEBUG) { \
+       if (P->flags & PSI_DEBUG) { \
                fprintf(stderr, "PSI> TOKEN: %d %.*s (EOF=%d %s:%u:%u)\n", \
                                P->num, (int) (P->cur-P->tok), P->tok, P->num == PSI_T_EOF, \
-                               P->psi.file.fn, P->line, P->col); \
+                               P->file.fn, P->line, P->col); \
        } \
        return t; \
 } while(1)
@@ -222,6 +210,7 @@ token_t psi_parser_scan(struct psi_parser *P)
                'ARRAY' {RETURN(PSI_T_ARRAY);}
                'OBJECT' {RETURN(PSI_T_OBJECT);}
                'CALLBACK' {RETURN(PSI_T_CALLBACK);}
+               'STATIC' {RETURN(PSI_T_STATIC);}
                'FUNCTION' {RETURN(PSI_T_FUNCTION);}
                'TYPEDEF' {RETURN(PSI_T_TYPEDEF);}
                'STRUCT' {RETURN(PSI_T_STRUCT);}
index 42106b2..e57f51e 100644 (file)
@@ -1,39 +1,65 @@
-#define _CONCAT(x,y) x##y
-#define CONCAT(x,y) _CONCAT(x,y)
-#define COUNTED(x) CONCAT(parse_ ##x## _, __LINE__)
+/*******************************************************************************
+ Copyright (c) 2016, Michael Wallner <mike@php.net>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+     * Redistributions of source code must retain the above copyright notice,
+       this list of conditions and the following disclaimer.
+     * Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#define CONCAT2(x,y) x##y
+#define CONCAT1(x,y) CONCAT2(x,y)
+#define COUNTED(x) CONCAT1(parse_ ##x## _, __LINE__)
 
 #ifdef GENERATE
-#define DEF(dn, dv) dn dv
-#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.
-#define TOKEN(t) t
-#define NAMED(t, name) t(name)
-#define TYPED(t, name) t(name)
-#define TOKEN_TYPE(token, type_) %type token {type_}
-#define TOKEN_DTOR(token, dtor) %destructor token {dtor}
+# define DEF(dn, dv) dn dv
+# 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.
+# define TOKEN(t) t
+# define NAMED(t, name) t(name)
+# define TYPED(t, name) t(name)
+# define TOKEN_TYPE(token, type_) %type token {type_}
+# define TOKEN_DTOR(token, dtor) %destructor token {dtor}
 #else
-#ifndef TEST
-#include "parser.h"
-#endif
-#define DEF(dn, dv)
-#define PASS(nt, rule) \
+# ifndef TEST
+#  include "parser.h"
+#  include "plist.h"
+# endif
+# define DEF(dn, dv)
+# define PASS(nt, rule) \
        static void COUNTED(nt) (struct psi_parser *P) { \
                (void) #rule; \
        }
-#define PARSE(nt, rule) \
+# define PARSE(nt, rule) \
        static void COUNTED(nt) (struct psi_parser *P rule)
-#define PARSE_NAMED(nt, nt_name, rule) \
+# define PARSE_NAMED(nt, nt_name, rule) \
        static void COUNTED(nt) (struct psi_parser *P NAMED(nt, nt_name) rule)
-#define PARSE_TYPED(nt, nt_name, rule) \
+# define PARSE_TYPED(nt, nt_name, rule) \
        static void COUNTED(nt) (struct psi_parser *P TYPED(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##_parse_t
-#define TOKEN_TYPE(token, type) typedef type TOKEN_TYPE_NAME(token);
-#define TOKEN_DTOR(token, dtor)
+# 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##_parse_t
+# define TOKEN_TYPE(token, type) typedef type TOKEN_TYPE_NAME(token);
+# define TOKEN_DTOR(token, dtor)
 #endif
 
 DEF(%name, psi_parser_proc_)
@@ -49,7 +75,7 @@ DEF(%syntax_error, {
        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");
+               psi_error(PSI_WARNING, P->file.fn, P->line, "PSI syntax error: Unexpected end of input");
        }
 })
 
@@ -68,111 +94,111 @@ DEF(%token_class, let_func_token ZVAL OBJVAL ARRVAL PATHVAL STRLEN STRVAL FLOATV
 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(decl_enum, decl_enum *)
-TOKEN_DTOR(decl_enum, free_decl_enum($$);)
-TOKEN_TYPE(decl_enum_items, decl_enum_items*)
-TOKEN_DTOR(decl_enum_items, free_decl_enum_items($$);)
-TOKEN_TYPE(decl_enum_item, decl_enum_item*)
-TOKEN_DTOR(decl_enum_item, free_decl_enum_item($$);)
-TOKEN_TYPE(decl_struct_args_block, decl_args*)
-TOKEN_DTOR(decl_struct_args_block, free_decl_args($$);) /* there was a typo */
-TOKEN_TYPE(decl_struct_args, decl_args*)
-TOKEN_DTOR(decl_struct_args, free_decl_args($$);)
-TOKEN_TYPE(decl_struct, decl_struct*)
-TOKEN_DTOR(decl_struct, free_decl_struct($$);)
-TOKEN_TYPE(align_and_size, decl_struct_layout)
-TOKEN_TYPE(decl_union, decl_union*)
-TOKEN_DTOR(decl_union, free_decl_union($$);)
-TOKEN_TYPE(const_type, const_type*)
-TOKEN_DTOR(const_type, free_const_type($$);)
-TOKEN_TYPE(constant, constant*)
-TOKEN_DTOR(constant, free_constant($$);)
-TOKEN_TYPE(decl_typedef, decl_arg*)
-TOKEN_DTOR(decl_typedef, free_decl_arg($$);)
-TOKEN_TYPE(decl_typedef_body_ex, decl_arg*)
-TOKEN_DTOR(decl_typedef_body_ex, free_decl_arg($$);)
-TOKEN_TYPE(decl_typedef_body, decl_arg*)
-TOKEN_DTOR(decl_typedef_body, free_decl_arg($$);)
-TOKEN_TYPE(decl_typedef_body_fn_args, decl_args *)
-TOKEN_DTOR(decl_typedef_body_fn_args, free_decl_args($$);)
-TOKEN_TYPE(decl, decl*)
-TOKEN_DTOR(decl, free_decl($$);)
-TOKEN_TYPE(decl_func, decl_arg*)
-TOKEN_DTOR(decl_func, free_decl_arg($$);)
-TOKEN_TYPE(decl_abi, decl_abi*)
-TOKEN_DTOR(decl_abi, free_decl_abi($$);)
-TOKEN_TYPE(decl_var, decl_var*)
-TOKEN_DTOR(decl_var, free_decl_var($$);)
-TOKEN_TYPE(decl_vars, decl_vars*)
-TOKEN_DTOR(decl_vars, free_decl_vars($$);)
-TOKEN_TYPE(decl_arg, decl_arg*)
-TOKEN_DTOR(decl_arg, free_decl_arg($$);)
-TOKEN_TYPE(decl_args, decl_args*)
-TOKEN_DTOR(decl_args, free_decl_args($$);)
-TOKEN_TYPE(struct_args, decl_args*)
-TOKEN_DTOR(struct_args, free_decl_args($$);)
-TOKEN_TYPE(struct_arg, decl_arg*)
-TOKEN_DTOR(struct_arg, free_decl_arg($$);)
-TOKEN_TYPE(struct_layout, decl_struct_layout*)
-TOKEN_DTOR(struct_layout, free_decl_struct_layout($$);)
-TOKEN_TYPE(decl_type, decl_type*)
-TOKEN_DTOR(decl_type, free_decl_type($$);)
-TOKEN_TYPE(const_decl_type, decl_type*)
-TOKEN_DTOR(const_decl_type, free_decl_type($$);)
-TOKEN_TYPE(impl, impl*)
-TOKEN_DTOR(impl, free_impl($$);)
-TOKEN_TYPE(impl_func, impl_func*)
-TOKEN_DTOR(impl_func, free_impl_func($$);)
-TOKEN_TYPE(impl_def_val, impl_def_val*)
-TOKEN_DTOR(impl_def_val, free_impl_def_val($$);)
-TOKEN_TYPE(impl_var, impl_var*)
-TOKEN_DTOR(impl_var, free_impl_var($$);)
-TOKEN_TYPE(impl_arg, impl_arg*)
-TOKEN_DTOR(impl_arg, free_impl_arg($$);)
-TOKEN_TYPE(impl_args, impl_args*)
-TOKEN_DTOR(impl_args, free_impl_args($$);)
-TOKEN_TYPE(impl_vararg, impl_arg*)
-TOKEN_DTOR(impl_vararg, free_impl_arg($$);)
-TOKEN_TYPE(impl_arg_list, impl_args*)
-TOKEN_DTOR(impl_arg_list, free_impl_args($$);)
-TOKEN_TYPE(impl_stmts, impl_stmts*)
-TOKEN_DTOR(impl_stmts, free_impl_stmts($$);)
-TOKEN_TYPE(impl_stmt, impl_stmt*)
-TOKEN_DTOR(impl_stmt, free_impl_stmt($$);)
-TOKEN_TYPE(num_exp, num_exp*)
-TOKEN_DTOR(num_exp, free_num_exp($$);)
-TOKEN_TYPE(let_stmt, let_stmt*)
-TOKEN_DTOR(let_stmt, free_let_stmt($$);)
-TOKEN_TYPE(let_calloc, let_calloc*)
-TOKEN_DTOR(let_calloc, free_let_calloc($$);)
-TOKEN_TYPE(let_func, let_func*)
-TOKEN_DTOR(let_func, free_let_func($$);)
-TOKEN_TYPE(callback_arg_list, set_values *)
-TOKEN_DTOR(callback_arg_list, free_set_values($$);)
-TOKEN_TYPE(callback_args, set_values *)
-TOKEN_DTOR(callback_args, free_set_values($$);)
-TOKEN_TYPE(let_val, let_val*)
-TOKEN_DTOR(let_val, free_let_val($$);)
-TOKEN_TYPE(let_vals, let_vals*)
-TOKEN_DTOR(let_vals, free_let_vals($$);)
-TOKEN_TYPE(set_stmt, set_stmt*)
-TOKEN_DTOR(set_stmt, free_set_stmt($$);)
-TOKEN_TYPE(set_value, set_value*)
-TOKEN_DTOR(set_value, free_set_value($$);)
-TOKEN_TYPE(set_vals, set_value*)
-TOKEN_DTOR(set_vals, free_set_value($$);)
-TOKEN_TYPE(set_func, set_func*)
-TOKEN_DTOR(set_func, free_set_func($$);)
-TOKEN_TYPE(return_stmt, return_stmt*)
-TOKEN_DTOR(return_stmt, free_return_stmt($$);)
-TOKEN_TYPE(free_stmt, free_stmt*)
-TOKEN_DTOR(free_stmt, free_free_stmt($$);)
-TOKEN_TYPE(free_calls, free_calls*)
-TOKEN_DTOR(free_calls, free_free_calls($$);)
-TOKEN_TYPE(free_call, free_call*)
-TOKEN_DTOR(free_call, free_free_call($$);)
-TOKEN_TYPE(impl_type, impl_type*)
-TOKEN_DTOR(impl_type, free_impl_type($$);)
+TOKEN_TYPE(decl_enum, struct psi_decl_enum *)
+TOKEN_DTOR(decl_enum, psi_decl_enum_free(&$$);)
+TOKEN_TYPE(decl_enum_items, struct psi_plist*)
+TOKEN_DTOR(decl_enum_items, psi_plist_free($$);)
+TOKEN_TYPE(decl_enum_item, struct psi_decl_enum_item*)
+TOKEN_DTOR(decl_enum_item, psi_decl_enum_item_free(&$$);)
+TOKEN_TYPE(decl_struct_args_block, struct psi_plist*)
+TOKEN_DTOR(decl_struct_args_block, psi_plist_free($$);) /* there was a typo */
+TOKEN_TYPE(decl_struct_args, struct psi_plist*)
+TOKEN_DTOR(decl_struct_args, psi_plist_free($$);)
+TOKEN_TYPE(decl_struct, struct psi_decl_struct*)
+TOKEN_DTOR(decl_struct, psi_decl_struct_free(&$$);)
+TOKEN_TYPE(align_and_size, struct psi_layout)
+TOKEN_TYPE(decl_union, struct psi_decl_union*)
+TOKEN_DTOR(decl_union, psi_decl_union_free(&$$);)
+TOKEN_TYPE(const_type, struct psi_const_type*)
+TOKEN_DTOR(const_type, psi_const_type_free(&$$);)
+TOKEN_TYPE(constant, struct psi_const*)
+TOKEN_DTOR(constant, psi_const_free(&$$);)
+TOKEN_TYPE(decl_typedef, struct psi_decl_arg*)
+TOKEN_DTOR(decl_typedef, psi_decl_arg_free(&$$);)
+TOKEN_TYPE(decl_typedef_body_ex, struct psi_decl_arg*)
+TOKEN_DTOR(decl_typedef_body_ex, psi_decl_arg_free(&$$);)
+TOKEN_TYPE(decl_typedef_body, struct psi_decl_arg*)
+TOKEN_DTOR(decl_typedef_body, psi_decl_arg_free(&$$);)
+TOKEN_TYPE(decl_typedef_body_fn_args, struct psi_plist*)
+TOKEN_DTOR(decl_typedef_body_fn_args, psi_plist_free($$);)
+TOKEN_TYPE(decl, struct psi_decl*)
+TOKEN_DTOR(decl, psi_decl_free(&$$);)
+TOKEN_TYPE(decl_func, struct psi_decl_arg*)
+TOKEN_DTOR(decl_func, psi_decl_arg_free(&$$);)
+TOKEN_TYPE(decl_abi, struct psi_decl_abi*)
+TOKEN_DTOR(decl_abi, psi_decl_abi_free(&$$);)
+TOKEN_TYPE(decl_var, struct psi_decl_var*)
+TOKEN_DTOR(decl_var, psi_decl_var_free(&$$);)
+TOKEN_TYPE(decl_vars, struct psi_plist*)
+TOKEN_DTOR(decl_vars, psi_plist_free($$);)
+TOKEN_TYPE(decl_arg, struct psi_decl_arg*)
+TOKEN_DTOR(decl_arg, psi_decl_arg_free(&$$);)
+TOKEN_TYPE(decl_args, struct psi_plist*)
+TOKEN_DTOR(decl_args, psi_plist_free($$);)
+TOKEN_TYPE(struct_args, struct psi_plist*)
+TOKEN_DTOR(struct_args, psi_plist_free($$);)
+TOKEN_TYPE(struct_arg, struct psi_decl_arg*)
+TOKEN_DTOR(struct_arg, psi_decl_arg_free(&$$);)
+TOKEN_TYPE(decl_layout, struct psi_layout*)
+TOKEN_DTOR(decl_layout, psi_layout_free(&$$);)
+TOKEN_TYPE(decl_type, struct psi_decl_type*)
+TOKEN_DTOR(decl_type, psi_decl_type_free(&$$);)
+TOKEN_TYPE(const_decl_type, struct psi_decl_type*)
+TOKEN_DTOR(const_decl_type, psi_decl_type_free(&$$);)
+TOKEN_TYPE(impl, struct psi_impl*)
+TOKEN_DTOR(impl, psi_impl_free(&$$);)
+TOKEN_TYPE(impl_func, struct psi_impl_func*)
+TOKEN_DTOR(impl_func, psi_impl_func_free(&$$);)
+TOKEN_TYPE(impl_def_val, struct psi_impl_def_val*)
+TOKEN_DTOR(impl_def_val, psi_impl_def_val_free(&$$);)
+TOKEN_TYPE(impl_var, struct psi_impl_var*)
+TOKEN_DTOR(impl_var, psi_impl_var_free(&$$);)
+TOKEN_TYPE(impl_arg, struct psi_impl_arg*)
+TOKEN_DTOR(impl_arg, psi_impl_arg_free(&$$);)
+TOKEN_TYPE(impl_args, struct psi_plist*)
+TOKEN_DTOR(impl_args, psi_plist_free($$);)
+TOKEN_TYPE(impl_vararg, struct psi_impl_arg*)
+TOKEN_DTOR(impl_vararg, psi_impl_arg_free(&$$);)
+TOKEN_TYPE(impl_stmts, struct psi_plist*)
+TOKEN_DTOR(impl_stmts, psi_plist_free($$);)
+TOKEN_TYPE(impl_stmt, struct psi_token**)
+TOKEN_DTOR(impl_stmt, psi_impl_stmt_free(&$$);)
+TOKEN_TYPE(num_exp, struct psi_num_exp*)
+TOKEN_DTOR(num_exp, psi_num_exp_free(&$$);)
+TOKEN_TYPE(let_stmt, struct psi_let_stmt*)
+TOKEN_DTOR(let_stmt, psi_let_stmt_free(&$$);)
+TOKEN_TYPE(let_calloc, struct psi_let_calloc*)
+TOKEN_DTOR(let_calloc, psi_let_calloc_free(&$$);)
+TOKEN_TYPE(let_func, struct psi_let_func*)
+TOKEN_DTOR(let_func, psi_let_func_free(&$$);)
+TOKEN_TYPE(callback_arg_list, struct psi_plist *)
+TOKEN_DTOR(callback_arg_list, psi_plist_free($$);)
+TOKEN_TYPE(callback_args, struct psi_plist *)
+TOKEN_DTOR(callback_args, psi_plist_free($$);)
+TOKEN_TYPE(let_callback, struct psi_let_callback*)
+TOKEN_DTOR(let_callback, psi_let_callback_free(&$$);)
+TOKEN_TYPE(let_exp, struct psi_let_exp*)
+TOKEN_DTOR(let_exp, psi_let_exp_free(&$$);)
+TOKEN_TYPE(let_exps, struct psi_plist*)
+TOKEN_DTOR(let_exps, psi_plist_free($$);)
+TOKEN_TYPE(set_stmt, struct psi_set_stmt*)
+TOKEN_DTOR(set_stmt, psi_set_stmt_free(&$$);)
+TOKEN_TYPE(set_exp, struct psi_set_exp*)
+TOKEN_DTOR(set_exp, psi_set_exp_free(&$$);)
+TOKEN_TYPE(set_exps, struct psi_plist*)
+TOKEN_DTOR(set_exps, psi_plist_free($$);)
+TOKEN_TYPE(set_func, struct psi_set_func*)
+TOKEN_DTOR(set_func, psi_set_func_free(&$$);)
+TOKEN_TYPE(return_stmt, struct psi_return_stmt*)
+TOKEN_DTOR(return_stmt, psi_return_stmt_free(&$$);)
+TOKEN_TYPE(free_stmt, struct psi_free_stmt*)
+TOKEN_DTOR(free_stmt, psi_free_stmt_free(&$$);)
+TOKEN_TYPE(free_exps, struct psi_plist*)
+TOKEN_DTOR(free_exps, psi_plist_free($$);)
+TOKEN_TYPE(free_exp, struct psi_free_exp*)
+TOKEN_DTOR(free_exp, psi_free_exp_free(&$$);)
+TOKEN_TYPE(impl_type, struct psi_impl_type*)
+TOKEN_DTOR(impl_type, psi_impl_type_free(&$$);)
 TOKEN_TYPE(reference, char)
 TOKEN_TYPE(indirection, unsigned)
 TOKEN_TYPE(pointers, unsigned)
@@ -184,71 +210,141 @@ PASS(blocks, blocks block)
 PASS(block, EOF)
 PASS(block, EOS)
 
+/*
+ * lib: LIB "soname" ;
+ */
 PARSE(block, NAMED(LIB, token) NAMED(QUOTED_STRING, libname) TOKEN(EOS)) {
-       if (P->psi.file.ln) {
-               P->error(P, token, PSI_WARNING, "Extra 'lib %s' statement has no effect", libname->text);
+       if (P->file.ln) {
+               P->error(PSI_DATA(P), token, PSI_WARNING, "Extra 'lib %s' statement has no effect", libname->text);
        } else {
-               P->psi.file.ln = strndup(libname->text + 1, libname->size - 2);
+               P->file.ln = strndup(libname->text + 1, libname->size - 2);
        }
        free(libname);
        free(token);
 }
+
 PARSE(block, TYPED(decl, decl)) {
-       P->decls = add_decl(P->decls, decl);
+       if (!P->decls) {
+               P->decls = psi_plist_init((psi_plist_dtor) psi_decl_free);
+       }
+       P->decls = psi_plist_add(P->decls, &decl);
 }
 
 PARSE(block, TYPED(impl, impl)) {
-       P->impls = add_impl(P->impls, impl);
+       if (!P->impls) {
+               P->impls = psi_plist_init((psi_plist_dtor) psi_impl_free);
+       }
+       P->impls = psi_plist_add(P->impls, &impl);
 }
 
 PARSE(block, TYPED(decl_typedef, def)) {
-       P->defs = add_decl_typedef(P->defs, def);
+       if (!P->types) {
+               P->types = psi_plist_init((psi_plist_dtor) psi_decl_arg_free);
+       }
+       P->types = psi_plist_add(P->types, &def);
+
        switch (def->type->type) {
        case PSI_T_STRUCT:
                if (def->type->real.strct) {
-                       P->structs = add_decl_struct(P->structs, def->type->real.strct);
+                       if (!P->structs) {
+                               P->structs = psi_plist_init((psi_plist_dtor) psi_decl_struct_free);
+                       }
+                       P->structs = psi_plist_add(P->structs, &def->type->real.strct);
                }
                break;
        case PSI_T_UNION:
                if (def->type->real.unn) {
-                       P->unions = add_decl_union(P->unions, def->type->real.unn);
+                       if (!P->unions) {
+                               P->unions = psi_plist_init((psi_plist_dtor) psi_decl_union_free);
+                       }
+                       P->unions = psi_plist_add(P->unions, &def->type->real.unn);
                }
                break;
        case PSI_T_ENUM:
                if (def->type->real.enm) {
-                       P->enums = add_decl_enum(P->enums, def->type->real.enm);
+                       if (!P->enums) {
+                               P->enums = psi_plist_init((psi_plist_dtor) psi_decl_enum_free);
+                       }
+                       P->enums = psi_plist_add(P->enums, &def->type->real.enm);
                }
                break;
        }
 }
 
 PARSE(block, TYPED(constant, constant)) {
-       P->consts = add_constant(P->consts, constant);
+       if (!P->consts) {
+               P->consts = psi_plist_init((psi_plist_dtor) psi_const_free);
+       }
+       P->consts = psi_plist_add(P->consts, &constant);
 }
 
 PARSE(block, TYPED(decl_struct, strct)) {
-       P->structs = add_decl_struct(P->structs, strct);
+       if (!P->structs) {
+               P->structs = psi_plist_init((psi_plist_dtor) psi_decl_struct_free);
+       }
+       P->structs = psi_plist_add(P->structs, &strct);
 }
 
 PARSE(block, TYPED(decl_union, u)) {
-       P->unions = add_decl_union(P->unions, u);
+       if (!P->unions) {
+               P->unions = psi_plist_init((psi_plist_dtor) psi_decl_union_free);
+       }
+       P->unions = psi_plist_add(P->unions, &u);
 }
 
 PARSE(block, TYPED(decl_enum, e)) {
-       P->enums = add_decl_enum(P->enums, e);
+       if (!P->enums) {
+               P->enums = psi_plist_init((psi_plist_dtor) psi_decl_enum_free);
+       }
+       P->enums = psi_plist_add(P->enums, &e);
 }
 
+/*
+ * optional_name: <empty>
+ */
 PARSE_NAMED(optional_name, n, ) {
        n = NULL;
 }
 
+/*
+ * optional_name: NAME
+ */
 PARSE_NAMED(optional_name, n,
                NAMED(NAME, N)) {
        n = N;
 }
 
+/*
+ * align_and_size: <empty>
+ */
+PARSE_TYPED(align_and_size, as, ) {
+       as.pos = 0;
+       as.len = 0;
+}
+
+/*
+ * align_and_size: :: ( NUMBER , NUMBER )
+ */
+PARSE_TYPED(align_and_size, as,
+               TOKEN(COLON)
+               TOKEN(COLON)
+               TOKEN(LPAREN)
+               NAMED(NUMBER, A)
+               TOKEN(COMMA)
+               NAMED(NUMBER, S)
+               TOKEN(RPAREN)) {
+       as.pos = atol(A->text);
+       as.len = atol(S->text);
+       free(A);
+       free(S);
+}
+
+/*
+ * enum_name: ENUM optional_name
+ */
 PARSE_NAMED(enum_name, n,
-               NAMED(ENUM, E) NAMED(optional_name, N)) {
+               NAMED(ENUM, E)
+               NAMED(optional_name, N)) {
        if (N) {
                n = N;
                free(E);
@@ -260,67 +356,95 @@ PARSE_NAMED(enum_name, n,
        }
 }
 
+/*
+ * struct_name: STRUCT optional_name
+ */
+PARSE_NAMED(struct_name, n,
+               NAMED(STRUCT, S)
+               NAMED(optional_name, N)) {
+       if (N) {
+               n = N;
+               free(S);
+       } else {
+               char digest[17];
+
+               psi_token_hash(S, digest);
+               n = psi_token_translit(psi_token_append(S, 1, digest), " ", "@");
+       }
+}
+
+/*
+ * union_name: UNION optional_name
+ */
+PARSE_NAMED(union_name, n,
+               NAMED(UNION, U)
+               NAMED(optional_name, N)) {
+       if (N) {
+               n = N;
+               free(U);
+       } else {
+               char digest[17];
+
+               psi_token_hash(U, digest);
+               n = psi_token_translit(psi_token_append(U, 1, digest), " ", "@");
+       }
+}
+
+/*
+ * decl_enum: enum_name { items }
+ */
 PARSE_TYPED(decl_enum, e,
                NAMED(enum_name, N)
                TOKEN(LBRACE)
                TYPED(decl_enum_items, list)
                TOKEN(RBRACE)) {
-       e = init_decl_enum(N->text, list);
+       e = psi_decl_enum_init(N->text, list);
        e->token = N;
 }
 
+/*
+ * decl_enum_items: item
+ */
 PARSE_TYPED(decl_enum_items, l,
                TYPED(decl_enum_item, i)) {
-       l = init_decl_enum_items(i);
+       l = psi_plist_add(psi_plist_init((psi_plist_dtor) psi_decl_enum_item_free),
+                       &i);
 }
+
+/*
+ * decl_enum_items: items , item
+ */
 PARSE_TYPED(decl_enum_items, l,
                TYPED(decl_enum_items, l_)
                TOKEN(COMMA)
                TYPED(decl_enum_item, i)) {
-       l = add_decl_enum_item(l_, i);
+       l = psi_plist_add(l_, &i);
 }
 
+/*
+ * decl_enum_item: name = num_exp
+ */
 PARSE_TYPED(decl_enum_item, i,
                NAMED(NAME, N)
                TOKEN(EQUALS)
                TYPED(num_exp, num)) {
-       i = init_decl_enum_item(N->text, num);
+       i = psi_decl_enum_item_init(N->text, num);
        i->token = N;
 }
+
+/*
+ * decl_enum_item: name
+ */
 PARSE_TYPED(decl_enum_item, i,
                NAMED(NAME, N)) {
-       i = init_decl_enum_item(N->text, NULL);
+       i = psi_decl_enum_item_init(N->text, NULL);
        i->token = N;
 }
 
-PARSE_NAMED(union_name, n,
-               NAMED(UNION, U)
-               NAMED(optional_name, N)) {
-       if (N) {
-               n = N;
-               free(U);
-       } else {
-               char digest[17];
-
-               psi_token_hash(U, digest);
-               n = psi_token_translit(psi_token_append(U, 1, digest), " ", "@");
-       }
-}
-
-PARSE_NAMED(struct_name, n,
-               NAMED(STRUCT, S)
-               NAMED(optional_name, N)) {
-       if (N) {
-               n = N;
-               free(S);
-       } else {
-               char digest[17];
-
-               psi_token_hash(S, digest);
-               n = psi_token_translit(psi_token_append(S, 1, digest), " ", "@");
-       }
-}
 
+/*
+ * decl_struct_args_block: { args }
+ */
 PARSE_TYPED(decl_struct_args_block, args_,
                TOKEN(LBRACE)
                TYPED(struct_args, args)
@@ -328,61 +452,62 @@ PARSE_TYPED(decl_struct_args_block, args_,
        args_ = args;
 }
 
+/*
+ * decl_struct_args: args_block
+ */
 PARSE_TYPED(decl_struct_args, args_,
                TYPED(decl_struct_args_block, args)) {
        args_ = args;
 }
+
+/*
+ * decl_struct_args: ;
+ */
 PARSE_TYPED(decl_struct_args, args_,
                TOKEN(EOS)) {
-       args_ = init_decl_args(NULL);
+       args_ = psi_plist_init((psi_plist_dtor) psi_decl_arg_free);
 }
 
+/*
+ * decl_struct: STRUCT name align_and_size struct_args
+ */
 PARSE_TYPED(decl_struct, strct,
                TOKEN(STRUCT)
                NAMED(NAME, N)
                TYPED(align_and_size, as)
                TYPED(decl_struct_args, args)) {
-       strct = init_decl_struct(N->text, args);
+       strct = psi_decl_struct_init(N->text, args);
        strct->align = as.pos;
        strct->size = as.len;
        strct->token = N;
 }
 
-PARSE_TYPED(align_and_size, as, ) {
-       as.pos = 0;
-       as.len = 0;
-}
-PARSE_TYPED(align_and_size, as,
-               TOKEN(COLON)
-               TOKEN(COLON)
-               TOKEN(LPAREN)
-               NAMED(NUMBER, A)
-               TOKEN(COMMA)
-               NAMED(NUMBER, S)
-               TOKEN(RPAREN)) {
-       as.pos = atol(A->text);
-       as.len = atol(S->text);
-       free(A);
-       free(S);
-}
-
+/*
+ * decl_union: UNION name align_and_size struct_args
+ */
 PARSE_TYPED(decl_union, u,
                TOKEN(UNION)
                NAMED(NAME, N)
                TYPED(align_and_size, as)
                TYPED(decl_struct_args, args)) {
-       u = init_decl_union(N->text, args);
+       u = psi_decl_union_init(N->text, args);
        u->align = as.pos;
        u->size = as.len;
        u->token = N;
 }
 
+/*
+ * const_type: const_type_token
+ */
 PARSE_TYPED(const_type, type_,
                NAMED(const_type_token, T)) {
-       type_ = init_const_type(T->type, T->text);
+       type_ = psi_const_type_init(T->type, T->text);
        free(T);
 }
 
+/*
+ * constant: CONST const_type NSNAME = def_val ;
+ */
 PARSE_TYPED(constant, constant,
                TOKEN(CONST)
                TYPED(const_type, type)
@@ -390,10 +515,13 @@ PARSE_TYPED(constant, constant,
                TOKEN(EQUALS)
                TYPED(impl_def_val, val)
                TOKEN(EOS)) {
-       constant = init_constant(type, T->text, val);
-       free(T);
+       constant = psi_const_init(type, T->text, val);
+       constant->token = T;
 }
 
+/*
+ * decl_typdef: TYPEDEF typedef_body ;
+ */
 PARSE_TYPED(decl_typedef, def,
                NAMED(TYPEDEF, T)
                TYPED(decl_typedef_body, def_)
@@ -402,88 +530,143 @@ PARSE_TYPED(decl_typedef, def,
        def->token = T;
 }
 
+/*
+ * decl_typedef_body_ex: struct_name align_and_size struct_args_block decl_var
+ */
 PARSE_TYPED(decl_typedef_body_ex, def,
                NAMED(struct_name, N)
                TYPED(align_and_size, as)
                TYPED(decl_struct_args_block, args)
                TYPED(decl_var, var)) {
-       def = init_decl_arg(init_decl_type(PSI_T_STRUCT, N->text), var);
+       def = psi_decl_arg_init(psi_decl_type_init(PSI_T_STRUCT, N->text), var);
        def->type->token = psi_token_copy(N);
-       def->type->real.strct = init_decl_struct(N->text, args);
+       def->type->real.strct = psi_decl_struct_init(N->text, args);
        def->type->real.strct->token = N;
        def->type->real.strct->align = as.pos;
        def->type->real.strct->size = as.len;
 }
+
+/*
+ * decl_typedef_body_ex: union_name align_and_size struct_args_block decl_var
+ */
 PARSE_TYPED(decl_typedef_body_ex, def,
                NAMED(union_name, N)
                TYPED(align_and_size, as)
                TYPED(decl_struct_args_block, args)
                TYPED(decl_var, var)) {
-       def = init_decl_arg(init_decl_type(PSI_T_UNION, N->text), var);
+       def = psi_decl_arg_init(psi_decl_type_init(PSI_T_UNION, N->text), var);
        def->type->token = psi_token_copy(N);
-       def->type->real.unn = init_decl_union(N->text, args);
+       def->type->real.unn = psi_decl_union_init(N->text, args);
        def->type->real.unn->token = N;
        def->type->real.unn->align = as.pos;
        def->type->real.unn->size = as.len;
 }
+
+/*
+ * decl_typedef_body_ex: decl_enum NAME
+ */
 PARSE_TYPED(decl_typedef_body_ex, def,
                TYPED(decl_enum, e)
                NAMED(NAME, ALIAS)) {
-       def = init_decl_arg(init_decl_type(PSI_T_ENUM, e->name), init_decl_var(ALIAS->text, 0, 0));
+       def = psi_decl_arg_init(psi_decl_type_init(PSI_T_ENUM, e->name), psi_decl_var_init(ALIAS->text, 0, 0));
        def->var->token = ALIAS;
        def->type->token = psi_token_copy(e->token);
        def->type->real.enm = e;
 }
 
+/*
+ * decl_typedef_body: decl_typedef_body_ex
+ */
 PARSE_TYPED(decl_typedef_body, def,
                TYPED(decl_typedef_body_ex, def_)) {
        def = def_;
 }
 
+/*
+ * decl_typedef_body_fn_args: ( decl_args )
+ */
 PARSE_TYPED(decl_typedef_body_fn_args, args,
                TOKEN(LPAREN)
                TYPED(decl_args, args_)
                TOKEN(RPAREN)) {
        args = args_;
 }
+
+/*
+ * decl_typedef_body: decl_func decl_typedef_body_fn_args
+ */
 PARSE_TYPED(decl_typedef_body, def,
                TYPED(decl_func, func_)
                TYPED(decl_typedef_body_fn_args, args)) {
-       def = init_decl_arg(init_decl_type(PSI_T_FUNCTION, func_->var->name), copy_decl_var(func_->var));
+       def = psi_decl_arg_init(psi_decl_type_init(PSI_T_FUNCTION, func_->var->name), psi_decl_var_copy(func_->var));
        def->type->token = psi_token_copy(func_->token);
-       def->type->real.func = init_decl(init_decl_abi("default"), func_, args);
+       def->type->real.func = psi_decl_init(psi_decl_abi_init("default"), func_, args);
 }
+
+/*
+ * decl_typedef_body: decl_arg
+ */
 PARSE_TYPED(decl_typedef_body, def,
                TYPED(decl_arg, arg)) {
        def = arg;
 }
 
+/*
+ * decl: decl_abi decl_func ( decl_args ) ;
+ */
+PARSE_TYPED(decl, decl,
+               TYPED(decl_abi, abi)
+               TYPED(decl_func, func)
+               TOKEN(LPAREN)
+               TYPED(decl_args, args)
+               TOKEN(RPAREN)
+               TOKEN(EOS)) {
+       decl = psi_decl_init(abi, func, args);
+}
+
+/*
+ * decl: decl_abi decl_func ( decl_args , ... ) ;
+ */
 PARSE_TYPED(decl, decl,
                TYPED(decl_abi, abi)
                TYPED(decl_func, func)
                TOKEN(LPAREN)
                TYPED(decl_args, args)
+               TOKEN(COMMA)
+               TOKEN(ELLIPSIS)
                TOKEN(RPAREN)
                TOKEN(EOS)) {
-       decl = init_decl(abi,&n