From 9bcb1df0786a8193d65949c857baaba2f4296e84 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Tue, 22 Nov 2016 15:33:08 +0100 Subject: [PATCH] raising the head after a three-weeks refactoring --- TODO | 6 +- m4/posix/signal.m4 | 2 +- m4/posix/unistd.m4 | 9 +- m4/psi/psi.m4 | 34 +- m4/psi/psi_type.m4 | 20 +- package.xml | 4 +- php_psi.h | 32 +- psi.d/getopt.psi | 25 +- psi.d/glob.psi | 12 +- psi.d/netdb.psi | 9 +- psi.d/time.psi | 33 +- src/calc.c | 138 +- src/calc.h | 56 +- src/call.c | 545 +++++++ src/call.h | 104 ++ src/context.c | 543 ++----- src/context.h | 58 +- src/data.c | 425 ++++- src/data.h | 67 +- src/engine.c | 769 --------- src/engine.h | 12 - src/error.c | 74 +- src/error.h | 11 +- src/libffi.c | 327 ++-- src/libffi.h | 29 +- src/libjit.c | 369 +++-- src/libjit.h | 29 +- src/marshal.c | 659 ++++---- src/marshal.h | 106 +- src/module.c | 148 +- src/parser.h | 37 +- src/parser.re | 33 +- src/parser_def.h | 1503 ++++++++++++------ src/parser_def.h.bak | 30 +- src/parser_proc.h | 31 +- src/parser_proc.inc | 10 +- src/parser_proc.y | 776 ++++----- src/parser_proc.y.bak | 30 +- src/plist.c | 149 ++ src/{types/constants.c => plist.h} | 51 +- src/token.c | 19 +- src/token.h | 3 +- src/types.h | 65 +- src/types/{constant.c => const.c} | 62 +- src/types/{constant.h => const.h} | 29 +- src/types/const_type.c | 45 +- src/types/const_type.h | 10 +- src/types/constants.h | 40 - src/types/decl.c | 126 +- src/types/decl.h | 43 +- src/types/decl_abi.c | 56 +- src/types/decl_abi.h | 18 +- src/types/decl_arg.c | 183 ++- src/types/decl_arg.h | 45 +- src/types/decl_args.c | 199 --- src/types/decl_args.h | 53 - src/types/decl_callinfo.h | 37 - src/types/decl_enum.c | 101 +- src/types/decl_enum.h | 22 +- src/types/decl_enum_item.c | 86 +- src/types/decl_enum_item.h | 52 +- src/types/decl_enum_items.c | 83 - src/types/decl_enum_items.h | 41 - src/types/decl_enums.c | 69 - src/types/decl_enums.h | 40 - src/types/decl_file.c | 59 +- src/types/decl_file.h | 13 +- src/types/decl_libs.c | 55 - src/types/decl_libs.h | 37 - src/types/decl_struct.c | 128 +- src/types/decl_struct.h | 26 +- src/types/decl_structs.c | 67 - src/types/decl_structs.h | 40 - src/types/decl_type.c | 308 ++-- src/types/decl_type.h | 64 +- src/types/decl_typedefs.c | 98 -- src/types/decl_union.c | 112 +- src/types/decl_union.h | 26 +- src/types/decl_unions.c | 66 - src/types/decl_unions.h | 40 - src/types/decl_var.c | 136 +- src/types/decl_var.h | 43 +- src/types/decl_vars.c | 58 - src/types/decl_vars.h | 40 - src/types/decls.c | 64 - src/types/decls.h | 40 - src/types/free_call.c | 64 - src/types/free_calls.c | 60 - src/types/free_calls.h | 40 - src/types/free_exp.c | 142 ++ src/types/{free_call.h => free_exp.h} | 36 +- src/types/free_stmt.c | 134 +- src/types/free_stmt.h | 23 +- src/types/impl.c | 206 ++- src/types/impl.h | 48 +- src/types/impl_arg.c | 49 +- src/types/impl_arg.h | 38 +- src/types/impl_args.c | 84 - src/types/impl_args.h | 46 - src/types/impl_def_val.c | 89 +- src/types/impl_def_val.h | 17 +- src/types/impl_func.c | 119 +- src/types/impl_func.h | 28 +- src/types/impl_stmt.c | 60 - src/types/impl_stmt.h | 50 - src/types/impl_stmts.c | 142 -- src/types/impl_stmts.h | 61 - src/types/impl_type.c | 33 +- src/types/impl_type.h | 9 +- src/types/impl_val.h | 3 + src/types/impl_var.c | 84 +- src/types/impl_var.h | 45 +- src/types/impls.c | 64 - src/types/impls.h | 40 - src/types/{decl_struct_layout.c => layout.c} | 56 +- src/types/{decl_struct_layout.h => layout.h} | 14 +- src/types/let_callback.c | 100 +- src/types/let_callback.h | 31 +- src/types/let_calloc.c | 56 +- src/types/let_calloc.h | 21 +- src/types/let_exp.c | 334 ++++ src/types/{let_val.h => let_exp.h} | 94 +- src/types/let_func.c | 395 ++++- src/types/let_func.h | 50 +- src/types/let_stmt.c | 151 +- src/types/let_stmt.h | 25 +- src/types/let_val.c | 225 --- src/types/let_vals.c | 65 - src/types/let_vals.h | 54 - src/types/num_exp.c | 406 +++-- src/types/num_exp.h | 75 +- src/types/return_stmt.c | 134 +- src/types/return_stmt.h | 29 +- src/types/set_exp.c | 204 +++ src/types/{decl_typedefs.h => set_exp.h} | 44 +- src/types/set_func.c | 285 +++- src/types/set_func.h | 23 +- src/types/set_stmt.c | 153 +- src/types/set_stmt.h | 32 +- src/types/set_value.c | 251 --- src/types/set_value.h | 58 - src/types/set_values.c | 66 - src/types/set_values.h | 40 - tests/getopt/getopt001.phpt | 59 +- tests/glob/glob001.phpt | 9 +- tests/glob/glob003.phpt | 8 +- tests/ndbm/ndbm.psi | 4 +- tests/parser/dump/dump001.phpt | 8 +- tests/parser/validate001.phpt | 4 +- tests/pipe/pipe.psi | 2 +- tests/sqlite/sqlite.psi | 8 +- tests/sqlite/sqlite001.phpt | 1 + tests/time/asc_gmtime001.phpt | 33 +- tests/time/times001.phpt | 4 +- 154 files changed, 8217 insertions(+), 7560 deletions(-) create mode 100644 src/call.c create mode 100644 src/call.h delete mode 100644 src/engine.c delete mode 100644 src/engine.h create mode 100644 src/plist.c rename src/{types/constants.c => plist.h} (66%) rename src/types/{constant.c => const.c} (51%) rename src/types/{constant.h => const.h} (75%) delete mode 100644 src/types/constants.h delete mode 100644 src/types/decl_args.c delete mode 100644 src/types/decl_args.h delete mode 100644 src/types/decl_callinfo.h delete mode 100644 src/types/decl_enum_items.c delete mode 100644 src/types/decl_enum_items.h delete mode 100644 src/types/decl_enums.c delete mode 100644 src/types/decl_enums.h delete mode 100644 src/types/decl_libs.c delete mode 100644 src/types/decl_libs.h delete mode 100644 src/types/decl_structs.c delete mode 100644 src/types/decl_structs.h delete mode 100644 src/types/decl_typedefs.c delete mode 100644 src/types/decl_unions.c delete mode 100644 src/types/decl_unions.h delete mode 100644 src/types/decl_vars.c delete mode 100644 src/types/decl_vars.h delete mode 100644 src/types/decls.c delete mode 100644 src/types/decls.h delete mode 100644 src/types/free_call.c delete mode 100644 src/types/free_calls.c delete mode 100644 src/types/free_calls.h create mode 100644 src/types/free_exp.c rename src/types/{free_call.h => free_exp.h} (70%) delete mode 100644 src/types/impl_args.c delete mode 100644 src/types/impl_args.h delete mode 100644 src/types/impl_stmt.c delete mode 100644 src/types/impl_stmt.h delete mode 100644 src/types/impl_stmts.c delete mode 100644 src/types/impl_stmts.h delete mode 100644 src/types/impls.c delete mode 100644 src/types/impls.h rename src/types/{decl_struct_layout.c => layout.c} (50%) rename src/types/{decl_struct_layout.h => layout.h} (85%) create mode 100644 src/types/let_exp.c rename src/types/{let_val.h => let_exp.h} (54%) delete mode 100644 src/types/let_val.c delete mode 100644 src/types/let_vals.c delete mode 100644 src/types/let_vals.h create mode 100644 src/types/set_exp.c rename src/types/{decl_typedefs.h => set_exp.h} (57%) delete mode 100644 src/types/set_value.c delete mode 100644 src/types/set_value.h delete mode 100644 src/types/set_values.c delete mode 100644 src/types/set_values.h diff --git a/TODO b/TODO index ffda07a..2e6e0a9 100644 --- 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 diff --git a/m4/posix/signal.m4 b/m4/posix/signal.m4 index 6895acf..ac266ac 100644 --- a/m4/posix/signal.m4 +++ b/m4/posix/signal.m4 @@ -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)]) diff --git a/m4/posix/unistd.m4 b/m4/posix/unistd.m4 index fde0fe9..0da8665 100644 --- a/m4/posix/unistd.m4 +++ b/m4/posix/unistd.m4 @@ -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 +} diff --git a/m4/psi/psi.m4 b/m4/psi/psi.m4 index ff112d7..96c648e 100644 --- a/m4/psi/psi.m4 +++ b/m4/psi/psi.m4 @@ -106,8 +106,22 @@ dnl Finish the headers with the pre-defined types etc. AC_DEFUN(PSI_CONFIG_DONE, [ cat >$PSI_STDINC < +#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 #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} diff --git a/m4/psi/psi_type.m4 b/m4/psi/psi_type.m4 index 826ae7e..b5fe39f 100644 --- a/m4/psi/psi_type.m4 +++ b/m4/psi/psi_type.m4 @@ -2,13 +2,13 @@ # Add a pre-defined type to $PSI_TYPES. psi_add_type() { cat >>$PSI_TYPES <>$PSI_STDTYPES </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_ (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) ]) diff --git a/package.xml b/package.xml index 20e16de..e7db772 100644 --- a/package.xml +++ b/package.xml @@ -164,8 +164,8 @@ and system interfaces of POSIX.1-2008 (http://pubs.opengroup.org/onlinepubs/9699 - - + + diff --git a/php_psi.h b/php_psi.h index 3dedff2..1609700 100644 --- a/php_psi.h +++ b/php_psi.h @@ -1,3 +1,28 @@ +/******************************************************************************* + Copyright (c) 2016, Michael Wallner . + 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); diff --git a/psi.d/getopt.psi b/psi.d/getopt.psi index 5e1e427..fcf1db7 100644 --- a/psi.d/getopt.psi +++ b/psi.d/getopt.psi @@ -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) ); } diff --git a/psi.d/glob.psi b/psi.d/glob.psi index 19aa6cb..f4a762a 100644 --- a/psi.d/glob.psi +++ b/psi.d/glob.psi @@ -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); } diff --git a/psi.d/netdb.psi b/psi.d/netdb.psi index 3eca291..f37476d 100644 --- a/psi.d/netdb.psi +++ b/psi.d/netdb.psi @@ -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, diff --git a/psi.d/time.psi b/psi.d/time.psi index 9302b13..25bc4e8 100644 --- a/psi.d/time.psi +++ b/psi.d/time.psi @@ -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, diff --git a/src/calc.c b/src/calc.c index 0e21ec5..b1b3a74 100644 --- a/src/calc.c +++ b/src/calc.c @@ -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 . + 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) { \ diff --git a/src/calc.h b/src/calc.h index db8fd7c..d294cfb 100644 --- a/src/calc.h +++ b/src/calc.h @@ -1,33 +1,37 @@ -#ifndef _PSI_CALC_H -#define _PSI_CALC_H +/******************************************************************************* + Copyright (c) 2016, Michael Wallner . + 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 index 0000000..46a1dde --- /dev/null +++ b/src/call.c @@ -0,0 +1,545 @@ +/******************************************************************************* + Copyright (c) 2016, Michael Wallner . + 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 index 0000000..01e6ead --- /dev/null +++ b/src/call.h @@ -0,0 +1,104 @@ +/******************************************************************************* + Copyright (c) 2016, Michael Wallner . + 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 diff --git a/src/context.c b/src/context.c index b7ae46f..3ac26c7 100644 --- a/src/context.c +++ b/src/context.c @@ -1,8 +1,27 @@ -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif +/******************************************************************************* + Copyright (c) 2016, Michael Wallner . + 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"); } diff --git a/src/context.h b/src/context.h index d132256..dc350fb 100644 --- a/src/context.h +++ b/src/context.h @@ -1,17 +1,54 @@ -#ifndef _PSI_CONTEXT_H -#define _PSI_CONTEXT_H +/******************************************************************************* + Copyright (c) 2016, Michael Wallner . + 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); diff --git a/src/data.c b/src/data.c index 860387d..9c2cefb 100644 --- a/src/data.c +++ b/src/data.c @@ -1,44 +1,433 @@ -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif +/******************************************************************************* + Copyright (c) 2016, Michael Wallner . + All rights reserved. -#include + 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 + +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; } diff --git a/src/data.h b/src/data.h index c31269c..3c48716 100644 --- a/src/data.h +++ b/src/data.h @@ -1,24 +1,61 @@ -#ifndef _PSI_DATA_H -#define _PSI_DATA_H +/******************************************************************************* + Copyright (c) 2016, Michael Wallner . + 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 + +#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 index 6fba400..0000000 --- a/src/engine.c +++ /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 index 624ddfb..0000000 --- a/src/engine.h +++ /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 diff --git a/src/error.c b/src/error.c index 2d764bc..c92b847 100644 --- a/src/error.c +++ b/src/error.c @@ -23,14 +23,72 @@ 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 -#include +/* 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); +} diff --git a/src/error.h b/src/error.h index 2c66d88..3f64f1f 100644 --- a/src/error.h +++ b/src/error.h @@ -28,15 +28,16 @@ #include -#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 */ diff --git a/src/libffi.c b/src/libffi.c index 8cf29dd..aea1cfa 100644 --- a/src/libffi.c +++ b/src/libffi.c @@ -1,16 +1,35 @@ -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif - +/******************************************************************************* + Copyright (c) 2016, Michael Wallner . + 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, ¶ms[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) diff --git a/src/libffi.h b/src/libffi.h index 8db73ee..df7865a 100644 --- a/src/libffi.h +++ b/src/libffi.h @@ -1,5 +1,30 @@ -#ifndef _PSI_LIBFFI_H -#define _PSI_LIBFFI_H +/******************************************************************************* + Copyright (c) 2016, Michael Wallner . + 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" diff --git a/src/libjit.c b/src/libjit.c index 23d53c1..da8f25e 100644 --- a/src/libjit.c +++ b/src/libjit.c @@ -1,35 +1,45 @@ -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif - +/******************************************************************************* + Copyright (c) 2016, Michael Wallner . + 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 -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, ¶ms[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) { diff --git a/src/libjit.h b/src/libjit.h index 602fc51..b4921bd 100644 --- a/src/libjit.h +++ b/src/libjit.h @@ -1,5 +1,30 @@ -#ifndef _PSI_LIBJIT_H -#define _PSI_LIBJIT_H +/******************************************************************************* + Copyright (c) 2016, Michael Wallner . + 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" diff --git a/src/marshal.c b/src/marshal.c index 1e71a64..87abf98 100644 --- a/src/marshal.c +++ b/src/marshal.c @@ -1,40 +1,176 @@ -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif +/******************************************************************************* + Copyright (c) 2016, Michael Wallner . + 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; diff --git a/src/marshal.h b/src/marshal.h index bf9267d..6fe15c6 100644 --- a/src/marshal.h +++ b/src/marshal.h @@ -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 . + 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 diff --git a/src/module.c b/src/module.c index a70a50a..8201d5a 100644 --- a/src/module.c +++ b/src/module.c @@ -1,8 +1,29 @@ -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif +/******************************************************************************* + Copyright (c) 2016, Michael Wallner . + 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(); } diff --git a/src/parser.h b/src/parser.h index b5ec9f5..7c64b25 100644 --- a/src/parser.h +++ b/src/parser.h @@ -1,12 +1,32 @@ -#ifndef _PSI_PARSER_H -#define _PSI_PARSER_H +/******************************************************************************* + Copyright (c) 2016, Michael Wallner . + 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 -#include #include -#include - -#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); diff --git a/src/parser.re b/src/parser.re index 48e90ed..d2edd5e 100644 --- a/src/parser.re +++ b/src/parser.re @@ -1,16 +1,5 @@ -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif - -#include -#include +#include "php_psi_stdinc.h" #include -#include -#include - -#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);} diff --git a/src/parser_def.h b/src/parser_def.h index 42106b2..e57f51e 100644 --- a/src/parser_def.h +++ b/src/parser_def.h @@ -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 . + 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: + */ PARSE_NAMED(optional_name, n, ) { n = NULL; } +/* + * optional_name: NAME + */ PARSE_NAMED(optional_name, n, NAMED(NAME, N)) { n = N; } +/* + * align_and_size: + */ +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, func, args); + decl = psi_decl_init(abi, func, args); + decl->varargs = 1; } +/* + * decl_func: decl_arg + */ PARSE_TYPED(decl_func, func, TYPED(decl_arg, arg)) { func = arg; } + /* special case for void functions */ +/* + * decl_func: VOID NAME + */ PARSE_TYPED(decl_func, func, NAMED(VOID, T) NAMED(NAME, N)) { - func = init_decl_arg( - init_decl_type(T->type, T->text), - init_decl_var(N->text, 0, 0) + func = psi_decl_arg_init( + psi_decl_type_init(T->type, T->text), + psi_decl_var_init(N->text, 0, 0) ); func->type->token = T; func->var->token = N; func->token = N; } + +/* + * decl_typedef_body: VOID indirection ( indirection NAME ) decl_typedef_body_fn_args + */ PARSE_TYPED(decl_typedef_body, def, NAMED(VOID, T) TYPED(indirection, decl_i) @@ -492,22 +675,26 @@ PARSE_TYPED(decl_typedef_body, def, NAMED(NAME, N) TOKEN(RPAREN) TYPED(decl_typedef_body_fn_args, args)) { - decl_arg *func_ = init_decl_arg( - init_decl_type(T->type, T->text), - init_decl_var(N->text, decl_i, 0) + struct psi_decl_arg *func_ = psi_decl_arg_init( + psi_decl_type_init(T->type, T->text), + psi_decl_var_init(N->text, decl_i, 0) ); func_->type->token = T; func_->var->token = N; func_->token = N; - 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->var->pointer_level = type_i; 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: CONST VOID pointers ( indirection NAME ) decl_typdef_body_fn_args + */ PARSE_TYPED(decl_typedef_body, def, TOKEN(CONST) NAMED(VOID, T) @@ -517,74 +704,107 @@ PARSE_TYPED(decl_typedef_body, def, NAMED(NAME, N) TOKEN(RPAREN) TYPED(decl_typedef_body_fn_args, args)) { - decl_arg *func_ = init_decl_arg( - init_decl_type(T->type, T->text), - init_decl_var(N->text, decl_i, 0) + struct psi_decl_arg *func_ = psi_decl_arg_init( + psi_decl_type_init(T->type, T->text), + psi_decl_var_init(N->text, decl_i, 0) ); func_->type->token = T; func_->var->token = N; func_->token = N; - 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->var->pointer_level = type_i; 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_abi: NAME + */ PARSE_TYPED(decl_abi, abi, NAMED(NAME, T)) { - abi = init_decl_abi(T->text); + abi = psi_decl_abi_init(T->text); abi->token = T; } +/* + * decl_var_array_size: + */ +PARSE_NAMED(decl_var_array_size, as, ) { + as = NULL; +} + +/* + * decl_var_array_size: [ NUMBER ] + */ +PARSE_NAMED(decl_var_array_size, as, + TOKEN(LBRACKET) + NAMED(NUMBER, D) + TOKEN(RBRACKET)) { + as = D; +} + +/* + * decl_var: NAME decl_var_array_size + */ PARSE_TYPED(decl_var, var, NAMED(NAME, T) NAMED(decl_var_array_size, as)) { - var = init_decl_var(T->text, 0, as?atol(as->text):0); + var = psi_decl_var_init(T->text, 0, as?atol(as->text):0); var->token = T; if (as) { free(as); } } + +/* + * decl_var: pointers NAME + */ PARSE_TYPED(decl_var, var, TYPED(pointers, p) NAMED(NAME, T) NAMED(decl_var_array_size, as)) { - var = init_decl_var(T->text, p+!!as, as?atol(as->text):0); + var = psi_decl_var_init(T->text, p+!!as, as?atol(as->text):0); var->token = T; if (as) { free(as); } } -PARSE_NAMED(decl_var_array_size, as, ) { - as = NULL; -} -PARSE_NAMED(decl_var_array_size, as, - TOKEN(LBRACKET) - NAMED(NUMBER, D) - TOKEN(RBRACKET)) { - as = D; -} +/* + * decl_vars: decl_var + */ PARSE_TYPED(decl_vars, vars, TYPED(decl_var, var)) { - vars = init_decl_vars(var); + vars = psi_plist_add(psi_plist_init((psi_plist_dtor) psi_decl_var_free), + &var); } + +/* + * decl_vars: decl_vars , decl_var + */ PARSE_TYPED(decl_vars, vars, TYPED(decl_vars, vars_) TOKEN(COMMA) TYPED(decl_var, var)) { - vars = add_decl_var(vars_, var); + vars = psi_plist_add(vars_, &var); } +/* + * decl_arg: const_decl_type decl_var + */ PARSE_TYPED(decl_arg, arg_, TYPED(const_decl_type, type) TYPED(decl_var, var)) { - arg_ = init_decl_arg(type, var); + arg_ = psi_decl_arg_init(type, var); } + +/* + * decl_typedef_body: const_decl_type indirection ( indirection NAME ) decl_typedef_body_fn_args + */ PARSE_TYPED(decl_typedef_body, def, TYPED(const_decl_type, type_) TYPED(indirection, decl_i) @@ -593,79 +813,106 @@ PARSE_TYPED(decl_typedef_body, def, NAMED(NAME, N) TOKEN(RPAREN) TYPED(decl_typedef_body_fn_args, args)) { - decl_arg *func_ = init_decl_arg( + struct psi_decl_arg *func_ = psi_decl_arg_init( type_, - init_decl_var(N->text, decl_i, 0) + psi_decl_var_init(N->text, decl_i, 0) ); func_->var->token = N; func_->token = N; - 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->var->pointer_level = type_i; 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); } /* void pointers need a specific rule */ +/* + * decl_arg: VOID pointers NAME + */ PARSE_TYPED(decl_arg, arg_, NAMED(VOID, T) TYPED(pointers, p) NAMED(NAME, N)) { - arg_ = init_decl_arg( - init_decl_type(T->type, T->text), - init_decl_var(N->text, p, 0) + arg_ = psi_decl_arg_init( + psi_decl_type_init(T->type, T->text), + psi_decl_var_init(N->text, p, 0) ); arg_->type->token = T; arg_->var->token = N; arg_->token = N; } + +/* + * decl_args: CONST VOID pointers NAME + */ PARSE_TYPED(decl_arg, arg_, TOKEN(CONST) NAMED(VOID, T) TYPED(pointers, p) NAMED(NAME, N)) { - arg_ = init_decl_arg( - init_decl_type(T->type, T->text), - init_decl_var(N->text, p, 0) + arg_ = psi_decl_arg_init( + psi_decl_type_init(T->type, T->text), + psi_decl_var_init(N->text, p, 0) ); arg_->type->token = T; arg_->var->token = N; arg_->token = N; } +/* + * decl_args: + */ PASS(decl_args, ) + +/* + * decl_args: VOID + */ PASS(decl_args, VOID) + +/* + * decl_args: decl_arg + */ PARSE_TYPED(decl_args, args, TYPED(decl_arg, arg)) { - args = init_decl_args(arg); + args = psi_plist_add(psi_plist_init((psi_plist_dtor) psi_decl_arg_free), + &arg); } + +/* + * decl_args: decl_args , decl_arg + */ PARSE_TYPED(decl_args, args, TYPED(decl_args, args_) TOKEN(COMMA) TYPED(decl_arg, arg)) { - args = add_decl_arg(args_, arg); -} -PARSE_TYPED(decl_args, args, - TYPED(decl_args, args_) - TOKEN(COMMA) - TOKEN(ELLIPSIS)) { - args = args_; - args->varargs = 1; + args = psi_plist_add(args_, &arg); } +/* + * struct_args: struct_arg + */ PARSE_TYPED(struct_args, args, TYPED(struct_arg, arg)) { - args = init_decl_args(arg); + args = psi_plist_add(psi_plist_init((psi_plist_dtor) psi_decl_arg_free), + &arg); } + +/* + * struct_args: struct_args , struct_arg + */ PARSE_TYPED(struct_args, args, TYPED(struct_args, args_) TYPED(struct_arg, arg)) { - args = add_decl_arg(args_, arg); + args = psi_plist_add(args_, &arg); } +/* + * struct_arg: decl_typedef_body_ex ; + */ PARSE_TYPED(struct_arg, arg_, TYPED(decl_typedef_body_ex, def) TOKEN(EOS)) { @@ -673,33 +920,53 @@ PARSE_TYPED(struct_arg, arg_, 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; } } + +/* + * struct_arg: decl_arg decl_layout ; + */ PARSE_TYPED(struct_arg, arg, TYPED(decl_arg, arg_) - TYPED(struct_layout, layout_) + TYPED(decl_layout, layout_) TOKEN(EOS)) { arg_->layout = layout_; arg = arg_; } -PARSE_TYPED(struct_layout, layout, ) { +/* + * decl_layout: + */ +PARSE_TYPED(decl_layout, layout, ) { layout = NULL; } -PARSE_TYPED(struct_layout, layout, + +/* + * decl_layout: :: ( NUMBER , NUMBER ) + */ +PARSE_TYPED(decl_layout, layout, TOKEN(COLON) TOKEN(COLON) TOKEN(LPAREN) @@ -707,16 +974,23 @@ PARSE_TYPED(struct_layout, layout, TOKEN(COMMA) NAMED(NUMBER, SIZ) TOKEN(RPAREN)) { - layout = init_decl_struct_layout(atol(POS->text), atol(SIZ->text)); + layout = psi_layout_init(atol(POS->text), atol(SIZ->text)); free(POS); free(SIZ); } /* un/signed, urgh */ +/* + * decl_scalar_type: CHAR + */ PARSE_NAMED(decl_scalar_type, type_, NAMED(CHAR, C)) { type_ = C; } + +/* + * decl_scalar_type: SHORT decl_scalar_type_short + */ PARSE_NAMED(decl_scalar_type, type_, NAMED(SHORT, S) NAMED(decl_scalar_type_short, s)) { @@ -728,18 +1002,33 @@ PARSE_NAMED(decl_scalar_type, type_, type_ = S; } } + +/* + * decl_scalar_type_short: + */ PARSE_NAMED(decl_scalar_type_short, s, ) { s = NULL; } +/* + * decl_scalar_type_short: INT + */ PARSE_NAMED(decl_scalar_type_short, s, NAMED(INT, I)) { s = I; } + +/* + * decl_sclara_type: INT + */ PARSE_NAMED(decl_scalar_type, type_, NAMED(INT, I)) { type_ = I; } + +/* + * decl_scalar_type: LONG decl_scalar_type_long + */ PARSE_NAMED(decl_scalar_type, type_, NAMED(LONG, L) NAMED(decl_scalar_type_long, l)) { @@ -751,13 +1040,25 @@ PARSE_NAMED(decl_scalar_type, type_, type_ = L; } } + +/* + * decl_scalar_type_long: + */ PARSE_NAMED(decl_scalar_type_long, l, ) { l = NULL; } + +/* + * decl_scalar_type_long: DOUBLE + */ PARSE_NAMED(decl_scalar_type_long, l, NAMED(DOUBLE, D)) { l = D; } + +/* + * decl_scalar_type_long: LONG decl_scalar_type_long_long + */ PARSE_NAMED(decl_scalar_type_long, l, NAMED(LONG, L) NAMED(decl_scalar_type_long_long, ll)) { @@ -769,320 +1070,468 @@ PARSE_NAMED(decl_scalar_type_long, l, l = L; } } + +/* + * decl_scalar_type_long_long: + */ PARSE_NAMED(decl_scalar_type_long_long, ll, ) { ll = NULL; } + +/* + * decl_scalar_type_long_long: INT + */ PARSE_NAMED(decl_scalar_type_long_long, ll, NAMED(INT, I)) { ll = I; } + +/* + * decl_type: UNSIGNED decl_scalar_type + */ PARSE_TYPED(decl_type, type_, NAMED(UNSIGNED, U) NAMED(decl_scalar_type, N)) { struct psi_token *T = psi_token_cat(2, U, N); - type_ = init_decl_type(T->type, T->text); + type_ = psi_decl_type_init(T->type, T->text); type_->token = T; free(U); free(N); } + +/* + * decl_type: SIGNED decl_scalar_type + */ PARSE_TYPED(decl_type, type_, NAMED(SIGNED, S) NAMED(decl_scalar_type, N)) { struct psi_token *T = psi_token_cat(2, S, N); - type_ = init_decl_type(T->type, T->text); + type_ = psi_decl_type_init(T->type, T->text); type_->token = T; free(S); free(N); } + +/* + * decl_type: UNSIGNED + */ PARSE_TYPED(decl_type, type_, NAMED(UNSIGNED, U)) { - type_ = init_decl_type(PSI_T_NAME, U->text); + type_ = psi_decl_type_init(PSI_T_NAME, U->text); type_->token = U; } + +/* + * decl_type: SIGNED + */ PARSE_TYPED(decl_type, type_, NAMED(SIGNED, S)) { - type_ = init_decl_type(PSI_T_NAME, S->text); + type_ = psi_decl_type_init(PSI_T_NAME, S->text); type_->token = S; } + +/* + * decl_type: decl_scalar_type + */ PARSE_TYPED(decl_type, type_, NAMED(decl_scalar_type, N)) { - type_ = init_decl_type(N->type, N->text); + type_ = psi_decl_type_init(N->type, N->text); type_->token = N; } + /* structs ! */ +/* + * decl_type: STRUCT NAME + */ PARSE_TYPED(decl_type, type_, NAMED(STRUCT, S) NAMED(NAME, T)) { - type_ = init_decl_type(S->type, T->text); + type_ = psi_decl_type_init(S->type, T->text); type_->token = T; free(S); } + +/* + * decl_type: UNION NAME + */ PARSE_TYPED(decl_type, type_, NAMED(UNION, U) NAMED(NAME, T)) { - type_ = init_decl_type(U->type, T->text); + type_ = psi_decl_type_init(U->type, T->text); type_->token = T; free(U); } + +/* + * decl_type: ENUM NAME + */ PARSE_TYPED(decl_type, type_, NAMED(ENUM, E) NAMED(NAME, T)) { - type_ = init_decl_type(E->type, T->text); + type_ = psi_decl_type_init(E->type, T->text); type_->token = T; free(E); } + +/* + * decl_type: decl_type_token + */ PARSE_TYPED(decl_type, type_, NAMED(decl_type_token, T)) { - type_ = init_decl_type(T->type, T->text); + type_ = psi_decl_type_init(T->type, T->text); type_->token = T; } - +/* + * const_decl_type: decl_type + */ PARSE_TYPED(const_decl_type, type, TYPED(decl_type, type_)) { type = type_; } + +/* + * const_decl_type: CONST decl_type + */ PARSE_TYPED(const_decl_type, type, TOKEN(CONST) TYPED(decl_type, type_)) { type = type_; } +/* + * impl: impl_func { impl_stmts } + */ +PARSE_TYPED(impl, impl, + TYPED(impl_func, func) + TOKEN(LBRACE) + TYPED(impl_stmts, stmts) + TOKEN(RBRACE)) { + impl = psi_impl_init(func, stmts); +} + +/* + * impl: STATIC impl_func { impl_stmts } + */ PARSE_TYPED(impl, impl, + TOKEN(STATIC) TYPED(impl_func, func) TOKEN(LBRACE) TYPED(impl_stmts, stmts) TOKEN(RBRACE)) { - impl = init_impl(func, stmts); + func->static_memory = 1; + impl = psi_impl_init(func, stmts); +} + +/* + * impl_func: FUNCTION reference NSNAME ( ) : impl_type + */ +PARSE_TYPED(impl_func, func, + TOKEN(FUNCTION) + TYPED(reference, r) + NAMED(NSNAME, NAME) + TOKEN(LPAREN) + TOKEN(RPAREN) + TOKEN(COLON) + TYPED(impl_type, type)) { + func = psi_impl_func_init(NAME->text, NULL, type); + func->token = NAME; + func->return_reference = r; } +/* + * impl_func: FUNCTION reference NSNAME ( impl_args ) : impl_type + */ PARSE_TYPED(impl_func, func, TOKEN(FUNCTION) TYPED(reference, r) NAMED(NSNAME, NAME) + TOKEN(LPAREN) TYPED(impl_args, args) + TOKEN(RPAREN) TOKEN(COLON) TYPED(impl_type, type)) { - func = init_impl_func(NAME->text, args, type, r); + func = psi_impl_func_init(NAME->text, args, type); func->token = NAME; + func->return_reference = r; } +/* + * impl_func: FUNCTION reference NSNAME ( impl_args , impl_type reference ... DOLLAR_NAME ) : impl_type + */ +PARSE_TYPED(impl_func, func, + TOKEN(FUNCTION) + TYPED(reference, func_r) + NAMED(NSNAME, NAME) + TOKEN(LPAREN) + TYPED(impl_args, args) + TOKEN(COMMA) + TYPED(impl_type, va_type) + TYPED(reference, va_r) + TOKEN(ELLIPSIS) + NAMED(DOLLAR_NAME, T) + TOKEN(RPAREN) + TOKEN(COLON) + TYPED(impl_type, func_type)) { + func = psi_impl_func_init(NAME->text, args, func_type); + func->token = NAME; + func->return_reference = func_r; + func->vararg = psi_impl_arg_init(va_type, psi_impl_var_init(T->text, va_r), NULL); + free(T); +} + +/* + * impl_def_val: impl_def_val_token + */ PARSE_TYPED(impl_def_val, def, NAMED(impl_def_val_token, T)) { - def = init_impl_def_val(T->type, T->text); - free(T); + def = psi_impl_def_val_init(T->type, T->text); + def->token = T; } +/* + * impl_var: reference DOLLAR_NAME + */ PARSE_TYPED(impl_var, var, TYPED(reference, r) NAMED(DOLLAR_NAME, T)) { - var = init_impl_var(T->text, r); + var = psi_impl_var_init(T->text, r); var->token = T; } +/* + * impl_type: impl_type_token + */ +PARSE_TYPED(impl_type, type_, + NAMED(impl_type_token, T)) { + type_ = psi_impl_type_init(T->type, T->text); + free(T); +} + +/* + * impl_arg: impl_type impl_var + */ PARSE_TYPED(impl_arg, arg, TYPED(impl_type, type) TYPED(impl_var, var)) { - arg = init_impl_arg(type, var, NULL); + arg = psi_impl_arg_init(type, var, NULL); } + +/* + * impl_arg: impl_type impl_var = impl_def_val + */ PARSE_TYPED(impl_arg, arg, TYPED(impl_type, type) TYPED(impl_var, var) TOKEN(EQUALS) TYPED(impl_def_val, def)) { - arg = init_impl_arg(type, var, def); + arg = psi_impl_arg_init(type, var, def); } +/* + * impl_args: impl_arg + */ PARSE_TYPED(impl_args, args, - TOKEN(LPAREN) - TOKEN(RPAREN)) { - args = NULL; -} -PARSE_TYPED(impl_args, args, - TOKEN(LPAREN) - TYPED(impl_arg_list, args_) - TOKEN(RPAREN)) { - args = args_; -} -PARSE_TYPED(impl_args, args, - TOKEN(LPAREN) - TYPED(impl_arg_list, args_) - TOKEN(COMMA) - TYPED(impl_vararg, va) - TOKEN(RPAREN)) { - args = args_; - args->vararg.name = va; -} - -PARSE_TYPED(impl_vararg, va, - TYPED(impl_type, type) - TYPED(reference, r) - TOKEN(ELLIPSIS) - NAMED(DOLLAR_NAME, T)) { - va = init_impl_arg(type, init_impl_var(T->text, r), NULL); - free(T); -} - -PARSE_TYPED(impl_arg_list, args, TYPED(impl_arg, arg)) { - args = init_impl_args(arg); + args = psi_plist_add(psi_plist_init((psi_plist_dtor) psi_impl_arg_free), + &arg); } -PARSE_TYPED(impl_arg_list, args, - TYPED(impl_arg_list, args_) + +/* + * impl_args: impl_args , impl_arg + */ +PARSE_TYPED(impl_args, args, + TYPED(impl_args, args_) TOKEN(COMMA) TYPED(impl_arg, arg)) { - args = add_impl_arg(args_, arg); + args = psi_plist_add(args_, &arg); } +/* + * impl_stmts: impl_stmt + */ PARSE_TYPED(impl_stmts, stmts, TYPED(impl_stmt, stmt)) { - stmts = init_impl_stmts(stmt); + stmts = psi_plist_add(psi_plist_init((psi_plist_dtor) psi_impl_stmt_free), + &stmt); } + +/* + * impl_stmts: impl_stmts , impl_stmt + */ PARSE_TYPED(impl_stmts, stmts, TYPED(impl_stmts, stmts_) TYPED(impl_stmt, stmt)) { - stmts = add_impl_stmt(stmts_, stmt); + stmts = psi_plist_add(stmts_, &stmt); } -PARSE_TYPED(impl_stmt, stmt, - TYPED(let_stmt, let)) { - stmt = init_impl_stmt(PSI_T_LET, let); +/* + * impl_stmt: return_stmt + */ +PARSE_TYPED(impl_stmt, i, + TYPED(return_stmt, r)) { + i = (struct psi_token**) r; } -PARSE_TYPED(impl_stmt, stmt, - TYPED(set_stmt, set)) { - stmt = init_impl_stmt(PSI_T_SET, set); + +/* + * impl_stmt: let_stmt + */ +PARSE_TYPED(impl_stmt, i, + TYPED(let_stmt, l)) { + i = (struct psi_token**) l; } -PARSE_TYPED(impl_stmt, stmt, - TYPED(return_stmt, ret)) { - stmt = init_impl_stmt(PSI_T_RETURN, ret); + +/* + * impl_stmt: set_stmt + */ +PARSE_TYPED(impl_stmt, i, + TYPED(set_stmt, s)) { + i = (struct psi_token**) s; } -PARSE_TYPED(impl_stmt, stmt, - TYPED(free_stmt, free)) { - stmt = init_impl_stmt(PSI_T_FREE, free); + +/* + * impl_stmt: free_stmt + */ +PARSE_TYPED(impl_stmt, i, + TYPED(free_stmt, f)) { + i = (struct psi_token**) f; } +/* + * num_exp: num_exp_token + */ PARSE_TYPED(num_exp, exp, NAMED(num_exp_token, tok)) { - exp = init_num_exp(tok->type, tok->text); + exp = psi_num_exp_init(tok->type, tok->text); exp->token = tok; } + +/* + * num_exp: decl_var + */ PARSE_TYPED(num_exp, exp, TYPED(decl_var, var)) { - exp = init_num_exp(PSI_T_NAME, var); + exp = psi_num_exp_init(PSI_T_NAME, var); exp->token = psi_token_copy(var->token); } + +/* + * num_exp: num_exp num_exp_op_token num_exp + */ PARSE_TYPED(num_exp, exp, TYPED(num_exp, exp_) NAMED(num_exp_op_token, operator_) TYPED(num_exp, operand_)) { - exp_->operator = operator_->type; + exp_->op = operator_->type; exp_->operand = operand_; exp = exp_; free(operator_); } -TOKEN_TYPE(let_exp, let_val*) -TOKEN_DTOR(let_exp, free_let_val($$);) - -TOKEN_TYPE(let_callback, let_callback*) -TOKEN_DTOR(let_callback, free_let_callback($$);) - /* - * let_val: NULL + * let_exp: NULL */ -PARSE_TYPED(let_val, val, +PARSE_TYPED(let_exp, val, TOKEN(NULL)) { - val = init_let_val(PSI_LET_NULL, NULL); + val = psi_let_exp_init(PSI_LET_NULL, NULL); } + /* - * let_val: &NULL + * let_exp: & NULL */ -PARSE_TYPED(let_val, val, +PARSE_TYPED(let_exp, val, TOKEN(AMPERSAND) TOKEN(NULL)) { - val = init_let_val(PSI_LET_NULL, NULL); + val = psi_let_exp_init(PSI_LET_NULL, NULL); val->is_reference = 1; } + /* - * let_val: callback + * let_exp: callback */ -PARSE_TYPED(let_val, val, +PARSE_TYPED(let_exp, val, TYPED(let_callback, cb)) { - val = init_let_val(PSI_LET_CALLBACK, cb); + val = psi_let_exp_init(PSI_LET_CALLBACK, cb); } + /* - * let_val: calloc + * let_exp: calloc */ -PARSE_TYPED(let_val, val, +PARSE_TYPED(let_exp, val, TYPED(let_calloc, ca)) { - val = init_let_val(PSI_LET_CALLOC, ca); + val = psi_let_exp_init(PSI_LET_CALLOC, ca); } + /* - * let_val: &calloc + * let_exp: & calloc */ -PARSE_TYPED(let_val, val, +PARSE_TYPED(let_exp, val, TOKEN(AMPERSAND) TYPED(let_calloc, ca)) { - val = init_let_val(PSI_LET_CALLOC, ca); + val = psi_let_exp_init(PSI_LET_CALLOC, ca); val->is_reference = 1; } + /* - * let_val: func + * let_exp: func */ -PARSE_TYPED(let_val, val, +PARSE_TYPED(let_exp, val, TYPED(let_func, fn)) { - val = init_let_val_ex(NULL, PSI_LET_FUNC, fn); + val = psi_let_exp_init_ex(NULL, PSI_LET_FUNC, fn); } + /* - * let_val: &func + * let_exp: & func */ -PARSE_TYPED(let_val, val, +PARSE_TYPED(let_exp, val, TOKEN(AMPERSAND) TYPED(let_func, fn)) { - val = init_let_val_ex(NULL, PSI_LET_FUNC, fn); + val = psi_let_exp_init_ex(NULL, PSI_LET_FUNC, fn); val->is_reference = 1; } + /* - * let_val: 1234 + * let_exp: num_exp */ -PARSE_TYPED(let_val, val, +PARSE_TYPED(let_exp, val, TYPED(num_exp, exp)) { - val = init_let_val_ex(NULL, PSI_LET_NUMEXP, exp); + val = psi_let_exp_init_ex(NULL, PSI_LET_NUMEXP, exp); } + /* - * let_val: &1234 + * let_exp: & num_exp */ -PARSE_TYPED(let_val, val, +PARSE_TYPED(let_exp, val, TOKEN(AMPERSAND) TYPED(num_exp, exp)) { - val = init_let_val_ex(NULL, PSI_LET_NUMEXP, exp); + val = psi_let_exp_init_ex(NULL, PSI_LET_NUMEXP, exp); val->is_reference = 1; } -/* - * let_exp: var = val +/* FIXME + * let_exp: decl_var = let_exp */ PARSE_TYPED(let_exp, exp, TYPED(decl_var, var_) TOKEN(EQUALS) - TYPED(let_val, val)) { + TYPED(let_exp, val)) { exp = val; exp->var = var_; } /* - * let_stmt: LET exp ; + * let_stmt: LET let_exp ; */ PARSE_TYPED(let_stmt, let, NAMED(LET, T) TYPED(let_exp, val) TOKEN(EOS)) { - let = init_let_stmt(val); + let = psi_let_stmt_init(val); let->token = T; } /* - * let_stmt: TEMP foo = bar ; + * let_stmt: TEMP decl_var = reference decl_var ; */ PARSE_TYPED(let_stmt, let, NAMED(TEMP, T) @@ -1091,16 +1540,16 @@ PARSE_TYPED(let_stmt, let, TYPED(reference, r) TYPED(decl_var, val_) TOKEN(EOS)) { - let = init_let_stmt(init_let_val_ex(var, PSI_LET_TMP, val_)); + let = psi_let_stmt_init(psi_let_exp_init_ex(var, PSI_LET_TMP, val_)); let->token = T; - let->val->is_reference = r ? 1 : 0; + let->exp->is_reference = r ? 1 : 0; } /* - * let_callback: CALLBACK cast($var($args)) + * let_callback: CALLBACK callback_rval ( impl_var ( callback_arg_lists ) ) */ PARSE_TYPED(let_callback, cb, - TOKEN(CALLBACK) + NAMED(CALLBACK, T) NAMED(callback_rval, F) TOKEN(LPAREN) TYPED(impl_var, var) @@ -1108,241 +1557,309 @@ PARSE_TYPED(let_callback, cb, TYPED(callback_arg_list, args_) TOKEN(RPAREN) TOKEN(RPAREN)) { - cb = init_let_callback(init_let_func(F->type, F->text, var), args_); + cb = psi_let_callback_init(psi_let_func_init(F->type, F->text, var), args_); + cb->token = T; free(F); } /* - * let_calloc: CALLOC ( num_exp nmemb , num_exp size ) + * let_calloc: CALLOC ( num_exp , num_exp ) */ PARSE_TYPED(let_calloc, alloc, - TOKEN(CALLOC) + NAMED(CALLOC, T) TOKEN(LPAREN) TYPED(num_exp, nmemb) TOKEN(COMMA) TYPED(num_exp, size) TOKEN(RPAREN)) { - alloc = init_let_calloc(nmemb, size); + alloc = psi_let_calloc_init(nmemb, size); + alloc->token = T; } /* - * let_func: FUNC ( $var ) + * let_func: let_func_token ( impl_var ) */ PARSE_TYPED(let_func, func, NAMED(let_func_token, T) TOKEN(LPAREN) TYPED(impl_var, var) TOKEN(RPAREN)) { - func = init_let_func(T->type, T->text, var); - free(T); + func = psi_let_func_init(T->type, T->text, var); + func->token = T; } /* - * let_func: FUNC ( $var (,exps)? ) + * let_func: let_func_token ( impl_var , let_exps ) */ PARSE_TYPED(let_func, func, NAMED(let_func_token, T) TOKEN(LPAREN) TYPED(impl_var, var) TOKEN(COMMA) - TYPED(let_vals, vals) + TYPED(let_exps, vals) TOKEN(RPAREN)) { - func = init_let_func(T->type, T->text, var); + func = psi_let_func_init(T->type, T->text, var); + func->token = T; func->inner = vals; - free(T); } /* - * let_vals: exps = exp + * let_exps: let_exp */ -PARSE_TYPED(let_vals, vals, - TYPED(let_exp, val)) { - vals = init_let_vals(val); -} -PARSE_TYPED(let_vals, vals, - TYPED(let_val, val)) { - vals = init_let_vals(val); +PARSE_TYPED(let_exps, exps, + TYPED(let_exp, exp)) { + exps = psi_plist_add(psi_plist_init((psi_plist_dtor) psi_let_exp_free), + &exp); } /* - * let_vals: exps = exps, exp + * let_exps: let_exps , let_exp */ -PARSE_TYPED(let_vals, vals, - TYPED(let_vals, vals_) +PARSE_TYPED(let_exps, exps, + TYPED(let_exps, exps_) TOKEN(COMMA) - TYPED(let_exp, val)) { - vals = add_let_val(vals_, val); -} -PARSE_TYPED(let_vals, vals, - TYPED(let_vals, vals_) - TOKEN(COMMA) - TYPED(let_val, val)) { - vals = add_let_val(vals_, val); + TYPED(let_exp, exp)) { + exps = psi_plist_add(exps_, &exp); } +/* + * callback_arg_list: + */ PASS(callback_arg_list, ) + +/* + * callback_arg_list: callback_args + */ PARSE_TYPED(callback_arg_list, args, TYPED(callback_args, args_)) { args = args_; } +/* + * callback_args: set_exp + */ PARSE_TYPED(callback_args, args, - TYPED(set_value, val)) { - args = init_set_values(val); + TYPED(set_exp, val)) { + args = psi_plist_add(psi_plist_init((psi_plist_dtor) psi_set_exp_free), + &val); } + +/* + * callback_args: callback_args , set_exp + */ PARSE_TYPED(callback_args, args, TYPED(callback_args, args_) TOKEN(COMMA) - TYPED(set_value, val)) { - args = add_set_value(args_, val); + TYPED(set_exp, val)) { + args = psi_plist_add(args_, &val); } + +/* + * callback_rval: let_func_token + */ PARSE_NAMED(callback_rval, rval, NAMED(let_func_token, F)) { rval = F; } + +/* + * callback_rval: VOID + */ PARSE_NAMED(callback_rval, rval, NAMED(VOID, V)) { rval = V; } -PARSE_TYPED(set_stmt, set, - TOKEN(SET) - TYPED(impl_var, var) - TOKEN(EQUALS) - TYPED(set_value, val) - TOKEN(EOS)) { - set = init_set_stmt(var, val); -} -PARSE_TYPED(set_value, val, - TYPED(set_func, func) +/* + * set_func: set_func_token ( decl_var ) + */ +PARSE_TYPED(set_func, func, + NAMED(set_func_token, T) TOKEN(LPAREN) TYPED(decl_var, var) TOKEN(RPAREN)) { - val = init_set_value(func, init_decl_vars(var)); + func = psi_set_func_init(T->type, T->text, var); + func->token = T; } -PARSE_TYPED(set_value, val, - TYPED(set_func, func) + +/* + * set_func: set_func_token ( decl_var , set_exps ) + */ +PARSE_TYPED(set_func, func, + NAMED(set_func_token, T) TOKEN(LPAREN) TYPED(decl_var, var) TOKEN(COMMA) - TYPED(num_exp, num_) + TYPED(set_exps, vals) TOKEN(RPAREN)) { - val = init_set_value(func, init_decl_vars(var)); - val->num = num_; + func = psi_set_func_init(T->type, T->text, var); + func->token = T; + func->inner = vals; } -PARSE_TYPED(set_value, val, - TYPED(set_func, func_) + +/* + * set_func: set_func_token ( decl_var , ... ) + */ +PARSE_TYPED(set_func, func, + NAMED(set_func_token, T) TOKEN(LPAREN) TYPED(decl_var, var) TOKEN(COMMA) - NAMED(ELLIPSIS, T) + TOKEN(ELLIPSIS) TOKEN(RPAREN)) { - free_set_func(func_); - val = init_set_value(init_set_func(T->type, T->text), init_decl_vars(var)); - val->func->token = T; + func = psi_set_func_init(T->type, T->text, var); + func->token = T; + func->recursive = 1; } -PARSE_TYPED(set_value, val, - TYPED(set_func, func_) - TOKEN(LPAREN) - TYPED(decl_var, var) - TOKEN(COMMA) - TYPED(set_vals, vals) - TOKEN(RPAREN)) { - val = vals; - val->func = func_; - val->vars = init_decl_vars(var); + +/* + * set_exp: set_func + */ +PARSE_TYPED(set_exp, val, + TYPED(set_func, fn)) { + val = psi_set_exp_init(PSI_SET_FUNC, fn); } -PARSE_TYPED(set_value, val, - TYPED(set_func, func_) - TOKEN(LPAREN) - TYPED(decl_var, var) - TOKEN(COMMA) - TYPED(num_exp, num_) - TOKEN(COMMA) - TYPED(set_vals, vals) - TOKEN(RPAREN)) { - val = vals; - val->func = func_; - val->num = num_; - val->vars = init_decl_vars(var); + +/* + * set_exp: num_exp + */ +PARSE_TYPED(set_exp, val, + TYPED(num_exp, num)) { + val = psi_set_exp_init(PSI_SET_NUMEXP, num); } -PARSE_TYPED(set_vals, vals, - TYPED(set_value, val)) { - vals = add_inner_set_value(init_set_value(NULL, NULL), val); +/* + * set_exps: set_exp + */ +PARSE_TYPED(set_exps, exps, + TYPED(set_exp, exp)) { + exps = psi_plist_add(psi_plist_init((psi_plist_dtor) psi_set_exp_free), + &exp); } -PARSE_TYPED(set_vals, vals, - TYPED(set_vals, vals_) + +/* + * set_exps: set_exps , set_exp + */ +PARSE_TYPED(set_exps, exps, + TYPED(set_exps, exps_) TOKEN(COMMA) - TYPED(set_value, val)) { - vals = add_inner_set_value(vals_, val); + TYPED(set_exp, exp)) { + exps = psi_plist_add(exps_, &exp); } -PARSE_TYPED(set_func, func, - NAMED(set_func_token, T)) { - func = init_set_func(T->type, T->text); - func->token = T; +/* FIXME + * set_exp: impl_var = set_exp + */ +PARSE_TYPED(set_exp, exp, + TYPED(impl_var, var_) + TOKEN(EQUALS) + TYPED(set_exp, val)) { + exp = val; + exp->var = var_; +} + +/* + * set_stmt: SET set_exp ; + */ +PARSE_TYPED(set_stmt, set, + NAMED(SET, T) + TYPED(set_exp, exp) + TOKEN(EOS)) { + set = psi_set_stmt_init(exp); + set->token = T; } +/* + * return_stmt: RETURN set_exp ; + */ PARSE_TYPED(return_stmt, ret, NAMED(RETURN, T) - TYPED(set_value, val) + TYPED(set_func, func) TOKEN(EOS)) { - ret = init_return_stmt(val); + ret = psi_return_stmt_init(psi_set_exp_init(PSI_SET_FUNC, func)); ret->token = T; } +/* + * free_stmt: FREE free_exps ; + */ PARSE_TYPED(free_stmt, free, TOKEN(FREE) - TYPED(free_calls, calls) + TYPED(free_exps, calls) TOKEN(EOS)) { - free = init_free_stmt(calls); + free = psi_free_stmt_init(calls); } -PARSE_TYPED(free_calls, calls, - TYPED(free_call, call)) { - calls = init_free_calls(call); +/* + * free_exps: free_exp + */ +PARSE_TYPED(free_exps, calls, + TYPED(free_exp, call)) { + calls = psi_plist_add(psi_plist_init((psi_plist_dtor) psi_free_exp_free), + &call); } -PARSE_TYPED(free_calls, calls, - TYPED(free_calls, calls_) + +/* + * free_exps: free_exps , free_exp + */ +PARSE_TYPED(free_exps, calls, + TYPED(free_exps, calls_) TOKEN(COMMA) - TYPED(free_call, call)) { - calls = add_free_call(calls_, call); + TYPED(free_exp, call)) { + calls = psi_plist_add(calls_, &call); } -PARSE_TYPED(free_call, call, +/* + * free_exp: NAME ( decl_vars ) + */ +PARSE_TYPED(free_exp, call, NAMED(NAME, F) TOKEN(LPAREN) TYPED(decl_vars, vars) TOKEN(RPAREN)) { - call = init_free_call(F->text, vars); + call = psi_free_exp_init(F->text, vars); call->token = F; } -PARSE_TYPED(impl_type, type_, - NAMED(impl_type_token, T)) { - type_ = init_impl_type(T->type, T->text); - free(T); -} - +/* + * reference: + */ PARSE_TYPED(reference, r, ) { r = 0; } + +/* + * reference: & + */ PARSE_TYPED(reference, r, TOKEN(AMPERSAND)) { r = 1; } +/* + * indirection: + */ PARSE_TYPED(indirection, i, ){ i = 0; } + +/* + * indirection: pointers + */ PARSE_TYPED(indirection, i, TYPED(pointers, p)) { i = p; } +/* + * pointers: * + */ PARSE_TYPED(pointers, p, TOKEN(ASTERISK)) { p = 1; } + +/* + * pointers: pointers * + */ PARSE_TYPED(pointers, p, TYPED(pointers, p_) TOKEN(ASTERISK)) { diff --git a/src/parser_def.h.bak b/src/parser_def.h.bak index c3861de..68f708b 100644 --- a/src/parser_def.h.bak +++ b/src/parser_def.h.bak @@ -151,8 +151,8 @@ 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_exp, let_exp*) +TOKEN_DTOR(let_exp, free_let_exp($$);) TOKEN_TYPE(set_stmt, set_stmt*) TOKEN_DTOR(set_stmt, free_set_stmt($$);) TOKEN_TYPE(set_value, set_value*) @@ -971,14 +971,14 @@ PARSE_TYPED(let_stmt, let, TOKEN(LET) TYPED(decl_var, var) TOKEN(EOS)) { - let = init_let_stmt(var, init_let_val(PSI_LET_NULL, NULL)); + let = init_let_stmt(var, init_let_exp(PSI_LET_NULL, NULL)); } PARSE_TYPED(let_stmt, let, TOKEN(LET) TYPED(decl_var, var) TOKEN(EQUALS) TYPED(reference, r) - TYPED(let_val, val) + TYPED(let_exp, val) TOKEN(EOS)) { val->flags.one.is_reference = r ? 1 : 0; let = init_let_stmt(var, val); @@ -989,7 +989,7 @@ PARSE_TYPED(let_stmt, let, TOKEN(EQUALS) TYPED(decl_var, val) TOKEN(EOS)) { - let = init_let_stmt(var, init_let_val(PSI_LET_TMP, val)); + let = init_let_stmt(var, init_let_exp(PSI_LET_TMP, val)); } PARSE_TYPED(let_calloc, alloc, @@ -1025,26 +1025,26 @@ PARSE_TYPED(callback_args, args, args = add_set_value(args_, val); } -PARSE_TYPED(let_val, val, +PARSE_TYPED(let_exp, val, TOKEN(NULL)) { - val = init_let_val(PSI_LET_NULL, NULL); + val = init_let_exp(PSI_LET_NULL, NULL); } -PARSE_TYPED(let_val, val, +PARSE_TYPED(let_exp, val, TYPED(num_exp, exp)) { - val = init_let_val(PSI_LET_NUMEXP, exp); + val = init_let_exp(PSI_LET_NUMEXP, exp); } -PARSE_TYPED(let_val, val, +PARSE_TYPED(let_exp, val, TOKEN(CALLOC) TOKEN(LPAREN) TYPED(let_calloc, alloc) TOKEN(RPAREN)) { - val = init_let_val(PSI_LET_CALLOC, alloc); + val = init_let_exp(PSI_LET_CALLOC, alloc); } -PARSE_TYPED(let_val, val, +PARSE_TYPED(let_exp, val, TYPED(let_func, func)) { - val = init_let_val(PSI_LET_FUNC, func); + val = init_let_exp(PSI_LET_FUNC, func); } -PARSE_TYPED(let_val, val, +PARSE_TYPED(let_exp, val, TOKEN(CALLBACK) NAMED(let_func_token, F) TOKEN(LPAREN) @@ -1053,7 +1053,7 @@ PARSE_TYPED(let_val, val, TYPED(callback_arg_list, args_) TOKEN(RPAREN) TOKEN(RPAREN)) { - val = init_let_val(PSI_LET_CALLBACK, init_let_callback( + val = init_let_exp(PSI_LET_CALLBACK, init_let_callback( init_let_func(F->type, F->text, var), args_)); free(F); } diff --git a/src/parser_proc.h b/src/parser_proc.h index ff30cc1..8eba108 100644 --- a/src/parser_proc.h +++ b/src/parser_proc.h @@ -54,25 +54,26 @@ #define PSI_T_CALLABLE 54 #define PSI_T_EOF 55 #define PSI_T_EOS 56 -#define PSI_T_ENUM 57 -#define PSI_T_LBRACE 58 -#define PSI_T_RBRACE 59 -#define PSI_T_COMMA 60 -#define PSI_T_EQUALS 61 -#define PSI_T_UNION 62 -#define PSI_T_STRUCT 63 -#define PSI_T_COLON 64 -#define PSI_T_LPAREN 65 -#define PSI_T_RPAREN 66 +#define PSI_T_COLON 57 +#define PSI_T_LPAREN 58 +#define PSI_T_COMMA 59 +#define PSI_T_RPAREN 60 +#define PSI_T_ENUM 61 +#define PSI_T_STRUCT 62 +#define PSI_T_UNION 63 +#define PSI_T_LBRACE 64 +#define PSI_T_RBRACE 65 +#define PSI_T_EQUALS 66 #define PSI_T_CONST 67 #define PSI_T_TYPEDEF 68 -#define PSI_T_LBRACKET 69 -#define PSI_T_RBRACKET 70 -#define PSI_T_ELLIPSIS 71 +#define PSI_T_ELLIPSIS 69 +#define PSI_T_LBRACKET 70 +#define PSI_T_RBRACKET 71 #define PSI_T_CHAR 72 #define PSI_T_SHORT 73 #define PSI_T_LONG 74 #define PSI_T_UNSIGNED 75 #define PSI_T_SIGNED 76 -#define PSI_T_FUNCTION 77 -#define PSI_T_DOLLAR_NAME 78 +#define PSI_T_STATIC 77 +#define PSI_T_FUNCTION 78 +#define PSI_T_DOLLAR_NAME 79 diff --git a/src/parser_proc.inc b/src/parser_proc.inc index 81489d5..9bd05e5 100644 --- a/src/parser_proc.inc +++ b/src/parser_proc.inc @@ -1,15 +1,9 @@ %include { -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif +#include "php_psi_stdinc.h" -#include #include -#include -#include #include +#include "plist.h" #include "parser.h" } diff --git a/src/parser_proc.y b/src/parser_proc.y index a5696b5..8ada20f 100644 --- a/src/parser_proc.y +++ b/src/parser_proc.y @@ -1,16 +1,10 @@ %include { -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif +#include "php_psi_stdinc.h" -#include #include -#include -#include #include +#include "plist.h" #include "parser.h" } %name psi_parser_proc_ @@ -19,7 +13,7 @@ %token_destructor {free($$);} %default_destructor {(void)P;} %extra_argument {struct psi_parser *P} -%syntax_error { ++P->errors; if (TOKEN && TOKEN->type != PSI_T_EOF) { psi_error(PSI_WARNING, TOKEN->file, TOKEN->line, "PSI syntax error: Unexpected token '%s' at pos %u", TOKEN->text, TOKEN->col); } else { psi_error(PSI_WARNING, P->psi.file.fn, P->line, "PSI syntax error: Unexpected end of input"); } } +%syntax_error { ++P->errors; if (TOKEN && TOKEN->type != PSI_T_EOF) { psi_error(PSI_WARNING, TOKEN->file, TOKEN->line, "PSI syntax error: Unexpected token '%s' at pos %u", TOKEN->text, TOKEN->col); } else { psi_error(PSI_WARNING, P->file.fn, P->line, "PSI syntax error: Unexpected end of input"); } } %nonassoc NAME. %left PLUS MINUS. %left ASTERISK SLASH. @@ -33,111 +27,111 @@ %token_class let_func_token ZVAL OBJVAL ARRVAL PATHVAL STRLEN STRVAL FLOATVAL INTVAL BOOLVAL COUNT. %token_class set_func_token TO_OBJECT TO_ARRAY TO_STRING TO_INT TO_FLOAT TO_BOOL ZVAL VOID. %token_class impl_type_token VOID MIXED BOOL INT FLOAT STRING ARRAY OBJECT CALLABLE. -%type decl_enum {decl_enum *} -%destructor decl_enum {free_decl_enum($$);} -%type decl_enum_items {decl_enum_items*} -%destructor decl_enum_items {free_decl_enum_items($$);} -%type decl_enum_item {decl_enum_item*} -%destructor decl_enum_item {free_decl_enum_item($$);} -%type decl_struct_args_block {decl_args*} -%destructor decl_struct_args_block {free_decl_args($$);} -%type decl_struct_args {decl_args*} -%destructor decl_struct_args {free_decl_args($$);} -%type decl_struct {decl_struct*} -%destructor decl_struct {free_decl_struct($$);} -%type align_and_size {decl_struct_layout} -%type decl_union {decl_union*} -%destructor decl_union {free_decl_union($$);} -%type const_type {const_type*} -%destructor const_type {free_const_type($$);} -%type constant {constant*} -%destructor constant {free_constant($$);} -%type decl_typedef {decl_arg*} -%destructor decl_typedef {free_decl_arg($$);} -%type decl_typedef_body_ex {decl_arg*} -%destructor decl_typedef_body_ex {free_decl_arg($$);} -%type decl_typedef_body {decl_arg*} -%destructor decl_typedef_body {free_decl_arg($$);} -%type decl_typedef_body_fn_args {decl_args *} -%destructor decl_typedef_body_fn_args {free_decl_args($$);} -%type decl {decl*} -%destructor decl {free_decl($$);} -%type decl_func {decl_arg*} -%destructor decl_func {free_decl_arg($$);} -%type decl_abi {decl_abi*} -%destructor decl_abi {free_decl_abi($$);} -%type decl_var {decl_var*} -%destructor decl_var {free_decl_var($$);} -%type decl_vars {decl_vars*} -%destructor decl_vars {free_decl_vars($$);} -%type decl_arg {decl_arg*} -%destructor decl_arg {free_decl_arg($$);} -%type decl_args {decl_args*} -%destructor decl_args {free_decl_args($$);} -%type struct_args {decl_args*} -%destructor struct_args {free_decl_args($$);} -%type struct_arg {decl_arg*} -%destructor struct_arg {free_decl_arg($$);} -%type struct_layout {decl_struct_layout*} -%destructor struct_layout {free_decl_struct_layout($$);} -%type decl_type {decl_type*} -%destructor decl_type {free_decl_type($$);} -%type const_decl_type {decl_type*} -%destructor const_decl_type {free_decl_type($$);} -%type impl {impl*} -%destructor impl {free_impl($$);} -%type impl_func {impl_func*} -%destructor impl_func {free_impl_func($$);} -%type impl_def_val {impl_def_val*} -%destructor impl_def_val {free_impl_def_val($$);} -%type impl_var {impl_var*} -%destructor impl_var {free_impl_var($$);} -%type impl_arg {impl_arg*} -%destructor impl_arg {free_impl_arg($$);} -%type impl_args {impl_args*} -%destructor impl_args {free_impl_args($$);} -%type impl_vararg {impl_arg*} -%destructor impl_vararg {free_impl_arg($$);} -%type impl_arg_list {impl_args*} -%destructor impl_arg_list {free_impl_args($$);} -%type impl_stmts {impl_stmts*} -%destructor impl_stmts {free_impl_stmts($$);} -%type impl_stmt {impl_stmt*} -%destructor impl_stmt {free_impl_stmt($$);} -%type num_exp {num_exp*} -%destructor num_exp {free_num_exp($$);} -%type let_stmt {let_stmt*} -%destructor let_stmt {free_let_stmt($$);} -%type let_calloc {let_calloc*} -%destructor let_calloc {free_let_calloc($$);} -%type let_func {let_func*} -%destructor let_func {free_let_func($$);} -%type callback_arg_list {set_values *} -%destructor callback_arg_list {free_set_values($$);} -%type callback_args {set_values *} -%destructor callback_args {free_set_values($$);} -%type let_val {let_val*} -%destructor let_val {free_let_val($$);} -%type let_vals {let_vals*} -%destructor let_vals {free_let_vals($$);} -%type set_stmt {set_stmt*} -%destructor set_stmt {free_set_stmt($$);} -%type set_value {set_value*} -%destructor set_value {free_set_value($$);} -%type set_vals {set_value*} -%destructor set_vals {free_set_value($$);} -%type set_func {set_func*} -%destructor set_func {free_set_func($$);} -%type return_stmt {return_stmt*} -%destructor return_stmt {free_return_stmt($$);} -%type free_stmt {free_stmt*} -%destructor free_stmt {free_free_stmt($$);} -%type free_calls {free_calls*} -%destructor free_calls {free_free_calls($$);} -%type free_call {free_call*} -%destructor free_call {free_free_call($$);} -%type impl_type {impl_type*} -%destructor impl_type {free_impl_type($$);} +%type decl_enum {struct psi_decl_enum *} +%destructor decl_enum {psi_decl_enum_free(&$$);} +%type decl_enum_items {struct psi_plist*} +%destructor decl_enum_items {psi_plist_free($$);} +%type decl_enum_item {struct psi_decl_enum_item*} +%destructor decl_enum_item {psi_decl_enum_item_free(&$$);} +%type decl_struct_args_block {struct psi_plist*} +%destructor decl_struct_args_block {psi_plist_free($$);} +%type decl_struct_args {struct psi_plist*} +%destructor decl_struct_args {psi_plist_free($$);} +%type decl_struct {struct psi_decl_struct*} +%destructor decl_struct {psi_decl_struct_free(&$$);} +%type align_and_size {struct psi_layout} +%type decl_union {struct psi_decl_union*} +%destructor decl_union {psi_decl_union_free(&$$);} +%type const_type {struct psi_const_type*} +%destructor const_type {psi_const_type_free(&$$);} +%type constant {struct psi_const*} +%destructor constant {psi_const_free(&$$);} +%type decl_typedef {struct psi_decl_arg*} +%destructor decl_typedef {psi_decl_arg_free(&$$);} +%type decl_typedef_body_ex {struct psi_decl_arg*} +%destructor decl_typedef_body_ex {psi_decl_arg_free(&$$);} +%type decl_typedef_body {struct psi_decl_arg*} +%destructor decl_typedef_body {psi_decl_arg_free(&$$);} +%type decl_typedef_body_fn_args {struct psi_plist*} +%destructor decl_typedef_body_fn_args {psi_plist_free($$);} +%type decl {struct psi_decl*} +%destructor decl {psi_decl_free(&$$);} +%type decl_func {struct psi_decl_arg*} +%destructor decl_func {psi_decl_arg_free(&$$);} +%type decl_abi {struct psi_decl_abi*} +%destructor decl_abi {psi_decl_abi_free(&$$);} +%type decl_var {struct psi_decl_var*} +%destructor decl_var {psi_decl_var_free(&$$);} +%type decl_vars {struct psi_plist*} +%destructor decl_vars {psi_plist_free($$);} +%type decl_arg {struct psi_decl_arg*} +%destructor decl_arg {psi_decl_arg_free(&$$);} +%type decl_args {struct psi_plist*} +%destructor decl_args {psi_plist_free($$);} +%type struct_args {struct psi_plist*} +%destructor struct_args {psi_plist_free($$);} +%type struct_arg {struct psi_decl_arg*} +%destructor struct_arg {psi_decl_arg_free(&$$);} +%type decl_layout {struct psi_layout*} +%destructor decl_layout {psi_layout_free(&$$);} +%type decl_type {struct psi_decl_type*} +%destructor decl_type {psi_decl_type_free(&$$);} +%type const_decl_type {struct psi_decl_type*} +%destructor const_decl_type {psi_decl_type_free(&$$);} +%type impl {struct psi_impl*} +%destructor impl {psi_impl_free(&$$);} +%type impl_func {struct psi_impl_func*} +%destructor impl_func {psi_impl_func_free(&$$);} +%type impl_def_val {struct psi_impl_def_val*} +%destructor impl_def_val {psi_impl_def_val_free(&$$);} +%type impl_var {struct psi_impl_var*} +%destructor impl_var {psi_impl_var_free(&$$);} +%type impl_arg {struct psi_impl_arg*} +%destructor impl_arg {psi_impl_arg_free(&$$);} +%type impl_args {struct psi_plist*} +%destructor impl_args {psi_plist_free($$);} +%type impl_vararg {struct psi_impl_arg*} +%destructor impl_vararg {psi_impl_arg_free(&$$);} +%type impl_stmts {struct psi_plist*} +%destructor impl_stmts {psi_plist_free($$);} +%type impl_stmt {struct psi_token**} +%destructor impl_stmt {psi_impl_stmt_free(&$$);} +%type num_exp {struct psi_num_exp*} +%destructor num_exp {psi_num_exp_free(&$$);} +%type let_stmt {struct psi_let_stmt*} +%destructor let_stmt {psi_let_stmt_free(&$$);} +%type let_calloc {struct psi_let_calloc*} +%destructor let_calloc {psi_let_calloc_free(&$$);} +%type let_func {struct psi_let_func*} +%destructor let_func {psi_let_func_free(&$$);} +%type callback_arg_list {struct psi_plist *} +%destructor callback_arg_list {psi_plist_free($$);} +%type callback_args {struct psi_plist *} +%destructor callback_args {psi_plist_free($$);} +%type let_callback {struct psi_let_callback*} +%destructor let_callback {psi_let_callback_free(&$$);} +%type let_exp {struct psi_let_exp*} +%destructor let_exp {psi_let_exp_free(&$$);} +%type let_exps {struct psi_plist*} +%destructor let_exps {psi_plist_free($$);} +%type set_stmt {struct psi_set_stmt*} +%destructor set_stmt {psi_set_stmt_free(&$$);} +%type set_exp {struct psi_set_exp*} +%destructor set_exp {psi_set_exp_free(&$$);} +%type set_exps {struct psi_plist*} +%destructor set_exps {psi_plist_free($$);} +%type set_func {struct psi_set_func*} +%destructor set_func {psi_set_func_free(&$$);} +%type return_stmt {struct psi_return_stmt*} +%destructor return_stmt {psi_return_stmt_free(&$$);} +%type free_stmt {struct psi_free_stmt*} +%destructor free_stmt {psi_free_stmt_free(&$$);} +%type free_exps {struct psi_plist*} +%destructor free_exps {psi_plist_free($$);} +%type free_exp {struct psi_free_exp*} +%destructor free_exp {psi_free_exp_free(&$$);} +%type impl_type {struct psi_impl_type*} +%destructor impl_type {psi_impl_type_free(&$$);} %type reference {char} %type indirection {unsigned} %type pointers {unsigned} @@ -147,51 +141,81 @@ blocks ::= blocks block. block ::= EOF. block ::= EOS. block ::= LIB(token) QUOTED_STRING(libname) 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); } block ::= 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); } block ::= 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); } block ::= 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; } } block ::= 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); } block ::= 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); } block ::= 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); } block ::= 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(n) ::= . { n = NULL; @@ -199,6 +223,16 @@ optional_name(n) ::= . { optional_name(n) ::= NAME(N). { n = N; } +align_and_size(as) ::= . { + as.pos = 0; + as.len = 0; +} +align_and_size(as) ::= COLON COLON LPAREN NUMBER(A) COMMA NUMBER(S) RPAREN. { + as.pos = atol(A->text); + as.len = atol(S->text); + free(A); + free(S); +} enum_name(n) ::= ENUM(E) optional_name(N). { if (N) { n = N; @@ -209,44 +243,45 @@ enum_name(n) ::= ENUM(E) optional_name(N). { n = psi_token_translit(psi_token_append(E, 1, digest), " ", "@"); } } +struct_name(n) ::= STRUCT(S) 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(n) ::= UNION(U) 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(e) ::= enum_name(N) LBRACE decl_enum_items(list) RBRACE. { - e = init_decl_enum(N->text, list); + e = psi_decl_enum_init(N->text, list); e->token = N; } decl_enum_items(l) ::= 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(l) ::= decl_enum_items(l_) COMMA decl_enum_item(i). { - l = add_decl_enum_item(l_, i); + l = psi_plist_add(l_, &i); } decl_enum_item(i) ::= NAME(N) EQUALS 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(i) ::= NAME(N). { - i = init_decl_enum_item(N->text, NULL); + i = psi_decl_enum_item_init(N->text, NULL); i->token = N; } -union_name(n) ::= UNION(U) 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), " ", "@"); - } -} -struct_name(n) ::= STRUCT(S) 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_) ::= LBRACE struct_args(args) RBRACE. { args_ = args; } @@ -254,60 +289,50 @@ decl_struct_args(args_) ::= decl_struct_args_block(args). { args_ = args; } decl_struct_args(args_) ::= EOS. { - args_ = init_decl_args(NULL); + args_ = psi_plist_init((psi_plist_dtor) psi_decl_arg_free); } decl_struct(strct) ::= STRUCT NAME(N) align_and_size(as) 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; } -align_and_size(as) ::= . { - as.pos = 0; - as.len = 0; -} -align_and_size(as) ::= COLON COLON LPAREN NUMBER(A) COMMA NUMBER(S) RPAREN. { - as.pos = atol(A->text); - as.len = atol(S->text); - free(A); - free(S); -} decl_union(u) ::= UNION NAME(N) align_and_size(as) 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(type_) ::= const_type_token(T). { - type_ = init_const_type(T->type, T->text); + type_ = psi_const_type_init(T->type, T->text); free(T); } constant(constant) ::= CONST const_type(type) NSNAME(T) EQUALS impl_def_val(val) EOS. { - constant = init_constant(type, T->text, val); - free(T); + constant = psi_const_init(type, T->text, val); + constant->token = T; } decl_typedef(def) ::= TYPEDEF(T) decl_typedef_body(def_) EOS. { def = def_; def->token = T; } decl_typedef_body_ex(def) ::= struct_name(N) align_and_size(as) decl_struct_args_block(args) 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(def) ::= union_name(N) align_and_size(as) decl_struct_args_block(args) 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(def) ::= decl_enum(e) 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; @@ -319,121 +344,126 @@ decl_typedef_body_fn_args(args) ::= LPAREN decl_args(args_) RPAREN. { args = args_; } decl_typedef_body(def) ::= decl_func(func_) 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(def) ::= decl_arg(arg). { def = arg; } decl(decl) ::= decl_abi(abi) decl_func(func) LPAREN decl_args(args) RPAREN EOS. { - decl = init_decl(abi, func, args); + decl = psi_decl_init(abi, func, args); +} +decl(decl) ::= decl_abi(abi) decl_func(func) LPAREN decl_args(args) COMMA ELLIPSIS RPAREN EOS. { + decl = psi_decl_init(abi, func, args); + decl->varargs = 1; } decl_func(func) ::= decl_arg(arg). { func = arg; } decl_func(func) ::= VOID(T) NAME(N). { - func = init_decl_arg( - init_decl_type(T->type, T->text), - init_decl_var(N->text, 0, 0) + func = psi_decl_arg_init( + psi_decl_type_init(T->type, T->text), + psi_decl_var_init(N->text, 0, 0) ); func->type->token = T; func->var->token = N; func->token = N; } decl_typedef_body(def) ::= VOID(T) indirection(decl_i) LPAREN indirection(type_i) NAME(N) RPAREN decl_typedef_body_fn_args(args). { - decl_arg *func_ = init_decl_arg( - init_decl_type(T->type, T->text), - init_decl_var(N->text, decl_i, 0) + struct psi_decl_arg *func_ = psi_decl_arg_init( + psi_decl_type_init(T->type, T->text), + psi_decl_var_init(N->text, decl_i, 0) ); func_->type->token = T; func_->var->token = N; func_->token = N; - 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->var->pointer_level = type_i; 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(def) ::= CONST VOID(T) pointers(decl_i) LPAREN indirection(type_i) NAME(N) RPAREN decl_typedef_body_fn_args(args). { - decl_arg *func_ = init_decl_arg( - init_decl_type(T->type, T->text), - init_decl_var(N->text, decl_i, 0) + struct psi_decl_arg *func_ = psi_decl_arg_init( + psi_decl_type_init(T->type, T->text), + psi_decl_var_init(N->text, decl_i, 0) ); func_->type->token = T; func_->var->token = N; func_->token = N; - 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->var->pointer_level = type_i; 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_abi(abi) ::= NAME(T). { - abi = init_decl_abi(T->text); + abi = psi_decl_abi_init(T->text); abi->token = T; } +decl_var_array_size(as) ::= . { + as = NULL; +} +decl_var_array_size(as) ::= LBRACKET NUMBER(D) RBRACKET. { + as = D; +} decl_var(var) ::= NAME(T) decl_var_array_size(as). { - var = init_decl_var(T->text, 0, as?atol(as->text):0); + var = psi_decl_var_init(T->text, 0, as?atol(as->text):0); var->token = T; if (as) { free(as); } } decl_var(var) ::= pointers(p) NAME(T) decl_var_array_size(as). { - var = init_decl_var(T->text, p+!!as, as?atol(as->text):0); + var = psi_decl_var_init(T->text, p+!!as, as?atol(as->text):0); var->token = T; if (as) { free(as); } } -decl_var_array_size(as) ::= . { - as = NULL; -} -decl_var_array_size(as) ::= LBRACKET NUMBER(D) RBRACKET. { - as = D; -} decl_vars(vars) ::= decl_var(var). { - vars = init_decl_vars(var); + vars = psi_plist_add(psi_plist_init((psi_plist_dtor) psi_decl_var_free), + &var); } decl_vars(vars) ::= decl_vars(vars_) COMMA decl_var(var). { - vars = add_decl_var(vars_, var); + vars = psi_plist_add(vars_, &var); } decl_arg(arg_) ::= const_decl_type(type) decl_var(var). { - arg_ = init_decl_arg(type, var); + arg_ = psi_decl_arg_init(type, var); } decl_typedef_body(def) ::= const_decl_type(type_) indirection(decl_i) LPAREN indirection(type_i) NAME(N) RPAREN decl_typedef_body_fn_args(args). { - decl_arg *func_ = init_decl_arg( + struct psi_decl_arg *func_ = psi_decl_arg_init( type_, - init_decl_var(N->text, decl_i, 0) + psi_decl_var_init(N->text, decl_i, 0) ); func_->var->token = N; func_->token = N; - 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->var->pointer_level = type_i; 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_arg(arg_) ::= VOID(T) pointers(p) NAME(N). { - arg_ = init_decl_arg( - init_decl_type(T->type, T->text), - init_decl_var(N->text, p, 0) + arg_ = psi_decl_arg_init( + psi_decl_type_init(T->type, T->text), + psi_decl_var_init(N->text, p, 0) ); arg_->type->token = T; arg_->var->token = N; arg_->token = N; } decl_arg(arg_) ::= CONST VOID(T) pointers(p) NAME(N). { - arg_ = init_decl_arg( - init_decl_type(T->type, T->text), - init_decl_var(N->text, p, 0) + arg_ = psi_decl_arg_init( + psi_decl_type_init(T->type, T->text), + psi_decl_var_init(N->text, p, 0) ); arg_->type->token = T; arg_->var->token = N; @@ -442,50 +472,57 @@ decl_arg(arg_) ::= CONST VOID(T) pointers(p) NAME(N). { decl_args ::= . decl_args ::= VOID. decl_args(args) ::= decl_arg(arg). { - args = init_decl_args(arg); + args = psi_plist_add(psi_plist_init((psi_plist_dtor) psi_decl_arg_free), + &arg); } decl_args(args) ::= decl_args(args_) COMMA decl_arg(arg). { - args = add_decl_arg(args_, arg); -} -decl_args(args) ::= decl_args(args_) COMMA ELLIPSIS. { - args = args_; - args->varargs = 1; + args = psi_plist_add(args_, &arg); } struct_args(args) ::= struct_arg(arg). { - args = init_decl_args(arg); + args = psi_plist_add(psi_plist_init((psi_plist_dtor) psi_decl_arg_free), + &arg); } struct_args(args) ::= struct_args(args_) struct_arg(arg). { - args = add_decl_arg(args_, arg); + args = psi_plist_add(args_, &arg); } struct_arg(arg_) ::= decl_typedef_body_ex(def) EOS. { arg_ = 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; } } -struct_arg(arg) ::= decl_arg(arg_) struct_layout(layout_) EOS. { +struct_arg(arg) ::= decl_arg(arg_) decl_layout(layout_) EOS. { arg_->layout = layout_; arg = arg_; } -struct_layout(layout) ::= . { +decl_layout(layout) ::= . { layout = NULL; } -struct_layout(layout) ::= COLON COLON LPAREN NUMBER(POS) COMMA NUMBER(SIZ) RPAREN. { - layout = init_decl_struct_layout(atol(POS->text), atol(SIZ->text)); +decl_layout(layout) ::= COLON COLON LPAREN NUMBER(POS) COMMA NUMBER(SIZ) RPAREN. { + layout = psi_layout_init(atol(POS->text), atol(SIZ->text)); free(POS); free(SIZ); } @@ -542,47 +579,47 @@ decl_scalar_type_long_long(ll) ::= INT(I). { } decl_type(type_) ::= UNSIGNED(U) decl_scalar_type(N). { struct psi_token *T = psi_token_cat(2, U, N); - type_ = init_decl_type(T->type, T->text); + type_ = psi_decl_type_init(T->type, T->text); type_->token = T; free(U); free(N); } decl_type(type_) ::= SIGNED(S) decl_scalar_type(N). { struct psi_token *T = psi_token_cat(2, S, N); - type_ = init_decl_type(T->type, T->text); + type_ = psi_decl_type_init(T->type, T->text); type_->token = T; free(S); free(N); } decl_type(type_) ::= UNSIGNED(U). { - type_ = init_decl_type(PSI_T_NAME, U->text); + type_ = psi_decl_type_init(PSI_T_NAME, U->text); type_->token = U; } decl_type(type_) ::= SIGNED(S). { - type_ = init_decl_type(PSI_T_NAME, S->text); + type_ = psi_decl_type_init(PSI_T_NAME, S->text); type_->token = S; } decl_type(type_) ::= decl_scalar_type(N). { - type_ = init_decl_type(N->type, N->text); + type_ = psi_decl_type_init(N->type, N->text); type_->token = N; } decl_type(type_) ::= STRUCT(S) NAME(T). { - type_ = init_decl_type(S->type, T->text); + type_ = psi_decl_type_init(S->type, T->text); type_->token = T; free(S); } decl_type(type_) ::= UNION(U) NAME(T). { - type_ = init_decl_type(U->type, T->text); + type_ = psi_decl_type_init(U->type, T->text); type_->token = T; free(U); } decl_type(type_) ::= ENUM(E) NAME(T). { - type_ = init_decl_type(E->type, T->text); + type_ = psi_decl_type_init(E->type, T->text); type_->token = T; free(E); } decl_type(type_) ::= decl_type_token(T). { - type_ = init_decl_type(T->type, T->text); + type_ = psi_decl_type_init(T->type, T->text); type_->token = T; } const_decl_type(type) ::= decl_type(type_). { @@ -592,163 +629,166 @@ const_decl_type(type) ::= CONST decl_type(type_). { type = type_; } impl(impl) ::= impl_func(func) LBRACE impl_stmts(stmts) RBRACE. { - impl = init_impl(func, stmts); + impl = psi_impl_init(func, stmts); } -impl_func(func) ::= FUNCTION reference(r) NSNAME(NAME) impl_args(args) COLON impl_type(type). { - func = init_impl_func(NAME->text, args, type, r); +impl(impl) ::= STATIC impl_func(func) LBRACE impl_stmts(stmts) RBRACE. { + func->static_memory = 1; + impl = psi_impl_init(func, stmts); +} +impl_func(func) ::= FUNCTION reference(r) NSNAME(NAME) LPAREN RPAREN COLON impl_type(type). { + func = psi_impl_func_init(NAME->text, NULL, type); func->token = NAME; + func->return_reference = r; } -impl_def_val(def) ::= impl_def_val_token(T). { - def = init_impl_def_val(T->type, T->text); +impl_func(func) ::= FUNCTION reference(r) NSNAME(NAME) LPAREN impl_args(args) RPAREN COLON impl_type(type). { + func = psi_impl_func_init(NAME->text, args, type); + func->token = NAME; + func->return_reference = r; +} +impl_func(func) ::= FUNCTION reference(func_r) NSNAME(NAME) LPAREN impl_args(args) COMMA impl_type(va_type) reference(va_r) ELLIPSIS DOLLAR_NAME(T) RPAREN COLON impl_type(func_type). { + func = psi_impl_func_init(NAME->text, args, func_type); + func->token = NAME; + func->return_reference = func_r; + func->vararg = psi_impl_arg_init(va_type, psi_impl_var_init(T->text, va_r), NULL); free(T); } +impl_def_val(def) ::= impl_def_val_token(T). { + def = psi_impl_def_val_init(T->type, T->text); + def->token = T; +} impl_var(var) ::= reference(r) DOLLAR_NAME(T). { - var = init_impl_var(T->text, r); + var = psi_impl_var_init(T->text, r); var->token = T; } +impl_type(type_) ::= impl_type_token(T). { + type_ = psi_impl_type_init(T->type, T->text); + free(T); +} impl_arg(arg) ::= impl_type(type) impl_var(var). { - arg = init_impl_arg(type, var, NULL); + arg = psi_impl_arg_init(type, var, NULL); } impl_arg(arg) ::= impl_type(type) impl_var(var) EQUALS impl_def_val(def). { - arg = init_impl_arg(type, var, def); + arg = psi_impl_arg_init(type, var, def); } -impl_args(args) ::= LPAREN RPAREN. { - args = NULL; +impl_args(args) ::= impl_arg(arg). { + args = psi_plist_add(psi_plist_init((psi_plist_dtor) psi_impl_arg_free), + &arg); } -impl_args(args) ::= LPAREN impl_arg_list(args_) RPAREN. { - args = args_; -} -impl_args(args) ::= LPAREN impl_arg_list(args_) COMMA impl_vararg(va) RPAREN. { - args = args_; - args->vararg.name = va; -} -impl_vararg(va) ::= impl_type(type) reference(r) ELLIPSIS DOLLAR_NAME(T). { - va = init_impl_arg(type, init_impl_var(T->text, r), NULL); - free(T); -} -impl_arg_list(args) ::= impl_arg(arg). { - args = init_impl_args(arg); -} -impl_arg_list(args) ::= impl_arg_list(args_) COMMA impl_arg(arg). { - args = add_impl_arg(args_, arg); +impl_args(args) ::= impl_args(args_) COMMA impl_arg(arg). { + args = psi_plist_add(args_, &arg); } impl_stmts(stmts) ::= impl_stmt(stmt). { - stmts = init_impl_stmts(stmt); + stmts = psi_plist_add(psi_plist_init((psi_plist_dtor) psi_impl_stmt_free), + &stmt); } impl_stmts(stmts) ::= impl_stmts(stmts_) impl_stmt(stmt). { - stmts = add_impl_stmt(stmts_, stmt); + stmts = psi_plist_add(stmts_, &stmt); } -impl_stmt(stmt) ::= let_stmt(let). { - stmt = init_impl_stmt(PSI_T_LET, let); +impl_stmt(i) ::= return_stmt(r). { + i = (struct psi_token**) r; } -impl_stmt(stmt) ::= set_stmt(set). { - stmt = init_impl_stmt(PSI_T_SET, set); +impl_stmt(i) ::= let_stmt(l). { + i = (struct psi_token**) l; } -impl_stmt(stmt) ::= return_stmt(ret). { - stmt = init_impl_stmt(PSI_T_RETURN, ret); +impl_stmt(i) ::= set_stmt(s). { + i = (struct psi_token**) s; } -impl_stmt(stmt) ::= free_stmt(free). { - stmt = init_impl_stmt(PSI_T_FREE, free); +impl_stmt(i) ::= free_stmt(f). { + i = (struct psi_token**) f; } num_exp(exp) ::= num_exp_token(tok). { - exp = init_num_exp(tok->type, tok->text); + exp = psi_num_exp_init(tok->type, tok->text); exp->token = tok; } num_exp(exp) ::= decl_var(var). { - exp = init_num_exp(PSI_T_NAME, var); + exp = psi_num_exp_init(PSI_T_NAME, var); exp->token = psi_token_copy(var->token); } num_exp(exp) ::= num_exp(exp_) num_exp_op_token(operator_) num_exp(operand_). { - exp_->operator = operator_->type; + exp_->op = operator_->type; exp_->operand = operand_; exp = exp_; free(operator_); } -%type let_exp {let_val*} -%destructor let_exp {free_let_val($$);} -%type let_callback {let_callback*} -%destructor let_callback {free_let_callback($$);} -let_val(val) ::= NULL. { - val = init_let_val(PSI_LET_NULL, NULL); +let_exp(val) ::= NULL. { + val = psi_let_exp_init(PSI_LET_NULL, NULL); } -let_val(val) ::= AMPERSAND NULL. { - val = init_let_val(PSI_LET_NULL, NULL); +let_exp(val) ::= AMPERSAND NULL. { + val = psi_let_exp_init(PSI_LET_NULL, NULL); val->is_reference = 1; } -let_val(val) ::= let_callback(cb). { - val = init_let_val(PSI_LET_CALLBACK, cb); +let_exp(val) ::= let_callback(cb). { + val = psi_let_exp_init(PSI_LET_CALLBACK, cb); } -let_val(val) ::= let_calloc(ca). { - val = init_let_val(PSI_LET_CALLOC, ca); +let_exp(val) ::= let_calloc(ca). { + val = psi_let_exp_init(PSI_LET_CALLOC, ca); } -let_val(val) ::= AMPERSAND let_calloc(ca). { - val = init_let_val(PSI_LET_CALLOC, ca); +let_exp(val) ::= AMPERSAND let_calloc(ca). { + val = psi_let_exp_init(PSI_LET_CALLOC, ca); val->is_reference = 1; } -let_val(val) ::= let_func(fn). { - val = init_let_val_ex(NULL, PSI_LET_FUNC, fn); +let_exp(val) ::= let_func(fn). { + val = psi_let_exp_init_ex(NULL, PSI_LET_FUNC, fn); } -let_val(val) ::= AMPERSAND let_func(fn). { - val = init_let_val_ex(NULL, PSI_LET_FUNC, fn); +let_exp(val) ::= AMPERSAND let_func(fn). { + val = psi_let_exp_init_ex(NULL, PSI_LET_FUNC, fn); val->is_reference = 1; } -let_val(val) ::= num_exp(exp). { - val = init_let_val_ex(NULL, PSI_LET_NUMEXP, exp); +let_exp(val) ::= num_exp(exp). { + val = psi_let_exp_init_ex(NULL, PSI_LET_NUMEXP, exp); } -let_val(val) ::= AMPERSAND num_exp(exp). { - val = init_let_val_ex(NULL, PSI_LET_NUMEXP, exp); +let_exp(val) ::= AMPERSAND num_exp(exp). { + val = psi_let_exp_init_ex(NULL, PSI_LET_NUMEXP, exp); val->is_reference = 1; } -let_exp(exp) ::= decl_var(var_) EQUALS let_val(val). { +let_exp(exp) ::= decl_var(var_) EQUALS let_exp(val). { exp = val; exp->var = var_; } let_stmt(let) ::= LET(T) let_exp(val) EOS. { - let = init_let_stmt(val); + let = psi_let_stmt_init(val); let->token = T; } let_stmt(let) ::= TEMP(T) decl_var(var) EQUALS reference(r) decl_var(val_) EOS. { - let = init_let_stmt(init_let_val_ex(var, PSI_LET_TMP, val_)); + let = psi_let_stmt_init(psi_let_exp_init_ex(var, PSI_LET_TMP, val_)); let->token = T; - let->val->is_reference = r ? 1 : 0; + let->exp->is_reference = r ? 1 : 0; } -let_callback(cb) ::= CALLBACK callback_rval(F) LPAREN impl_var(var) LPAREN callback_arg_list(args_) RPAREN RPAREN. { - cb = init_let_callback(init_let_func(F->type, F->text, var), args_); +let_callback(cb) ::= CALLBACK(T) callback_rval(F) LPAREN impl_var(var) LPAREN callback_arg_list(args_) RPAREN RPAREN. { + cb = psi_let_callback_init(psi_let_func_init(F->type, F->text, var), args_); + cb->token = T; free(F); } -let_calloc(alloc) ::= CALLOC LPAREN num_exp(nmemb) COMMA num_exp(size) RPAREN. { - alloc = init_let_calloc(nmemb, size); +let_calloc(alloc) ::= CALLOC(T) LPAREN num_exp(nmemb) COMMA num_exp(size) RPAREN. { + alloc = psi_let_calloc_init(nmemb, size); + alloc->token = T; } let_func(func) ::= let_func_token(T) LPAREN impl_var(var) RPAREN. { - func = init_let_func(T->type, T->text, var); - free(T); + func = psi_let_func_init(T->type, T->text, var); + func->token = T; } -let_func(func) ::= let_func_token(T) LPAREN impl_var(var) COMMA let_vals(vals) RPAREN. { - func = init_let_func(T->type, T->text, var); +let_func(func) ::= let_func_token(T) LPAREN impl_var(var) COMMA let_exps(vals) RPAREN. { + func = psi_let_func_init(T->type, T->text, var); + func->token = T; func->inner = vals; - free(T); -} -let_vals(vals) ::= let_exp(val). { - vals = init_let_vals(val); -} -let_vals(vals) ::= let_val(val). { - vals = init_let_vals(val); } -let_vals(vals) ::= let_vals(vals_) COMMA let_exp(val). { - vals = add_let_val(vals_, val); +let_exps(exps) ::= let_exp(exp). { + exps = psi_plist_add(psi_plist_init((psi_plist_dtor) psi_let_exp_free), + &exp); } -let_vals(vals) ::= let_vals(vals_) COMMA let_val(val). { - vals = add_let_val(vals_, val); +let_exps(exps) ::= let_exps(exps_) COMMA let_exp(exp). { + exps = psi_plist_add(exps_, &exp); } callback_arg_list ::= . callback_arg_list(args) ::= callback_args(args_). { args = args_; } -callback_args(args) ::= set_value(val). { - args = init_set_values(val); +callback_args(args) ::= set_exp(val). { + args = psi_plist_add(psi_plist_init((psi_plist_dtor) psi_set_exp_free), + &val); } -callback_args(args) ::= callback_args(args_) COMMA set_value(val). { - args = add_set_value(args_, val); +callback_args(args) ::= callback_args(args_) COMMA set_exp(val). { + args = psi_plist_add(args_, &val); } callback_rval(rval) ::= let_func_token(F). { rval = F; @@ -756,63 +796,59 @@ callback_rval(rval) ::= let_func_token(F). { callback_rval(rval) ::= VOID(V). { rval = V; } -set_stmt(set) ::= SET impl_var(var) EQUALS set_value(val) EOS. { - set = init_set_stmt(var, val); +set_func(func) ::= set_func_token(T) LPAREN decl_var(var) RPAREN. { + func = psi_set_func_init(T->type, T->text, var); + func->token = T; } -set_value(val) ::= set_func(func) LPAREN decl_var(var) RPAREN. { - val = init_set_value(func, init_decl_vars(var)); +set_func(func) ::= set_func_token(T) LPAREN decl_var(var) COMMA set_exps(vals) RPAREN. { + func = psi_set_func_init(T->type, T->text, var); + func->token = T; + func->inner = vals; } -set_value(val) ::= set_func(func) LPAREN decl_var(var) COMMA num_exp(num_) RPAREN. { - val = init_set_value(func, init_decl_vars(var)); - val->num = num_; +set_func(func) ::= set_func_token(T) LPAREN decl_var(var) COMMA ELLIPSIS RPAREN. { + func = psi_set_func_init(T->type, T->text, var); + func->token = T; + func->recursive = 1; } -set_value(val) ::= set_func(func_) LPAREN decl_var(var) COMMA ELLIPSIS(T) RPAREN. { - free_set_func(func_); - val = init_set_value(init_set_func(T->type, T->text), init_decl_vars(var)); - val->func->token = T; +set_exp(val) ::= set_func(fn). { + val = psi_set_exp_init(PSI_SET_FUNC, fn); } -set_value(val) ::= set_func(func_) LPAREN decl_var(var) COMMA set_vals(vals) RPAREN. { - val = vals; - val->func = func_; - val->vars = init_decl_vars(var); +set_exp(val) ::= num_exp(num). { + val = psi_set_exp_init(PSI_SET_NUMEXP, num); } -set_value(val) ::= set_func(func_) LPAREN decl_var(var) COMMA num_exp(num_) COMMA set_vals(vals) RPAREN. { - val = vals; - val->func = func_; - val->num = num_; - val->vars = init_decl_vars(var); +set_exps(exps) ::= set_exp(exp). { + exps = psi_plist_add(psi_plist_init((psi_plist_dtor) psi_set_exp_free), + &exp); } -set_vals(vals) ::= set_value(val). { - vals = add_inner_set_value(init_set_value(NULL, NULL), val); +set_exps(exps) ::= set_exps(exps_) COMMA set_exp(exp). { + exps = psi_plist_add(exps_, &exp); } -set_vals(vals) ::= set_vals(vals_) COMMA set_value(val). { - vals = add_inner_set_value(vals_, val); +set_exp(exp) ::= impl_var(var_) EQUALS set_exp(val). { + exp = val; + exp->var = var_; } -set_func(func) ::= set_func_token(T). { - func = init_set_func(T->type, T->text); - func->token = T; +set_stmt(set) ::= SET(T) set_exp(exp) EOS. { + set = psi_set_stmt_init(exp); + set->token = T; } -return_stmt(ret) ::= RETURN(T) set_value(val) EOS. { - ret = init_return_stmt(val); +return_stmt(ret) ::= RETURN(T) set_func(func) EOS. { + ret = psi_return_stmt_init(psi_set_exp_init(PSI_SET_FUNC, func)); ret->token = T; } -free_stmt(free) ::= FREE free_calls(calls) EOS. { - free = init_free_stmt(calls); +free_stmt(free) ::= FREE free_exps(calls) EOS. { + free = psi_free_stmt_init(calls); } -free_calls(calls) ::= free_call(call). { - calls = init_free_calls(call); +free_exps(calls) ::= free_exp(call). { + calls = psi_plist_add(psi_plist_init((psi_plist_dtor) psi_free_exp_free), + &call); } -free_calls(calls) ::= free_calls(calls_) COMMA free_call(call). { - calls = add_free_call(calls_, call); +free_exps(calls) ::= free_exps(calls_) COMMA free_exp(call). { + calls = psi_plist_add(calls_, &call); } -free_call(call) ::= NAME(F) LPAREN decl_vars(vars) RPAREN. { - call = init_free_call(F->text, vars); +free_exp(call) ::= NAME(F) LPAREN decl_vars(vars) RPAREN. { + call = psi_free_exp_init(F->text, vars); call->token = F; } -impl_type(type_) ::= impl_type_token(T). { - type_ = init_impl_type(T->type, T->text); - free(T); -} reference(r) ::= . { r = 0; } diff --git a/src/parser_proc.y.bak b/src/parser_proc.y.bak index b46053a..20b4e68 100644 --- a/src/parser_proc.y.bak +++ b/src/parser_proc.y.bak @@ -728,14 +728,14 @@ num_exp(exp) ::= num_exp(exp_) num_exp_op_token(operator_) num_exp(operand_). { %type let_stmt {let_stmt*} %destructor let_stmt {free_let_stmt($$);} let_stmt(let) ::= LET decl_var(var) EOS. { - let = init_let_stmt(var, init_let_val(PSI_LET_NULL, NULL)); + let = init_let_stmt(var, init_let_exp(PSI_LET_NULL, NULL)); } -let_stmt(let) ::= LET decl_var(var) EQUALS reference(r) let_val(val) EOS. { +let_stmt(let) ::= LET decl_var(var) EQUALS reference(r) let_exp(val) EOS. { val->flags.one.is_reference = r ? 1 : 0; let = init_let_stmt(var, val); } let_stmt(let) ::= TEMP decl_var(var) EQUALS decl_var(val) EOS. { - let = init_let_stmt(var, init_let_val(PSI_LET_TMP, val)); + let = init_let_stmt(var, init_let_exp(PSI_LET_TMP, val)); } %type let_calloc {let_calloc*} @@ -767,22 +767,22 @@ callback_args(args) ::= callback_args(args_) COMMA set_value(val). { args = add_set_value(args_, val); } -%type let_val {let_val*} -%destructor let_val {free_let_val($$);} -let_val(val) ::= NULL. { - val = init_let_val(PSI_LET_NULL, NULL); +%type let_exp {let_exp*} +%destructor let_exp {free_let_exp($$);} +let_exp(val) ::= NULL. { + val = init_let_exp(PSI_LET_NULL, NULL); } -let_val(val) ::= num_exp(exp). { - val = init_let_val(PSI_LET_NUMEXP, exp); +let_exp(val) ::= num_exp(exp). { + val = init_let_exp(PSI_LET_NUMEXP, exp); } -let_val(val) ::= CALLOC LPAREN let_calloc(alloc) RPAREN. { - val = init_let_val(PSI_LET_CALLOC, alloc); +let_exp(val) ::= CALLOC LPAREN let_calloc(alloc) RPAREN. { + val = init_let_exp(PSI_LET_CALLOC, alloc); } -let_val(val) ::= let_func(func). { - val = init_let_val(PSI_LET_FUNC, func); +let_exp(val) ::= let_func(func). { + val = init_let_exp(PSI_LET_FUNC, func); } -let_val(val) ::= CALLBACK let_func_token(F) LPAREN impl_var(var) LPAREN callback_arg_list(args_) RPAREN RPAREN. { - val = init_let_val(PSI_LET_CALLBACK, init_let_callback( +let_exp(val) ::= CALLBACK let_func_token(F) LPAREN impl_var(var) LPAREN callback_arg_list(args_) RPAREN RPAREN. { + val = init_let_exp(PSI_LET_CALLBACK, init_let_callback( init_let_func(F->type, F->text, var), args_)); free(F); } diff --git a/src/plist.c b/src/plist.c new file mode 100644 index 0000000..d759b84 --- /dev/null +++ b/src/plist.c @@ -0,0 +1,149 @@ +/******************************************************************************* + Copyright (c) 2016, Michael Wallner . + 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. +*******************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#else +# include "php_config.h" +#endif + +#include "php_psi_stdinc.h" + +#include "plist.h" + +struct psi_plist { + size_t size; + size_t count; + void (*dtor)(void *); + void *list[1]; +}; + +#define PLIST_ELE(l, i) (((char *)(l)->list) + (l)->size * (i)) +#define PLIST_CPY(list, dest, src) do { \ + if (list->size == sizeof(void *)) { \ + *(void **)dest = *(void **)src; \ + } else { \ + memcpy(dest, src, list->size); \ + } \ +} while (0) +#define PLIST_MOV(l, i) memmove(PLIST_ELE(l, i), PLIST_ELE(l, i + 1), (l)->size * ((l)->count - i)) + +struct psi_plist *psi_plist_init(void (*dtor)(void *)) { + return psi_plist_init_ex(0, dtor); +} +struct psi_plist *psi_plist_init_ex(size_t size, void (*dtor)(void *)) { + struct psi_plist *list = calloc(1, sizeof(*list)); + + list->size = size ?: sizeof(void*); + list->dtor = dtor; + + return list; +} + +void psi_plist_free(struct psi_plist *list) { + size_t i; + + if (list->dtor) for (i = 0; i < list->count; ++i) { + list->dtor(PLIST_ELE(list, i)); + } + free(list); +} + +size_t psi_plist_count(struct psi_plist *list) { + return list ? list->count : 0; +} + +struct psi_plist *psi_plist_add(struct psi_plist *list, void *ptr) { + if (list->count) { + list = realloc(list, sizeof(*list) + list->count * list->size); + } + if (list) { + PLIST_CPY(list, PLIST_ELE(list, list->count++), ptr); + } + return list; +} + +bool psi_plist_get(struct psi_plist *list, size_t index, void *ptr) { + if (list && list->count > index) { + PLIST_CPY(list, ptr, PLIST_ELE(list, index)); + return true; + } + return false; +} + +bool psi_plist_del(struct psi_plist *list, size_t index, void *ptr) { + if (list->count > index) { + if (ptr) { + PLIST_CPY(list, ptr, PLIST_ELE(list, index)); + } + if (--list->count > index) { + PLIST_MOV(list, index); + } + return true; + } + return false; +} + +bool psi_plist_shift(struct psi_plist *list, void *ptr) { + if (list->count) { + if (ptr) { + PLIST_CPY(list, ptr, PLIST_ELE(list, 0)); + } + if (--list->count) { + PLIST_MOV(list, 0); + } + return true; + } + return false; +} + +bool psi_plist_pop(struct psi_plist *list, void *ptr) { + if (list->count) { + --list->count; + if (ptr) { + PLIST_CPY(list, ptr, PLIST_ELE(list, list->count)); + } + return true; + } + return false; +} + + +static void swp_ptr(void *a, void *b) { + void **_a = a, **_b = b, *_c; + + _c = *_b; + *_b = *_a; + *_a = _c; +} + +void psi_plist_sort(struct psi_plist *list, compare_func_t cmp, swap_func_t swp) { + if (!swp && list->size == sizeof(void *)) { + swp = swp_ptr; + } + assert(swp); + zend_insert_sort((void *) list->list, list->count, list->size, cmp, swp); +} + diff --git a/src/types/constants.c b/src/plist.h similarity index 66% rename from src/types/constants.c rename to src/plist.h index 2bcbd49..7c84a86 100644 --- a/src/types/constants.c +++ b/src/plist.h @@ -23,43 +23,28 @@ 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 +#ifndef PSI_PLIST_H +#define PSI_PLIST_H + +struct psi_plist; -#include -#include +typedef void (*psi_plist_dtor)(void *); -#include "constants.h" +struct psi_plist *psi_plist_init(void (*dtor)(void *)); +struct psi_plist *psi_plist_init_ex(size_t size, void (*dtor)(void *)); +void psi_plist_free(struct psi_plist *list); -constants *add_constant(constants *consts, constant *constant) { - if (!consts) { - consts = calloc(1, sizeof(*consts)); - } - consts->list = realloc(consts->list, - ++consts->count * sizeof(*consts->list)); - consts->list[consts->count - 1] = constant; - return consts; -} +size_t psi_plist_count(struct psi_plist *list); -void free_constants(constants *consts) { - size_t i; - for (i = 0; i < consts->count; ++i) { - free_constant(consts->list[i]); - } - free(consts->list); - free(consts); -} +struct psi_plist *psi_plist_add(struct psi_plist *list, void *ptr); +bool psi_plist_get(struct psi_plist *list, size_t index, void *ptr); +bool psi_plist_del(struct psi_plist *list, size_t index, void *ptr); +bool psi_plist_shift(struct psi_plist *list, void *ptr); +bool psi_plist_pop(struct psi_plist *list, void *ptr); -void dump_constants(int fd, constants *consts) { - size_t i; +#include "Zend/zend.h" +#include "Zend/zend_sort.h" - for (i = 0; i < consts->count; ++i) { - constant *cnst = consts->list[i]; +void psi_plist_sort(struct psi_plist *list, compare_func_t cmp, swap_func_t swp); - dump_constant(fd, cnst); - dprintf(fd, "\n"); - } -} +#endif diff --git a/src/token.c b/src/token.c index 5f56e75..01c45f1 100644 --- a/src/token.c +++ b/src/token.c @@ -23,19 +23,8 @@ 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 -#include -#include -#include -#include - -#include "parser_proc.h" +#include "php_psi_stdinc.h" + #include "token.h" #include "parser.h" @@ -54,7 +43,7 @@ struct psi_token *psi_token_alloc(struct psi_parser *P) { token_typ = P->num; token_len = P->cur - P->tok; - fname_len = strlen(P->psi.file.fn); + fname_len = strlen(P->file.fn); T = calloc(1, psi_token_alloc_size(token_len, fname_len)); T->type = token_typ; @@ -65,7 +54,7 @@ struct psi_token *psi_token_alloc(struct psi_parser *P) { T->col = P->col; memcpy(T->text, P->tok, token_len); - memcpy(T->file, P->psi.file.fn, fname_len); + memcpy(T->file, P->file.fn, fname_len); return T; } diff --git a/src/token.h b/src/token.h index 413a14c..68b8062 100644 --- a/src/token.h +++ b/src/token.h @@ -94,13 +94,14 @@ static inline size_t psi_t_size(token_t t) return SIZEOF_FLOAT; case PSI_T_DOUBLE: return SIZEOF_DOUBLE; + case PSI_T_VOID: case PSI_T_POINTER: case PSI_T_FUNCTION: return SIZEOF_VOID_P; case PSI_T_ENUM: return SIZEOF_INT; default: - assert(0); + assert(!t); } return 0; } diff --git a/src/types.h b/src/types.h index 97f00d4..0c0ca49 100644 --- a/src/types.h +++ b/src/types.h @@ -1,60 +1,67 @@ -#ifndef _PSI_TYPES_H -#define _PSI_TYPES_H +/******************************************************************************* + Copyright (c) 2016, Michael Wallner . + All rights reserved. -#include "token.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. +*******************************************************************************/ +#ifndef PSI_TYPES_H +#define PSI_TYPES_H + +#include "token.h" #include "types/impl_val.h" #include "types/decl_type.h" #include "types/decl_var.h" -#include "types/decl_struct_layout.h" #include "types/decl_arg.h" -#include "types/decl_typedefs.h" -#include "types/decl_vars.h" -#include "types/decl_args.h" #include "types/decl_abi.h" -#include "types/decl_callinfo.h" #include "types/decl.h" -#include "types/decls.h" #include "types/decl_struct.h" -#include "types/decl_structs.h" #include "types/decl_union.h" -#include "types/decl_unions.h" #include "types/impl_type.h" #include "types/impl_var.h" #include "types/impl_def_val.h" #include "types/const_type.h" -#include "types/constant.h" -#include "types/constants.h" +#include "types/const.h" #include "types/impl_arg.h" -#include "types/impl_args.h" #include "types/impl_func.h" #include "types/num_exp.h" #include "types/decl_enum_item.h" -#include "types/decl_enum_items.h" #include "types/decl_enum.h" -#include "types/decl_enums.h" #include "types/let_calloc.h" #include "types/let_callback.h" #include "types/let_func.h" -#include "types/let_val.h" -#include "types/let_vals.h" +#include "types/let_exp.h" #include "types/let_stmt.h" #include "types/set_func.h" -#include "types/set_value.h" -#include "types/set_values.h" +#include "types/set_exp.h" #include "types/set_stmt.h" #include "types/return_stmt.h" -#include "types/free_call.h" -#include "types/free_calls.h" #include "types/free_stmt.h" -#include "types/impl_stmt.h" -#include "types/impl_stmts.h" #include "types/impl.h" -#include "types/impls.h" #include "types/decl_file.h" -#include "types/decl_libs.h" +#include "types/free_exp.h" +#include "types/free_stmt.h" +#include "types/layout.h" -static inline impl_val *deref_impl_val(impl_val *ret_val, decl_var *var) { +static inline impl_val *deref_impl_val(impl_val *ret_val, struct psi_decl_var *var) { unsigned i; ZEND_ASSERT(!var->arg || var->arg->var != var); @@ -72,7 +79,7 @@ static inline impl_val *deref_impl_val(impl_val *ret_val, decl_var *var) { return ret_val; } -static inline impl_val *enref_impl_val(void *ptr, decl_var *var) { +static inline impl_val *enref_impl_val(void *ptr, struct psi_decl_var *var) { impl_val *val, *val_ptr; unsigned i; @@ -98,7 +105,7 @@ static inline impl_val *enref_impl_val(void *ptr, decl_var *var) { return val; } -static inline impl_val *struct_member_ref(decl_arg *set_arg, impl_val *struct_ptr, impl_val **to_free) { +static inline impl_val *struct_member_ref(struct psi_decl_arg *set_arg, impl_val *struct_ptr, impl_val **to_free) { void *ptr = (char *) struct_ptr + set_arg->layout->pos; #if 0 fprintf(stderr, "struct member %s: %p\n", set_arg->var->name, ptr); diff --git a/src/types/constant.c b/src/types/const.c similarity index 51% rename from src/types/constant.c rename to src/types/const.c index dcd8450..a40a0e2 100644 --- a/src/types/constant.c +++ b/src/types/const.c @@ -5,11 +5,11 @@ 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. + * 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 @@ -21,44 +21,48 @@ 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. -*******************************************************************************/ + *******************************************************************************/ -#ifdef HAVE_CONFIG_H -# include "config.h" -# else -# include "php_config.h" -#endif +#include "php_psi_stdinc.h" +#include "data.h" -#include -#include -#include - -#include "constant.h" - -constant *init_constant(const_type *type, const char *name, impl_def_val *val) { - constant *c = calloc(1, sizeof(*c)); +struct psi_const *psi_const_init(struct psi_const_type *type, const char *name, + struct psi_impl_def_val *val) +{ + struct psi_const *c = calloc(1, sizeof(*c)); c->type = type; c->name = strdup(name); c->val = val; return c; } -void free_constant(constant *constant) { - free_const_type(constant->type); - free(constant->name); - free_impl_def_val(constant->val); - free(constant); +void psi_const_free(struct psi_const **constant_ptr) +{ + if (*constant_ptr) { + struct psi_const *constant = *constant_ptr; + + *constant_ptr = NULL; + if (constant->token) { + free(constant->token); + } + psi_const_type_free(&constant->type); + free(constant->name); + psi_impl_def_val_free(&constant->val); + free(constant); + } } -void dump_constant(int fd, constant *cnst) { +void psi_const_dump(int fd, struct psi_const *cnst) +{ dprintf(fd, "const "); - dump_const_type(fd, cnst->type); + psi_const_type_dump(fd, cnst->type); dprintf(fd, " %s = ", cnst->name); - dump_impl_def_val(fd, cnst->val); + psi_impl_def_val_dump(fd, cnst->val); dprintf(fd, ";"); } -int validate_constant(struct psi_data *data, constant *c) { +bool psi_const_validate(struct psi_data *data, struct psi_const *c) +{ /* FIXME */ - return 1; + return true; } diff --git a/src/types/constant.h b/src/types/const.h similarity index 75% rename from src/types/constant.h rename to src/types/const.h index c09fc10..8af18f2 100644 --- a/src/types/constant.h +++ b/src/types/const.h @@ -23,23 +23,24 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *******************************************************************************/ -#ifndef PSI_TYPES_CONSTANT_H -#define PSI_TYPES_CONSTANT_H +#ifndef PSI_TYPES_CONST_H +#define PSI_TYPES_CONST_H -#include "const_type.h" -#include "impl_def_val.h" +struct psi_data; +struct psi_token; +struct psi_const_type; +struct psi_impl_def_val; -typedef struct constant { - const_type *type; +struct psi_const { + struct psi_token *token; + struct psi_const_type *type; char *name; - impl_def_val *val; -} constant; - -constant *init_constant(const_type *type, const char *name, impl_def_val *val); -void free_constant(constant *constant); -void dump_constant(int fd, constant *cnst); + struct psi_impl_def_val *val; +}; -struct psi_data; +struct psi_const *psi_const_init(struct psi_const_type *type, const char *name, struct psi_impl_def_val *val); +void psi_const_free(struct psi_const **constant_ptr); +void psi_const_dump(int fd, struct psi_const *cnst); +bool psi_const_validate(struct psi_data *data, struct psi_const *c); -int validate_constant(struct psi_data *data, constant *c); #endif diff --git a/src/types/const_type.c b/src/types/const_type.c index 46b5199..33c1233 100644 --- a/src/types/const_type.c +++ b/src/types/const_type.c @@ -5,11 +5,11 @@ 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. + * 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 @@ -21,32 +21,33 @@ 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. -*******************************************************************************/ + *******************************************************************************/ -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif +#include "php_psi_stdinc.h" +#include "data.h" -#include -#include -#include +struct psi_const_type *psi_const_type_init(token_t type, const char *name) +{ + struct psi_const_type *ct = calloc(1, sizeof(*ct)); -#include "const_type.h" - -const_type *init_const_type(token_t type, const char *name) { - const_type *ct = calloc(1, sizeof(*ct)); ct->type = type; ct->name = strdup(name); + return ct; } -void free_const_type(const_type *type) { - free(type->name); - free(type); +void psi_const_type_free(struct psi_const_type **type_ptr) +{ + if (*type_ptr) { + struct psi_const_type *type = *type_ptr; + + *type_ptr = NULL; + free(type->name); + free(type); + } } -void dump_const_type(int fd, const_type *type) { +void psi_const_type_dump(int fd, struct psi_const_type *type) +{ dprintf(fd, "%s", type->name); } diff --git a/src/types/const_type.h b/src/types/const_type.h index 7ca6d6e..42fc58f 100644 --- a/src/types/const_type.h +++ b/src/types/const_type.h @@ -28,13 +28,13 @@ #include "token.h" -typedef struct const_type { +struct psi_const_type { token_t type; char *name; -} const_type; +}; -const_type *init_const_type(token_t type, const char *name); -void free_const_type(const_type *type); -void dump_const_type(int fd, const_type *type); +struct psi_const_type *psi_const_type_init(token_t type, const char *name); +void psi_const_type_free(struct psi_const_type **type_tr); +void psi_const_type_dump(int fd, struct psi_const_type *type); #endif diff --git a/src/types/constants.h b/src/types/constants.h deleted file mode 100644 index a41cde5..0000000 --- a/src/types/constants.h +++ /dev/null @@ -1,40 +0,0 @@ -/******************************************************************************* - Copyright (c) 2016, Michael Wallner . - 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_TYPES_CONSTANTS_H -#define PSI_TYPES_CONSTANTS_H - -#include "constant.h" - -typedef struct constants { - size_t count; - constant **list; -} constants; - -constants *add_constant(constants *constants, constant *constant); -void free_constants(constants *constants); -void dump_constants(int fd, constants *constants); - -#endif diff --git a/src/types/decl.c b/src/types/decl.c index ef6bd6d..9c1b0c5 100644 --- a/src/types/decl.c +++ b/src/types/decl.c @@ -5,11 +5,11 @@ 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. + * 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 @@ -21,13 +21,9 @@ 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. -*******************************************************************************/ + *******************************************************************************/ -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif +#include "php_psi_stdinc.h" #if __GNUC__ >= 5 # pragma GCC diagnostic ignored "-Wdiscarded-qualifiers" @@ -38,96 +34,122 @@ # pragma GCC diagnostic pop #endif -#include -#include -#include #include #include "data.h" -decl *init_decl(decl_abi *abi, decl_arg *func, decl_args *args) { - decl *d = calloc(1, sizeof(*d)); +struct psi_decl *psi_decl_init(struct psi_decl_abi *abi, + struct psi_decl_arg *func, struct psi_plist *args) +{ + struct psi_decl *d = calloc(1, sizeof(*d)); d->abi = abi; d->func = func; d->args = args; return d; } -void free_decl(decl *d) { - free_decl_abi(d->abi); - free_decl_arg(d->func); - if (d->args) { - free_decl_args(d->args); +void psi_decl_free(struct psi_decl **d_ptr) +{ + if (*d_ptr) { + struct psi_decl *d = *d_ptr; + + *d_ptr = NULL; + + psi_decl_abi_free(&d->abi); + psi_decl_arg_free(&d->func); + if (d->args) { + psi_plist_free(d->args); + } + free(d); } - free(d); } -void dump_decl(int fd, decl *decl) { - dump_decl_abi(fd, decl->abi); +void psi_decl_dump(int fd, struct psi_decl *decl) +{ + psi_decl_abi_dump(fd, decl->abi); dprintf(fd, " "); - dump_decl_arg(fd, decl->func, 0); + psi_decl_arg_dump(fd, decl->func, 0); dprintf(fd, "("); if (decl->args) { - dump_decl_args(fd, decl->args, 0); + size_t i; + struct psi_decl_arg *arg; + + for (i = 0; psi_plist_get(decl->args, i, &arg); ++i) { + if (i) { + dprintf(fd, ", "); + } + psi_decl_arg_dump(fd, arg, 0); + } + if (decl->varargs) { + dprintf(fd, ", ..."); + } } dprintf(fd, ");"); } -static inline int validate_decl_func(struct psi_data *data, void *dl, decl *decl, decl_arg *func) +static inline bool psi_decl_validate_func(struct psi_data *data, + struct psi_decl *decl, struct psi_decl_arg *func, void *dl) { struct psi_func_redir *redir; if (!strcmp(func->var->name, "dlsym")) { - data->error(data, func->token, PSI_WARNING, "Cannot dlsym dlsym (sic!)"); - return 0; + data->error(data, func->token, PSI_WARNING, + "Cannot dlsym dlsym (sic!)"); + return false; } for (redir = &psi_func_redirs[0]; redir->name; ++redir) { if (!strcmp(func->var->name, redir->name)) { - decl->call.sym = redir->func; + decl->sym = redir->func; } } - if (!decl->call.sym) { + if (!decl->sym) { #ifndef RTLD_NEXT # define RTLD_NEXT ((void *) -1l) #endif - decl->call.sym = dlsym(dl ?: RTLD_NEXT, func->var->name); - if (!decl->call.sym) { + decl->sym = dlsym(dl ?: RTLD_NEXT, func->var->name); + if (!decl->sym) { data->error(data, func->token, PSI_WARNING, - "Failed to locate symbol '%s': %s", - func->var->name, dlerror() ?: "not found"); + "Failed to locate symbol '%s': %s", func->var->name, + dlerror() ?: "not found"); + return false; } } - return 1; + return true; } -int validate_decl(struct psi_data *data, void *dl, decl *decl) { - if (!validate_decl_nodl(data, decl)) { - return 0; +bool psi_decl_validate(struct psi_data *data, struct psi_decl *decl, void *dl) +{ + if (!psi_decl_validate_nodl(data, decl)) { + return false; } - if (!validate_decl_func(data, dl, decl, decl->func)) { - return 0; + if (!psi_decl_validate_func(data, decl, decl->func, dl)) { + return false; } - return 1; + + return true; } -int validate_decl_nodl(struct psi_data *data, decl *decl) { - if (!validate_decl_abi(data, decl->abi)) { +bool psi_decl_validate_nodl(struct psi_data *data, struct psi_decl *decl) +{ + if (!psi_decl_abi_validate(data, decl->abi)) { data->error(data, decl->abi->token, PSI_WARNING, "Invalid calling convention: '%s'", decl->abi->token->text); - return 0; + return false; } - if (!validate_decl_arg(data, decl->func)) { - return 0; + if (!psi_decl_arg_validate(data, decl->func)) { + return false; } if (decl->args) { - size_t i; + size_t i = 0; + struct psi_decl_arg *arg; - for (i = 0; i < decl->args->count; ++i) { - if (!validate_decl_arg(data, decl->args->args[i])) { - return 0; + while (psi_plist_get(decl->args, i++, &arg)) { + if (!psi_decl_arg_validate(data, arg)) { + return false; } } } - return 1; + + return true; } diff --git a/src/types/decl.h b/src/types/decl.h index 5a51104..b7af241 100644 --- a/src/types/decl.h +++ b/src/types/decl.h @@ -26,26 +26,29 @@ #ifndef PSI_TYPES_DECL_H #define PSI_TYPES_DECL_H -#include "decl_abi.h" -#include "decl_arg.h" -#include "decl_args.h" -#include "decl_callinfo.h" - -typedef struct decl { - decl_abi *abi; - decl_arg *func; - decl_args *args; - struct impl *impl; - decl_callinfo call; -} decl; - -decl *init_decl(decl_abi *abi, decl_arg *func, decl_args *args); -void free_decl(decl *d); -void dump_decl(int fd, decl *decl); - struct psi_data; - -int validate_decl(struct psi_data *data, void *dl, decl *decl); -int validate_decl_nodl(struct psi_data *data, decl *decl); +struct psi_plist; +struct psi_decl_abi; +struct psi_decl_arg; + +struct psi_decl { + struct psi_decl_abi *abi; + struct psi_decl_arg *func; + struct psi_plist *args; + void *sym; + void *info; + unsigned varargs:1; +}; + +struct psi_decl *psi_decl_init(struct psi_decl_abi *abi, struct psi_decl_arg *func, struct psi_plist *args); +void psi_decl_free(struct psi_decl **d_ptr); +void psi_decl_dump(int fd, struct psi_decl *decl); + +bool psi_decl_validate(struct psi_data *data, struct psi_decl *decl, void *dl); +bool psi_decl_validate_nodl(struct psi_data *data, struct psi_decl *decl); + +static inline struct psi_decl_arg *psi_decl_get_arg(struct psi_decl *decl, struct psi_decl_var *var) { + return psi_decl_arg_get_by_var(var, decl->args, decl->func); +} #endif diff --git a/src/types/decl_abi.c b/src/types/decl_abi.c index 2994f25..3db51e6 100644 --- a/src/types/decl_abi.c +++ b/src/types/decl_abi.c @@ -5,11 +5,11 @@ 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. + * 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 @@ -21,35 +21,34 @@ 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. -*******************************************************************************/ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif - -#include -#include -#include + *******************************************************************************/ +#include "php_psi_stdinc.h" #include "data.h" -decl_abi *init_decl_abi(const char *convention) { - decl_abi *abi = calloc(1, sizeof(*abi)); +struct psi_decl_abi *psi_decl_abi_init(const char *convention) +{ + struct psi_decl_abi *abi = calloc(1, sizeof(*abi)); abi->convention = strdup(convention); return abi; } -void free_decl_abi(decl_abi *abi) { - if (abi->token) { - free(abi->token); +void psi_decl_abi_free(struct psi_decl_abi **abi_ptr) +{ + if (*abi_ptr) { + struct psi_decl_abi *abi = *abi_ptr; + + *abi_ptr = NULL; + if (abi->token) { + free(abi->token); + } + free(abi->convention); + free(abi); } - free(abi->convention); - free(abi); } -void dump_decl_abi(int fd, decl_abi *abi) { +void psi_decl_abi_dump(int fd, struct psi_decl_abi *abi) +{ dprintf(fd, "%s", abi->convention); } @@ -62,13 +61,14 @@ static const char * const abi_ccs[] = { "fastcall", }; -int validate_decl_abi(struct psi_data *data, decl_abi *abi) { +bool psi_decl_abi_validate(struct psi_data *data, struct psi_decl_abi *abi) +{ size_t i; - for (i = 0; i < sizeof(abi_ccs)/sizeof(char*); ++i) { + for (i = 0; i < sizeof(abi_ccs) / sizeof(char *); ++i) { if (strcasecmp(abi->convention, abi_ccs[i])) { - return 1; + return true; } } - return 0; + return false; } diff --git a/src/types/decl_abi.h b/src/types/decl_abi.h index 7b1ac83..d601792 100644 --- a/src/types/decl_abi.h +++ b/src/types/decl_abi.h @@ -26,17 +26,17 @@ #ifndef PSI_TYPES_DECL_ABI_H #define PSI_TYPES_DECL_ABI_H -typedef struct decl_abi { +struct psi_token; +struct psi_data; + +struct psi_decl_abi { struct psi_token *token; char *convention; -} decl_abi; - -decl_abi *init_decl_abi(const char *convention); -void free_decl_abi(decl_abi *abi); -void dump_decl_abi(int fd, decl_abi *abi); - -struct psi_data; +}; -int validate_decl_abi(struct psi_data *data, decl_abi *abi); +struct psi_decl_abi *psi_decl_abi_init(const char *convention); +void psi_decl_abi_free(struct psi_decl_abi **abi_ptr); +void psi_decl_abi_dump(int fd, struct psi_decl_abi *abi); +bool psi_decl_abi_validate(struct psi_data *data, struct psi_decl_abi *abi); #endif diff --git a/src/types/decl_arg.c b/src/types/decl_arg.c index d1f8592..1c29619 100644 --- a/src/types/decl_arg.c +++ b/src/types/decl_arg.c @@ -5,11 +5,11 @@ 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. + * 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 @@ -21,106 +21,151 @@ 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. -*******************************************************************************/ + *******************************************************************************/ -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif - -#include -#include +#include "php_psi_stdinc.h" #include #include "data.h" -decl_arg *init_decl_arg(decl_type *type, decl_var *var) { - decl_arg *arg = calloc(1, sizeof(*arg)); +struct psi_decl_arg *psi_decl_arg_init(struct psi_decl_type *type, + struct psi_decl_var *var) +{ + struct psi_decl_arg *arg = calloc(1, sizeof(*arg)); arg->token = var->token; arg->type = type; arg->var = var; var->arg = arg; - arg->ptr = &arg->val; - arg->let = arg->ptr; return arg; } -void free_decl_arg(decl_arg *arg) { - if (arg->token && arg->token != arg->var->token) { - free(arg->token); - } - free_decl_type(arg->type); - free_decl_var(arg->var); - if (arg->layout) { - free_decl_struct_layout(arg->layout); +void psi_decl_arg_free(struct psi_decl_arg **arg_ptr) +{ + if (*arg_ptr) { + struct psi_decl_arg *arg = *arg_ptr; + + *arg_ptr = NULL; + if (arg->token && arg->token != arg->var->token) { + free(arg->token); + } + psi_decl_type_free(&arg->type); + psi_decl_var_free(&arg->var); + if (arg->layout) { + psi_layout_free(&arg->layout); + } + free(arg); } - free(arg); } -void dump_decl_arg(int fd, decl_arg *arg, unsigned level) { +void psi_decl_arg_dump(int fd, struct psi_decl_arg *arg, unsigned level) +{ if (arg->type->type == PSI_T_FUNCTION) { - dump_decl_type(fd, arg->type->real.func->func->type, level); + psi_decl_type_dump(fd, arg->type->real.func->func->type, level); dprintf(fd, " (*"); - dump_decl_var(fd, arg->var); + psi_decl_var_dump(fd, arg->var); dprintf(fd, ")("); if (arg->type->real.func->args) { - size_t j; + size_t j = 0; + struct psi_decl_arg *farg; - for (j = 0; j < arg->type->real.func->args->count; ++j) { - if (j) { + ++level; + while (psi_plist_get(arg->type->real.func->args, j++, &farg)) { + if (j > 1) { dprintf(fd, ", "); } - dump_decl_arg(fd, arg->type->real.func->args->args[j], level+1); + psi_decl_arg_dump(fd, farg, level); } - if (arg->type->real.func->args->varargs) { + --level; + if (arg->type->real.func->varargs) { dprintf(fd, ", ..."); } } dprintf(fd, ")"); } else { - dump_decl_type(fd, arg->type, level); + psi_decl_type_dump(fd, arg->type, level); dprintf(fd, " "); - dump_decl_var(fd, arg->var); + psi_decl_var_dump(fd, arg->var); } } -int validate_decl_arg(struct psi_data *data, decl_arg *arg) { - if (!validate_decl_type(data, arg->type, NULL)) { +bool psi_decl_arg_validate(struct psi_data *data, struct psi_decl_arg *arg) +{ + if (!psi_decl_type_validate(data, arg->type, NULL)) { data->error(data, arg->type->token, PSI_WARNING, - "Cannot use '%s' as type for '%s'", - arg->type->name, arg->var->name); - return 0; + "Cannot use '%s' as type for '%s': %s", arg->type->name, + arg->var->name, data->last_error); + return false; } - return 1; + return true; } -size_t align_decl_arg(decl_arg *darg, size_t *pos, size_t *len) { - size_t align = alignof_decl_arg(darg); +bool psi_decl_arg_validate_typedef(struct psi_data *data, struct psi_decl_arg *def) +{ + if (!psi_decl_type_validate(data, def->type, def)) { + const char *pre; + + switch (def->type->type) { + case PSI_T_STRUCT: + pre = "struct "; + break; + case PSI_T_UNION: + pre = "union "; + break; + case PSI_T_ENUM: + pre = "enum "; + break; + default: + pre = ""; + break; + } + data->error(data, def->token, PSI_WARNING, + "Type '%s' cannot be aliased to '%s%s': %s", def->var->name, pre, + def->type->name, data->last_error); + return false; + } + if (def->type->type == PSI_T_VOID) { + if (def->var->pointer_level) { + def->type->type = PSI_T_POINTER; + } else { + data->error(data, def->token, PSI_WARNING, + "Type '%s' cannot be aliased to 'void'", def->type->name); + return false; + } + } + + return true; +} + +size_t psi_decl_arg_align(struct psi_decl_arg *darg, size_t *pos, size_t *len) +{ + size_t align = psi_decl_arg_get_align(darg); assert(align > 0); - *len = sizeof_decl_arg(darg); + *len = psi_decl_arg_get_size(darg); *pos = psi_align(align, *pos); return align; } -size_t alignof_decl_arg(decl_arg *darg) { +size_t psi_decl_arg_get_align(struct psi_decl_arg *darg) +{ size_t align; - if (darg->var->pointer_level && (!darg->var->array_size || darg->var->pointer_level > 2)) { + if (darg->var->pointer_level + && (!darg->var->array_size || darg->var->pointer_level > 2)) { align = psi_t_alignment(PSI_T_POINTER); } else { - align = alignof_decl_type(darg->type); + align = psi_decl_type_get_align(darg->type); } return align; } -size_t sizeof_decl_arg(decl_arg *darg) { +size_t psi_decl_arg_get_size(struct psi_decl_arg *darg) +{ size_t size; - decl_type *real = real_decl_type(darg->type); + struct psi_decl_type *real = psi_decl_type_get_real(darg->type); if (darg->var->array_size) { if (darg->var->pointer_level > 2) { @@ -145,7 +190,39 @@ size_t sizeof_decl_arg(decl_arg *darg) { } } - assert(size > 0); - return size; } + +struct psi_decl_arg *psi_decl_arg_get_by_name(struct psi_plist *args, + const char *name) +{ + size_t i = 0; + struct psi_decl_arg *arg; + + if (args) + while (psi_plist_get(args, i++, &arg)) { + if (!strcmp(name, arg->var->name)) { + return arg; + } + } + + return NULL; +} + +struct psi_decl_arg *psi_decl_arg_get_by_var(struct psi_decl_var *var, + struct psi_plist *args, struct psi_decl_arg *func) +{ + struct psi_decl_arg *arg = psi_decl_arg_get_by_name(args, var->name); + + if (arg) { + assert(!var->arg || var->arg == arg); + + return var->arg = arg; + } + + if (func && !strcmp(var->name, func->var->name)) { + return var->arg = func; + } + + return NULL; +} diff --git a/src/types/decl_arg.h b/src/types/decl_arg.h index 351cb10..0ac1fc2 100644 --- a/src/types/decl_arg.h +++ b/src/types/decl_arg.h @@ -26,32 +26,33 @@ #ifndef PSI_TYPES_DECL_ARG_H #define PSI_TYPES_DECL_ARG_H -#include "decl_type.h" -#include "decl_var.h" -#include "decl_struct_layout.h" -#include "impl_val.h" +struct psi_data; +struct psi_token; +struct psi_plist; +struct psi_decl_type; +struct psi_decl_var; +struct psi_layout; -typedef struct decl_arg { +struct psi_decl_arg { struct psi_token *token; - decl_type *type; - decl_var *var; - decl_struct_layout *layout; - impl_val val; - void *ptr; - void *let; - void *mem; -} decl_arg; - -decl_arg *init_decl_arg(decl_type *type, decl_var *var); -void free_decl_arg(decl_arg *arg); -void dump_decl_arg(int fd, decl_arg *arg, unsigned level); + struct psi_decl_type *type; + struct psi_decl_var *var; + struct psi_layout *layout; +}; -struct psi_data; +struct psi_decl_arg *psi_decl_arg_init(struct psi_decl_type *type, struct psi_decl_var *var); +void psi_decl_arg_free(struct psi_decl_arg **arg_ptr); +void psi_decl_arg_dump(int fd, struct psi_decl_arg *arg, unsigned level); + +bool psi_decl_arg_validate(struct psi_data *data, struct psi_decl_arg *arg); +bool psi_decl_arg_validate_typedef(struct psi_data *data, struct psi_decl_arg *def); + +size_t psi_decl_arg_align(struct psi_decl_arg *darg, size_t *pos, size_t *len); +size_t psi_decl_arg_get_align(struct psi_decl_arg *darg); +size_t psi_decl_arg_get_size(struct psi_decl_arg *darg); -int validate_decl_arg(struct psi_data *data, decl_arg *arg); +struct psi_decl_arg *psi_decl_arg_get_by_name(struct psi_plist *args, const char *name); +struct psi_decl_arg *psi_decl_arg_get_by_var(struct psi_decl_var *var, struct psi_plist *args, struct psi_decl_arg *func); -size_t align_decl_arg(decl_arg *darg, size_t *pos, size_t *len); -size_t alignof_decl_arg(decl_arg *darg); -size_t sizeof_decl_arg(decl_arg *darg); #endif diff --git a/src/types/decl_args.c b/src/types/decl_args.c deleted file mode 100644 index 46c0d25..0000000 --- a/src/types/decl_args.c +++ /dev/null @@ -1,199 +0,0 @@ -/******************************************************************************* - Copyright (c) 2016, Michael Wallner . - 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. -*******************************************************************************/ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif - -#include -#include - -#include "data.h" - -decl_args *init_decl_args(decl_arg *arg) { - decl_args *args = calloc(1, sizeof(*args)); - if (arg) { - args->count = 1; - args->args = calloc(1, sizeof(*args->args)); - args->args[0] = arg; - } - return args; -} - -decl_args *add_decl_arg(decl_args *args, decl_arg *arg) { - args->args = realloc(args->args, ++args->count * sizeof(*args->args)); - args->args[args->count - 1] = arg; - return args; -} - -void free_decl_args(decl_args *args) { - size_t i; - for (i = 0; i < args->count; ++i) { - free_decl_arg(args->args[i]); - } - free(args->args); - free(args); -} - -void dump_decl_args(int fd, decl_args *args, unsigned level) { - size_t i; - - for (i = 0; i < args->count; ++i) { - if (i) { - dprintf(fd, ", "); - } - dump_decl_arg(fd, args->args[i], level); - } - if (args->varargs) { - dprintf(fd, ", ..."); - } -} - -void dump_decl_args_with_layout(int fd, decl_args *args, unsigned level) { - size_t j; - - dprintf(fd, " {\n"); - if (args) { - ++level; - for (j = 0; j < args->count; ++j) { - decl_arg *sarg = args->args[j]; - - dprintf(fd, "%s", psi_t_indent(level)); - dump_decl_arg(fd, sarg, level); - dprintf(fd, "::(%zu, %zu);\n", sarg->layout->pos, sarg->layout->len); - } - --level; - } - dprintf(fd, "%s", psi_t_indent(level)); - dprintf(fd, "}"); -} - -decl_arg *locate_decl_arg(decl_args *args, const char *name) { - size_t i; - - if (args) for (i = 0; i < args->count; ++i) { - decl_arg *arg = args->args[i]; - - if (!strcmp(name, arg->var->name)) { - return arg; - } - } - - return NULL; -} - -size_t alignof_decl_args(decl_args *args) { - size_t i, maxalign = 0; - - for (i = 0; i < args->count; ++i) { - decl_arg *darg = args->args[i]; - size_t align = alignof_decl_arg(darg); - - if (align > maxalign) { - maxalign = align; - } - } - - return maxalign; -} - -int validate_decl_arg_args(struct psi_data *data, decl_arg *darg, void *current) { - decl_type *real = real_decl_type(darg->type); - - /* pre-validate any structs/unions/enums */ - switch (real->type) { - case PSI_T_STRUCT: - if (current && current == real->real.strct) { - return 1; - } - if (!locate_decl_type_struct(data->structs, real)) { - return 0; - } - if (!validate_decl_struct(data, real->real.strct)) { - return 0; - } - break; - case PSI_T_UNION: - if (current && current == real->real.unn) { - return 1; - } - if (!locate_decl_type_union(data->unions, real)) { - return 0; - } - if (!validate_decl_union(data, real->real.unn)) { - return 0; - } - break; - case PSI_T_ENUM: - if (current && current == real->real.enm) { - return 1; - } - if (!locate_decl_type_enum(data->enums, real)) { - return 0; - } - if (!validate_decl_enum(data, real->real.enm)) { - return 0; - } - break; - } - - return 1; -} - -static int sort_args_cmp(const void *_a, const void *_b) { - decl_arg *a = *(decl_arg **)_a, *b = *(decl_arg **)_b; - - if (a->layout->pos == b->layout->pos) { - if (a->layout->len == b->layout->len) { - return 0; - } else if (a->layout->len > b->layout->len) { - return -1; - } else { - return 1; - } - } else if (a->layout->pos > b->layout->pos) { - return 1; - } else { - return -1; - } -} - -static void sort_args_swp(void *a, void *b) { - decl_arg **_a = a, **_b = b, *_c; - - _c = *_b; - *_b = *_a; - *_a = _c; -} - -#include "Zend/zend_sort.h" - -void sort_decl_args(decl_args *args) { - zend_insert_sort((void *) args->args, args->count, - sizeof(args), sort_args_cmp, sort_args_swp); -} - diff --git a/src/types/decl_args.h b/src/types/decl_args.h deleted file mode 100644 index 37d7a7f..0000000 --- a/src/types/decl_args.h +++ /dev/null @@ -1,53 +0,0 @@ -/******************************************************************************* - Copyright (c) 2016, Michael Wallner . - 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_TYPES_DECL_ARGS_H -#define PSI_TYPES_DECL_ARGS_H - -#include "decl_arg.h" - -typedef struct decl_args { - decl_arg **args; - size_t count; - unsigned varargs:1; -} decl_args; - -decl_args *init_decl_args(decl_arg *arg); -decl_args *add_decl_arg(decl_args *args, decl_arg *arg); -void free_decl_args(decl_args *args); -void dump_decl_args(int fd, decl_args *args, unsigned level); -void dump_decl_args_with_layout(int fd, decl_args *args, unsigned level); - -decl_arg *locate_decl_arg(decl_args *args, const char *name); - -struct psi_data; - -int validate_decl_arg_args(struct psi_data *data, decl_arg *darg, void *current); - -size_t alignof_decl_args(decl_args *args); - -void sort_decl_args(decl_args *args); - -#endif diff --git a/src/types/decl_callinfo.h b/src/types/decl_callinfo.h deleted file mode 100644 index a39c467..0000000 --- a/src/types/decl_callinfo.h +++ /dev/null @@ -1,37 +0,0 @@ -/******************************************************************************* - Copyright (c) 2016, Michael Wallner . - 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_TYPES_DECL_CALLINFO_H -#define PSI_TYPES_DECL_CALLINFO_H - -typedef struct decl_callinfo { - void *sym; - void *info; - size_t argc; - void **args; - void **rval; -} decl_callinfo; - -#endif diff --git a/src/types/decl_enum.c b/src/types/decl_enum.c index ee1d93a..85ce187 100644 --- a/src/types/decl_enum.c +++ b/src/types/decl_enum.c @@ -5,11 +5,11 @@ 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. + * 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 @@ -21,74 +21,73 @@ 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. -*******************************************************************************/ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif - -#include -#include -#include + *******************************************************************************/ +#include "php_psi_stdinc.h" #include "data.h" -decl_enum *init_decl_enum(const char *name, decl_enum_items *l) { - decl_enum *e = calloc(1, sizeof(*e)); +struct psi_decl_enum *psi_decl_enum_init(const char *name, struct psi_plist *l) +{ + struct psi_decl_enum *e = calloc(1, sizeof(*e)); e->name = strdup(name); e->items = l; return e; } -void free_decl_enum(decl_enum *e) { - if (e->token) { - free(e->token); - } - if (e->items) { - free_decl_enum_items(e->items); +void psi_decl_enum_free(struct psi_decl_enum **e_ptr) +{ + if (*e_ptr) { + struct psi_decl_enum *e = *e_ptr; + + *e_ptr = NULL; + if (e->token) { + free(e->token); + } + if (e->items) { + psi_plist_free(e->items); + } + free(e->name); + free(e); } - free(e->name); - free(e); } -void dump_decl_enum(int fd, decl_enum *e, unsigned level) { +void psi_decl_enum_dump(int fd, struct psi_decl_enum *e, unsigned level) +{ dprintf(fd, "enum %s {\n", e->name); if (e->items) { - dump_decl_enum_items(fd, e->items, level); + size_t i = 0; + struct psi_decl_enum_item *item; + + ++level; + while (psi_plist_get(e->items, i++, &item)) { + if (i > 1) { + dprintf(fd, ",\n"); + } + dprintf(fd, "%s", psi_t_indent(level)); + psi_decl_enum_item_dump(fd, item); + } + --level; } dprintf(fd, "\n}"); } -int validate_decl_enum(struct psi_data *data, decl_enum *e) { - size_t j; +bool psi_decl_enum_validate(struct psi_data *data, struct psi_decl_enum *e) +{ + size_t seq; + struct psi_decl_enum_item *i, *p = NULL; - if (!e->items || !e->items->count) { + if (!psi_plist_count(e->items)) { data->error(data, e->token, PSI_WARNING, "Empty enum '%s'", e->name); - return 0; + return false; } - for (j = 0; j < e->items->count; ++j) { - decl_enum_item *i = e->items->list[j]; - - if (!i->num) { - if (j) { - i->inc.t = PSI_T_NUMBER; - i->inc.u.numb = "1"; - i->inc.operator = PSI_T_PLUS; - i->inc.operand = i->prev->num ?: &i->prev->inc; - i->num = &i->inc; - } else { - i->inc.t = PSI_T_NUMBER; - i->inc.u.numb = "0"; - i->num = &i->inc; - } - } - if (!validate_num_exp(data, i->num, NULL, NULL, e)) { - return 0; + for (seq = 0; psi_plist_get(e->items, seq, &i); ++seq) { + i->prev = p; + if (!psi_decl_enum_item_validate(data, e, i, seq)) { + return false; } + p = i; } - return 1; + return true; } diff --git a/src/types/decl_enum.h b/src/types/decl_enum.h index 69d1ee4..8082f3c 100644 --- a/src/types/decl_enum.h +++ b/src/types/decl_enum.h @@ -26,21 +26,19 @@ #ifndef PSI_TYPES_DECL_ENUM_H #define PSI_TYPES_DECL_ENUM_H -#include "token.h" -#include "decl_enum_items.h" +struct psi_data; +struct psi_token; +struct psi_plist; -typedef struct decl_enum { +struct psi_decl_enum { struct psi_token *token; char *name; - decl_enum_items *items; -} decl_enum; - -decl_enum *init_decl_enum(const char *name, decl_enum_items *l); -void free_decl_enum(decl_enum *e); -void dump_decl_enum(int fd, decl_enum *e, unsigned level); - -struct psi_data; + struct psi_plist *items; +}; -int validate_decl_enum(struct psi_data *data, decl_enum *e); +struct psi_decl_enum *psi_decl_enum_init(const char *name, struct psi_plist *l); +void psi_decl_enum_free(struct psi_decl_enum **e_ptr); +void psi_decl_enum_dump(int fd, struct psi_decl_enum *e, unsigned level); +bool psi_decl_enum_validate(struct psi_data *data, struct psi_decl_enum *e); #endif diff --git a/src/types/decl_enum_item.c b/src/types/decl_enum_item.c index 26e2d26..5f664b0 100644 --- a/src/types/decl_enum_item.c +++ b/src/types/decl_enum_item.c @@ -5,11 +5,11 @@ 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. + * 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 @@ -21,34 +21,68 @@ 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. -*******************************************************************************/ + *******************************************************************************/ -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif +#include "php_psi_stdinc.h" +#include "data.h" -#include -#include -#include - -#include "decl_enum_item.h" - -decl_enum_item *init_decl_enum_item(const char *name, num_exp *num) { - decl_enum_item *i = calloc(1, sizeof(*i)); +struct psi_decl_enum_item *psi_decl_enum_item_init(const char *name, + struct psi_num_exp *num) +{ + struct psi_decl_enum_item *i = calloc(1, sizeof(*i)); i->name = strdup(name); i->num = num; return i; } -void free_decl_enum_item(decl_enum_item *i) { - if (i->token) { - free(i->token); +void psi_decl_enum_item_free(struct psi_decl_enum_item **i_ptr) +{ + if (*i_ptr) { + struct psi_decl_enum_item *i = *i_ptr; + + *i_ptr = NULL; + if (i->token) { + free(i->token); + } + if (i->num && i->num != &i->inc) { + psi_num_exp_free(&i->num); + } + free(i->name); + free(i); + } +} + +void psi_decl_enum_item_dump(int fd, struct psi_decl_enum_item *item) +{ + dprintf(fd, "%s", item->name); + if (item->num && item->num != &item->inc) { + dprintf(fd, " = "); + psi_num_exp_dump(fd, item->num); } - if (i->num && i->num != &i->inc) { - free_num_exp(i->num); +} + +bool psi_decl_enum_item_validate(struct psi_data *data, + struct psi_decl_enum *enm, struct psi_decl_enum_item *item, size_t seq) +{ + if (!item->num) { + if (seq) { + item->inc.type = PSI_T_INT64; + item->inc.data.ival.i64 = 1; + item->inc.op = PSI_T_PLUS; + item->inc.operand = item->prev->num ? : &item->prev->inc; + item->num = &item->inc; + } else { + item->inc.type = PSI_T_INT64; + item->inc.data.ival.i64 = 0; + item->num = &item->inc; + } + } + + if (!psi_num_exp_validate(data, item->num, NULL, NULL, NULL, NULL, enm)) { + return false; } - free(i->name); - free(i); + + item->val = psi_long_num_exp(item->num, NULL); + + return true; } diff --git a/src/types/decl_enum_item.h b/src/types/decl_enum_item.h index 802d535..4a3e9a7 100644 --- a/src/types/decl_enum_item.h +++ b/src/types/decl_enum_item.h @@ -1,18 +1,48 @@ -#ifndef _PSI_TYPES_DECL_ENUM_ITEM_H -#define _PSI_TYPES_DECL_ENUM_ITEM_H +/******************************************************************************* + Copyright (c) 2016, Michael Wallner . + All rights reserved. -#include "token.h" -#include "num_exp.h" + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: -typedef struct decl_enum_item { + * 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_TYPES_DECL_ENUM_ITEM_H +#define PSI_TYPES_DECL_ENUM_ITEM_H + +struct psi_data; +struct psi_token; +struct psi_num_exp; +struct psi_decl_enum; + +struct psi_decl_enum_item { struct psi_token *token; char *name; - num_exp *num; - num_exp inc; - struct decl_enum_item *prev; -} decl_enum_item; + int64_t val; + struct psi_num_exp inc; + struct psi_num_exp *num; + struct psi_decl_enum_item *prev; +}; -decl_enum_item *init_decl_enum_item(const char *name, num_exp *num); -void free_decl_enum_item(decl_enum_item *i); +struct psi_decl_enum_item *psi_decl_enum_item_init(const char *name, struct psi_num_exp *num); +void psi_decl_enum_item_free(struct psi_decl_enum_item **i_ptr); +void psi_decl_enum_item_dump(int fd, struct psi_decl_enum_item *item); +bool psi_decl_enum_item_validate(struct psi_data *data, struct psi_decl_enum *enm, struct psi_decl_enum_item *item, size_t seq); #endif diff --git a/src/types/decl_enum_items.c b/src/types/decl_enum_items.c deleted file mode 100644 index 1ddeed9..0000000 --- a/src/types/decl_enum_items.c +++ /dev/null @@ -1,83 +0,0 @@ -/******************************************************************************* - Copyright (c) 2016, Michael Wallner . - 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. -*******************************************************************************/ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif - -#include -#include - -#include "decl_enum_items.h" - -decl_enum_items *init_decl_enum_items(decl_enum_item *i) { - decl_enum_items *l = calloc(1, sizeof(*l)); - if (i) { - l->count = 1; - l->list = calloc(1, sizeof(*l->list)); - l->list[0] = i; - } - return l; -} - -decl_enum_items *add_decl_enum_item(decl_enum_items *l, decl_enum_item *i) { - l->list = realloc(l->list, sizeof(*l->list) * (l->count + 1)); - l->list[l->count] = i; - if (l->count) { - i->prev = l->list[l->count - 1]; - } - ++l->count; - return l; -} - -void free_decl_enum_items(decl_enum_items *l) { - if (l->list) { - size_t j; - for (j = 0; j < l->count; ++j) { - free_decl_enum_item(l->list[j]); - } - free(l->list); - } - free(l); -} - -void dump_decl_enum_items(int fd, decl_enum_items *items, unsigned level) { - size_t i; - for (i = 0; i < items->count; ++i) { - decl_enum_item *item = items->list[i]; - - if (i) { - dprintf(fd, ",\n"); - } - dprintf(fd, "%s", psi_t_indent(level+1)); - dprintf(fd, "%s", item->name); - if (item->num && item->num != &item->inc) { - dprintf(fd, " = "); - dump_num_exp(fd, item->num); - } - } -} diff --git a/src/types/decl_enum_items.h b/src/types/decl_enum_items.h deleted file mode 100644 index c52996f..0000000 --- a/src/types/decl_enum_items.h +++ /dev/null @@ -1,41 +0,0 @@ -/******************************************************************************* - Copyright (c) 2016, Michael Wallner . - 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_TYPES_DECL_ENUM_ITEMS_H -#define PSI_TYPES_DECL_ENUM_ITEMS_H - -#include "decl_enum_item.h" - -typedef struct decl_enum_items { - decl_enum_item **list; - size_t count; -} decl_enum_items; - -decl_enum_items *init_decl_enum_items(decl_enum_item *i); -decl_enum_items *add_decl_enum_item(decl_enum_items *l, decl_enum_item *i); -void free_decl_enum_items(decl_enum_items *l); -void dump_decl_enum_items(int fd, decl_enum_items *i, unsigned level); - -#endif diff --git a/src/types/decl_enums.c b/src/types/decl_enums.c deleted file mode 100644 index 28933bf..0000000 --- a/src/types/decl_enums.c +++ /dev/null @@ -1,69 +0,0 @@ -/******************************************************************************* - Copyright (c) 2016, Michael Wallner . - 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. -*******************************************************************************/ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif - -#include -#include - -#include "decl_enums.h" -#include "decl_type.h" - -decl_enums *add_decl_enum(decl_enums *es, decl_enum *e) { - if (!es) { - es = calloc(1, sizeof(*es)); - } - es->list = realloc(es->list, ++es->count * sizeof(*es->list)); - es->list[es->count - 1] = e; - return es; -} - -void free_decl_enums(decl_enums *es) { - if (es->list) { - size_t j; - for (j = 0; j < es->count; ++j) { - free_decl_enum(es->list[j]); - } - } - free(es->list); - free(es); -} - -void dump_decl_enums(int fd, decl_enums *enums) { - size_t i; - - for (i = 0; i < enums->count; ++i) { - decl_enum *e = enums->list[i]; - - if (!is_anon_type(e->name, "enum")) { - dump_decl_enum(fd, e, 0); - dprintf(fd, "\n"); - } - } -} diff --git a/src/types/decl_enums.h b/src/types/decl_enums.h deleted file mode 100644 index 2583538..0000000 --- a/src/types/decl_enums.h +++ /dev/null @@ -1,40 +0,0 @@ -/******************************************************************************* - Copyright (c) 2016, Michael Wallner . - 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_TYPES_DECL_ENUMS_H -#define PSI_TYPES_DECL_ENUMS_H - -#include "decl_enum.h" - -typedef struct decl_enums { - decl_enum **list; - size_t count; -} decl_enums; - -decl_enums *add_decl_enum(decl_enums *es, decl_enum *e); -void free_decl_enums(decl_enums *es); -void dump_decl_enums(int fd, decl_enums *es); - -#endif diff --git a/src/types/decl_file.c b/src/types/decl_file.c index 8bd7936..c425705 100644 --- a/src/types/decl_file.c +++ b/src/types/decl_file.c @@ -5,11 +5,11 @@ 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. + * 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 @@ -21,22 +21,15 @@ 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. -*******************************************************************************/ + *******************************************************************************/ -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif +#include "php_psi_stdinc.h" +#include "data.h" -#include -#include -#include #include -#include "data.h" - -void free_decl_file(decl_file* file) { +void psi_decl_file_dtor(struct psi_decl_file *file) +{ if (file->ln) { free(file->ln); } @@ -46,26 +39,40 @@ void free_decl_file(decl_file* file) { memset(file, 0, sizeof(*file)); } -int validate_file(struct psi_data *data, void **dlopened) { +bool psi_decl_file_validate(struct psi_data *dst, struct psi_data *src, void **dlopened) +{ char lib[MAXPATHLEN]; - const char *ptr = data->psi.file.ln; + const char *ptr = src->file.ln; size_t len; if (!ptr) { /* FIXME: assume stdlib */ - return 1; + return true; } else if (!strchr(ptr, '/')) { len = snprintf(lib, MAXPATHLEN, "lib%s.%s", ptr, PHP_PSI_SHLIB_SUFFIX); if (MAXPATHLEN == len) { - data->error(data, NULL, PSI_WARNING, "Library name too long: '%s'", ptr); + dst->error(dst, NULL, PSI_WARNING, "Library name too long: '%s'", + ptr); } lib[len] = 0; ptr = lib; } - if (!(*dlopened = dlopen(ptr, RTLD_LAZY|RTLD_LOCAL))) { - data->error(data, NULL, PSI_WARNING, "Could not open library '%s': %s.", - data->psi.file.ln, dlerror()); - return 0; + if (!(*dlopened = dlopen(ptr, RTLD_LAZY | RTLD_LOCAL))) { + dst->error(dst, NULL, PSI_WARNING, "Could not open library '%s': %s.", + src->file.ln, dlerror()); + return false; + } + + if (!dst->libs) { + dst->libs = psi_plist_init((psi_plist_dtor) psi_libs_free); + } + dst->libs = psi_plist_add(dst->libs, dlopened); + + return true; +} + +void psi_libs_free(void **dlopened) { + if (*dlopened) { + dlclose(*dlopened); } - return 1; } diff --git a/src/types/decl_file.h b/src/types/decl_file.h index bc853f2..63fc2ef 100644 --- a/src/types/decl_file.h +++ b/src/types/decl_file.h @@ -26,15 +26,16 @@ #ifndef PSI_TYPES_DECL_FILE_H #define PSI_TYPES_DECL_FILE_H -typedef struct decl_file { +struct psi_data; + +struct psi_decl_file { char *ln; char *fn; -} decl_file; +}; -void free_decl_file(decl_file *file); - -struct psi_data; +void psi_decl_file_dtor(struct psi_decl_file *file); +bool psi_decl_file_validate(struct psi_data *dst, struct psi_data *src, void **dlopened); -int validate_file(struct psi_data *data, void **dlopened); +void psi_libs_free(void **dlopened); #endif diff --git a/src/types/decl_libs.c b/src/types/decl_libs.c deleted file mode 100644 index 7a35f8b..0000000 --- a/src/types/decl_libs.c +++ /dev/null @@ -1,55 +0,0 @@ -/******************************************************************************* - Copyright (c) 2016, Michael Wallner . - 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. -*******************************************************************************/ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif - -#include -#include -#include -#include - -#include "decl_libs.h" - -void free_decl_libs(decl_libs *libs) { - if (libs->dl) { - size_t i; - for (i = 0; i < libs->count; ++i) { - if (libs->dl[i]) { - dlclose(libs->dl[i]); - } - } - free(libs->dl); - } - memset(libs, 0, sizeof(*libs)); -} - -void add_decl_lib(decl_libs *libs, void *dlopened) { - libs->dl = realloc(libs->dl, ++libs->count * sizeof(*libs->dl)); - libs->dl[libs->count - 1] = dlopened; -} diff --git a/src/types/decl_libs.h b/src/types/decl_libs.h deleted file mode 100644 index 1bfce0e..0000000 --- a/src/types/decl_libs.h +++ /dev/null @@ -1,37 +0,0 @@ -/******************************************************************************* - Copyright (c) 2016, Michael Wallner . - 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_TYPES_DECL_LIBS_H -#define PSI_TYPES_DECL_LIBS_H - -typedef struct decl_libs { - void **dl; - size_t count; -} decl_libs; - -void free_decl_libs(decl_libs *libs); -void add_decl_lib(decl_libs *libs, void *dlopened); - -#endif diff --git a/src/types/decl_struct.c b/src/types/decl_struct.c index 522e405..bdee3fe 100644 --- a/src/types/decl_struct.c +++ b/src/types/decl_struct.c @@ -5,11 +5,11 @@ 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. + * 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 @@ -21,86 +21,84 @@ 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. -*******************************************************************************/ + *******************************************************************************/ -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif +#include "php_psi_stdinc.h" +#include "data.h" -#include -#include -#include #include -#include "data.h" - -decl_struct* init_decl_struct(const char* name, decl_args* args) { - decl_struct* s = calloc(1, sizeof(*s)); +struct psi_decl_struct* psi_decl_struct_init(const char *name, + struct psi_plist *args) +{ + struct psi_decl_struct *s = calloc(1, sizeof(*s)); s->name = strdup(name); s->args = args; return s; } -void free_decl_struct(decl_struct* s) { - if (s->token) { - free(s->token); - } - if (s->args) { - free_decl_args(s->args); - } - if (s->engine.type && s->engine.dtor) { - s->engine.dtor(s->engine.type); +void psi_decl_struct_free(struct psi_decl_struct **s_ptr) +{ + if (*s_ptr) { + struct psi_decl_struct *s = *s_ptr; + + *s_ptr = NULL; + if (s->token) { + free(s->token); + } + if (s->args) { + psi_plist_free(s->args); + } + if (s->engine.type && s->engine.dtor) { + s->engine.dtor(s->engine.type); + } + free(s->name); + free(s); } - free(s->name); - free(s); } -void dump_decl_struct(int fd, decl_struct *strct) { - dprintf(fd, "struct %s::(%zu, %zu)", strct->name, strct->align, strct->size); - if (strct->args && strct->args->count) { - dump_decl_args_with_layout(fd, strct->args, 0); +void psi_decl_struct_dump(int fd, struct psi_decl_struct *strct) +{ + dprintf(fd, "struct %s::(%zu, %zu)", strct->name, strct->align, + strct->size); + if (psi_plist_count(strct->args)) { + psi_decl_type_dump_args_with_layout(fd, strct->args, 0); } else { dprintf(fd, ";"); } } -decl_arg *locate_decl_struct_member(decl_struct *s, decl_var *var) { +struct psi_decl_arg *psi_decl_struct_get_arg(struct psi_decl_struct *s, + struct psi_decl_var *var) +{ if (s->args) { - return locate_decl_var_arg(var, s->args, NULL); + return psi_decl_arg_get_by_var(var, s->args, NULL); } return NULL; } -int validate_decl_struct(struct psi_data *data, decl_struct *s) { +bool psi_decl_struct_validate(struct psi_data *data, struct psi_decl_struct *s) +{ size_t i, pos, len, size, align; + struct psi_decl_arg *darg, *prev_arg; - if (!s->size && !s->args->count) { + if (!s->size && !psi_plist_count(s->args)) { data->error(data, s->token, PSI_WARNING, - "Cannot compute size of empty struct '%s'", - s->name); - return 0; + "Cannot compute size of empty struct '%s'", s->name); + return false; } - for (i = 0; i < s->args->count; ++i) { - decl_arg *darg = s->args->args[i]; + for (i = 0; psi_plist_get(s->args, i, &darg); ++i) { + darg->var->arg = darg; - if (!validate_decl_arg(data, darg)) { - return 0; + if (!psi_decl_arg_validate(data, darg)) { + return false; } - assert(!darg->var->arg || darg->var->arg == darg); - - darg->var->arg = darg; - - if (!validate_decl_arg_args(data, darg, s)) { - return 0; - } else if (darg->layout) { + if (darg->layout) { pos = darg->layout->pos; - - align = align_decl_arg(darg, &pos, &len); + align = psi_decl_arg_align(darg, &pos, &len); if (darg->layout->len != len) { data->error(data, darg->token, PSI_WARNING, @@ -115,27 +113,26 @@ int validate_decl_struct(struct psi_data *data, decl_struct *s) { " pre-defined offset %zu", pos, s->name, darg->var->name, darg->layout->pos); } - } else { + } else { if (i) { - pos = s->args->args[i-1]->layout->pos + - s->args->args[i-1]->layout->len; + pos = prev_arg->layout->pos + prev_arg->layout->len; } else { pos = 0; } - align = align_decl_arg(darg, &pos, &len); - darg->layout = init_decl_struct_layout(pos, len); + align = psi_decl_arg_align(darg, &pos, &len); + darg->layout = psi_layout_init(pos, len); } if (align > s->align) { s->align = align; } + prev_arg = darg; } - sort_decl_args(s->args); - - if (s->args->count) { - decl_arg *darg = s->args->args[s->args->count-1]; + if (psi_plist_count(s->args)) { + psi_plist_sort(s->args, psi_layout_sort_cmp, NULL); + psi_plist_get(s->args, psi_plist_count(s->args) - 1, &darg); size = darg->layout->pos + darg->layout->len; if (s->size < size) { @@ -143,12 +140,13 @@ int validate_decl_struct(struct psi_data *data, decl_struct *s) { } } - return 1; + return true; } -size_t alignof_decl_struct(decl_struct *s) { +size_t psi_decl_struct_get_align(struct psi_decl_struct *s) +{ if (!s->align) { - s->align = alignof_decl_args(s->args); + s->align = psi_decl_type_get_args_align(s->args); } return s->align; } diff --git a/src/types/decl_struct.h b/src/types/decl_struct.h index e72aa38..4ac9e8c 100644 --- a/src/types/decl_struct.h +++ b/src/types/decl_struct.h @@ -26,30 +26,30 @@ #ifndef PSI_TYPES_DECL_STRUCT_H #define PSI_TYPES_DECL_STRUCT_H -#include "decl_args.h" +struct psi_data; +struct psi_token; +struct psi_plist; +struct psi_decl_var; -typedef struct decl_struct { +struct psi_decl_struct { struct psi_token *token; char *name; - decl_args *args; + struct psi_plist *args; size_t size; size_t align; struct { void *type; void (*dtor)(void *type); } engine; -} decl_struct; - -decl_struct *init_decl_struct(const char *name, decl_args *args); -void free_decl_struct(decl_struct *s); -void dump_decl_struct(int fd, decl_struct *strct); +}; -decl_arg *locate_decl_struct_member(decl_struct *s, decl_var *var); - -struct psi_data; +struct psi_decl_struct *psi_decl_struct_init(const char *name, struct psi_plist *args); +void psi_decl_struct_free(struct psi_decl_struct **s_ptr); +void psi_decl_struct_dump(int fd, struct psi_decl_struct *strct); -int validate_decl_struct(struct psi_data *data, decl_struct *s); +bool psi_decl_struct_validate(struct psi_data *data, struct psi_decl_struct *s); -size_t alignof_decl_struct(decl_struct *s); +struct psi_decl_arg *psi_decl_struct_get_arg(struct psi_decl_struct *s, struct psi_decl_var *var); +size_t psi_decl_struct_get_align(struct psi_decl_struct *s); #endif diff --git a/src/types/decl_structs.c b/src/types/decl_structs.c deleted file mode 100644 index d479a4a..0000000 --- a/src/types/decl_structs.c +++ /dev/null @@ -1,67 +0,0 @@ -/******************************************************************************* - Copyright (c) 2016, Michael Wallner . - 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. -*******************************************************************************/ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif - -#include -#include - -#include "decl_structs.h" -#include "decl_type.h" - -decl_structs *add_decl_struct(decl_structs *ss, decl_struct *s) { - if (!ss) { - ss = calloc(1, sizeof(*ss)); - } - ss->list = realloc(ss->list, ++ss->count * sizeof(*ss->list)); - ss->list[ss->count - 1] = s; - return ss; -} - -void free_decl_structs(decl_structs *ss) { - size_t i; - for (i = 0; i < ss->count; ++i) { - free_decl_struct(ss->list[i]); - } - free(ss->list); - free(ss); -} - -void dump_decl_structs(int fd, decl_structs *ss) { - size_t i; - - for (i = 0; i < ss->count; ++i) { - decl_struct *strct = ss->list[i]; - - if (!is_anon_type(strct->name, "struct")) { - dump_decl_struct(fd, strct); - dprintf(fd, "\n"); - } - } -} diff --git a/src/types/decl_structs.h b/src/types/decl_structs.h deleted file mode 100644 index 251d986..0000000 --- a/src/types/decl_structs.h +++ /dev/null @@ -1,40 +0,0 @@ -/******************************************************************************* - Copyright (c) 2016, Michael Wallner . - 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_TYPES_DECL_STRUCTS_H -#define PSI_TYPES_DECL_STRUCTS_H - -#include "decl_struct.h" - -typedef struct decl_structs { - size_t count; - decl_struct **list; -} decl_structs; - -decl_structs *add_decl_struct(decl_structs *ss, decl_struct *s); -void free_decl_structs(decl_structs *ss); -void dump_decl_structs(int fd, decl_structs *ss); - -#endif diff --git a/src/types/decl_type.c b/src/types/decl_type.c index c7b19b6..4f494d6 100644 --- a/src/types/decl_type.c +++ b/src/types/decl_type.c @@ -5,11 +5,11 @@ 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. + * 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 @@ -21,46 +21,48 @@ 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. -*******************************************************************************/ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif - -#include -#include + *******************************************************************************/ +#include "php_psi_stdinc.h" #include "token.h" #include "php_psi_stdtypes.h" - #include "data.h" -decl_type *init_decl_type(token_t type, const char *name) { - decl_type *t = calloc(1, sizeof(*t)); +struct psi_decl_type *psi_decl_type_init(token_t type, const char *name) +{ + struct psi_decl_type *t = calloc(1, sizeof(*t)); t->type = type; t->name = strdup(name); return t; } -void free_decl_type(decl_type *type) { - if (type->token) { - free(type->token); - } - if (type->type == PSI_T_FUNCTION) { - free_decl(type->real.func); +void psi_decl_type_free(struct psi_decl_type **type_ptr) +{ + if (*type_ptr) { + struct psi_decl_type *type = *type_ptr; + + *type_ptr = NULL; + if (type->token) { + free(type->token); + } + if (type->type == PSI_T_FUNCTION) { + psi_decl_free(&type->real.func); + } + free(type->name); + free(type); } - free(type->name); - free(type); } -decl_args *extract_decl_type_args(decl_type *dtyp, decl_type **real_typ_ptr) { - decl_type *var_typ; - var_typ = real_decl_type(dtyp); +struct psi_plist *psi_decl_type_get_args(struct psi_decl_type *dtyp, + struct psi_decl_type **real_typ_ptr) +{ + struct psi_decl_type *var_typ; + + var_typ = psi_decl_type_get_real(dtyp); if (real_typ_ptr) { *real_typ_ptr = var_typ; } + switch (var_typ->type) { case PSI_T_STRUCT: return var_typ->real.strct->args; @@ -71,12 +73,16 @@ decl_args *extract_decl_type_args(decl_type *dtyp, decl_type **real_typ_ptr) { } } -size_t extract_decl_type_size(decl_type *dtyp, decl_type **real_typ_ptr) { - decl_type *var_typ; - var_typ = real_decl_type(dtyp); +size_t psi_decl_type_get_size(struct psi_decl_type *dtyp, + struct psi_decl_type **real_typ_ptr) +{ + struct psi_decl_type *var_typ; + + var_typ = psi_decl_type_get_real(dtyp); if (real_typ_ptr) { *real_typ_ptr = var_typ; } + switch (var_typ->type) { case PSI_T_STRUCT: return var_typ->real.strct->size; @@ -87,134 +93,183 @@ size_t extract_decl_type_size(decl_type *dtyp, decl_type **real_typ_ptr) { } } - - -int locate_decl_type_alias(decl_typedefs *defs, decl_type *type) { - size_t i; +bool psi_decl_type_get_alias(struct psi_decl_type *type, struct psi_plist *defs) +{ + size_t i = 0; struct psi_std_type *stdtyp; + struct psi_decl_arg *def; if (type->real.def) { - return 1; + return true; } - if (defs) for (i = 0; i < defs->count; ++i) { - decl_arg *def = defs->list[i]; - - if (def->type->type != type->type && !strcmp(def->var->name, type->name)) { - type->real.def = def; - return 1; + if (defs) + while (psi_plist_get(defs, i++, &def)) { + if (def->type->type != type->type + && !strcmp(def->var->name, type->name)) { + type->real.def = def; + return true; + } } - } for (stdtyp = &psi_std_types[0]; stdtyp->type_tag; ++stdtyp) { if (!strcmp(type->name, stdtyp->alias ?: stdtyp->type_name)) { type->type = stdtyp->type_tag; - return 1; + return true; } } - return 0; + return false; } -int locate_decl_type_struct(decl_structs *structs, decl_type *type) { - size_t i; +bool psi_decl_type_get_struct(struct psi_decl_type *type, struct psi_plist *structs) +{ + size_t i = 0; + struct psi_decl_struct *s; if (type->real.strct) { - return 1; + return true; } - if (structs) for (i = 0; i < structs->count; ++i) { - if (!strcmp(structs->list[i]->name, type->name)) { - type->real.strct = structs->list[i]; - return 1; + if (structs) { + while (psi_plist_get(structs, i++, &s)) { + if (!strcmp(s->name, type->name)) { + type->real.strct = s; + return true; + } } } - return 0; + return false; } -int locate_decl_type_union(decl_unions *unions, decl_type *type) { - size_t i; +bool psi_decl_type_get_union(struct psi_decl_type *type, struct psi_plist *unions) +{ + size_t i = 0; + struct psi_decl_union *u; if (type->real.unn) { - return 1; + return true; } - if (unions) for (i = 0; i < unions->count; ++i) { - if (!strcmp(unions->list[i]->name, type->name)) { - type->real.unn = unions->list[i]; - return 1; + if (unions) { + while (psi_plist_get(unions, i++, &u)) { + if (!strcmp(u->name, type->name)) { + type->real.unn = u; + return true; + } } } - return 0; + return false; } -int locate_decl_type_enum(decl_enums *enums, decl_type *type) { - size_t i; +bool psi_decl_type_get_enum(struct psi_decl_type *type, struct psi_plist *enums) +{ + size_t i = 0; + struct psi_decl_enum *e; if (type->real.enm) { - return 1; + return true; } - if (enums) for (i = 0; i < enums->count; ++i) { - if (!strcmp(enums->list[i]->name, type->name)) { - type->real.enm = enums->list[i]; - return 1; + if (enums) { + while (psi_plist_get(enums, i++, &e)) { + if (!strcmp(e->name, type->name)) { + type->real.enm = e; + return true; + } } } - return 0; + return false; } -int locate_decl_type_decl(decls *decls, decl_type *type) { - size_t i; +bool psi_decl_type_get_decl(struct psi_decl_type *type, struct psi_plist *decls) +{ + size_t i = 0; + struct psi_decl *decl; if (type->real.func) { - return 1; + return true; } - if (decls) for (i = 0; i < decls->count; ++i) { - if (!strcmp(decls->list[i]->func->var->name, type->name)) { - type->real.func = decls->list[i]; - return 1; + if (decls) { + while (psi_plist_get(decls, i++, &decl)) { + if (!strcmp(decl->func->var->name, type->name)) { + type->real.func = decl; + return true; + } } } - - return 0; + return false; } -int validate_decl_type(struct psi_data *data, decl_type *type, decl_arg *def) { - if (weak_decl_type(type)) { - if (!locate_decl_type_alias(data->defs, type)) { - return 0; +bool psi_decl_type_validate(struct psi_data *data, struct psi_decl_type *type, + struct psi_decl_arg *def) +{ + if (psi_decl_type_is_weak(type)) { + if (!psi_decl_type_get_alias(type, data->types)) { + return false; } if (type->real.def) { - return validate_decl_type(data, type->real.def->type, type->real.def); + return psi_decl_type_validate(data, type->real.def->type, + type->real.def); } - return 1; + return true; } switch (type->type) { case PSI_T_STRUCT: - if (!locate_decl_type_struct(data->structs, type)) { - return 0; + if (!psi_decl_type_get_struct(type, data->structs) && !def) { + data->error(data, type->token, PSI_WARNING, + "Unknown struct '%s'", type->name); + return false; } break; case PSI_T_UNION: - if (!locate_decl_type_union(data->unions, type)) { - return 0; + if (!psi_decl_type_get_union(type, data->unions) && !def) { + data->error(data, type->token, PSI_WARNING, + "Unknown union '%s'", type->name); + return false; } break; case PSI_T_ENUM: - if (!locate_decl_type_enum(data->enums, type)) { - return 0; + if (!psi_decl_type_get_enum(type, data->enums) && !def) { + data->error(data, type->token, PSI_WARNING, + "Unknown enum '%s'", type->name); + return false; } break; case PSI_T_FUNCTION: - if (!locate_decl_type_decl(data->decls, type)) { - return 0; + if (!psi_decl_type_get_decl(type, data->decls)) { + data->error(data, type->token, PSI_WARNING, + "Unknown decl '%s'", type->name); + return false; } - if (!validate_decl_nodl(data, type->real.func)) { - return 0; + if (!psi_decl_validate_nodl(data, type->real.func)) { + return false; } break; } - return 1; + return true; } -void dump_decl_type(int fd, decl_type *t, unsigned level) { +void psi_decl_type_dump_args_with_layout(int fd, struct psi_plist *args, + unsigned level) +{ + size_t i = 0; + + dprintf(fd, " {\n"); + if (args) { + struct psi_decl_arg *sarg; + + ++level; + while (psi_plist_get(args, i++, &sarg)) { + dprintf(fd, "%s", psi_t_indent(level)); + psi_decl_arg_dump(fd, sarg, level); + dprintf(fd, "::(%zu, %zu);\n", sarg->layout->pos, + sarg->layout->len); + } + --level; + } + dprintf(fd, "%s", psi_t_indent(level)); + dprintf(fd, "}"); +} + +void psi_decl_type_dump(int fd, struct psi_decl_type *t, unsigned level) +{ switch (t->type) { case PSI_T_POINTER: dprintf(fd, "%s *", t->name); @@ -222,24 +277,37 @@ void dump_decl_type(int fd, decl_type *t, unsigned level) { case PSI_T_ENUM: dprintf(fd, "enum "); - if (is_anon_type(t->name, "enum")) { - dump_decl_enum_items(fd, t->real.enm->items, level); + if (psi_decl_type_is_anon(t->name, "enum")) { + size_t i = 0, c = psi_plist_count(t->real.enm->items); + struct psi_decl_enum_item *item; + + dprintf(fd, "{\n"); + ++level; + while (psi_plist_get(t->real.enm->items, i++, &item)) { + dprintf(fd, "%s", psi_t_indent(level)); + psi_decl_enum_item_dump(fd, item); + if (i < c) { + dprintf(fd, "%s\n", i < c ? "," : ""); + } + } + --level; + dprintf(fd, "%s} ", psi_t_indent(level)); return; } break; case PSI_T_STRUCT: dprintf(fd, "struct "); - if (is_anon_type(t->name, "struct")) { - dump_decl_args_with_layout(fd, t->real.strct->args, level); + if (psi_decl_type_is_anon(t->name, "struct")) { + psi_decl_type_dump_args_with_layout(fd, t->real.strct->args, level); return; } break; case PSI_T_UNION: dprintf(fd, "union "); - if (is_anon_type(t->name, "union")) { - dump_decl_args_with_layout(fd, t->real.unn->args, level); + if (psi_decl_type_is_anon(t->name, "union")) { + psi_decl_type_dump_args_with_layout(fd, t->real.unn->args, level); return; } break; @@ -247,7 +315,8 @@ void dump_decl_type(int fd, decl_type *t, unsigned level) { dprintf(fd, "%s", t->name); } -int weak_decl_type(decl_type *type) { +int psi_decl_type_is_weak(struct psi_decl_type *type) +{ switch (type->type) { case PSI_T_CHAR: case PSI_T_SHORT: @@ -260,23 +329,25 @@ int weak_decl_type(decl_type *type) { } } -decl_type *real_decl_type(decl_type *type) { - while (weak_decl_type(type) && type->real.def) { +struct psi_decl_type *psi_decl_type_get_real(struct psi_decl_type *type) +{ + while (psi_decl_type_is_weak(type) && type->real.def) { type = type->real.def->type; } return type; } -size_t alignof_decl_type(decl_type *t) { - decl_type *real = real_decl_type(t); +size_t psi_decl_type_get_align(struct psi_decl_type *t) +{ + struct psi_decl_type *real = psi_decl_type_get_real(t); size_t align; switch (real->type) { case PSI_T_STRUCT: - align = alignof_decl_struct(real->real.strct); + align = psi_decl_struct_get_align(real->real.strct); break; case PSI_T_UNION: - align = alignof_decl_union(real->real.unn); + align = psi_decl_union_get_align(real->real.unn); break; case PSI_T_ENUM: default: @@ -285,3 +356,20 @@ size_t alignof_decl_type(decl_type *t) { return align; } + +size_t psi_decl_type_get_args_align(struct psi_plist *args) +{ + size_t i = 0, maxalign = 0; + struct psi_decl_arg *darg; + + while (psi_plist_get(args, i++, &darg)) { + size_t align = psi_decl_arg_get_align(darg); + + if (align > maxalign) { + maxalign = align; + } + } + + return maxalign; +} + diff --git a/src/types/decl_type.h b/src/types/decl_type.h index 4f88ef9..f5aa4dc 100644 --- a/src/types/decl_type.h +++ b/src/types/decl_type.h @@ -28,48 +28,52 @@ #include "token.h" -typedef struct decl_type { +struct psi_data; +struct psi_token; +struct psi_plist; +struct psi_decl_arg; +struct psi_decl_struct; +struct psi_decl_union; +struct psi_decl_enum; +struct psi_decl; + +struct psi_decl_type { struct psi_token *token; char *name; token_t type; union { - struct decl_arg *def; - struct decl_struct *strct; - struct decl_union *unn; - struct decl_enum *enm; - struct decl *func; + struct psi_decl_arg *def; + struct psi_decl_struct *strct; + struct psi_decl_union *unn; + struct psi_decl_enum *enm; + struct psi_decl *func; } real; -} decl_type; +}; #include -#define is_anon_type(name, type) !strncmp(name, type "@", sizeof(type)) - -decl_type *init_decl_type(token_t type, const char *name); -void free_decl_type(decl_type *type); -void dump_decl_type(int fd, decl_type *t, unsigned level); +#define psi_decl_type_is_anon(name, type) !strncmp(name, type "@", sizeof(type)) -struct decl_args *extract_decl_type_args(decl_type *dtyp, decl_type** real_typ_ptr); -size_t extract_decl_type_size(decl_type *dtyp, decl_type **real_typ_ptr); +struct psi_decl_type *psi_decl_type_init(token_t type, const char *name); +void psi_decl_type_free(struct psi_decl_type **type_ptr); +void psi_decl_type_dump(int fd, struct psi_decl_type *t, unsigned level); +bool psi_decl_type_validate(struct psi_data *data, struct psi_decl_type *type, struct psi_decl_arg *def); -int weak_decl_type(decl_type *type); -decl_type *real_decl_type(decl_type *type); +bool psi_decl_type_validate_args(struct psi_data *data, struct psi_decl_type *decl_type, token_t type, void *current); -struct decl_typedefs; -struct decl_structs; -struct decl_unions; -struct decl_enums; -struct decls; +size_t psi_decl_type_get_size(struct psi_decl_type *dtyp, struct psi_decl_type **real_typ_ptr); +size_t psi_decl_type_get_align(struct psi_decl_type *t); +int psi_decl_type_is_weak(struct psi_decl_type *type); +struct psi_decl_type *psi_decl_type_get_real(struct psi_decl_type *type); -int locate_decl_type_alias(struct decl_typedefs *defs, decl_type *type); -int locate_decl_type_struct(struct decl_structs *structs, decl_type *type); -int locate_decl_type_union(struct decl_unions *unions, decl_type *type); -int locate_decl_type_enum(struct decl_enums *enums, decl_type *type); -int locate_decl_type_decl(struct decls *decls, decl_type *type); - -struct psi_data; +struct psi_plist *psi_decl_type_get_args(struct psi_decl_type *dtyp, struct psi_decl_type **real_typ_ptr); +void psi_decl_type_dump_args_with_layout(int fd, struct psi_plist *args, unsigned level); +size_t psi_decl_type_get_args_align(struct psi_plist *args); -int validate_decl_type(struct psi_data *data, decl_type *type, struct decl_arg *def); -size_t alignof_decl_type(decl_type *t); +bool psi_decl_type_get_alias(struct psi_decl_type *type, struct psi_plist *typedefs); +bool psi_decl_type_get_struct(struct psi_decl_type *type, struct psi_plist *structs); +bool psi_decl_type_get_union(struct psi_decl_type *type, struct psi_plist *unions); +bool psi_decl_type_get_enum(struct psi_decl_type *type, struct psi_plist *enums); +bool psi_decl_type_get_decl(struct psi_decl_type *type, struct psi_plist *decls); #endif diff --git a/src/types/decl_typedefs.c b/src/types/decl_typedefs.c deleted file mode 100644 index 8986005..0000000 --- a/src/types/decl_typedefs.c +++ /dev/null @@ -1,98 +0,0 @@ -/******************************************************************************* - Copyright (c) 2016, Michael Wallner . - 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. -*******************************************************************************/ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif - -#include -#include - -#include "data.h" - -decl_typedefs *add_decl_typedef(decl_typedefs *defs, decl_arg *def) { - if (!defs) { - defs = calloc(1, sizeof(*defs)); - } - defs->list = realloc(defs->list, ++defs->count * sizeof(*defs->list)); - defs->list[defs->count - 1] = def; - return defs; -} - -void free_decl_typedefs(decl_typedefs *defs) { - size_t i; - for (i = 0; i < defs->count; ++i) { - free_decl_arg(defs->list[i]); - } - free(defs->list); - free(defs); -} - -static inline void dump_typedef(int fd, decl_arg *tdef) { - dprintf(fd, "typedef "); - dump_decl_arg(fd, tdef, 0); - dprintf(fd, ";"); -} - -void dump_decl_typedefs(int fd, decl_typedefs *defs) { - size_t i; - - for (i = 0; i < defs->count; ++i) { - decl_arg *tdef = defs->list[i]; - - dump_typedef(fd, tdef); - dprintf(fd, "\n"); - } -} - -int validate_decl_typedef(struct psi_data *data, decl_arg *def) { - if (!validate_decl_type(data, def->type, def)) { - const char *pre; - - switch (def->type->type) { - case PSI_T_STRUCT: pre = "struct "; break; - case PSI_T_UNION: pre = "union "; break; - case PSI_T_ENUM: pre = "enum "; break; - default: pre = ""; break; - } - data->error(data, def->token, PSI_WARNING, - "Type '%s' cannot be aliased to %s'%s'", - def->var->name, pre, def->type->name); - return 0; - } - if (def->type->type == PSI_T_VOID) { - if (def->var->pointer_level) { - def->type->type = PSI_T_POINTER; - } else { - data->error(data, def->token, PSI_WARNING, - "Type '%s' cannot be aliased to 'void'", - def->type->name); - return 0; - } - } - return 1; -} diff --git a/src/types/decl_union.c b/src/types/decl_union.c index 7e58cbf..f329997 100644 --- a/src/types/decl_union.c +++ b/src/types/decl_union.c @@ -5,11 +5,11 @@ 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. + * 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 @@ -21,88 +21,86 @@ 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. -*******************************************************************************/ + *******************************************************************************/ -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif +#include "php_psi_stdinc.h" +#include "data.h" -#include -#include -#include #include -#include "data.h" - -decl_union* init_decl_union(const char* name, decl_args* args) { - decl_union* u = calloc(1, sizeof(*u)); +struct psi_decl_union* psi_decl_union_init(const char *name, + struct psi_plist *args) +{ + struct psi_decl_union *u = calloc(1, sizeof(*u)); u->name = strdup(name); u->args = args; return u; } -void free_decl_union(decl_union* u) { - if (u->token) { - free(u->token); - } - if (u->args) { - free_decl_args(u->args); +void psi_decl_union_free(struct psi_decl_union **u_ptr) +{ + if (*u_ptr) { + struct psi_decl_union *u = *u_ptr; + + *u_ptr = NULL; + if (u->token) { + free(u->token); + } + if (u->args) { + psi_plist_free(u->args); + } + free(u->name); + free(u); } - free(u->name); - free(u); } -void dump_decl_union(int fd, decl_union *unn) { +void psi_decl_union_dump(int fd, struct psi_decl_union *unn) +{ dprintf(fd, "union %s::(%zu, %zu)", unn->name, unn->align, unn->size); - if (unn->args && unn->args->count) { - dump_decl_args_with_layout(fd, unn->args, 0); + if (psi_plist_count(unn->args)) { + psi_decl_type_dump_args_with_layout(fd, unn->args, 0); } else { dprintf(fd, ";"); } } -decl_arg *locate_decl_union_member(decl_union *u, decl_var *var) { +struct psi_decl_arg *psi_decl_union_get_arg(struct psi_decl_union *u, + struct psi_decl_var *var) +{ if (u->args) { - return locate_decl_var_arg(var, u->args, NULL); + return psi_decl_arg_get_by_var(var, u->args, NULL); } return NULL; } -int validate_decl_union(struct psi_data *data, decl_union *u) { +bool psi_decl_union_validate(struct psi_data *data, struct psi_decl_union *u) +{ size_t i, pos, len, size = 0, align; + struct psi_decl_arg *darg; - if (!u->size && !u->args->count) { + if (!u->size && !psi_plist_count(u->args)) { data->error(data, u->token, PSI_WARNING, - "Cannot compute size of empty union %s", - u->name); - return 0; + "Cannot compute size of empty union %s", u->name); + return false; } - for (i = 0; i < u->args->count; ++i) { - decl_arg *darg = u->args->args[i]; + for (i = 0; psi_plist_get(u->args, i, &darg); ++i) { + darg->var->arg = darg; - if (!validate_decl_arg(data, darg)) { - return 0; + if (!psi_decl_arg_validate(data, darg)) { + return false; } - assert(!darg->var->arg || darg->var->arg == darg); - - darg->var->arg = darg; - - if (!validate_decl_arg_args(data, darg, u)) { - return 0; - } else if (darg->layout) { + if (darg->layout) { pos = darg->layout->pos; - align = align_decl_arg(darg, &pos, &len); + align = psi_decl_arg_align(darg, &pos, &len); if (darg->layout->pos != 0) { data->error(data, darg->token, PSI_WARNING, - "Offset of %s.%s should be 0", - u->name, darg->var->name); + "Offset of %s.%s should be 0", u->name, + darg->var->name); darg->layout->pos = 0; } if (darg->layout->len != len) { @@ -115,9 +113,8 @@ int validate_decl_union(struct psi_data *data, decl_union *u) { } else { pos = 0; - align = align_decl_arg(darg, &pos, &len); - darg->layout = init_decl_struct_layout(pos, len); - + align = psi_decl_arg_align(darg, &pos, &len); + darg->layout = psi_layout_init(pos, len); } if (len > size) { size = len; @@ -127,18 +124,19 @@ int validate_decl_union(struct psi_data *data, decl_union *u) { } } - sort_decl_args(u->args); + psi_plist_sort(u->args, psi_layout_sort_cmp, NULL); if (u->size < size) { u->size = psi_align(size, u->align); } - return 1; + return true; } -size_t alignof_decl_union(decl_union *u) { +size_t psi_decl_union_get_align(struct psi_decl_union *u) +{ if (!u->align) { - u->align = alignof_decl_args(u->args); + u->align = psi_decl_type_get_args_align(u->args); } return u->align; } diff --git a/src/types/decl_union.h b/src/types/decl_union.h index b914495..619b3f5 100644 --- a/src/types/decl_union.h +++ b/src/types/decl_union.h @@ -25,26 +25,26 @@ #ifndef PSI_TYPES_DECL_UNION_H #define PSI_TYPES_DECL_UNION_H -#include "decl_args.h" +struct psi_data; +struct psi_token; +struct psi_plist; +struct psi_decl_var; -typedef struct decl_union { +struct psi_decl_union { struct psi_token *token; char *name; - decl_args *args; + struct psi_plist *args; size_t size; size_t align; -} decl_union; - -decl_union *init_decl_union(const char *name, decl_args *args); -void free_decl_union(decl_union *u); -void dump_decl_union(int fd, decl_union *unn); +}; -decl_arg *locate_decl_union_member(decl_union *u, decl_var *var); - -struct psi_data; +struct psi_decl_union *psi_decl_union_init(const char *name, struct psi_plist *args); +void psi_decl_union_free(struct psi_decl_union **u_ptr); +void psi_decl_union_dump(int fd, struct psi_decl_union *unn); -int validate_decl_union(struct psi_data *data, decl_union *u); +bool psi_decl_union_validate(struct psi_data *data, struct psi_decl_union *u); -size_t alignof_decl_union(decl_union *u); +size_t psi_decl_union_get_align(struct psi_decl_union *u); +struct psi_decl_arg *psi_decl_union_get_arg(struct psi_decl_union *u, struct psi_decl_var *var); #endif diff --git a/src/types/decl_unions.c b/src/types/decl_unions.c deleted file mode 100644 index 1722f3b..0000000 --- a/src/types/decl_unions.c +++ /dev/null @@ -1,66 +0,0 @@ -/******************************************************************************* - Copyright (c) 2016, Michael Wallner . - 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. -*******************************************************************************/ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif - -#include -#include - -#include - -decl_unions *add_decl_union(decl_unions *uu, decl_union *u) { - if (!uu) { - uu = calloc(1, sizeof(*uu)); - } - uu->list = realloc(uu->list, ++uu->count * sizeof(*uu->list)); - uu->list[uu->count - 1] = u; - return uu; -} - -void free_decl_unions(decl_unions *uu) { - size_t i; - for (i = 0; i < uu->count; ++i) { - free_decl_union(uu->list[i]); - } - free(uu->list); - free(uu); -} - -void dump_decl_unions(int fd, decl_unions *unions) { - size_t i; - - for (i = 0; i < unions->count; ++i) { - decl_union *unn = unions->list[i]; - - if (!is_anon_type(unn->name, "union")) { - dump_decl_union(fd, unn); - dprintf(fd, "\n"); - } - } -} diff --git a/src/types/decl_unions.h b/src/types/decl_unions.h deleted file mode 100644 index 13c254e..0000000 --- a/src/types/decl_unions.h +++ /dev/null @@ -1,40 +0,0 @@ -/******************************************************************************* - Copyright (c) 2016, Michael Wallner . - 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_TYPES_DECL_UNOINS_H -#define PSI_TYPES_DECL_UNOINS_H - -#include "decl_union.h" - -typedef struct decl_unions { - decl_union **list; - size_t count; -} decl_unions; - -decl_unions *add_decl_union(decl_unions *uu, decl_union *u); -void free_decl_unions(decl_unions *uu); -void dump_decl_unions(int fd, decl_unions *unions); - -#endif diff --git a/src/types/decl_var.c b/src/types/decl_var.c index fa495bf..763ea18 100644 --- a/src/types/decl_var.c +++ b/src/types/decl_var.c @@ -5,11 +5,11 @@ 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. + * 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 @@ -21,66 +21,130 @@ 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. -*******************************************************************************/ + *******************************************************************************/ -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif +#include "php_psi_stdinc.h" +#include "data.h" -#include -#include #include -#include "data.h" - -decl_var *init_decl_var(const char *name, unsigned pl, unsigned as) { - decl_var *v = calloc(1, sizeof(*v)); - v->name = (char *) strdup((const char *) name); +struct psi_decl_var *psi_decl_var_init(const char *name, unsigned pl, + unsigned as) +{ + struct psi_decl_var *v = calloc(1, sizeof(*v)); + v->name = strdup(name); + v->fqn = strdup(name); v->pointer_level = pl; v->array_size = as; return v; } -decl_var *copy_decl_var(decl_var *src) { - decl_var *dest = calloc(1, sizeof(*dest)); - memcpy(dest, src, sizeof(*dest)); +struct psi_decl_var *psi_decl_var_copy(struct psi_decl_var *src) +{ + struct psi_decl_var *dest = calloc(1, sizeof(*dest)); + + *dest = *src; dest->name = strdup(dest->name); + dest->fqn = strdup(dest->fqn); + if (dest->token) { dest->token = psi_token_copy(dest->token); } return dest; } -void free_decl_var(decl_var *var) { - if (var->token) { - free(var->token); +void psi_decl_var_free(struct psi_decl_var **var_ptr) +{ + if (*var_ptr) { + struct psi_decl_var *var = *var_ptr; + + *var_ptr = NULL; + if (var->token) { + free(var->token); + } + free(var->name); + free(var->fqn); + free(var); } - free(var->name); - free(var); } -void dump_decl_var(int fd, decl_var *var) { +void psi_decl_var_dump(int fd, struct psi_decl_var *var) +{ dprintf(fd, "%s%s", - psi_t_indirection(var->pointer_level-!!var->array_size), var->name); + psi_t_indirection(var->pointer_level - !!var->array_size), + var->name); if (var->array_size) { dprintf(fd, "[%u]", var->array_size); } } -decl_arg *locate_decl_var_arg(decl_var *var, decl_args *args, decl_arg *func) { - decl_arg *arg = locate_decl_arg(args, var->name); +bool psi_decl_var_validate(struct psi_data *data, struct psi_decl_var *dvar, + struct psi_decl *decl, struct psi_let_exp *let_exp, + struct psi_set_exp *set_exp) +{ + bool okay = false; + struct psi_let_exp *current_let_exp = let_exp; + struct psi_set_exp *current_set_exp = set_exp; + + if (current_let_exp) { + /* walk up the let expression tree until found */ + while ((current_let_exp = current_let_exp->outer)) { + struct psi_decl_var *svar = current_let_exp->var; + - if (arg) { - assert(!var->arg || var->arg == arg); + if (!okay) { + struct psi_plist *args = psi_decl_type_get_args(svar->arg->type, + NULL); - return var->arg = arg; + if (args && psi_decl_arg_get_by_var(dvar, args, NULL)) { + okay = true; + } else if (!strcmp(svar->name, dvar->name)) { + dvar->arg = svar->arg; + okay = true; + } + } + if (okay) { + dvar->fqn = psi_decl_var_name_prepend(dvar->fqn, svar->name); + } + } + } else if (current_set_exp) { + /* walk up the set expression tree until found */ + while ((current_set_exp = current_set_exp->outer)) { + struct psi_decl_var *svar = psi_set_exp_get_decl_var( + current_set_exp); + + if (!okay) { + struct psi_plist *args = psi_decl_type_get_args(svar->arg->type, + NULL); + + if (args && psi_decl_arg_get_by_var(dvar, args, NULL)) { + okay = true; + } else if (!strcmp(svar->name, dvar->name)) { + dvar->arg = svar->arg; + okay = true; + } + } + if (okay) { + dvar->fqn = psi_decl_var_name_prepend(dvar->fqn, svar->name); + } + } + } + + if (decl && !okay && psi_decl_get_arg(decl, dvar)) { + okay = true; } - if (func && !strcmp(var->name, func->var->name)) { - return var->arg = func; + return okay; +} + +size_t psi_decl_var_get_size(struct psi_decl_var *var) +{ + struct psi_decl_var *decl_var = var->arg->var; + size_t pointer_level = decl_var->pointer_level - var->pointer_level; + + if (pointer_level) { + return SIZEOF_VOID_P; } - return NULL; + return psi_decl_type_get_size(var->arg->type, NULL); } diff --git a/src/types/decl_var.h b/src/types/decl_var.h index 8fd75db..ba73321 100644 --- a/src/types/decl_var.h +++ b/src/types/decl_var.h @@ -26,22 +26,43 @@ #ifndef PSI_TYPES_DECL_VAR_H #define PSI_TYPES_DECL_VAR_H -typedef struct decl_var { +struct psi_data; +struct psi_token; +struct psi_decl_arg; +struct psi_let_exp; +struct psi_set_exp; + +struct psi_decl_var { struct psi_token *token; - char *name; + char *name, *fqn; unsigned pointer_level; unsigned array_size; - struct decl_arg *arg; -} decl_var; + struct psi_decl_arg *arg; +}; + +struct psi_decl_var *psi_decl_var_init(const char *name, unsigned pl, unsigned as); +struct psi_decl_var *psi_decl_var_copy(struct psi_decl_var *src); +void psi_decl_var_free(struct psi_decl_var **var_ptr); +void psi_decl_var_dump(int fd, struct psi_decl_var *var); + +#include + +static inline char *psi_decl_var_name_prepend(char *current, const char *prepend) { + size_t c_len = strlen(current); + size_t p_len = strlen(prepend); -decl_var *init_decl_var(const char *name, unsigned pl, unsigned as); -decl_var *copy_decl_var(decl_var *src); -void free_decl_var(decl_var *var); -void dump_decl_var(int fd, decl_var *var); + current = realloc(current, p_len + 1 + c_len + 1); + if (current) { + memmove(current + p_len + 1, current, c_len + 1); + current[p_len] = '.'; + memcpy(current, prepend, p_len); + } + return current; +} -struct decl_arg; -struct decl_args; +bool psi_decl_var_validate(struct psi_data *data, struct psi_decl_var *dvar, struct psi_decl *decl, + struct psi_let_exp *current_let_exp, struct psi_set_exp *current_set_exp); -struct decl_arg *locate_decl_var_arg(decl_var *var, struct decl_args *args, struct decl_arg *func); +size_t psi_decl_var_get_size(struct psi_decl_var *var); #endif diff --git a/src/types/decl_vars.c b/src/types/decl_vars.c deleted file mode 100644 index 38b6e5d..0000000 --- a/src/types/decl_vars.c +++ /dev/null @@ -1,58 +0,0 @@ -/******************************************************************************* - Copyright (c) 2016, Michael Wallner . - 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. -*******************************************************************************/ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include -#include - -#include "decl_vars.h" - -decl_vars *init_decl_vars(decl_var *var) { - decl_vars *vars = calloc(1, sizeof(*vars)); - if (var) { - vars->count = 1; - vars->vars = calloc(1, sizeof(*vars->vars)); - vars->vars[0] = var; - } - return vars; -} - -decl_vars *add_decl_var(decl_vars *vars, decl_var *var) { - vars->vars = realloc(vars->vars, ++vars->count * sizeof(*vars->vars)); - vars->vars[vars->count - 1] = var; - return vars; -} - -void free_decl_vars(decl_vars *vars) { - size_t i; - for (i = 0; i < vars->count; ++i) { - free_decl_var(vars->vars[i]); - } - free(vars->vars); - free(vars); -} diff --git a/src/types/decl_vars.h b/src/types/decl_vars.h deleted file mode 100644 index 22b03e8..0000000 --- a/src/types/decl_vars.h +++ /dev/null @@ -1,40 +0,0 @@ -/******************************************************************************* - Copyright (c) 2016, Michael Wallner . - 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_TYPES_DECL_VARS_H -#define PSI_TYPES_DECL_VARS_H - -#include "decl_var.h" - -typedef struct decl_vars { - decl_var **vars; - size_t count; -} decl_vars; - -decl_vars *init_decl_vars(decl_var *var); -decl_vars *add_decl_var(decl_vars *vars, decl_var *var); -void free_decl_vars(decl_vars *vars); - -#endif diff --git a/src/types/decls.c b/src/types/decls.c deleted file mode 100644 index 2dff0a2..0000000 --- a/src/types/decls.c +++ /dev/null @@ -1,64 +0,0 @@ -/******************************************************************************* - Copyright (c) 2016, Michael Wallner . - 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. -*******************************************************************************/ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif - -#include -#include - -#include "decls.h" - -decls *add_decl(decls *decls, decl *decl) { - if (!decls) { - decls = calloc(1, sizeof(*decls)); - } - decls->list = realloc(decls->list, ++decls->count * sizeof(*decls->list)); - decls->list[decls->count - 1] = decl; - return decls; -} - -void free_decls(decls *decls) { - size_t i; - for (i = 0; i < decls->count; ++i) { - free_decl(decls->list[i]); - } - free(decls->list); - free(decls); -} - -void dump_decls(int fd, decls *decls) { - size_t i; - - for (i = 0; i < decls->count; ++i) { - decl *decl = decls->list[i]; - - dump_decl(fd, decl); - dprintf(fd, "\n"); - } -} diff --git a/src/types/decls.h b/src/types/decls.h deleted file mode 100644 index 9ccae74..0000000 --- a/src/types/decls.h +++ /dev/null @@ -1,40 +0,0 @@ -/******************************************************************************* - Copyright (c) 2016, Michael Wallner . - 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_TYPES_DECLS_H -#define PSI_TYPES_DECLS_H - -#include "decl.h" - -typedef struct decls { - size_t count; - decl **list; -} decls; - -decls *add_decl(decls *decls, decl *decl); -void free_decls(decls *decls); -void dump_decls(int fd, decls *decls); - -#endif diff --git a/src/types/free_call.c b/src/types/free_call.c deleted file mode 100644 index 80f3130..0000000 --- a/src/types/free_call.c +++ /dev/null @@ -1,64 +0,0 @@ -/******************************************************************************* - Copyright (c) 2016, Michael Wallner . - 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. -*******************************************************************************/ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif - -#include -#include -#include - -#include "free_call.h" - -free_call *init_free_call(const char *func, decl_vars *vars) { - free_call *f = calloc(1, sizeof(*f)); - f->func = strdup(func); - f->vars = vars; - return f; -} - -void free_free_call(free_call *f) { - if (f->token) { - free(f->token); - } - free(f->func); - free_decl_vars(f->vars); - free(f); -} - -void dump_free_call(int fd, free_call *call) { - size_t l; - - dprintf(fd, "%s(", call->func); - for (l = 0; l < call->vars->count; ++l) { - decl_var *fvar = call->vars->vars[l]; - - dump_decl_var(fd, fvar); - } - dprintf(fd, ");"); -} diff --git a/src/types/free_calls.c b/src/types/free_calls.c deleted file mode 100644 index 19739df..0000000 --- a/src/types/free_calls.c +++ /dev/null @@ -1,60 +0,0 @@ -/******************************************************************************* - Copyright (c) 2016, Michael Wallner . - 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. -*******************************************************************************/ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif - -#include -#include - -#include "free_calls.h" - -free_calls *init_free_calls(free_call *f) { - free_calls *fcs = calloc(1, sizeof(*fcs)); - if (f) { - fcs->count = 1; - fcs->list = calloc(1, sizeof(*fcs->list)); - fcs->list[0] = f; - } - return fcs; -} - -void free_free_calls(free_calls *fcs) { - size_t i; - for (i = 0; i < fcs->count; ++i) { - free_free_call(fcs->list[i]); - } - free(fcs->list); - free(fcs); -} - -free_calls *add_free_call(free_calls *fcs, free_call *f) { - fcs->list = realloc(fcs->list, ++fcs->count * sizeof(*fcs->list)); - fcs->list[fcs->count - 1] = f; - return fcs; -} diff --git a/src/types/free_calls.h b/src/types/free_calls.h deleted file mode 100644 index 9e156ed..0000000 --- a/src/types/free_calls.h +++ /dev/null @@ -1,40 +0,0 @@ -/******************************************************************************* - Copyright (c) 2016, Michael Wallner . - 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_TYPES_FREE_CALLS_H -#define PSI_TYPES_FREE_CALLS_H - -#include "free_call.h" - -typedef struct free_calls { - free_call **list; - size_t count; -} free_calls; - -free_calls *init_free_calls(free_call *f); -void free_free_calls(free_calls *fcs); -free_calls *add_free_call(free_calls *fcs, free_call *f); - -#endif diff --git a/src/types/free_exp.c b/src/types/free_exp.c new file mode 100644 index 0000000..19c7a60 --- /dev/null +++ b/src/types/free_exp.c @@ -0,0 +1,142 @@ +/******************************************************************************* + Copyright (c) 2016, Michael Wallner . + 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 "call.h" + +struct psi_free_exp *psi_free_exp_init(const char *func, struct psi_plist *vars) +{ + struct psi_free_exp *f = calloc(1, sizeof(*f)); + f->func = strdup(func); + f->vars = vars; + return f; +} + +void psi_free_exp_free(struct psi_free_exp **f_ptr) +{ + if (*f_ptr) { + struct psi_free_exp *f = *f_ptr; + + *f_ptr = NULL; + if (f->token) { + free(f->token); + } + free(f->func); + psi_plist_free(f->vars); + if (f->let) { + free(f->let); + } + free(f); + } +} + +void psi_free_exp_dump(int fd, struct psi_free_exp *call) +{ + size_t l = 0, c = psi_plist_count(call->vars); + struct psi_decl_var *fvar; + + dprintf(fd, "%s(", call->func); + while (psi_plist_get(call->vars, l++, &fvar)) { + psi_decl_var_dump(fd, fvar); + if (l < c) { + dprintf(fd, ", "); + } + } + dprintf(fd, ")"); +} + +static inline struct psi_decl *locate_free_decl(struct psi_plist *decls, + struct psi_free_exp *f) +{ + if (decls) { + size_t i = 0; + struct psi_decl *decl; + + while (psi_plist_get(decls, i++, &decl)) { + if (!strcmp(decl->func->var->name, f->func)) { + return f->decl = decl; + } + } + } + + return NULL; +} + +bool psi_free_exp_validate(struct psi_data *data, struct psi_free_exp *exp, + struct psi_impl *impl) +{ + size_t i; + struct psi_decl_var *free_var; + + /* first find the decl of the free func */ + if (!locate_free_decl(data->decls, exp)) { + data->error(data, exp->token, PSI_WARNING, + "Missing declaration '%s' in `free` statement" + " of implementation '%s'", exp->func, impl->func->name); + return false; + } + + /* now check for known vars */ + exp->let = calloc(psi_plist_count(exp->vars), sizeof(*exp->let)); + for (i = 0; psi_plist_get(exp->vars, i, &free_var); ++i) { + if (!psi_decl_arg_get_by_var(free_var, impl->decl->args, + impl->decl->func)) { + data->error(data, free_var->token, PSI_WARNING, + "Unknown variable '%s' of `free` statement" + " of implementation '%s'", + free_var->name, impl->func->name); + return false; + } + + exp->let[i] = psi_impl_get_let(impl, free_var); + assert(exp->let[i]); + } + + return true; +} + +void psi_free_exp_exec(struct psi_free_exp *f, struct psi_call_frame *frame) +{ + size_t i; + void **args; + struct psi_decl_var *dvar; + struct psi_call_frame *free_call; + + free_call = psi_call_frame_init(frame->context, f->decl, NULL); + psi_call_frame_enter(free_call); + + args = psi_call_frame_get_arg_pointers(free_call); + for (i = 0; psi_plist_get(f->vars, i, &dvar); ++i) { + struct psi_call_frame_symbol *frame_sym; + struct psi_let_exp *let = f->let[i]->exp; + + frame_sym = psi_call_frame_fetch_symbol(frame, let->var); + args[i] = deref_impl_val(frame_sym->ptr, dvar); + } + + psi_call_frame_do_call(free_call); + psi_call_frame_free(free_call); +} diff --git a/src/types/free_call.h b/src/types/free_exp.h similarity index 70% rename from src/types/free_call.h rename to src/types/free_exp.h index 86f2ba7..c295b56 100644 --- a/src/types/free_call.h +++ b/src/types/free_exp.h @@ -23,21 +23,31 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *******************************************************************************/ -#ifndef PSI_TYPES_FREE_CALL_H -#define PSI_TYPES_FREE_CALL_H - -#include "decl_vars.h" -#include "decl.h" - -typedef struct free_call { +#ifndef PSI_TYPES_FREE_EXP_H +#define PSI_TYPES_FREE_EXP_H + +struct psi_data; +struct psi_token; +struct psi_plist; +struct psi_impl; +struct psi_decl; +struct psi_let_stmt; +struct psi_call_frame; + +struct psi_free_exp { struct psi_token *token; char *func; - decl_vars *vars; - decl *decl; -} free_call; + struct psi_plist *vars; + struct psi_decl *decl; + struct psi_let_stmt **let; +}; + +struct psi_free_exp *psi_free_exp_init(const char *func, struct psi_plist *vars); +void psi_free_exp_free(struct psi_free_exp **f_ptr); +void psi_free_exp_dump(int fd, struct psi_free_exp *call); + +bool psi_free_exp_validate(struct psi_data *data, struct psi_free_exp *fc, struct psi_impl *impl); -free_call *init_free_call(const char *func, decl_vars *vars); -void free_free_call(free_call *f); -void dump_free_call(int fd, free_call *call); +void psi_free_exp_exec(struct psi_free_exp *f, struct psi_call_frame *frame); #endif diff --git a/src/types/free_stmt.c b/src/types/free_stmt.c index a19c97f..980b134 100644 --- a/src/types/free_stmt.c +++ b/src/types/free_stmt.c @@ -5,11 +5,11 @@ 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. + * 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 @@ -21,109 +21,69 @@ 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. -*******************************************************************************/ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif - -#include -#include + *******************************************************************************/ +#include "php_psi_stdinc.h" #include "data.h" -free_stmt *init_free_stmt(free_calls *calls) { - free_stmt *f = calloc(1, sizeof(*f)); - f->calls = calls; +struct psi_free_stmt *psi_free_stmt_init(struct psi_plist *exps) +{ + struct psi_free_stmt *f = calloc(1, sizeof(*f)); + f->exps = exps; return f; } -void free_free_stmt(free_stmt *f) { - free_free_calls(f->calls); - free(f); +void psi_free_stmt_free(struct psi_free_stmt **f_ptr) +{ + if (*f_ptr) { + struct psi_free_stmt *f = *f_ptr; + + *f_ptr = NULL; + psi_plist_free(f->exps); + free(f); + } } -void dump_free_stmt(int fd, free_stmt *fre) { - size_t k; +void psi_free_stmt_dump(int fd, struct psi_free_stmt *fre) +{ + size_t i; + struct psi_free_exp *exp; dprintf(fd, "\tfree "); - for (k = 0; k < fre->calls->count; ++k) { - free_call *call = fre->calls->list[k]; - - if (k) { + for (i = 0; psi_plist_get(fre->exps, i, &exp); ++i) { + if (i) { dprintf(fd, ", "); } - dump_free_call(fd, call); - dprintf(fd, "\n"); + psi_free_exp_dump(fd, exp); } + dprintf(fd, ";\n"); } -static inline decl *locate_free_decl(decls *decls, free_call *f) { - if (decls) { - size_t i; +bool psi_free_stmts_validate(struct psi_data *data, struct psi_impl *impl) +{ + size_t i; + struct psi_free_stmt *fre; - for (i = 0; i < decls->count; ++i) { - if (!strcmp(decls->list[i]->func->var->name, f->func)) { - f->decl = decls->list[i]; - return decls->list[i]; + /* we can have any count of free stmts; freeing any out vars */ + for (i = 0; psi_plist_get(impl->stmts.fre, i, &fre); ++i) { + size_t j; + struct psi_free_exp *exp; + + for (j = 0; psi_plist_get(fre->exps, j, &exp); ++j) { + if (!psi_free_exp_validate(data, exp, impl)) { + return false; } } } - - return NULL; + return true; } -int validate_free_stmts(struct psi_data *data, impl *impl) { - size_t i, j, k, l; - /* we can have any count of free stmts; freeing any out vars */ - for (i = 0; i < impl->stmts->fre.count; ++i) { - free_stmt *fre = impl->stmts->fre.list[i]; - - for (j = 0; j < fre->calls->count; ++j) { - free_call *free_call = fre->calls->list[j]; +void psi_free_stmt_exec(struct psi_free_stmt *fre, struct psi_call_frame *frame) +{ + size_t i = 0; + struct psi_free_exp *exp; - /* first find the decl of the free func */ - if (!locate_free_decl(data->decls, free_call)) { - data->error(data, free_call->token, PSI_WARNING, - "Missing declaration '%s' in `free` statement" - " of implementation '%s'", - free_call->func, impl->func->name); - return 0; - } - - - - /* now check for known vars */ - for (l = 0; l < free_call->vars->count; ++l) { - int check = 0; - decl_var *free_var = free_call->vars->vars[l]; - - if (!strcmp(free_var->name, impl->decl->func->var->name)) { - check = 1; - free_var->arg = impl->decl->func; - } else if (impl->decl->args) { - for (k = 0; k < impl->decl->args->count; ++k) { - decl_arg *free_arg = impl->decl->args->args[k]; - - if (!strcmp(free_var->name, free_arg->var->name)) { - check = 1; - free_var->arg = free_arg; - break; - } - } - } - - if (!check) { - data->error(data, free_var->token, PSI_WARNING, - "Unknown variable '%s' of `free` statement" - " of implementation '%s'", - free_var->name, impl->func->name); - return 0; - } - } - } + while (psi_plist_get(fre->exps, i++, &exp)) { + psi_free_exp_exec(exp, frame); } - return 1; } diff --git a/src/types/free_stmt.h b/src/types/free_stmt.h index 131f534..1c88cfc 100644 --- a/src/types/free_stmt.h +++ b/src/types/free_stmt.h @@ -26,19 +26,20 @@ #ifndef PSI_TYPES_FREE_STMT_H #define PSI_TYPES_FREE_STMT_H -#include "free_calls.h" - -typedef struct free_stmt { - free_calls *calls; -} free_stmt; +struct psi_data; +struct psi_plist; +struct psi_impl; +struct psi_call_frame; -free_stmt *init_free_stmt(free_calls *calls); -void free_free_stmt(free_stmt *f); -void dump_free_stmt(int fd, free_stmt *fre); +struct psi_free_stmt { + struct psi_plist *exps; +}; -struct psi_data; -struct impl; +struct psi_free_stmt *psi_free_stmt_init(struct psi_plist *calls); +void psi_free_stmt_free(struct psi_free_stmt **f_ptr); +void psi_free_stmt_dump(int fd, struct psi_free_stmt *fre); -int validate_free_stmts(struct psi_data *data, struct impl *impl); +bool psi_free_stmts_validate(struct psi_data *data, struct psi_impl *impl); +void psi_free_stmt_exec(struct psi_free_stmt *fre, struct psi_call_frame *frame); #endif diff --git a/src/types/impl.c b/src/types/impl.c index e28a7d2..33d3301 100644 --- a/src/types/impl.c +++ b/src/types/impl.c @@ -5,11 +5,11 @@ 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. + * 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 @@ -21,44 +21,186 @@ 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. -*******************************************************************************/ + *******************************************************************************/ -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif +#include "php_psi_stdinc.h" +#include "data.h" -#include -#include +#include -#include "data.h" +struct psi_impl *psi_impl_init(struct psi_impl_func *func, + struct psi_plist *stmts) +{ + struct psi_impl *impl = calloc(1, sizeof(*impl)); + size_t i = 0; + struct psi_token **abstract_stmt; -impl *init_impl(impl_func *func, impl_stmts *stmts) { - impl *i = calloc(1, sizeof(*i)); - i->func = func; - i->stmts = stmts; - return i; + impl->stmts.ret = psi_plist_init((psi_plist_dtor) psi_return_stmt_free); + impl->stmts.let = psi_plist_init((psi_plist_dtor) psi_let_stmt_free); + impl->stmts.set = psi_plist_init((psi_plist_dtor) psi_set_stmt_free); + impl->stmts.fre = psi_plist_init((psi_plist_dtor) psi_free_stmt_free); + + while (psi_plist_get(stmts, i++, &abstract_stmt)) { + switch ((*abstract_stmt)->type) { + case PSI_T_RETURN: + impl->stmts.ret = psi_plist_add(impl->stmts.ret, &abstract_stmt); + break; + case PSI_T_LET: + case PSI_T_TEMP: + impl->stmts.let = psi_plist_add(impl->stmts.let, &abstract_stmt); + break; + case PSI_T_SET: + impl->stmts.set = psi_plist_add(impl->stmts.set, &abstract_stmt); + break; + case PSI_T_FREE: + impl->stmts.fre = psi_plist_add(impl->stmts.fre, &abstract_stmt); + break; + default: + assert(0); + } + } + free(stmts); + + impl->func = func; + + return impl; } -void free_impl(impl *impl) { - free_impl_func(impl->func); - free_impl_stmts(impl->stmts); - free(impl); +void psi_impl_free(struct psi_impl **impl_ptr) +{ + if (*impl_ptr) { + struct psi_impl *impl = *impl_ptr; + + *impl_ptr = NULL; + psi_impl_func_free(&impl->func); + psi_plist_free(impl->stmts.ret); + psi_plist_free(impl->stmts.let); + psi_plist_free(impl->stmts.set); + psi_plist_free(impl->stmts.fre); + free(impl); + } } -void dump_impl(int fd, impl *impl) { - dump_impl_func(fd, impl->func); +void psi_impl_dump(int fd, struct psi_impl *impl) +{ + size_t i; + struct psi_return_stmt *ret; + struct psi_let_stmt *let; + struct psi_set_stmt *set; + struct psi_free_stmt *fre; + + psi_impl_func_dump(fd, impl->func); dprintf(fd, " {\n"); - if (impl->stmts) { - dump_impl_stmts(fd, impl->stmts); + for (i = 0; psi_plist_get(impl->stmts.let, i, &let); ++i) { + psi_let_stmt_dump(fd, let); } - dprintf(fd, "}"); + for (i = 0; psi_plist_get(impl->stmts.ret, i, &ret); ++i) { + psi_return_stmt_dump(fd, ret); + } + for (i = 0; psi_plist_get(impl->stmts.set, i, &set); ++i) { + psi_set_stmt_dump(fd, set); + } + for (i = 0; psi_plist_get(impl->stmts.fre, i, &fre); ++i) { + psi_free_stmt_dump(fd, fre); + } + dprintf(fd, "}\n"); } -int validate_impl(struct psi_data *data, impl *impl) { - if (!validate_impl_args(data, impl)) { - return 0; +bool psi_impl_validate(struct psi_data *data, struct psi_impl *impl) +{ + if (!psi_impl_func_validate(data, impl->func)) { + return false; + } + if (!psi_return_stmt_validate(data, impl)) { + return false; + } + if (!psi_let_stmts_validate(data, impl)) { + return false; + } + if (!psi_set_stmts_validate(data, impl)) { + return false; + } + if (!psi_free_stmts_validate(data, impl)) { + return false; + } + return true; +} + +size_t psi_impl_num_min_args(struct psi_impl *impl) +{ + size_t i; + struct psi_impl_arg *arg; + + for (i = 0; psi_plist_get(impl->func->args, i, &arg); ++i) { + if (arg->def) { + break; + } + } + return i; +} + +void psi_impl_stmt_free(struct psi_token ***abstract_stmt) +{ + switch ((**abstract_stmt)->type) { + case PSI_T_LET: + psi_let_stmt_free((void *) abstract_stmt); + break; + case PSI_T_SET: + psi_set_stmt_free((void *) abstract_stmt); + break; + case PSI_T_RETURN: + psi_return_stmt_free((void *) abstract_stmt); + break; + case PSI_T_FREE: + psi_free_stmt_free((void *) abstract_stmt); + break; + default: + assert(0); + } +} + +struct psi_let_stmt *psi_impl_get_let(struct psi_impl *impl, + struct psi_decl_var* var) +{ + size_t i = 0; + struct psi_let_stmt *let; + + while (psi_plist_get(impl->stmts.let, i++, &let)) { + if (let->exp->var->arg == var->arg) { + return let; + } + } + return NULL; +} + +struct psi_impl_arg *psi_impl_get_arg(struct psi_impl *impl, + struct psi_impl_var* var) +{ + size_t i = 0; + struct psi_impl_arg *iarg; + + while (psi_plist_get(impl->func->args, i++, &iarg)) { + if (!strcmp(var->name, iarg->var->name)) { + return var->arg = iarg; + } + } + return NULL; +} + +struct psi_decl_arg *psi_impl_get_temp_let_arg(struct psi_impl *impl, + struct psi_decl_var* var) +{ + size_t j = 0; + struct psi_let_stmt *let = NULL; + + while (psi_plist_get(impl->stmts.let, j++, &let)) { + if (let->exp->kind != PSI_LET_TMP) { + continue; + } + if (strcmp(let->exp->var->name, var->name)) { + continue; + } + return var->arg = let->exp->var->arg; } - return validate_impl_stmts(data, impl); + return NULL; } diff --git a/src/types/impl.h b/src/types/impl.h index 5b38020..83b0e81 100644 --- a/src/types/impl.h +++ b/src/types/impl.h @@ -26,22 +26,38 @@ #ifndef PSI_TYPES_IMPL_H #define PSI_TYPES_IMPL_H -#include "impl_func.h" -#include "impl_stmts.h" -#include "decl.h" - -typedef struct impl { - impl_func *func; - impl_stmts *stmts; - decl *decl; -} impl; - -impl *init_impl(impl_func *func, impl_stmts *stmts); -void free_impl(impl *impl); -void dump_impl(int fd, impl *impl); - struct psi_data; - -int validate_impl(struct psi_data *data, impl *impl); +struct psi_token; +struct psi_plist; +struct psi_decl; +struct psi_decl_var; +struct psi_impl_var; +struct psi_impl_func; + +struct psi_impl { + struct psi_impl_func *func; + struct psi_decl *decl; + struct { + struct psi_plist *ret; + struct psi_plist *let; + struct psi_plist *set; + struct psi_plist *fre; + } stmts; +}; + +struct psi_impl *psi_impl_init(struct psi_impl_func *func, struct psi_plist *stmts); +void psi_impl_free(struct psi_impl **impl_ptr); +void psi_impl_dump(int fd, struct psi_impl *impl); +bool psi_impl_validate(struct psi_data *data, struct psi_impl *impl); + +size_t psi_impl_num_min_args(struct psi_impl *impl); + +void psi_impl_stmt_free(struct psi_token ***abstract_stm); + +struct psi_let_stmt *psi_impl_get_let(struct psi_impl *impl, struct psi_decl_var *var); +struct psi_impl_arg *psi_impl_get_arg(struct psi_impl *impl, struct psi_impl_var *var); + +struct psi_decl_arg *psi_impl_get_temp_let_arg(struct psi_impl *impl, + struct psi_decl_var *var); #endif diff --git a/src/types/impl_arg.c b/src/types/impl_arg.c index 8c0f82d..d9cb473 100644 --- a/src/types/impl_arg.c +++ b/src/types/impl_arg.c @@ -23,19 +23,13 @@ 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 -#include - -#include "impl_arg.h" - -impl_arg *init_impl_arg(impl_type *type, impl_var *var, impl_def_val *def) { - impl_arg *arg = calloc(1, sizeof(*arg)); +struct psi_impl_arg *psi_impl_arg_init(struct psi_impl_type *type, + struct psi_impl_var *var, struct psi_impl_def_val *def) +{ + struct psi_impl_arg *arg = calloc(1, sizeof(*arg)); arg->type = type; arg->var = var; arg->var->arg = arg; @@ -43,11 +37,30 @@ impl_arg *init_impl_arg(impl_type *type, impl_var *var, impl_def_val *def) { return arg; } -void free_impl_arg(impl_arg *arg) { - free_impl_type(arg->type); - free_impl_var(arg->var); - if (arg->def) { - free_impl_def_val(arg->def); +void psi_impl_arg_free(struct psi_impl_arg **arg_ptr) +{ + if (*arg_ptr) { + struct psi_impl_arg *arg = *arg_ptr; + + *arg_ptr = NULL; + psi_impl_type_free(&arg->type); + psi_impl_var_free(&arg->var); + if (arg->def) { + psi_impl_def_val_free(&arg->def); + } + free(arg); } - free(arg); +} + +void psi_impl_arg_dump(int fd, struct psi_impl_arg *iarg, bool vararg) +{ + dprintf(fd, "%s %s%s%s", + iarg->type->name, + iarg->var->reference ? "&" : "", + vararg ? "..." : "", + iarg->var->name); + if (iarg->def) { + dprintf(fd, " = %s", iarg->def->text); + } + } diff --git a/src/types/impl_arg.h b/src/types/impl_arg.h index 4bf5129..d3e470a 100644 --- a/src/types/impl_arg.h +++ b/src/types/impl_arg.h @@ -28,30 +28,18 @@ #include "token.h" -#include "impl_type.h" -#include "impl_var.h" -#include "impl_def_val.h" -#include "impl_val.h" - -#include "Zend/zend_types.h" - -typedef struct impl_arg { - impl_type *type; - impl_var *var; - impl_def_val *def; - impl_val val; - zval *_zv; -} impl_arg; - -typedef struct impl_vararg { - impl_arg *name; - struct impl_args *args; - token_t *types; - impl_val *values; - void **free_list; -} impl_vararg; - -impl_arg *init_impl_arg(impl_type *type, impl_var *var, impl_def_val *def); -void free_impl_arg(impl_arg *arg); +struct psi_impl_type; +struct psi_impl_var; +struct psi_impl_def_val; + +struct psi_impl_arg { + struct psi_impl_type *type; + struct psi_impl_var *var; + struct psi_impl_def_val *def; +}; + +struct psi_impl_arg *psi_impl_arg_init(struct psi_impl_type *type, struct psi_impl_var *var, struct psi_impl_def_val *def); +void psi_impl_arg_free(struct psi_impl_arg **arg_ptr); +void psi_impl_arg_dump(int fd, struct psi_impl_arg *iarg, bool vararg); #endif diff --git a/src/types/impl_args.c b/src/types/impl_args.c deleted file mode 100644 index 74e1d31..0000000 --- a/src/types/impl_args.c +++ /dev/null @@ -1,84 +0,0 @@ -/******************************************************************************* - Copyright (c) 2016, Michael Wallner . - 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. -*******************************************************************************/ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif - -#include -#include - -#include "data.h" - -impl_args *init_impl_args(impl_arg *arg) { - impl_args *args = calloc(1, sizeof(*args)); - if (arg) { - args->count = 1; - args->args = calloc(1, sizeof(*args->args)); - args->args[0] = arg; - } - return args; -} - -impl_args *add_impl_arg(impl_args *args, impl_arg *arg) { - args->args = realloc(args->args, ++args->count * sizeof(*args->args)); - args->args[args->count - 1] = arg; - return args; -} - -void free_impl_args(impl_args *args) { - size_t i; - for (i = 0; i < args->count; ++i) { - free_impl_arg(args->args[i]); - } - if (args->vararg.name) { - free_impl_arg(args->vararg.name); - } - free(args->args); - free(args); -} - -int validate_impl_args(struct psi_data *data, impl *impl) { - int def = 0; - size_t i; - - for (i = 0; i < impl->func->args->count; ++i) { - impl_arg *iarg = impl->func->args->args[i]; - - if (iarg->def) { - def = 1; - } else if (def) { - data->error(data, impl->func->token, PSI_WARNING, - "Non-optional argument %zu '$%s' of implementation '%s'" - " follows optional argument", - i+1, iarg->var->name, impl->func->name); - return 0; - } - } - - return 1; -} diff --git a/src/types/impl_args.h b/src/types/impl_args.h deleted file mode 100644 index 191670d..0000000 --- a/src/types/impl_args.h +++ /dev/null @@ -1,46 +0,0 @@ -/******************************************************************************* - Copyright (c) 2016, Michael Wallner . - 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_TYPES_IMPL_ARGS_H -#define PSI_TYPES_IMPL_ARGS_H - -#include "impl_arg.h" - -typedef struct impl_args { - impl_arg **args; - size_t count; - impl_vararg vararg; -} impl_args; - -impl_args *init_impl_args(impl_arg *arg); -impl_args *add_impl_arg(impl_args *args, impl_arg *arg); -void free_impl_args(impl_args *args); - -struct psi_data; -struct impl; - -int validate_impl_args(struct psi_data *data, struct impl *impl); - -#endif diff --git a/src/types/impl_def_val.c b/src/types/impl_def_val.c index 0d176f3..61c4e8b 100644 --- a/src/types/impl_def_val.c +++ b/src/types/impl_def_val.c @@ -23,34 +23,85 @@ 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 -#include +#include -#include "impl_def_val.h" +struct psi_impl_def_val *psi_impl_def_val_init(token_t t, const char *text) +{ + struct psi_impl_def_val *def = calloc(1, sizeof(*def)); -void free_impl_def_val(impl_def_val *def) { - free(def->text); - free(def); -} - -impl_def_val *init_impl_def_val(token_t t, const char *text) { - impl_def_val *def = calloc(1, sizeof(*def)); def->type = t; def->text = strdup(text); + return def; } -void dump_impl_def_val(int fd, impl_def_val *val) { - if (val->type == PSI_T_QUOTED_STRING) { +void psi_impl_def_val_free(struct psi_impl_def_val **def_ptr) +{ + if (*def_ptr) { + struct psi_impl_def_val *def = *def_ptr; + + *def_ptr = NULL; + if (def->token) { + free(def->token); + } + switch (def->type) { + case PSI_T_STRING: + assert(0); + /* no break */ + case PSI_T_QUOTED_STRING: + if (def->ival.zend.str) { + zend_string_release(def->ival.zend.str); + } + break; + } + free(def->text); + free(def); + } +} + +bool psi_impl_def_val_validate(struct psi_data *data, + struct psi_impl_def_val *def, struct psi_impl_type *type) +{ + if (def->type != PSI_T_NULL) { + switch (type->type) { + case PSI_T_BOOL: + def->ival.zend.bval = def->type == PSI_T_TRUE ? 1 : 0; + break; + case PSI_T_INT: + def->ival.zend.lval = zend_atol(def->text, strlen(def->text)); + break; + case PSI_T_FLOAT: + case PSI_T_DOUBLE: + def->ival.dval = zend_strtod(def->text, NULL); + break; + case PSI_T_STRING: + assert(0); + /* no break */ + case PSI_T_QUOTED_STRING: + def->ival.zend.str = zend_string_init(&def->text[1], strlen(def->text) - 2, 1); + break; + default: + data->error(data, def->token, PSI_WARNING, + "Invalid default value type '%s', expected one of bool, int, double, string.", + type->name); + return false; + } + } + return true; +} + +void psi_impl_def_val_dump(int fd, struct psi_impl_def_val *val) { + switch (val->type) { + case PSI_T_STRING: + assert(0); + /* no break */ + case PSI_T_QUOTED_STRING: dprintf(fd, "\"%s\"", val->text); - } else { + break; + default: dprintf(fd, "%s", val->text); } - } diff --git a/src/types/impl_def_val.h b/src/types/impl_def_val.h index 07c02cd..d483d8e 100644 --- a/src/types/impl_def_val.h +++ b/src/types/impl_def_val.h @@ -27,14 +27,21 @@ #define PSI_TYPES_IMPL_DEF_VAL_H #include "token.h" +#include "impl_val.h" -typedef struct impl_def_val { +struct psi_data; +struct psi_impl_type; + +struct psi_impl_def_val { + struct psi_token *token; token_t type; char *text; -} impl_def_val; + impl_val ival; +}; -impl_def_val *init_impl_def_val(token_t t, const char *text); -void free_impl_def_val(impl_def_val *def); -void dump_impl_def_val(int fd, impl_def_val *val); +struct psi_impl_def_val *psi_impl_def_val_init(token_t t, const char *text); +void psi_impl_def_val_free(struct psi_impl_def_val **def_ptr); +void psi_impl_def_val_dump(int fd, struct psi_impl_def_val *val); +bool psi_impl_def_val_validate(struct psi_data *data, struct psi_impl_def_val *def, struct psi_impl_type *type); #endif diff --git a/src/types/impl_func.c b/src/types/impl_func.c index 690ce4a..52a8e25 100644 --- a/src/types/impl_func.c +++ b/src/types/impl_func.c @@ -5,11 +5,11 @@ 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. + * 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 @@ -21,67 +21,90 @@ 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. -*******************************************************************************/ + *******************************************************************************/ -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif +#include "php_psi_stdinc.h" +#include "data.h" -#include -#include -#include +struct psi_impl_func *psi_impl_func_init(const char *name, + struct psi_plist *args, struct psi_impl_type *type) +{ + struct psi_impl_func *func = calloc(1, sizeof(*func)); -#include "impl_func.h" - -impl_func *init_impl_func(char *name, impl_args *args, impl_type *type, - int ret_reference) { - impl_func *func = calloc(1, sizeof(*func)); func->name = strdup(name); - func->args = args ? args : init_impl_args(NULL); + func->args = args ? : psi_plist_init((psi_plist_dtor) psi_impl_arg_free); + func->return_type = type; - func->return_reference = ret_reference; + return func; } -void free_impl_func(impl_func *f) { - if (f->token) { - free(f->token); +void psi_impl_func_free(struct psi_impl_func **f_ptr) +{ + if (*f_ptr) { + struct psi_impl_func *f = *f_ptr; + + *f_ptr = NULL; + if (f->token) { + free(f->token); + } + + psi_impl_type_free(&f->return_type); + psi_plist_free(f->args); + + if (f->vararg) { + psi_impl_arg_free(&f->vararg); + } + + free(f->name); + free(f); } - free_impl_type(f->return_type); - free_impl_args(f->args); - free(f->name); - free(f); } -void dump_impl_func(int fd, impl_func *func) { - size_t j; +bool psi_impl_func_validate(struct psi_data *data, struct psi_impl_func *func) +{ + int def = 0; + size_t i = 0; + struct psi_impl_arg *iarg; + + while (psi_plist_get(func->args, i++, &iarg)) { + if (iarg->def) { + def = 1; + if (!psi_impl_def_val_validate(data, iarg->def, iarg->type)) { + return 0; + } + } else if (def) { + data->error(data, func->token, PSI_WARNING, + "Non-optional argument %zu '$%s' of implementation '%s'" + " follows optional argument", + i + 1, + iarg->var->name, func->name); + return false; + } + } + + return true; +} +void psi_impl_func_dump(int fd, struct psi_impl_func *func) +{ dprintf(fd, "function %s(", func->name); if (func->args) { - for (j = 0; j < func->args->count; ++j) { - impl_arg *iarg = func->args->args[j]; - - dprintf(fd, "%s%s %s%s", - j ? ", " : "", - iarg->type->name, - iarg->var->reference ? "&" : "", - iarg->var->name); - if (iarg->def) { - dprintf(fd, " = %s", iarg->def->text); + size_t i = 0; + struct psi_impl_arg *iarg; + + while (psi_plist_get(func->args, i++, &iarg)) { + if (i > 1) { + dprintf(fd, ", "); } + psi_impl_arg_dump(fd, iarg, false); } - if (func->args->vararg.name) { - impl_arg *vararg = func->args->vararg.name; - dprintf(fd, ", %s %s...%s", - vararg->type->name, - vararg->var->reference ? "&" : "", - vararg->var->name); + if (func->vararg) { + dprintf(fd, ", "); + psi_impl_arg_dump(fd, func->vararg, true); } } - dprintf(fd, ") : %s%s", - func->return_reference ? "&":"", + dprintf(fd, ") : %s%s", func->return_reference ? "&" : "", func->return_type->name); } diff --git a/src/types/impl_func.h b/src/types/impl_func.h index 740a7aa..52c4a66 100644 --- a/src/types/impl_func.h +++ b/src/types/impl_func.h @@ -26,20 +26,26 @@ #ifndef PSI_TYPES_IMPL_FUNC_H #define PSI_TYPES_IMPL_FUNC_H -#include "impl_args.h" -#include "impl_type.h" - -typedef struct impl_func { +struct psi_data; +struct psi_token; +struct psi_plist; +struct psi_impl; +struct psi_impl_arg; +struct psi_impl_type; + +struct psi_impl_func { struct psi_token *token; char *name; - impl_args *args; - impl_type *return_type; + struct psi_plist *args; + struct psi_impl_arg *vararg; + struct psi_impl_type *return_type; unsigned return_reference:1; -} impl_func; + unsigned static_memory:1; +}; -impl_func *init_impl_func(char *name, impl_args *args, impl_type *type, - int ret_reference); -void free_impl_func(impl_func *f); -void dump_impl_func(int fd, impl_func *func); +struct psi_impl_func *psi_impl_func_init(const char *name, struct psi_plist *args, struct psi_impl_type *return_type); +void psi_impl_func_free(struct psi_impl_func **f_ptr); +void psi_impl_func_dump(int fd, struct psi_impl_func *func); +bool psi_impl_func_validate(struct psi_data *data, struct psi_impl_func *func); #endif diff --git a/src/types/impl_stmt.c b/src/types/impl_stmt.c deleted file mode 100644 index 35a95f3..0000000 --- a/src/types/impl_stmt.c +++ /dev/null @@ -1,60 +0,0 @@ -/******************************************************************************* - Copyright (c) 2016, Michael Wallner . - 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. -*******************************************************************************/ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif - -#include -#include - -#include "impl_stmt.h" - -impl_stmt *init_impl_stmt(token_t type, void *ptr) { - impl_stmt *stmt = calloc(1, sizeof(*stmt)); - stmt->type = type; - stmt->s.ptr = ptr; - return stmt; -} - -void free_impl_stmt(impl_stmt *stmt) { - switch (stmt->type) { - case PSI_T_LET: - free_let_stmt(stmt->s.let); - break; - case PSI_T_SET: - free_set_stmt(stmt->s.set); - break; - case PSI_T_RETURN: - free_return_stmt(stmt->s.ret); - break; - case PSI_T_FREE: - free_free_stmt(stmt->s.fre); - break; - } - free(stmt); -} diff --git a/src/types/impl_stmt.h b/src/types/impl_stmt.h deleted file mode 100644 index 0a916ed..0000000 --- a/src/types/impl_stmt.h +++ /dev/null @@ -1,50 +0,0 @@ -/******************************************************************************* - Copyright (c) 2016, Michael Wallner . - 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_TYPES_IMPL_STMT_H -#define PSI_TYPES_IMPL_STMT_H - -#include "token.h" - -#include "let_stmt.h" -#include "set_stmt.h" -#include "return_stmt.h" -#include "free_stmt.h" - -typedef struct impl_stmt { - token_t type; - union { - let_stmt *let; - set_stmt *set; - return_stmt *ret; - free_stmt *fre; - void *ptr; - } s; -} impl_stmt; - -impl_stmt *init_impl_stmt(token_t type, void *ptr); -void free_impl_stmt(impl_stmt *stmt); - -#endif diff --git a/src/types/impl_stmts.c b/src/types/impl_stmts.c deleted file mode 100644 index efc7cea..0000000 --- a/src/types/impl_stmts.c +++ /dev/null @@ -1,142 +0,0 @@ -/******************************************************************************* - Copyright (c) 2016, Michael Wallner . - 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. -*******************************************************************************/ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif - -#include -#include - -#include "data.h" - -void *add_impl_stmt_ex(void *list, size_t count, void *stmt) { - list = realloc(list, count * sizeof(list)); - ((void**) list)[count - 1] = stmt; - return list; -} - -impl_stmts *add_impl_stmt(impl_stmts *stmts, impl_stmt *stmt) { - switch (stmt->type) { - case PSI_T_RETURN: - stmts->ret.list = add_impl_stmt_ex(stmts->ret.list, ++stmts->ret.count, - stmt->s.ret); - break; - case PSI_T_LET: - stmts->let.list = add_impl_stmt_ex(stmts->let.list, ++stmts->let.count, - stmt->s.let); - break; - case PSI_T_SET: - stmts->set.list = add_impl_stmt_ex(stmts->set.list, ++stmts->set.count, - stmt->s.set); - break; - case PSI_T_FREE: - stmts->fre.list = add_impl_stmt_ex(stmts->fre.list, ++stmts->fre.count, - stmt->s.fre); - break; - } - free(stmt); - return stmts; -} - -impl_stmts *init_impl_stmts(impl_stmt *stmt) { - impl_stmts *stmts = calloc(1, sizeof(*stmts)); - return add_impl_stmt(stmts, stmt); -} - -void free_impl_stmts(impl_stmts *stmts) { - size_t i; - for (i = 0; i < stmts->let.count; ++i) { - free_let_stmt(stmts->let.list[i]); - } - free(stmts->let.list); - for (i = 0; i < stmts->ret.count; ++i) { - free_return_stmt(stmts->ret.list[i]); - } - free(stmts->ret.list); - for (i = 0; i < stmts->set.count; ++i) { - free_set_stmt(stmts->set.list[i]); - } - free(stmts->set.list); - for (i = 0; i < stmts->fre.count; ++i) { - free_free_stmt(stmts->fre.list[i]); - } - free(stmts->fre.list); - free(stmts); -} - -void dump_impl_stmts(int fd, impl_stmts *stmts) { - size_t j; - - for (j = 0; j < stmts->let.count; ++j) { - let_stmt *let = stmts->let.list[j]; - dump_let_stmt(fd, let); - dprintf(fd, "\n"); - } - for (j = 0; j < stmts->ret.count; ++j) { - return_stmt *ret = stmts->ret.list[j]; - dump_return_stmt(fd, ret); - dprintf(fd, "\n"); - } - for (j = 0; j < stmts->set.count; ++j) { - set_stmt *set = stmts->set.list[j]; - - dump_set_stmt(fd, set); - dprintf(fd, "\n"); - } - for (j = 0; j < stmts->fre.count; ++j) { - free_stmt *fre = stmts->fre.list[j]; - - dump_free_stmt(fd, fre); - dprintf(fd, "\n"); - } -} - -int validate_impl_stmts(struct psi_data *data, impl *impl) { - if (!impl->stmts) { - data->error(data, impl->func->token, PSI_WARNING, - "Missing body for implementation %s!", - impl->func->name); - return 0; - } - - if (!validate_return_stmt(data, impl)) { - return 0; - } - - if (!validate_let_stmts(data, impl)) { - return 0; - } - if (!validate_set_stmts(data, impl)) { - return 0; - } - if (!validate_free_stmts(data, impl)) { - return 0; - } - - return 1; -} diff --git a/src/types/impl_stmts.h b/src/types/impl_stmts.h deleted file mode 100644 index a346279..0000000 --- a/src/types/impl_stmts.h +++ /dev/null @@ -1,61 +0,0 @@ -/******************************************************************************* - Copyright (c) 2016, Michael Wallner . - 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_TYPES_IMPL_STMTS_H -#define PSI_TYPES_IMPL_STMTS_H - -#include "impl_stmt.h" - -typedef struct impl_stmts { - struct { - return_stmt **list; - size_t count; - } ret; - struct { - let_stmt **list; - size_t count; - } let; - struct { - set_stmt **list; - size_t count; - } set; - struct { - free_stmt **list; - size_t count; - } fre; -} impl_stmts; - -void *add_impl_stmt_ex(void *list, size_t count, void *stmt); -impl_stmts *add_impl_stmt(impl_stmts *stmts, impl_stmt *stmt); -impl_stmts *init_impl_stmts(impl_stmt *stmt); -void free_impl_stmts(impl_stmts *stmts); -void dump_impl_stmts(int fd, impl_stmts *stmts); - -struct psi_data; -struct impl; - -int validate_impl_stmts(struct psi_data *data, struct impl *impl); - -#endif diff --git a/src/types/impl_type.c b/src/types/impl_type.c index a5b2188..f865bd8 100644 --- a/src/types/impl_type.c +++ b/src/types/impl_type.c @@ -23,26 +23,29 @@ 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 -#include -#include +struct psi_impl_type *psi_impl_type_init(token_t type, const char *name) +{ + struct psi_impl_type *t = calloc(1, sizeof(*t)); -#include "impl_type.h" - -impl_type *init_impl_type(token_t type, const char *name) { - impl_type *t = calloc(1, sizeof(*t)); t->type = type; t->name = strdup(name); + return t; } -void free_impl_type(impl_type *type) { - free(type->name); - free(type); +void psi_impl_type_free(struct psi_impl_type **type_ptr) +{ + if (*type_ptr) { + struct psi_impl_type *type = *type_ptr; + + *type_ptr = NULL; + if (type->token) { + free(type->token); + } + free(type->name); + free(type); + } } diff --git a/src/types/impl_type.h b/src/types/impl_type.h index e1197e7..3a5ce21 100644 --- a/src/types/impl_type.h +++ b/src/types/impl_type.h @@ -28,12 +28,13 @@ #include "token.h" -typedef struct impl_type { +struct psi_impl_type { + struct psi_token *token; char *name; token_t type; -} impl_type; +}; -impl_type *init_impl_type(token_t type, const char *name); -void free_impl_type(impl_type *type); +struct psi_impl_type *psi_impl_type_init(token_t type, const char *name); +void psi_impl_type_free(struct psi_impl_type **type_ptr); #endif diff --git a/src/types/impl_val.h b/src/types/impl_val.h index 1866320..8e119cd 100644 --- a/src/types/impl_val.h +++ b/src/types/impl_val.h @@ -59,6 +59,9 @@ typedef union impl_val { zend_fcall *cb; } zend; void *ptr; +#ifdef PHP_DEBUG + char _dbg[sizeof(void *)]; +#endif } impl_val; #endif diff --git a/src/types/impl_var.c b/src/types/impl_var.c index 487a997..c793500 100644 --- a/src/types/impl_var.c +++ b/src/types/impl_var.c @@ -5,11 +5,11 @@ 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. + * 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 @@ -21,55 +21,73 @@ 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. -*******************************************************************************/ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif - -#include -#include -#include + *******************************************************************************/ +#include "php_psi_stdinc.h" #include "data.h" -impl_var *init_impl_var(const char *name, int is_reference) { - impl_var *var = calloc(1, sizeof(*var)); +struct psi_impl_var *psi_impl_var_init(const char *name, bool is_reference) +{ + struct psi_impl_var *var = calloc(1, sizeof(*var)); + var->name = strdup(name); + var->fqn = strdup(name); + var->reference = is_reference; return var; } -impl_var *copy_impl_var(impl_var *var) { - impl_var *cpy = malloc(sizeof(*cpy)); - memcpy(cpy, var, sizeof(*cpy)); +struct psi_impl_var *psi_impl_var_copy(struct psi_impl_var *var) +{ + struct psi_impl_var *cpy = malloc(sizeof(*cpy)); + + *cpy = *var; + cpy->name = strdup(cpy->name); + cpy->fqn = strdup(cpy->fqn); + if (cpy->token) { cpy->token = psi_token_copy(cpy->token); } return cpy; } -void free_impl_var(impl_var *var) { - if (var->token) { - free(var->token); +void psi_impl_var_free(struct psi_impl_var **var_ptr) +{ + if (*var_ptr) { + struct psi_impl_var *var = *var_ptr; + + *var_ptr = NULL; + if (var->token) { + free(var->token); + } + free(var->name); + free(var->fqn); + free(var); } - free(var->name); - free(var); } -impl_arg *locate_impl_var_arg(impl_var *var, impl_args *args) { - size_t i; - for (i = 0; i < args->count; ++i) { - impl_arg *iarg = args->args[i]; +bool psi_impl_var_validate(struct psi_data *data, struct psi_impl_var *ivar, + struct psi_impl *impl, struct psi_let_exp *let_exp, + struct psi_set_exp *set_exp) +{ + struct psi_let_exp *current_let_exp = let_exp; + struct psi_set_exp *current_set_exp = set_exp; + + if (current_let_exp) { + while ((current_let_exp = current_let_exp->outer)) { + struct psi_impl_var *svar = psi_let_exp_get_impl_var(current_let_exp); + + ivar->fqn = psi_impl_var_name_prepend(ivar->fqn, svar->name + 1); + } + } else if (current_set_exp) { + while ((current_set_exp = current_set_exp->outer)) { + struct psi_impl_var *svar = psi_set_exp_get_impl_var(current_set_exp); - if (!strcmp(var->name, iarg->var->name)) { - return var->arg = iarg; + ivar->fqn = psi_impl_var_name_prepend(ivar->fqn, svar->name + 1); } } - return NULL; + return true; } diff --git a/src/types/impl_var.h b/src/types/impl_var.h index e35a8b7..4576cb9 100644 --- a/src/types/impl_var.h +++ b/src/types/impl_var.h @@ -26,19 +26,46 @@ #ifndef PSI_TYPES_IMPL_VAR_H #define PSI_TYPES_IMPL_VAR_H -typedef struct impl_var { +struct psi_token; +struct psi_impl; +struct psi_impl_arg; + +struct psi_impl_var { struct psi_token *token; - char *name; - struct impl_arg *arg; + char *name, *fqn; + struct psi_impl_arg *arg; unsigned reference:1; -} impl_var; +}; + +struct psi_impl_var *psi_impl_var_init(const char *name, bool is_reference); +struct psi_impl_var *psi_impl_var_copy(struct psi_impl_var *var); +void psi_impl_var_free(struct psi_impl_var **var_ptr); + +#include -impl_var *init_impl_var(const char *name, int is_reference); -impl_var *copy_impl_var(impl_var *var); -void free_impl_var(impl_var *var); +static inline char *psi_impl_var_name_prepend(char *current, const char *prepend) { + size_t c_len = strlen(current); + size_t p_len = strlen(prepend); -struct impl_args; + current = realloc(current, p_len + + c_len // includes '$' + + 1 // connecting dot + + 1 // terminating 0 + ); + if (current) { + if (c_len > 1) { + memmove(current + p_len + 1 + 1, current + 1, c_len - 1 + 1); + current[p_len + 1] = '.'; + } else { + /* just '$' */ + current[p_len + 1] = '\0'; + } + memcpy(current + 1, prepend, p_len); + } + return current; +} -struct impl_arg *locate_impl_var_arg(impl_var *var, struct impl_args *args); +bool psi_impl_var_validate(struct psi_data *data, struct psi_impl_var *ivar, struct psi_impl *impl, + struct psi_let_exp *current_let_exp, struct psi_set_exp *current_set_exp); #endif diff --git a/src/types/impls.c b/src/types/impls.c deleted file mode 100644 index 033f6d9..0000000 --- a/src/types/impls.c +++ /dev/null @@ -1,64 +0,0 @@ -/******************************************************************************* - Copyright (c) 2016, Michael Wallner . - 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. -*******************************************************************************/ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif - -#include -#include - -#include "impls.h" - -impls *add_impl(impls *impls, impl *impl) { - if (!impls) { - impls = calloc(1, sizeof(*impls)); - } - impls->list = realloc(impls->list, ++impls->count * sizeof(*impls->list)); - impls->list[impls->count - 1] = impl; - return impls; -} - -void free_impls(impls *impls) { - size_t i; - for (i = 0; i < impls->count; ++i) { - free_impl(impls->list[i]); - } - free(impls->list); - free(impls); -} - -void dump_impls(int fd, impls *impls) { - size_t i; - - for (i = 0; i < impls->count; ++i) { - impl *impl = impls->list[i]; - - dump_impl(fd, impl); - dprintf(fd, "\n"); - } -} diff --git a/src/types/impls.h b/src/types/impls.h deleted file mode 100644 index 51de860..0000000 --- a/src/types/impls.h +++ /dev/null @@ -1,40 +0,0 @@ -/******************************************************************************* - Copyright (c) 2016, Michael Wallner . - 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_TYPES_IMPLS_H -#define PSI_TYPES_IMPLS_H - -#include "impl.h" - -typedef struct impls { - size_t count; - impl **list; -} impls; - -impls *add_impl(impls *impls, impl *impl); -void free_impls(impls *impls); -void dump_impls(int fd, impls *impls); - -#endif diff --git a/src/types/decl_struct_layout.c b/src/types/layout.c similarity index 50% rename from src/types/decl_struct_layout.c rename to src/types/layout.c index 8868160..3c8deaa 100644 --- a/src/types/decl_struct_layout.c +++ b/src/types/layout.c @@ -5,11 +5,11 @@ 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. + * 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 @@ -21,22 +21,16 @@ 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. -*******************************************************************************/ + *******************************************************************************/ -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif +#include "php_psi_stdinc.h" +#include "data.h" -#include -#include #include -#include "decl_struct_layout.h" - -decl_struct_layout *init_decl_struct_layout(size_t pos, size_t len) { - decl_struct_layout *l = calloc(1, sizeof(*l)); +struct psi_layout *psi_layout_init(size_t pos, size_t len) +{ + struct psi_layout *l = calloc(1, sizeof(*l)); assert(pos + len); @@ -46,6 +40,30 @@ decl_struct_layout *init_decl_struct_layout(size_t pos, size_t len) { return l; } -void free_decl_struct_layout(decl_struct_layout *l) { - free(l); +void psi_layout_free(struct psi_layout **l_ptr) +{ + if (*l_ptr) { + free(*l_ptr); + *l_ptr = NULL; + } +} + +int psi_layout_sort_cmp(const void *_a, const void *_b) +{ + struct psi_decl_arg *a = *(struct psi_decl_arg **) _a; + struct psi_decl_arg *b = *(struct psi_decl_arg **) _b; + + if (a->layout->pos == b->layout->pos) { + if (a->layout->len == b->layout->len) { + return 0; + } else if (a->layout->len > b->layout->len) { + return -1; + } else { + return 1; + } + } else if (a->layout->pos > b->layout->pos) { + return 1; + } else { + return -1; + } } diff --git a/src/types/decl_struct_layout.h b/src/types/layout.h similarity index 85% rename from src/types/decl_struct_layout.h rename to src/types/layout.h index 1711e1a..53550f9 100644 --- a/src/types/decl_struct_layout.h +++ b/src/types/layout.h @@ -23,15 +23,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *******************************************************************************/ -#ifndef PSI_TYPES_DECL_STRUCT_LAYOUT_H -#define PSI_TYPES_DECL_STRUCT_LAYOUT_H +#ifndef PSI_TYPES_LAYOUT_H +#define PSI_TYPES_LAYOUT_H -typedef struct decl_struct_layout { +struct psi_layout { size_t pos; size_t len; -} decl_struct_layout; +}; -decl_struct_layout *init_decl_struct_layout(size_t pos, size_t len); -void free_decl_struct_layout(decl_struct_layout *l); +struct psi_layout *psi_layout_init(size_t pos, size_t len); +void psi_layout_free(struct psi_layout **l_ptr); + +int psi_layout_sort_cmp(const void *_a, const void *_b); #endif diff --git a/src/types/let_callback.c b/src/types/let_callback.c index e1a6ac9..f6b08ba 100644 --- a/src/types/let_callback.c +++ b/src/types/let_callback.c @@ -5,11 +5,11 @@ 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. + * 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 @@ -21,53 +21,87 @@ 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. -*******************************************************************************/ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif - -#include -#include + *******************************************************************************/ +#include "php_psi_stdinc.h" #include "data.h" -let_callback *init_let_callback(struct let_func *func, struct set_values *args) { - let_callback *cb = calloc(1, sizeof(*cb)); +struct psi_let_callback *psi_let_callback_init(struct psi_let_func *func, + struct psi_plist *args) +{ + struct psi_let_callback *cb = calloc(1, sizeof(*cb)); cb->func = func; cb->args = args; return cb; } -void free_let_callback(let_callback *cb) { - free_let_func(cb->func); - free_set_values(cb->args); - free(cb); +void psi_let_callback_free(struct psi_let_callback **cb_ptr) +{ + if (*cb_ptr) { + struct psi_let_callback *cb = *cb_ptr; + + *cb_ptr = NULL; + psi_let_func_free(&cb->func); + psi_plist_free(cb->args); + if (cb->token) { + free(cb->token); + } + free(cb); + } } -int validate_let_callback(struct psi_data *data, decl_var *cb_var, let_callback *cb, impl *impl) { - size_t i; - decl *cb_func; - decl_type *cb_type = real_decl_type(cb_var->arg->type); +bool psi_let_callback_validate(struct psi_data *data, struct psi_let_exp *exp, + struct psi_let_callback *cb, struct psi_impl *impl) +{ + size_t i = 0; + struct psi_decl *cb_func; + struct psi_decl_type *cb_type; + struct psi_decl_var *cb_var = exp->var; + struct psi_set_exp *set_exp; + cb_type = psi_decl_type_get_real(cb_var->arg->type); if (cb_type->type != PSI_T_FUNCTION) { - data->error(data, cb_var->token, PSI_WARNING, "Not a function: %s", cb_var->name); - return 0; + data->error(data, cb_var->token, PSI_WARNING, + "Expected a function: %s", + cb_var->name); + return false; } cb_func = cb_type->real.func; - for (i = 0; i < cb->args->count; ++i) { - if (!validate_set_value(data, cb->args->vals[i], cb_func->args->count, cb_func->args->args, 0)) { - return 0; + + while (psi_plist_get(cb->args, i++, &set_exp)) { + if (!psi_set_exp_validate(data, set_exp, impl, cb_func)) { + return false; } } - if (!validate_decl_nodl(data, cb_func)) { - return 0; + if (!psi_decl_validate_nodl(data, cb_func)) { + return false; } cb->decl = cb_func; - return 1; + return true; +} + +void psi_let_callback_dump(int fd, struct psi_let_callback *callback, + unsigned level) +{ + dprintf(fd, "callback %s(%s(", + callback->func->name, + callback->func->var->name); + + if (callback->args) { + size_t i = 0, last = psi_plist_count(callback->args); + struct psi_set_exp *set; + + dprintf(fd, "\n"); + ++level; + while (psi_plist_get(callback->args, i++, &set)) { + psi_set_exp_dump(fd, set, level, i == last); + dprintf(fd, "\n"); + } + --level; + dprintf(fd, "%s", psi_t_indent(level)); + } + dprintf(fd, "))"); } diff --git a/src/types/let_callback.h b/src/types/let_callback.h index e461b5a..f7e2bd2 100644 --- a/src/types/let_callback.h +++ b/src/types/let_callback.h @@ -26,20 +26,23 @@ #ifndef PSI_TYPES_LET_CALLBACK_H #define PSI_TYPES_LET_CALLBACK_H -#include "decl.h" - -typedef struct let_callback { - struct let_func *func; - struct set_values *args; - decl *decl; -} let_callback; - -let_callback *init_let_callback(struct let_func *func, struct set_values *args); -void free_let_callback(let_callback *cb); - struct psi_data; -struct impl; - -int validate_let_callback(struct psi_data *data, decl_var *cb_var, let_callback *cb, struct impl *impl); +struct psi_impl; +struct psi_decl; +struct psi_plist; +struct psi_let_exp; +struct psi_let_func; + +struct psi_let_callback { + struct psi_token *token; + struct psi_let_func *func; + struct psi_plist *args; + struct psi_decl *decl; +}; + +struct psi_let_callback *psi_let_callback_init(struct psi_let_func *func, struct psi_plist *args); +void psi_let_callback_free(struct psi_let_callback **cb_ptr); +void psi_let_callback_dump(int fd, struct psi_let_callback *cb, unsigned level); +bool psi_let_callback_validate(struct psi_data *data, struct psi_let_exp *exp, struct psi_let_callback *cb, struct psi_impl *impl); #endif diff --git a/src/types/let_calloc.c b/src/types/let_calloc.c index 7c23112..e14ef69 100644 --- a/src/types/let_calloc.c +++ b/src/types/let_calloc.c @@ -5,11 +5,11 @@ 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. + * 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 @@ -21,28 +21,42 @@ 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. -*******************************************************************************/ + *******************************************************************************/ -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif +#include "php_psi_stdinc.h" +#include "data.h" -#include -#include +struct psi_let_calloc *psi_let_calloc_init(struct psi_num_exp *nmemb, + struct psi_num_exp *size) +{ + struct psi_let_calloc *alloc = calloc(1, sizeof(*alloc)); -#include "let_calloc.h" - -let_calloc *init_let_calloc(num_exp *nmemb, num_exp *size) { - let_calloc *alloc = calloc(1, sizeof(*alloc)); alloc->nmemb = nmemb; alloc->size = size; + return alloc; } -void free_let_calloc(let_calloc *alloc) { - free_num_exp(alloc->nmemb); - free_num_exp(alloc->size); - free(alloc); +void psi_let_calloc_free(struct psi_let_calloc **alloc_ptr) +{ + if (*alloc_ptr) { + struct psi_let_calloc *alloc = *alloc_ptr; + + *alloc_ptr = NULL; + psi_num_exp_free(&alloc->nmemb); + psi_num_exp_free(&alloc->size); + if (alloc->token) { + free(alloc->token); + } + free(alloc); + } +} + +void psi_let_calloc_dump(int fd, struct psi_let_calloc *alloc) +{ + dprintf(fd, "calloc("); + psi_num_exp_dump(fd, alloc->nmemb); + dprintf(fd, ", "); + psi_num_exp_dump(fd, alloc->size); + dprintf(fd, ")"); } diff --git a/src/types/let_calloc.h b/src/types/let_calloc.h index dd0e65a..73e4914 100644 --- a/src/types/let_calloc.h +++ b/src/types/let_calloc.h @@ -26,14 +26,17 @@ #ifndef PSI_TYPES_LET_CALLOC_H #define PSI_TYPES_LET_CALLOC_H -#include "num_exp.h" - -typedef struct let_calloc { - num_exp *nmemb; - num_exp *size; -} let_calloc; - -let_calloc *init_let_calloc(num_exp *nmemb, num_exp *size); -void free_let_calloc(let_calloc *alloc); +struct psi_token; +struct psi_num_exp; + +struct psi_let_calloc { + struct psi_token *token; + struct psi_num_exp *nmemb; + struct psi_num_exp *size; +}; + +struct psi_let_calloc *psi_let_calloc_init(struct psi_num_exp *nmemb, struct psi_num_exp *size); +void psi_let_calloc_free(struct psi_let_calloc **alloc_ptr); +void psi_let_calloc_dump(int fd, struct psi_let_calloc *alloc); #endif diff --git a/src/types/let_exp.c b/src/types/let_exp.c new file mode 100644 index 0000000..1d8e2ec --- /dev/null +++ b/src/types/let_exp.c @@ -0,0 +1,334 @@ +/******************************************************************************* + Copyright (c) 2016, Michael Wallner . + 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 "call.h" + +#include + +struct psi_let_exp *psi_let_exp_init_ex(struct psi_decl_var *var, + enum psi_let_exp_kind kind, void *data) +{ + struct psi_let_exp *val = psi_let_exp_init(kind, data); + val->var = var; + return val; +} + +struct psi_let_exp *psi_let_exp_init(enum psi_let_exp_kind kind, void *data) +{ + struct psi_let_exp *let = calloc(1, sizeof(*let)); + switch (let->kind = kind) { + case PSI_LET_NULL: + assert(!data); + break; + case PSI_LET_NUMEXP: + let->data.num = data; + break; + case PSI_LET_CALLOC: + let->data.alloc = data; + break; + case PSI_LET_CALLBACK: + let->data.callback = data; + break; + case PSI_LET_FUNC: + let->data.func = data; + break; + case PSI_LET_TMP: + let->data.var = data; + break; + default: + assert(0); + } + return let; +} + +void psi_let_exp_free(struct psi_let_exp **let_ptr) +{ + if (*let_ptr) { + struct psi_let_exp *let = *let_ptr; + + *let_ptr = NULL; + switch (let->kind) { + case PSI_LET_NULL: + break; + case PSI_LET_NUMEXP: + psi_num_exp_free(&let->data.num); + break; + case PSI_LET_CALLOC: + psi_let_calloc_free(&let->data.alloc); + break; + case PSI_LET_CALLBACK: + psi_let_callback_free(&let->data.callback); + break; + case PSI_LET_FUNC: + psi_let_func_free(&let->data.func); + break; + case PSI_LET_TMP: + psi_decl_var_free(&let->data.var); + break; + default: + assert(0); + } + if (let->var) { + psi_decl_var_free(&let->var); + } + free(let); + } +} + +void psi_let_exp_dump(int fd, struct psi_let_exp *val, unsigned level, int last) +{ + if (level > 1) { + /* only if not directly after `set ...` */ + dprintf(fd, "%s", psi_t_indent(level)); + } + + if (val->var) { + if (val->var->token) { + psi_decl_var_dump(fd, val->var); + dprintf(fd, " = "); + } + } + if (val->is_reference) { + dprintf(fd, "&"); + } + + switch (val->kind) { + case PSI_LET_NULL: + dprintf(fd, "NULL"); + break; + case PSI_LET_TMP: + psi_decl_var_dump(fd, val->data.var); + dprintf(fd, "\t/* fqn=%s */", val->data.var->fqn); + break; + case PSI_LET_CALLOC: + psi_let_calloc_dump(fd, val->data.alloc); + break; + case PSI_LET_CALLBACK: + psi_let_callback_dump(fd, val->data.callback, level); + break; + case PSI_LET_FUNC: + psi_let_func_dump(fd, val->data.func, level); + break; + case PSI_LET_NUMEXP: + psi_num_exp_dump(fd, val->data.num); + break; + + default: + assert(0); + } + + if (val->var) { + dprintf(fd, "\t/* fqn=%s */", val->var->fqn); + } + + if (level > 1) { + if (!last) { + dprintf(fd, ","); + } + } else { + dprintf(fd, ";"); + } +} + +bool psi_let_exp_validate(struct psi_data *data, struct psi_let_exp *val, + struct psi_impl *impl) +{ + struct psi_decl_var *dvar = psi_let_exp_get_decl_var(val); + + switch (val->kind) { + case PSI_LET_TMP: + if (!psi_decl_var_validate(data, val->data.var, impl->decl, val, NULL)) { + data->error(data, dvar->token ? : **(struct psi_token ***) &val->data, + PSI_WARNING, "Unknown variable '%s'", dvar->name); + return false; + } + break; + + default: + if (!psi_decl_var_validate(data, dvar, impl->decl, val, NULL)) { + data->error(data, dvar->token ? : **(struct psi_token ***) &val->data, + PSI_WARNING, "Unknown variable '%s'", dvar->name); + return false; + } + break; + } + + switch (val->kind) { + case PSI_LET_NULL: + break; + case PSI_LET_TMP: + /* e.g. let bar = &strval($bar); // decl_arg(char **bar) */ + /* e.g. let foo = *bar; */ + val->var->pointer_level = val->data.var->pointer_level; + val->var->arg = val->data.var->arg; + break; + case PSI_LET_NUMEXP: + if (!psi_num_exp_validate(data, val->data.num, impl, NULL, val, NULL, NULL)) { + return false; + } + break; + case PSI_LET_CALLOC: + if (!psi_num_exp_validate(data, val->data.alloc->nmemb, impl, NULL, val, NULL, NULL)) { + return false; + } + if (!psi_num_exp_validate(data, val->data.alloc->size, impl, NULL, val, NULL, NULL)) { + return false; + } + break; + case PSI_LET_CALLBACK: + if (!psi_let_func_validate(data, val, val->data.callback->func, impl)) { + return false; + } + if (!psi_let_callback_validate(data, val, val->data.callback, impl)) { + return false; + } + break; + case PSI_LET_FUNC: + if (!psi_let_func_validate(data, val, val->data.func, impl)) { + return false; + } + break; + } + + return true; +} + +void *psi_let_exp_exec(struct psi_let_exp *val, struct psi_decl_arg *darg, + void *actual_location, size_t actual_size, struct psi_call_frame *frame) +{ + struct psi_call_frame_symbol *frame_sym; + + frame_sym = psi_call_frame_fetch_symbol(frame, val->var); + + switch (val->kind) { + case PSI_LET_NULL: + /* FIXME: sizeof_decl_arg */ + if (darg && darg->var->array_size) { + frame_sym->temp_val.ptr = ecalloc(1, psi_decl_arg_get_size(darg)); + } else { + memset(&frame_sym->temp_val, 0, sizeof(frame_sym->temp_val)); + } + break; + + case PSI_LET_TMP: + { + struct psi_let_stmt *let_temp = psi_impl_get_let(frame->impl, + val->data.var); + struct psi_call_frame_symbol *temp_arg; + + temp_arg = psi_call_frame_fetch_symbol(frame, let_temp->exp->var); + frame_sym->temp_val = *deref_impl_val(temp_arg->ptr, val->data.var); + } + break; + + case PSI_LET_CALLOC: + { + zend_long n = psi_long_num_exp(val->data.alloc->nmemb, frame); + zend_long s = psi_long_num_exp(val->data.alloc->size, frame); + void *tmp = *psi_call_frame_push_auto(frame, + safe_emalloc(n, s, sizeof(void *))); + + memset(tmp, 0, n * s + sizeof(void *)); + frame_sym->temp_val.ptr = tmp; + } + break; + + case PSI_LET_NUMEXP: + frame_sym->temp_val.zend.lval = psi_long_num_exp(val->data.num, frame); + break; + + case PSI_LET_CALLBACK: + frame_sym->temp_val.ptr = val->data.callback->decl->sym; + break; + + case PSI_LET_FUNC: + if (!psi_let_func_exec(val, val->data.func, darg, frame)) { + return NULL; + } + break; + } + + if (val->is_reference) { + frame_sym->ptr = &frame_sym->ival_ptr; + } else { + frame_sym->ptr = frame_sym->ival_ptr; + } + + if (actual_location) { + assert(!val->is_reference || actual_size == SIZEOF_VOID_P); + memcpy(actual_location, frame_sym->ptr, actual_size); + frame_sym->ptr = actual_location; + } + + return frame_sym->ptr; +} + +struct psi_let_func* psi_let_exp_get_func(struct psi_let_exp* exp) +{ + if (exp) { + switch (exp->kind) { + case PSI_LET_CALLBACK: + return exp->data.callback->func; + case PSI_LET_FUNC: + return exp->data.func; + default: + break; + } + } + return NULL; +} + +struct psi_decl_var *psi_let_exp_get_decl_var(struct psi_let_exp *val) +{ + if (!val->var) { + const char *name = psi_let_exp_get_decl_var_name(val); + + if (name) { + val->var = psi_decl_var_init(name, 0, 0); + } + } + return val->var; +} + +struct psi_impl_var *psi_let_exp_get_impl_var(struct psi_let_exp *val) +{ + struct psi_let_func* fn = psi_let_exp_get_func(val); + return fn ? fn->var : NULL; +} + +const char* psi_let_exp_get_decl_var_name(struct psi_let_exp* val) +{ + struct psi_impl_var* var; + if (val->var) { + return val->var->name; + } + var = psi_let_exp_get_impl_var(val); + if (var) { + return &var->name[1]; + } + return NULL; +} diff --git a/src/types/let_val.h b/src/types/let_exp.h similarity index 54% rename from src/types/let_val.h rename to src/types/let_exp.h index c741633..8429b61 100644 --- a/src/types/let_val.h +++ b/src/types/let_exp.h @@ -26,13 +26,16 @@ #ifndef PSI_TYPES_LET_VAL_H #define PSI_TYPES_LET_VAL_H -#include "decl_var.h" -#include "num_exp.h" -#include "let_calloc.h" -#include "let_callback.h" -#include "let_func.h" - -enum let_val_kind { +struct psi_data; +struct psi_call_frame; +struct psi_impl; +struct psi_decl_var; +struct psi_num_exp; +struct psi_let_calloc; +struct psi_let_callback; +struct psi_let_func; + +enum psi_let_exp_kind { PSI_LET_NULL, PSI_LET_NUMEXP, PSI_LET_CALLOC, @@ -41,69 +44,32 @@ enum let_val_kind { PSI_LET_TMP, }; -#define PSI_LET_REFERENCE 0x1; - -typedef struct let_val { - enum let_val_kind kind; - decl_var *var; +struct psi_let_exp { + enum psi_let_exp_kind kind; + struct psi_let_exp *outer; + struct psi_decl_var *var; union { - num_exp *num; - let_calloc *alloc; - let_callback *callback; - let_func *func; - decl_var *var; + struct psi_num_exp *num; + struct psi_let_calloc *alloc; + struct psi_let_callback *callback; + struct psi_let_func *func; + struct psi_decl_var *var; } data; unsigned is_reference:1; -} let_val; - - -let_val* init_let_val(enum let_val_kind kind, void* data); -let_val* init_let_val_ex(decl_var *var, enum let_val_kind kind, void* data); -void free_let_val(let_val* let); -void dump_let_val(int fd, let_val *val, unsigned level, int last); - -struct psi_data; -struct impl; - -int validate_let_val(struct psi_data *data, let_val *val, decl_var *let_var, struct impl *impl); - -static inline let_func *locate_let_val_func(let_val *val) { - if (val) { - switch (val->kind) { - case PSI_LET_CALLBACK: - return val->data.callback->func; - case PSI_LET_FUNC: - return val->data.func; - default: - break; - } - } - - return NULL; -} - -static inline decl_arg *locate_let_val_inner_ref(let_val *val) { - let_func *fn = locate_let_val_func(val); - return fn ? fn->ref: NULL; -} +}; -static inline impl_var *locate_let_val_impl_var(let_val *val) { - let_func *fn = locate_let_val_func(val); - return fn ? fn->var : NULL; -} -static inline const char *locate_let_val_varname(let_val *val) { - impl_var *var; +struct psi_let_exp *psi_let_exp_init(enum psi_let_exp_kind kind, void *data); +struct psi_let_exp *psi_let_exp_init_ex(struct psi_decl_var *var, enum psi_let_exp_kind kind, void *data); +void psi_let_exp_free(struct psi_let_exp **let_ptr); +void psi_let_exp_dump(int fd, struct psi_let_exp *exp, unsigned level, int last); - if (val->var) { - return val->var->name; - } +void *psi_let_exp_exec(struct psi_let_exp *exp, struct psi_decl_arg *darg, void *actual_location, size_t actual_size, struct psi_call_frame *frame); +bool psi_let_exp_validate(struct psi_data *data, struct psi_let_exp *exp, struct psi_impl *impl); - var = locate_let_val_impl_var(val); +struct psi_let_func *psi_let_exp_get_func(struct psi_let_exp *exp); +struct psi_impl_var *psi_let_exp_get_impl_var(struct psi_let_exp *exp); +struct psi_decl_var *psi_let_exp_get_decl_var(struct psi_let_exp *val); +const char *psi_let_exp_get_decl_var_name(struct psi_let_exp *exp); - if (var) { - return &var->name[1]; - } - return NULL; -} #endif diff --git a/src/types/let_func.c b/src/types/let_func.c index 42180ec..27c3702 100644 --- a/src/types/let_func.c +++ b/src/types/let_func.c @@ -5,11 +5,11 @@ 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. + * 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 @@ -21,57 +21,69 @@ 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. -*******************************************************************************/ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif - -#include -#include -#include -#include + *******************************************************************************/ +#include "php_psi_stdinc.h" #include "data.h" +#include "call.h" #include "marshal.h" -let_func *init_let_func(token_t type, const char *name, impl_var *var) { - let_func *func = calloc(1, sizeof(*func)); +#include "php.h" + +#include + +struct psi_let_func *psi_let_func_init(token_t type, const char *name, + struct psi_impl_var *var) +{ + struct psi_let_func *func = calloc(1, sizeof(*func)); func->type = type; func->name = strdup(name); func->var = var; return func; } -void free_let_func(let_func *func) { - free_impl_var(func->var); - free(func->name); - if (func->inner) { - free_let_vals(func->inner); +void psi_let_func_free(struct psi_let_func **func_ptr) +{ + if (*func_ptr) { + struct psi_let_func *func = *func_ptr; + + *func_ptr = NULL; + if (func->token) { + free(func->token); + } + psi_impl_var_free(&func->var); + free(func->name); + if (func->inner) { + psi_plist_free(func->inner); + } + free(func); } - free(func); } -void dump_let_func(int fd, let_func *func, unsigned level) { - dprintf(fd, "%s(%s", func->name, func->var->name); +void psi_let_func_dump(int fd, struct psi_let_func *func, unsigned level) +{ + dprintf(fd, "%s(%s\t/* fqn=%s */", func->name, func->var->name, func->var->fqn); if (func->inner) { - size_t i; + size_t i = 0, count = psi_plist_count(func->inner); + struct psi_let_exp *inner; dprintf(fd, ","); - for (i = 0; i < func->inner->count; ++i) { + ++level; + while (psi_plist_get(func->inner, i++, &inner)) { dprintf(fd, "\n"); - dump_let_val(fd, func->inner->vals[i], level+1, i+1 == func->inner->count); + psi_let_exp_dump(fd, inner, level, i == count); } + --level; dprintf(fd, "\n"); dprintf(fd, "%s", psi_t_indent(level)); } dprintf(fd, ")"); } -static inline int validate_let_func_type(struct psi_data *data, let_func *func, impl *impl) { +static inline int validate_let_func_type(struct psi_data *data, + struct psi_let_func *func, struct psi_impl *impl) +{ switch (func->type) { case PSI_T_BOOLVAL: case PSI_T_INTVAL: @@ -79,99 +91,318 @@ static inline int validate_let_func_type(struct psi_data *data, let_func *func, case PSI_T_STRVAL: case PSI_T_STRLEN: case PSI_T_PATHVAL: - case PSI_T_ARRVAL: case PSI_T_OBJVAL: case PSI_T_ZVAL: case PSI_T_VOID: case PSI_T_COUNT: - return 1; + return true; + + case PSI_T_ARRVAL: + if (!func->inner) { + data->error(data, func->token, PSI_WARNING, + "Expected sub-expressions in `arrval` expression"); + return false; + } + return true; + default: data->error(data, func->var->token, PSI_WARNING, "Unknown `let` cast function '%s' of implementation '%s'", func->name, impl->func->name); - return 0; + return false; } } -static inline int validate_let_func_inner(struct psi_data *data, let_val *val, let_func *func, decl_var *let_var, impl *impl) { - +static inline bool validate_let_func_inner(struct psi_data *data, + struct psi_let_exp *exp, struct psi_let_func *func, + struct psi_impl *impl) +{ if (func->inner) { - size_t i; - decl_type *var_typ; - decl_args *sub_args = extract_decl_type_args(let_var->arg->type, &var_typ); + struct psi_decl_var *let_var = psi_let_exp_get_decl_var(exp); + struct psi_decl_type *var_typ; + struct psi_plist *sub_args; + + sub_args = psi_decl_type_get_args(let_var->arg->type, &var_typ); if (func->type == PSI_T_ARRVAL && sub_args) { /* struct = arrval($array, * member = strval($member) ...) */ - size_t i; + size_t i = 0; + struct psi_let_exp *inner; + + while (psi_plist_get(func->inner, i++, &inner)) { + const char *name = psi_let_exp_get_decl_var_name(inner); + struct psi_decl_arg *sub_arg; - for (i = 0; i < func->inner->count; ++i) { - let_val *inner = func->inner->vals[i]; - const char *name = locate_let_val_varname(inner); - let_func *fn = locate_let_val_func(inner); - decl_arg *sub_arg; + inner->outer = exp; if (name) { - sub_arg = locate_decl_arg(sub_args, name); + sub_arg = psi_decl_arg_get_by_name(sub_args, name); } if (!name || !sub_arg) { - data->error(data, let_var->token, PSI_WARNING, - "Unknown variable '%s'", name); - return 0; - } - - fn->outer = val; - fn->ref = sub_arg; - - if (!validate_let_val(data, inner, sub_arg->var, impl)) { - return 0; + /* remove expr for portability with different struct members */ + psi_plist_del(func->inner, --i, NULL); + psi_let_exp_free(&inner); + } else if (!psi_let_exp_validate(data, inner, impl)) { + return false; } } - } else if (func->type == PSI_T_ARRVAL && func->inner->count == 1 && let_var->arg->var->pointer_level) { + } else if (func->type == PSI_T_ARRVAL + && psi_plist_count(func->inner) == 1 + && let_var->arg->var->pointer_level) { /* array = arrval($array, * strval($array)) // cast foreach entry */ - impl_var *sub_var = locate_let_val_impl_var(val); - impl_var *sub_ref = locate_let_val_impl_var(func->inner->vals[0]); + struct psi_let_exp *inner; + struct psi_impl_var *sub_var; + struct psi_impl_var *sub_ref; + psi_plist_get(func->inner, 0, &inner); + inner->outer = exp; + + sub_var = psi_let_exp_get_impl_var(exp); + sub_ref = psi_let_exp_get_impl_var(inner); if (strcmp(sub_var->name, sub_ref->name)) { - data->error(data, sub_var->token, E_WARNING, "Inner `set` statement casts on pointers must reference the same variable"); - return 0; + data->error(data, sub_var->token, E_WARNING, + "Inner `set` statement casts on pointers must" + " reference the same variable"); + return false; } - if (!validate_let_val(data, func->inner->vals[0], let_var, impl)) { - return 0; + if (!psi_let_exp_validate(data, inner, impl)) { + return false; } } else { data->error(data, let_var->token, PSI_WARNING, - "Inner let statement's values must refer to a structure or array type, got '%s%s' for '%s'", - var_typ->name, psi_t_indirection(let_var->arg->var->pointer_level), let_var->name); - return 0; + "Inner let statement's values must refer to a structure or" + " array type, got '%s%s' for '%s'", var_typ->name, + psi_t_indirection(let_var->arg->var->pointer_level), + let_var->name); + return false; + } + + if (!psi_plist_count(func->inner)) { + data->error(data, func->token, PSI_WARNING, + "No valid sub-expressions left"); + return false; } } - return 1; -} -int validate_let_func(struct psi_data *data, let_val *val, let_func *func, decl_var *let_var, impl *impl) { - if (func->outer) { + return true; +} - } +bool psi_let_func_validate(struct psi_data *data, struct psi_let_exp *val, + struct psi_let_func *func, struct psi_impl *impl) +{ if (impl->func->args) { - locate_impl_var_arg(func->var, impl->func->args); + /* FIXME, func->var does not need to be referring to a func arg */ + psi_impl_get_arg(impl, func->var); } - if (!func->var->arg && !func->ref) { - data->error(data, func->var->token, PSI_WARNING, - "Unknown variable '%s%s' of `let` statement" - " for cast '%s' of implementation '%s'", - *func->var->name == '$' ? "" : "$", - func->var->name, func->name, impl->func->name); - return 0; + + if (!psi_impl_var_validate(data, func->var, impl, val, NULL)) { + return false; } + if (!validate_let_func_type(data, func, impl)) { - return 0; + return false; } - if (!validate_let_func_inner(data, val, func, let_var, impl)) { - return 0; + if (!validate_let_func_inner(data, val, func, impl)) { + return false; } return 1; } + +void exec_let_func_arrval_inner(struct psi_let_func *func, + struct psi_decl_arg *darg, struct psi_decl_arg *inner_decl_arg, + struct psi_call_frame_argument *frame_arg, + struct psi_let_exp *inner_let_exp, void *container, + struct psi_call_frame *frame) +{ + struct psi_let_func *inner_func = psi_let_exp_get_func(inner_let_exp); + struct psi_impl_var *inner_var = inner_func->var; + + if (psi_decl_type_get_real(darg->type)->type == PSI_T_UNION) { + /* skip if there's no entry in the outer_zval; + * we only want to set supplied data on unions + */ + if (!zend_symtable_str_exists(Z_ARRVAL_P(frame_arg->zval_ptr), + &inner_var->name[1], strlen(&inner_var->name[1]))) { + return; + } + } + psi_call_frame_sub_argument(frame, inner_var, frame_arg->zval_ptr, + inner_func->var->fqn); + + /* example from dm_store/dbm_fetch with arrval($string) conversion: + let key = arrval($key, + dptr = strval($0), + dsize = strlen($0) + ); + # --- + darg = key + frame_arg = $key + inner_var = $0 + full_func_var_name = $key.0 + inner_decl_arg = key.dptr + */ + psi_let_exp_exec(inner_let_exp, inner_decl_arg, + ((char *) container) + inner_decl_arg->layout->pos, + inner_decl_arg->layout->len, frame); +} + +static void *exec_let_func_arrval(struct psi_let_exp *val, + struct psi_let_func *func, struct psi_decl_arg *darg, + struct psi_call_frame *frame); + +void exec_let_func_arrval_seq(struct psi_let_func *func, + struct psi_decl_arg *darg, struct psi_decl_type *darg_type, + struct psi_call_frame_argument *frame_arg, + struct psi_let_exp *inner_let_exp, void *container, + struct psi_call_frame *frame) +{ + zval *zval_ptr; + psi_marshal_let let_fn; + size_t i = 0, size; + struct psi_decl_var *dvar; + + if (inner_let_exp->var) { + /* arrval($foo, *foo = intval($foo)); */ + dvar = inner_let_exp->var; + } else { + /* arrval($foo, intval($foo)); */ + dvar = psi_decl_var_copy(darg->var); + assert(dvar->pointer_level); + --dvar->pointer_level; + } + + dvar->pointer_level += inner_let_exp->is_reference; + size = psi_decl_var_get_size(dvar); + dvar->pointer_level -= inner_let_exp->is_reference; + + let_fn = locate_let_func_fn(inner_let_exp->data.func->type); + + ZEND_HASH_FOREACH_VAL_IND(Z_ARRVAL_P(frame_arg->zval_ptr), zval_ptr) + { + void *temp = NULL; + impl_val val = {0}, *ptr, *sub; + + if (let_fn) { + ptr = let_fn(&val, darg_type, 0, NULL, zval_ptr, &temp); + if (temp) { + psi_call_frame_push_auto(frame, temp); + } + } else if (func->type == PSI_T_ARRVAL) { + ptr = exec_let_func_arrval(inner_let_exp, + inner_let_exp->data.func, darg, frame); + } else { + assert(0); + } + + sub = deref_impl_val(ptr, dvar); + + memcpy(&((char *) container)[size * i++], &sub, size); + } + ZEND_HASH_FOREACH_END(); + + if (dvar != inner_let_exp->var) { + psi_decl_var_free(&dvar); + } +} + +static void *exec_let_func_arrval(struct psi_let_exp *val, + struct psi_let_func *func, struct psi_decl_arg *darg, + struct psi_call_frame *frame) +{ + void *container = NULL; + struct psi_call_frame_argument *frame_arg; + struct psi_decl_type *darg_type; + struct psi_plist *darg_members; + + darg_members = psi_decl_type_get_args(darg->type, &darg_type); + frame_arg = psi_call_frame_get_argument(frame, func->var->fqn); + + if (frame_arg->zval_ptr && Z_TYPE_P(frame_arg->zval_ptr) != IS_ARRAY) { + convert_to_array(frame_arg->zval_ptr); + } + + if (darg_members && func->inner) { + /* struct or union + * arrval($foo, + * str = strval($str), + * num = intval($num)); + */ + size_t i = 0, size; + struct psi_let_exp *inner; + struct psi_decl_arg *darg_member; + + val->var->pointer_level += val->is_reference; + size = psi_decl_var_get_size(val->var); + container = ecalloc(1, size); + val->var->pointer_level -= val->is_reference; + + if (frame_arg->zval_ptr) { + while (psi_plist_get(func->inner, i++, &inner)) { + darg_member = psi_decl_arg_get_by_name(darg_members, + psi_let_exp_get_decl_var_name(inner)); + + exec_let_func_arrval_inner(func, darg, darg_member, frame_arg, + inner, container, frame); + } + } + } else if (func->inner) { + /* array + * arrval($foo, foo = intval($foo)) + */ + size_t arcount; + struct psi_let_exp *inner; + + if (!frame_arg->zval_ptr) { + return NULL; + } + assert(psi_plist_count(func->inner) == 1); + + arcount = zend_array_count(Z_ARRVAL_P(frame_arg->zval_ptr)); + psi_plist_get(func->inner, 0, &inner); + + inner->var->pointer_level += inner->is_reference; + container = ecalloc(arcount + 1, psi_decl_var_get_size(inner->var)); + inner->var->pointer_level -= inner->is_reference; + + exec_let_func_arrval_seq(func, darg, darg_type, frame_arg, inner, + container, frame); + } else { + assert(0); + } + + return *psi_call_frame_push_auto(frame, container); +} + +void *psi_let_func_exec(struct psi_let_exp *val, struct psi_let_func *func, + struct psi_decl_arg *darg, struct psi_call_frame *frame) +{ + struct psi_call_frame_symbol *frame_sym; + psi_marshal_let let_fn = locate_let_func_fn(func->type); + + frame_sym = psi_call_frame_fetch_symbol(frame, val->var); + + if (let_fn) { + void *temp = NULL; + struct psi_call_frame_argument *iarg; + + iarg = psi_call_frame_get_argument(frame, func->var->fqn); + + assert(iarg); + + frame_sym->ival_ptr = let_fn(&frame_sym->temp_val, + psi_decl_type_get_real(darg->type), + iarg->spec ? iarg->spec->type->type : 0, iarg->ival_ptr, + iarg->zval_ptr, &temp); + if (temp) { + psi_call_frame_push_auto(frame, temp); + } + } else if (func->type == PSI_T_ARRVAL) { + frame_sym->ival_ptr = exec_let_func_arrval(val, func, darg, frame); + } + + return frame_sym->ival_ptr; +} diff --git a/src/types/let_func.h b/src/types/let_func.h index 936c38d..8917a0c 100644 --- a/src/types/let_func.h +++ b/src/types/let_func.h @@ -28,26 +28,46 @@ #include "token.h" -#include "impl_var.h" -#include "decl_arg.h" +struct psi_data; +struct psi_impl; +struct psi_decl_arg; +struct psi_impl_var; +struct psi_let_exp; +struct psi_call_frame; -typedef struct let_func { +struct psi_let_func { + struct psi_token *token; token_t type; char *name; - impl_var *var; - struct let_vals *inner; - struct let_val *outer; - decl_arg *ref; -} let_func; + struct psi_impl_var *var; + struct psi_plist *inner; +}; -let_func *init_let_func(token_t type, const char *name, impl_var *var); -void free_let_func(let_func *func); -void dump_let_func(int fd, let_func *func, unsigned level); +struct psi_let_func *psi_let_func_init(token_t type, const char *name, struct psi_impl_var *var); +void psi_let_func_free(struct psi_let_func **func_ptr); +void psi_let_func_dump(int fd, struct psi_let_func *func, unsigned level); -struct psi_data; -struct impl; -struct let_val; +void *psi_let_func_exec(struct psi_let_exp *func_val, struct psi_let_func *func, struct psi_decl_arg *darg, struct psi_call_frame *frame); +bool psi_let_func_validate(struct psi_data *data, struct psi_let_exp *exp, struct psi_let_func *func, struct psi_impl *impl); + +#include "marshal.h" + +static inline psi_marshal_let locate_let_func_fn(token_t type) { + psi_marshal_let let_fn = NULL; -int validate_let_func(struct psi_data *data, struct let_val *val, let_func *func, decl_var *let_var, struct impl *impl); + switch (type) { + case PSI_T_BOOLVAL: let_fn = psi_let_boolval; break; + case PSI_T_INTVAL: let_fn = psi_let_intval; break; + case PSI_T_FLOATVAL: let_fn = psi_let_floatval; break; + case PSI_T_STRVAL: let_fn = psi_let_strval; break; + case PSI_T_STRLEN: let_fn = psi_let_strlen; break; + case PSI_T_PATHVAL: let_fn = psi_let_pathval; break; + case PSI_T_OBJVAL: let_fn = psi_let_objval; break; + case PSI_T_ZVAL: let_fn = psi_let_zval; break; + case PSI_T_VOID: let_fn = psi_let_void; break; + case PSI_T_COUNT: let_fn = psi_let_count; break; + } + return let_fn; +} #endif diff --git a/src/types/let_stmt.c b/src/types/let_stmt.c index 5474ae2..0984457 100644 --- a/src/types/let_stmt.c +++ b/src/types/let_stmt.c @@ -5,11 +5,11 @@ 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. + * 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 @@ -21,104 +21,115 @@ 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. -*******************************************************************************/ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif - -#include -#include + *******************************************************************************/ +#include "php_psi_stdinc.h" #include "data.h" -let_stmt *init_let_stmt(let_val *val) { - let_stmt *let = calloc(1, sizeof(*let)); - let->val = val; +struct psi_let_stmt *psi_let_stmt_init(struct psi_let_exp *exp) +{ + struct psi_let_stmt *let = calloc(1, sizeof(*let)); + let->exp = exp; return let; } -void free_let_stmt(let_stmt *stmt) { - if (stmt->val) { - free_let_val(stmt->val); - } - if (stmt->token) { - free(stmt->token); +void psi_let_stmt_free(struct psi_let_stmt **stmt_ptr) +{ + if (*stmt_ptr) { + struct psi_let_stmt *stmt = *stmt_ptr; + + *stmt_ptr = NULL; + if (stmt->exp) { + psi_let_exp_free(&stmt->exp); + } + if (stmt->token) { + free(stmt->token); + } + free(stmt); } - free(stmt); } -void dump_let_stmt(int fd, let_stmt *let) { - dprintf(fd, "\t%s ", let->val->kind == PSI_LET_TMP ? "temp" : "let"); - dump_let_val(fd, let->val, 1, 1); +void psi_let_stmt_dump(int fd, struct psi_let_stmt *let) +{ + dprintf(fd, "\t%s ", let->exp->kind == PSI_LET_TMP ? "temp" : "let"); + psi_let_exp_dump(fd, let->exp, 1, 1); + dprintf(fd, "\n"); } -int validate_let_stmts(struct psi_data *data, impl *impl) { - size_t i, j; - /* we can have multiple let stmts */ +bool psi_let_stmts_validate(struct psi_data *data, struct psi_impl *impl) +{ + size_t i = 0; + struct psi_let_stmt *let; + /* we can have multiple let stmts */ /* check that we have a decl arg and impl arg for every let stmt */ - for (i = 0; i < impl->stmts->let.count; ++i) { - let_stmt *let = impl->stmts->let.list[i]; - decl_var *let_var; - impl_var *let_ivar = NULL; + while (psi_plist_get(impl->stmts.let, i++, &let)) { + struct psi_decl_var *let_var; + struct psi_impl_var *let_ivar = NULL; - if (let->val && let->val->kind == PSI_LET_TMP) { - let_var = let->val->data.var; + if (let->exp->kind == PSI_LET_TMP) { + let_var = let->exp->data.var; } else { - let_var = let->val->var; + let_var = let->exp->var; } - if (!locate_decl_var_arg(let_var, impl->decl->args, impl->decl->func)) { - data->error(data, let_var->token, PSI_WARNING, "Unknown variable '%s' in `let` statement" - " of implementation '%s'", let_var->name, impl->func->name); - return 0; + if (!let->exp->var) { + data->error(data, let->token, PSI_WARNING, + "Missing variable in `let` statement for implementation %s", + impl->func->name); + return false; } - switch (let->val->kind) { + + if (!psi_decl_get_arg(impl->decl, let_var)) { + data->error(data, let_var->token, PSI_WARNING, + "Unknown variable '%s' in `let` statement of implementation '%s'", + let_var->name, impl->func->name); + return false; + } + switch (let->exp->kind) { case PSI_LET_CALLBACK: - let_ivar = let->val->data.callback->func->var; + let_ivar = let->exp->data.callback->func->var; break; case PSI_LET_FUNC: - let_ivar = let->val->data.func->var; + let_ivar = let->exp->data.func->var; break; default: break; } - if (let_ivar && !locate_impl_var_arg(let_ivar, impl->func->args)) { - data->error(data, let_var->token, PSI_WARNING, "Unknown variable '%s' in `let` statement" - " of implementation '%s'", let_ivar->name, impl->func->name); - return 0; + if (let_ivar && !psi_impl_get_arg(impl, let_ivar)) { + data->error(data, let_var->token, PSI_WARNING, + "Unknown variable '%s' in `let` statement of implementation '%s'", + let_ivar->name, impl->func->name); + return false; } - if (!validate_let_val(data, let->val, let->val->var, impl)) { - return 0; + if (!psi_let_exp_validate(data, let->exp, impl)) { + return false; } } /* check that we have a let stmt for every decl arg */ - if (impl->decl->args) for (i = 0; i < impl->decl->args->count; ++i) { - decl_arg *darg = impl->decl->args->args[i]; - int check = 0; - - for (j = 0; j < impl->stmts->let.count; ++j) { - let_stmt *let = impl->stmts->let.list[j]; - - if (!strcmp(let->val->var->name, darg->var->name)) { - check = 1; - break; + if (impl->decl->args) { + struct psi_decl_arg *darg; + + for (i = 0; psi_plist_get(impl->decl->args, i, &darg); ++i) { + if (!psi_impl_get_let(impl, darg->var)) { + data->error(data, impl->func->token, PSI_WARNING, + "Missing `let` statement for arg '%s %s%s'" + " of declaration '%s' for implementation '%s'", + darg->type->name, + psi_t_indirection(darg->var->pointer_level), + darg->var->name, impl->decl->func->var->name, + impl->func->name); + return false; } } - if (!check) { - data->error(data, impl->func->token, PSI_WARNING, - "Missing `let` statement for arg '%s %.*s%s'" - " of declaration '%s' for implementation '%s'", - darg->type->name, (int) darg->var->pointer_level, "*****", - darg->var->name, impl->decl->func->var->name, impl->func->name); - return 0; - } } - return 1; + return true; +} + +void *psi_let_stmt_exec(struct psi_let_stmt *let, struct psi_call_frame *frame) +{ + return psi_let_exp_exec(let->exp, let->exp->var->arg, NULL, 0, frame); } diff --git a/src/types/let_stmt.h b/src/types/let_stmt.h index 3b6ab3c..2c16f8b 100644 --- a/src/types/let_stmt.h +++ b/src/types/let_stmt.h @@ -26,21 +26,22 @@ #ifndef PSI_TYPES_LET_STMT_H #define PSI_TYPES_LET_STMT_H -#include "decl_var.h" -#include "let_val.h" +struct psi_data; +struct psi_token; +struct psi_let_exp; +struct psi_call_frame; +struct psi_impl; -typedef struct let_stmt { +struct psi_let_stmt { struct psi_token *token; - let_val *val; -} let_stmt; - -let_stmt *init_let_stmt(let_val *val); -void free_let_stmt(let_stmt *stmt); -void dump_let_stmt(int fd, let_stmt *let); + struct psi_let_exp *exp; +}; -struct psi_data; -struct impl; +struct psi_let_stmt *psi_let_stmt_init(struct psi_let_exp *exp); +void psi_let_stmt_free(struct psi_let_stmt **stmt_ptr); +void psi_let_stmt_dump(int fd, struct psi_let_stmt *stmt); -int validate_let_stmts(struct psi_data *data, struct impl *impl); +void *psi_let_stmt_exec(struct psi_let_stmt *stmt, struct psi_call_frame *frame); +bool psi_let_stmts_validate(struct psi_data *data, struct psi_impl *impl); #endif diff --git a/src/types/let_val.c b/src/types/let_val.c deleted file mode 100644 index 23b3afc..0000000 --- a/src/types/let_val.c +++ /dev/null @@ -1,225 +0,0 @@ -/******************************************************************************* - Copyright (c) 2016, Michael Wallner . - 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. -*******************************************************************************/ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif - -#include -#include -#include - -#include "data.h" - -let_val *init_let_val_ex(decl_var *var, enum let_val_kind kind, void *data) { - let_val *val = init_let_val(kind, data); - val->var = var; - return val; -} - -let_val *init_let_val(enum let_val_kind kind, void *data) { - let_val *let = calloc(1, sizeof(*let)); - switch (let->kind = kind) { - case PSI_LET_NULL: - assert(!data); - break; - case PSI_LET_NUMEXP: - let->data.num = data; - break; - case PSI_LET_CALLOC: - let->data.alloc = data; - break; - case PSI_LET_CALLBACK: - let->data.callback = data; - break; - case PSI_LET_FUNC: - let->data.func = data; - break; - case PSI_LET_TMP: - let->data.var = data; - break; - default: - assert(0); - } - return let; -} - -void free_let_val(let_val *let) { - switch (let->kind) { - case PSI_LET_NULL: - break; - case PSI_LET_NUMEXP: - free_num_exp(let->data.num); - break; - case PSI_LET_CALLOC: - free_let_calloc(let->data.alloc); - break; - case PSI_LET_CALLBACK: - free_let_callback(let->data.callback); - break; - case PSI_LET_FUNC: - free_let_func(let->data.func); - break; - case PSI_LET_TMP: - if (let->var->arg) { - free_decl_arg(let->var->arg); - } - free_decl_var(let->data.var); - break; - default: - assert(0); - } - if (let->var) { - free_decl_var(let->var); - } - free(let); -} - -void dump_let_val(int fd, let_val *val, unsigned level, int last) { - if (level > 1) { - /* only if not directly after `set ...` */ - dprintf(fd, "%s", psi_t_indent(level)); - } - - if (val->var) { - dump_decl_var(fd, val->var); - dprintf(fd, " = "); - } - if (val->is_reference) { - dprintf(fd, "&"); - } - - switch (val->kind) { - case PSI_LET_NULL: - dprintf(fd, "NULL"); - break; - case PSI_LET_TMP: - dump_decl_var(fd, val->data.var); - break; - case PSI_LET_CALLOC: - dprintf(fd, "calloc("); - dump_num_exp(fd, val->data.alloc->nmemb); - dprintf(fd, ", "); - dump_num_exp(fd, val->data.alloc->size); - dprintf(fd, ")"); - break; - case PSI_LET_CALLBACK: - dprintf(fd, "callback %s(%s(", val->data.callback->func->name, - val->data.callback->func->var->name); - if (val->data.callback->args) { - size_t i, c = val->data.callback->args->count; - - dprintf(fd, "\n"); - for (i = 0; i < c; ++i) { - set_value *set = val->data.callback->args->vals[i]; - ++level; - dump_set_value(fd, set, level, i + 1 == c); - --level; - } - dprintf(fd, "%s", psi_t_indent(level)); - } - dprintf(fd, "))"); - break; - case PSI_LET_FUNC: - dump_let_func(fd, val->data.func, level); - break; - case PSI_LET_NUMEXP: - dump_num_exp(fd, val->data.num); - break; - - default: - assert(0); - } - - if (level > 1) { - if (!last) { - dprintf(fd, ","); - } - } else { - dprintf(fd, ";"); - } -} - -int validate_let_val(struct psi_data *data, let_val *val, decl_var *let_var, impl *impl) { - switch (val->kind) { - case PSI_LET_NULL: - break; - case PSI_LET_TMP: - if (!let_var) { - data->error(data, NULL, PSI_WARNING, - "Ivalid temp statement value of implementation '%s'", - impl->func->name); - return 0; - } - /* e.g. let bar = &strval($bar); // decl_arg(char **bar) */ - /* e.g. let foo = *bar; */ - let_var->pointer_level = val->data.var->pointer_level; - let_var->arg = init_decl_arg( - init_decl_type( - real_decl_type(val->data.var->arg->type)->type, - real_decl_type(val->data.var->arg->type)->name), - init_decl_var( - let_var->name, - let_var->pointer_level, - let_var->array_size)); - break; - case PSI_LET_NUMEXP: - if (!validate_num_exp(data, val->data.num, impl->decl->args, impl->decl->func, NULL)) { - return 0; - } - break; - case PSI_LET_CALLOC: - if (!validate_num_exp(data, val->data.alloc->nmemb, impl->decl->args, impl->decl->func, NULL)) { - return 0; - } - if (!validate_num_exp(data, val->data.alloc->size, impl->decl->args, impl->decl->func, NULL)) { - return 0; - } - break; - case PSI_LET_CALLBACK: - if (!let_var) { - data->error(data, NULL, PSI_WARNING, - "Ivalid let statement value of implementation '%s'", - impl->func->name); - return 0; - } - if (!validate_let_func(data, val, val->data.callback->func, let_var, impl)) { - return 0; - } - if (!validate_let_callback(data, let_var, val->data.callback, impl)) { - return 0; - } - break; - case PSI_LET_FUNC: - if (!validate_let_func(data, val, val->data.func, let_var, impl)) { - return 0; - } - break; - } - - return 1; -} diff --git a/src/types/let_vals.c b/src/types/let_vals.c deleted file mode 100644 index 05b7bc2..0000000 --- a/src/types/let_vals.c +++ /dev/null @@ -1,65 +0,0 @@ -/******************************************************************************* - Copyright (c) 2016, Michael Wallner . - 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. -*******************************************************************************/ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif - -#include -#include - -#include "let_vals.h" - -let_vals *init_let_vals(struct let_val *val) { - let_vals *vals = calloc(1, sizeof(*vals)); - if (val) { - vals->count = 1; - vals->vals = calloc(1, sizeof(val)); - vals->vals[0] = val; - } - return vals; -} - -let_vals *add_let_val(let_vals *vals, struct let_val *val) { - if (!vals) { - vals = calloc(1, sizeof(*vals)); - } - vals->vals = realloc(vals->vals, ++vals->count * sizeof(val)); - vals->vals[vals->count - 1] = val; - return vals; -} - -void free_let_vals(let_vals *vals) { - if (vals->vals) { - size_t i; - for (i = 0; i < vals->count; ++i) { - free_let_val(vals->vals[i]); - } - free(vals->vals); - } - free(vals); -} diff --git a/src/types/let_vals.h b/src/types/let_vals.h deleted file mode 100644 index 01b1d84..0000000 --- a/src/types/let_vals.h +++ /dev/null @@ -1,54 +0,0 @@ -/******************************************************************************* - Copyright (c) 2016, Michael Wallner . - 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_TYPES_LET_VALS_H -#define PSI_TYPES_LET_VALS_H - -#include "let_val.h" - -typedef struct let_vals { - struct let_val **vals; - size_t count; -} let_vals; - -let_vals *init_let_vals(struct let_val *val); -let_vals *add_let_val(let_vals *vals, struct let_val *val); -void free_let_vals(let_vals *vals); - -static inline let_val *locate_let_vals_val(let_vals *vals, const char *name) { - size_t i; - - for (i = 0; i < vals->count; ++i) { - let_val *val = vals->vals[i]; - const char *var = locate_let_val_varname(val); - - if (!strcmp(var, name)) { - return val; - } - } - - return NULL; -} -#endif diff --git a/src/types/num_exp.c b/src/types/num_exp.c index d2fcc1a..7d752a3 100644 --- a/src/types/num_exp.c +++ b/src/types/num_exp.c @@ -5,11 +5,11 @@ 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. + * 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 @@ -21,61 +21,60 @@ 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. -*******************************************************************************/ + *******************************************************************************/ -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif +#include "php_psi_stdinc.h" -#include -#include -#include #include #include "data.h" +#include "call.h" #include "calc.h" -num_exp *init_num_exp(token_t t, void *num) { - num_exp *exp = calloc(1, sizeof(*exp)); - switch (exp->t = t) { +struct psi_num_exp *psi_num_exp_init(token_t t, void *num) +{ + struct psi_num_exp *exp = calloc(1, sizeof(*exp)); + + switch (exp->type = t) { case PSI_T_NUMBER: case PSI_T_NSNAME: - exp->u.numb = strdup(num); + exp->data.numb = strdup(num); break; case PSI_T_NAME: - exp->u.dvar = num; + exp->data.dvar = num; break; default: assert(0); } + return exp; } -num_exp *copy_num_exp(num_exp *exp) { - decl_var *dvar; - num_exp *num = calloc(1, sizeof(*num)); - memcpy(num, exp, sizeof(*num)); +struct psi_num_exp *psi_num_exp_copy(struct psi_num_exp *exp) +{ + struct psi_num_exp *num = calloc(1, sizeof(*num)); + + *num = *exp; + if (num->token) { num->token = psi_token_copy(num->token); } if (num->operand) { - num->operand = copy_num_exp(num->operand); + num->operand = psi_num_exp_copy(num->operand); } - switch (num->t) { + + switch (num->type) { + case PSI_T_INT64: + case PSI_T_DOUBLE: + case PSI_T_ENUM: + case PSI_T_CONST: + break; case PSI_T_NUMBER: case PSI_T_NSNAME: - num->u.numb = strdup(num->u.numb); + num->data.numb = strdup(num->data.numb); break; case PSI_T_NAME: - dvar = init_decl_var(num->u.dvar->name, num->u.dvar->pointer_level, - num->u.dvar->array_size); - dvar->arg = num->u.dvar->arg; - if (num->u.dvar->token) { - dvar->token = psi_token_copy(num->u.dvar->token); - } - num->u.dvar = dvar; + num->data.dvar = psi_decl_var_copy(num->data.dvar); break; default: assert(0); @@ -83,151 +82,306 @@ num_exp *copy_num_exp(num_exp *exp) { return num; } -void free_num_exp(num_exp *exp) { - if (exp->token) { - free(exp->token); - } - switch (exp->t) { - case PSI_T_NUMBER: - free(exp->u.numb); - break; - case PSI_T_NSNAME: - break; - case PSI_T_NAME: - free_decl_var(exp->u.dvar); - break; - case PSI_T_ENUM: - break; - default: - assert(0); - } - if (exp->operand) { - free_num_exp(exp->operand); +void psi_num_exp_free(struct psi_num_exp **exp_ptr) +{ + if (*exp_ptr) { + struct psi_num_exp *exp = *exp_ptr; + + *exp_ptr = NULL; + if (exp->token) { + free(exp->token); + } + switch (exp->type) { + case PSI_T_INT64: + case PSI_T_DOUBLE: + case PSI_T_ENUM: + case PSI_T_CONST: + break; + case PSI_T_NSNAME: + case PSI_T_NUMBER: + free(exp->data.numb); + break; + case PSI_T_NAME: + psi_decl_var_free(&exp->data.dvar); + break; + default: + assert(0); + } + if (exp->operand) { + psi_num_exp_free(&exp->operand); + } + free(exp); } - free(exp); } -void dump_num_exp(int fd, num_exp *exp) { +void psi_num_exp_dump(int fd, struct psi_num_exp *exp) +{ while (exp) { - switch (exp->t) { - case PSI_T_NUMBER: - dprintf(fd, "%s", exp->u.numb); + switch (exp->type) { + case PSI_T_INT64: + dprintf(fd, "%" PRId64, exp->data.ival.i64); + break; + case PSI_T_DOUBLE: + dprintf(fd, "%F", exp->data.ival.dval); break; + case PSI_T_NUMBER: case PSI_T_NSNAME: - dprintf(fd, "%s", exp->u.cnst->name); + dprintf(fd, "%s", exp->data.numb); break; - case PSI_T_NAME: - dump_decl_var(fd, exp->u.dvar); + case PSI_T_CONST: + dprintf(fd, "%s", exp->data.cnst->name); break; case PSI_T_ENUM: - dprintf(fd, "%s", exp->u.enm->name); + dprintf(fd, "%s", exp->data.enm->name); + break; + case PSI_T_NAME: + psi_decl_var_dump(fd, exp->data.dvar); break; default: assert(0); } + if (exp->operand) { char op; - switch (exp->operator) { - case PSI_T_PLUS: op = '+'; break; - case PSI_T_MINUS: op = '-'; break; - case PSI_T_ASTERISK:op = '*'; break; - case PSI_T_SLASH: op = '/'; break; + switch (exp->op) { + case PSI_T_PLUS: + op = '+'; + break; + case PSI_T_MINUS: + op = '-'; + break; + case PSI_T_ASTERISK: + op = '*'; + break; + case PSI_T_SLASH: + op = '/'; + break; default: assert(0); } dprintf(fd, " %c ", op); } + exp = exp->operand; } } -static inline constant *locate_num_exp_constant(num_exp *exp, constants *consts) { - size_t i; - - for (i = 0; i < consts->count; ++i) { - constant *cnst = consts->list[i]; +static inline bool psi_num_exp_validate_enum(struct psi_data *data, struct psi_num_exp *exp, + struct psi_decl_enum *enm) +{ + size_t i = 0; + struct psi_decl_enum_item *itm; - if (!strcmp(cnst->name, exp->u.numb)) { - free(exp->u.numb); - return exp->u.cnst = cnst; + while (psi_plist_get(enm->items, i++, &itm)) { + if (!strcmp(itm->name, exp->data.dvar->name)) { + psi_decl_var_free(&exp->data.dvar); + exp->type = PSI_T_ENUM; + exp->data.enm = itm; + return psi_num_exp_validate(data, exp, NULL, NULL, NULL, NULL, enm); } } - return NULL; + return false; } -static inline decl_enum_item *locate_num_exp_enum_item_ex(num_exp *exp, decl_enum *e) { - size_t k; - if (e) for (k = 0; k < e->items->count; ++k) { - decl_enum_item *i = e->items->list[k]; - - if (!strcmp(i->name, exp->u.dvar->name)) { - free_decl_var(exp->u.dvar); - exp->t = PSI_T_ENUM; - exp->u.enm = i; - return i; - } - } - return NULL; -} -static inline decl_enum_item *locate_num_exp_enum_item(num_exp *exp, decl_enums *enums) { - size_t j; - - if (enums) for (j = 0; j < enums->count; ++j) { - decl_enum *e = enums->list[j]; - decl_enum_item *i = locate_num_exp_enum_item_ex(exp, e); - - if (i) { - return i; - } - } - return NULL; -} +bool psi_num_exp_validate(struct psi_data *data, struct psi_num_exp *exp, + struct psi_impl *impl, struct psi_decl *cb_decl, struct psi_let_exp *current_let, + struct psi_set_exp *current_set, struct psi_decl_enum *current_enum) +{ + size_t i = 0; + impl_val tmp = {0}; + struct psi_const *cnst; + struct psi_decl_enum *enm; -int validate_num_exp(struct psi_data *data, num_exp *exp, decl_args *dargs, decl_arg *func, decl_enum *enm) { if (exp->operand) { - switch (exp->operator) { + switch (exp->op) { case PSI_T_PLUS: - exp->calculator = psi_calc_add; + exp->calc = psi_calc_add; break; case PSI_T_MINUS: - exp->calculator = psi_calc_sub; + exp->calc = psi_calc_sub; break; case PSI_T_ASTERISK: - exp->calculator = psi_calc_mul; + exp->calc = psi_calc_mul; break; case PSI_T_SLASH: - exp->calculator = psi_calc_div; + exp->calc = psi_calc_div; break; default: - assert(0); + data->error(data, exp->token, PSI_WARNING, + "Unknown numeric operator (%d)", exp->op); + return false; } - if (!validate_num_exp(data, exp->operand, dargs, func, enm)) { - return 0; + if (!psi_num_exp_validate(data, exp->operand, impl, cb_decl, current_let, + current_set, current_enum)) { + return false; } } - switch (exp->t) { + + switch (exp->type) { + case PSI_T_CONST: + case PSI_T_INT64: + case PSI_T_DOUBLE: + case PSI_T_ENUM: + return true; + case PSI_T_NAME: - if (!locate_decl_var_arg(exp->u.dvar, dargs, func)) { - if (!locate_num_exp_enum_item(exp, data->enums) && !locate_num_exp_enum_item_ex(exp, enm)) { - data->error(data, exp->token, PSI_WARNING, "Unknown variable '%s' in numeric expression", - exp->u.dvar->name); - return 0; + if (current_enum && psi_num_exp_validate_enum(data, exp, current_enum)) { + return true; + } + while (psi_plist_get(data->enums, i++, &enm)) { + if (psi_num_exp_validate_enum(data, exp, enm)) { + return true; } } - return 1; + if (exp->data.dvar->arg) { + return true; + } + if (psi_decl_var_validate(data, exp->data.dvar, impl ? impl->decl : NULL, + current_let, current_set)) { + return true; + } + if (cb_decl && psi_decl_var_validate(data, exp->data.dvar, cb_decl, NULL, NULL)) { + return true; + } + data->error(data, exp->token, PSI_WARNING, + "Unknown variable '%s' in numeric expression", + exp->data.dvar->name); + return false; + case PSI_T_NSNAME: - if (!locate_num_exp_constant(exp, data->consts)) { - data->error(data, exp->token, PSI_WARNING, "Unknown constant '%s' in numeric expression", - exp->u.numb); - return 0; + while (psi_plist_get(data->consts, i++, &cnst)) { + if (!strcmp(cnst->name, exp->data.numb)) { + free(exp->data.numb); + exp->type = PSI_T_CONST; + exp->data.cnst = cnst; + return true; + } } - return 1; + data->error(data, exp->token, PSI_WARNING, + "Unknown constant '%s' in numeric expression", + exp->data.numb); + return false; + case PSI_T_NUMBER: - case PSI_T_ENUM: - return 1; + switch (is_numeric_string(exp->data.numb, strlen(exp->data.numb), (zend_long *) &tmp, (double *) &tmp, 0)) { + case IS_LONG: + free(exp->data.numb); + exp->type = PSI_T_INT64; + exp->data.ival.i64 = tmp.zend.lval; + return true; + + case IS_DOUBLE: + free(exp->data.numb); + exp->type = PSI_T_DOUBLE; + exp->data.ival.dval = tmp.dval; + return true; + } + data->error(data, exp->token, PSI_WARNING, "Expected numeric entity (parser error?)"); + return false; + + default: + assert(0); + } + + return false; +} + +#include "Zend/zend_constants.h" + +static inline token_t psi_num_exp_eval_constant(struct psi_num_exp *exp, + impl_val *res, struct psi_call_frame *frame) +{ + switch (exp->data.cnst->type->type) { + case PSI_T_INT: + res->i64 = zend_get_constant_str(exp->data.cnst->name, + strlen(exp->data.cnst->name))->value.lval; + return PSI_T_INT64; + case PSI_T_FLOAT: + res->dval = zend_get_constant_str(exp->data.cnst->name, + strlen(exp->data.cnst->name))->value.dval; + return PSI_T_DOUBLE; default: return 0; } } + +static inline token_t psi_num_exp_eval_decl_var(struct psi_num_exp *exp, + impl_val *res, struct psi_call_frame *frame) +{ + impl_val *ref; + struct psi_call_frame_symbol *sym; + struct psi_decl_type *real; + size_t size; + + real = psi_decl_type_get_real(exp->data.dvar->arg->type); + size = psi_decl_arg_get_size(exp->data.dvar->arg); + sym = psi_call_frame_fetch_symbol(frame, exp->data.dvar); + ref = deref_impl_val(sym->ptr, exp->data.dvar); + + memcpy(res, ref, size); + + switch (real->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: + case PSI_T_FLOAT: + case PSI_T_DOUBLE: + break; + default: + assert(0); + } + + return real->type; +} + +static inline token_t psi_num_exp_eval(struct psi_num_exp *exp, impl_val *res, + struct psi_call_frame *frame) +{ + switch (exp->type) { + case PSI_T_INT64: + case PSI_T_DOUBLE: + *res = exp->data.ival; + return exp->type; + + case PSI_T_ENUM: + res->i64 = exp->data.enm->val; + return PSI_T_INT64; + + case PSI_T_CONST: + return psi_num_exp_eval_constant(exp, res, frame); + break; + + case PSI_T_NAME: + return psi_num_exp_eval_decl_var(exp, res, frame); + break; + + default: + assert(0); + } + return 0; +} + +token_t psi_num_exp_exec(struct psi_num_exp *exp, impl_val *res, + struct psi_call_frame *frame) +{ + impl_val num = {0}; + token_t num_type = psi_num_exp_eval(exp, &num, frame); + + /* FIXME operator precedence */ + if (exp->operand) { + impl_val tmp = {0}; + token_t tmp_type = psi_num_exp_exec(exp->operand, &tmp, frame); + + return exp->calc(num_type, &num, tmp_type, &tmp, res); + } + + *res = num; + return num_type; +} diff --git a/src/types/num_exp.h b/src/types/num_exp.h index e1b3b22..8666cb8 100644 --- a/src/types/num_exp.h +++ b/src/types/num_exp.h @@ -27,35 +27,64 @@ #define PSI_TYPES_NUM_EXP #include "token.h" +#include "Zend/zend_types.h" -#include "constant.h" -#include "decl_var.h" -#include "impl_val.h" +struct psi_data; +struct psi_token; +struct psi_impl; +struct psi_const; +struct psi_decl_enum_item; +struct psi_let_exp; +struct psi_set_exp; +struct psi_call_frame; -typedef struct num_exp { +struct psi_num_exp { struct psi_token *token; - token_t t; + token_t type; union { char *numb; - constant *cnst; - decl_var *dvar; - struct decl_enum_item *enm; - } u; - token_t operator; - int (*calculator)(int t1, impl_val *v1, int t2, impl_val *v2, impl_val *res); - struct num_exp *operand; -} num_exp; - -num_exp *init_num_exp(token_t t, void *num); -num_exp *copy_num_exp(num_exp *exp); -void free_num_exp(num_exp *exp); -void dump_num_exp(int fd, num_exp *exp); + impl_val ival; + struct psi_const *cnst; + struct psi_decl_var *dvar; + struct psi_decl_enum_item *enm; + } data; + token_t op; + struct psi_num_exp *operand; + token_t (*calc)(token_t t1, impl_val *v1, token_t t2, impl_val *v2, impl_val *res); +}; -struct psi_data; -struct decl_args; -struct decl_arg; -struct decl_enum; +struct psi_num_exp *psi_num_exp_init(token_t t, void *num); +struct psi_num_exp *psi_num_exp_copy(struct psi_num_exp *exp); +void psi_num_exp_free(struct psi_num_exp **exp_ptr); +void psi_num_exp_dump(int fd, struct psi_num_exp *exp); + +bool psi_num_exp_validate(struct psi_data *data, struct psi_num_exp *exp, + struct psi_impl *impl, struct psi_decl *cb_decl, + struct psi_let_exp *current_let, struct psi_set_exp *current_set, + struct psi_decl_enum *current_enum); + +token_t psi_num_exp_exec(struct psi_num_exp *exp, impl_val *res, struct psi_call_frame *frame); + +#include + +static inline zend_long psi_long_num_exp(struct psi_num_exp *exp, struct psi_call_frame *frame) { + impl_val val = {0}; -int validate_num_exp(struct psi_data *data, num_exp *exp, struct decl_args *dargs, struct decl_arg *func, struct decl_enum *enm); + switch (psi_num_exp_exec(exp, &val, frame)) { + 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; + default: + assert(0); + } + return 0; +} #endif diff --git a/src/types/return_stmt.c b/src/types/return_stmt.c index 8d32fc8..5df8481 100644 --- a/src/types/return_stmt.c +++ b/src/types/return_stmt.c @@ -5,11 +5,11 @@ 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. + * 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 @@ -21,86 +21,92 @@ 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. -*******************************************************************************/ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif - -#include -#include + *******************************************************************************/ +#include "php_psi_stdinc.h" #include "data.h" +#include "call.h" -return_stmt *init_return_stmt(set_value *val) { - return_stmt *ret = calloc(1, sizeof(*ret)); +struct psi_return_stmt *psi_return_stmt_init(struct psi_set_exp *val) +{ + struct psi_return_stmt *ret = calloc(1, sizeof(*ret)); ret->set = val; return ret; } -void free_return_stmt(return_stmt *ret) { - if (ret->token) { - free(ret->token); - } - free_set_value(ret->set); - free(ret); +void psi_return_stmt_exec(struct psi_return_stmt *ret, zval *return_value, + struct psi_call_frame *frame) +{ + psi_set_exp_exec_ex(ret->set, return_value, frame->rpointer, frame); } -void dump_return_stmt(int fd, return_stmt *ret) { - dprintf(fd, "\treturn "); - dump_set_value(fd, ret->set, 1, 0); -} - -static inline decl *locate_impl_decl(decls *decls, return_stmt *ret) { - if (decls) { - size_t i; +void psi_return_stmt_free(struct psi_return_stmt **ret_ptr) +{ + if (*ret_ptr) { + struct psi_return_stmt *ret = *ret_ptr; - for (i = 0; i < decls->count; ++i) { - if (!strcmp(decls->list[i]->func->var->name, ret->set->vars->vars[0]->name)) { - ret->decl = decls->list[i]->func; - return decls->list[i]; - } + *ret_ptr = NULL; + if (ret->token) { + free(ret->token); } + psi_set_exp_free(&ret->set); + free(ret); } +} - return NULL; +void psi_return_stmt_dump(int fd, struct psi_return_stmt *ret) +{ + dprintf(fd, "\treturn "); + psi_set_exp_dump(fd, ret->set, 1, 1); + dprintf(fd, ";\n"); } -int validate_return_stmt(struct psi_data *data, impl *impl) { - return_stmt *ret; - - /* we must have exactly one ret stmt delcaring the native func to call */ - /* and which type cast to apply */ - if (impl->stmts->ret.count != 1) { - if (impl->stmts->ret.count > 1) { - data->error(data, impl->stmts->ret.list[1]->token, PSI_WARNING, - "Too many `return` statements for implmentation %s;" - " found %zu, exactly one is needed", - impl->func->name, impl->stmts->ret.count); - } else { - data->error(data, impl->func->token, PSI_WARNING, - "Missing `return` statement for implementation %s", - impl->func->name); - } - return 0; +bool psi_return_stmt_validate(struct psi_data *data, struct psi_impl *impl) +{ + size_t i = 0; + struct psi_decl *decl; + struct psi_return_stmt *ret; + size_t count = psi_plist_count(impl->stmts.ret); + + psi_plist_get(impl->stmts.ret, 0, &ret); + + /* + * we must have exactly one ret stmt declaring the native func to call + * and which type cast to apply + */ + switch (count) { + default: + data->error(data, ret->token, PSI_WARNING, + "Too many `return` statements for implementation %s;" + " found %zu, exactly one is required", + impl->func->name, count); + return false; + case 0: + data->error(data, impl->func->token, PSI_WARNING, + "Missing `return` statement for implementation %s", + impl->func->name); + return false; + case 1: + break; } - ret = impl->stmts->ret.list[0]; + while (psi_plist_get(data->decls, i++, &decl)) { + if (!strcmp(decl->func->var->name, ret->set->data.func->var->name)) { + impl->decl = decl; + break; + } + } - if (!(impl->decl = locate_impl_decl(data->decls, ret))) { + if (!impl->decl) { data->error(data, ret->token, PSI_WARNING, - "Missing declaration '%s' for `return` statment for implementation %s", - ret->set->vars->vars[0]->name, impl->func->name); - return 0; + "Missing declaration '%s' for `return` statement of implementation %s", + ret->set->data.func->var->name, impl->func->name); + return false; } - if (!validate_set_value(data, ret->set, 1, &ret->decl, impl->decl->args ? (int) impl->decl->args->count : 0, impl->decl->args ? impl->decl->args->args : NULL, 0)) { - return 0; + if (!psi_set_exp_validate(data, ret->set, impl, NULL)) { + return false; } - //impl->decl->impl = impl; - - return 1; + return true; } diff --git a/src/types/return_stmt.h b/src/types/return_stmt.h index ee4dc6d..db4820c 100644 --- a/src/types/return_stmt.h +++ b/src/types/return_stmt.h @@ -26,22 +26,23 @@ #ifndef PSI_TYPES_RETURN_STMT_H #define PSI_TYPES_RETURN_STMT_H -#include "set_value.h" -#include "decl_arg.h" - -typedef struct return_stmt { - struct psi_token *token; - set_value *set; - decl_arg *decl; -} return_stmt; - -return_stmt *init_return_stmt(set_value *val); -void free_return_stmt(return_stmt *ret); -void dump_return_stmt(int fd, return_stmt *ret); +#include "Zend/zend_types.h" struct psi_data; -struct impl; +struct psi_token; +struct psi_call_frame; +struct psi_impl; +struct psi_set_exp; -int validate_return_stmt(struct psi_data *data, struct impl *impl); +struct psi_return_stmt { + struct psi_token *token; + struct psi_set_exp *set; +}; + +struct psi_return_stmt *psi_return_stmt_init(struct psi_set_exp *val); +void psi_return_stmt_free(struct psi_return_stmt **ret_ptr); +void psi_return_stmt_dump(int fd, struct psi_return_stmt *ret); +void psi_return_stmt_exec(struct psi_return_stmt *ret, zval *return_value, struct psi_call_frame *frame); +bool psi_return_stmt_validate(struct psi_data *data, struct psi_impl *impl); #endif diff --git a/src/types/set_exp.c b/src/types/set_exp.c new file mode 100644 index 0000000..ac55c3a --- /dev/null +++ b/src/types/set_exp.c @@ -0,0 +1,204 @@ +/******************************************************************************* + Copyright (c) 2016, Michael Wallner . + 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 "call.h" +#include "marshal.h" + +struct psi_set_exp *psi_set_exp_init(enum psi_set_exp_kind kind, void *data) +{ + struct psi_set_exp *val = calloc(1, sizeof(*val)); + + switch (val->kind = kind) { + case PSI_SET_FUNC: + val->data.func = data; + val->inner = val->data.func->inner; + break; + case PSI_SET_NUMEXP: + val->data.num = data; + break; + default: + assert(0); + } + + return val; +} + +void psi_set_exp_exec(struct psi_set_exp *val, struct psi_call_frame *frame) +{ + struct psi_call_frame_symbol *frame_sym = NULL; + struct psi_call_frame_argument *frame_arg; + struct psi_decl_var *set_dvar = psi_set_exp_get_decl_var(val); + struct psi_impl_var *set_ivar = psi_set_exp_get_impl_var(val); + + assert(set_dvar); + assert(set_ivar); + + frame_sym = psi_call_frame_fetch_symbol(frame, set_dvar); + frame_arg = psi_call_frame_get_argument(frame, set_ivar->fqn); + + if (frame_arg && frame_arg->zval_ptr) { + zval_dtor(frame_arg->zval_ptr); + psi_set_exp_exec_ex(val, frame_arg->zval_ptr, frame_sym->ptr, frame); + } +} + +void psi_set_exp_exec_ex(struct psi_set_exp *val, zval *zv, impl_val *iv, + struct psi_call_frame *frame) +{ + switch (val->kind) { + case PSI_SET_FUNC: + val->data.func->handler(zv, val, iv, frame); + break; + case PSI_SET_NUMEXP: + psi_num_exp_exec(val->data.num, iv, frame); + psi_set_to_int(zv, val, iv, frame); + break; + default: + assert(0); + break; + } +} + +void psi_set_exp_free(struct psi_set_exp **exp_ptr) +{ + if (*exp_ptr) { + struct psi_set_exp *exp = *exp_ptr; + + *exp_ptr = NULL; + + if (exp->inner && (!exp->outer || exp->outer->inner != exp->inner)) { + psi_plist_free(exp->inner); + } + + switch (exp->kind) { + case PSI_SET_FUNC: + psi_set_func_free(&exp->data.func); + break; + case PSI_SET_NUMEXP: + psi_num_exp_free(&exp->data.num); + break; + default: + assert(0); + break; + } + if (exp->var) { + psi_impl_var_free(&exp->var); + } + free(exp); + } +} + +void psi_set_exp_dump(int fd, struct psi_set_exp *set, unsigned level, int last) +{ + if (level > 1) { + /* only if not directly after `set ...` */ + dprintf(fd, "%s", psi_t_indent(level)); + } + + if (set->var) { + /* parsed, or generated */ + if (set->var->token) { + dprintf(fd, "%s = ", set->var->name); + } + } + + switch (set->kind) { + case PSI_SET_FUNC: + psi_set_func_dump(fd, set->data.func, level); + break; + case PSI_SET_NUMEXP: + psi_num_exp_dump(fd, set->data.num); + break; + default: + assert(0); + } + + if (!last) { + dprintf(fd, ","); + } + + if (set->var) { + dprintf(fd, "\t/* fqn=%s */", set->var->fqn); + } +} + +struct psi_decl_var *psi_set_exp_get_decl_var(struct psi_set_exp *exp) +{ + switch (exp->kind) { + case PSI_SET_FUNC: + return exp->data.func->var; + default: + return NULL; + } +} + +struct psi_impl_var *psi_set_exp_get_impl_var(struct psi_set_exp *exp) +{ + if (!exp->var) { + struct psi_decl_var *dvar = psi_set_exp_get_decl_var(exp); + char *dollar_name; + + if (!dvar) { + return NULL; + } + + dollar_name = psi_impl_var_name_prepend(strdup("$"), dvar->name); + exp->var = psi_impl_var_init(dollar_name, 0); + free(dollar_name); + } + + return exp->var; +} + +bool psi_set_exp_validate(struct psi_data *data, struct psi_set_exp *set, + struct psi_impl *impl, struct psi_decl *cb_decl) +{ + struct psi_impl_var *ivar = psi_set_exp_get_impl_var(set); + + if (ivar && !psi_impl_var_validate(data, ivar, impl, NULL, set)) { + data->error(data, ivar->token ? : **(struct psi_token ***) &set->data, + PSI_WARNING, "Unknown variable '%s'", ivar->name); + return false; + } + + switch (set->kind) { + case PSI_SET_NUMEXP: + if (!psi_num_exp_validate(data, set->data.num, impl, cb_decl, NULL, set, NULL)) { + return false; + } + break; + case PSI_SET_FUNC: + if (!psi_set_func_validate(data, set->data.func, set, impl, cb_decl)) { + return false; + } + break; + default: + assert(0); + } + return true; +} + diff --git a/src/types/decl_typedefs.h b/src/types/set_exp.h similarity index 57% rename from src/types/decl_typedefs.h rename to src/types/set_exp.h index 7b6a515..c43cf06 100644 --- a/src/types/decl_typedefs.h +++ b/src/types/set_exp.h @@ -23,22 +23,42 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *******************************************************************************/ -#ifndef PSI_TYPES_DECL_TYPEDEFS_H -#define PSI_TYPES_DECL_TYPEDEFS_H +#ifndef PSI_TYPES_SET_EXP_H +#define PSI_TYPES_SET_EXP_H -#include "decl_arg.h" +struct psi_data; +struct psi_plist; +struct psi_call_frame; +struct psi_let_exp; +struct psi_set_func; +struct psi_num_exp; +struct psi_impl; +struct psi_decl; -typedef struct decl_typedefs { - size_t count; - decl_arg **list; -} decl_typedefs; +enum psi_set_exp_kind { + PSI_SET_FUNC, + PSI_SET_NUMEXP, +}; -decl_typedefs *add_decl_typedef(decl_typedefs *defs, decl_arg *def); -void free_decl_typedefs(decl_typedefs *defs); -void dump_decl_typedefs(int fd, decl_typedefs *defs); +struct psi_set_exp { + enum psi_set_exp_kind kind; + struct psi_impl_var *var; + struct psi_set_exp *outer; + struct psi_plist *inner; + union { + struct psi_set_func *func; + struct psi_num_exp *num; + } data; +}; -struct psi_data; +struct psi_set_exp *psi_set_exp_init(enum psi_set_exp_kind kind, void *data); +void psi_set_exp_free(struct psi_set_exp **exp_ptr); +void psi_set_exp_dump(int fd, struct psi_set_exp *set, unsigned level, int last); +void psi_set_exp_exec(struct psi_set_exp *val, struct psi_call_frame *frame); +void psi_set_exp_exec_ex(struct psi_set_exp *val, zval *zv, impl_val *iv, struct psi_call_frame *frame); +bool psi_set_exp_validate(struct psi_data *data, struct psi_set_exp *set, struct psi_impl *impl, struct psi_decl *cb_decl); -int validate_decl_typedef(struct psi_data *data, decl_arg *def); +struct psi_impl_var *psi_set_exp_get_impl_var(struct psi_set_exp *exp); +struct psi_decl_var *psi_set_exp_get_decl_var(struct psi_set_exp *exp); #endif diff --git a/src/types/set_func.c b/src/types/set_func.c index f06fbf6..fff7c88 100644 --- a/src/types/set_func.c +++ b/src/types/set_func.c @@ -5,11 +5,11 @@ 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. + * 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 @@ -21,31 +21,270 @@ 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. -*******************************************************************************/ + *******************************************************************************/ -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif +#include "php_psi_stdinc.h" +#include "data.h" -#include -#include -#include +struct psi_set_func *psi_set_func_init(token_t type, const char *name, + struct psi_decl_var *var) +{ + struct psi_set_func *func = calloc(1, sizeof(*func)); -#include "set_func.h" - -set_func *init_set_func(token_t type, const char *name) { - set_func *func = calloc(1, sizeof(*func)); func->type = type; func->name = strdup(name); + func->var = var; + return func; } -void free_set_func(set_func *func) { - if (func->token) { - free(func->token); +void psi_set_func_free(struct psi_set_func **func_ptr) +{ + if (*func_ptr) { + struct psi_set_func *func = *func_ptr; + + *func_ptr = NULL; + if (func->token) { + free(func->token); + } + psi_decl_var_free(&func->var); + free(func->name); + free(func); } - free(func->name); - free(func); +} + +void psi_set_func_dump(int fd, struct psi_set_func *func, unsigned level) +{ + dprintf(fd, "%s(", func->name); + psi_decl_var_dump(fd, func->var); + dprintf(fd, "\t/* fqn=%s */", func->var->fqn); + if (func->inner && !func->recursive) { + size_t i = 0, count = psi_plist_count(func->inner); + struct psi_set_exp *inner; + + dprintf(fd, ","); + ++level; + while (psi_plist_get(func->inner, i++, &inner)) { + dprintf(fd, "\n"); + psi_set_exp_dump(fd, inner, level, i == count); + } + --level; + } + if (func->recursive) { + dprintf(fd, ", ..."); + } + if (func->inner && !func->recursive) { + dprintf(fd, "\n%s", psi_t_indent(level)); + } + dprintf(fd, ")"); +} + +static inline bool psi_set_func_validate_to_string(struct psi_data *data, + struct psi_set_func *func, struct psi_set_exp *set, + struct psi_impl *impl) +{ + struct psi_set_exp *sub_exp; + + psi_plist_get(func->inner, 0, &sub_exp); + + switch (psi_plist_count(func->inner)) { + default: + data->error(data, **(struct psi_token ***) &sub_exp->data, PSI_WARNING, + "Unexpected sub-expressions"); + return false; + + case 1: + if (sub_exp->kind != PSI_SET_NUMEXP) { + data->error(data, **(struct psi_token ***) &sub_exp->data, + PSI_WARNING, "Expected numeric expression"); + return false; + } + func->handler = psi_set_to_stringl; + return true; + + case 0: + func->handler = psi_set_to_string; + return true; + } +} + +static inline bool psi_set_func_validate_to_array(struct psi_data *data, + struct psi_set_func *func, struct psi_set_exp *set, + struct psi_impl *impl) +{ + struct psi_set_exp *sub_exp; + struct psi_decl_var *set_var = psi_set_exp_get_decl_var(set); + + switch (psi_plist_count(set->inner)) { + case 0: + if (func->recursive) { + func->handler = psi_set_to_recursive; + set->inner = func->inner = set->outer->inner; + return true; + } + data->error(data, func->token, PSI_WARNING, + "Expected sub-expressions in to_array() cast expression"); + return false; + + case 1: + psi_plist_get(set->inner, 0, &sub_exp); + if (sub_exp->kind != PSI_SET_FUNC) { + data->error(data, **(struct psi_token ***) &sub_exp->data, + PSI_WARNING, "Expected to_type() cast expression"); + return false; + } + if (strcmp(set_var->name, psi_set_exp_get_decl_var(sub_exp)->name)) { + /* no warning, because of ambiguity with a one-field-struct monstrosity */ + goto complex; + } + func->handler = psi_set_to_array_simple; + return true; + + case 2: + psi_plist_get(set->inner, 0, &sub_exp); + if (sub_exp->kind != PSI_SET_NUMEXP) { + goto complex; + } + psi_plist_get(set->inner, 1, &sub_exp); + if (sub_exp->kind != PSI_SET_FUNC) { + data->error(data, **(struct psi_token ***) &sub_exp->data, + PSI_WARNING, "Expected to_type() cast expression"); + return false; + } + if (strcmp(set_var->name, psi_set_exp_get_decl_var(sub_exp)->name)) { + data->error(data, **(struct psi_token ***) &sub_exp->data, + PSI_WARNING, + "Expected %s(%s) cast expression to reference the same" + " variable like the outer `set` statement, '%s'", + sub_exp->data.func->name, + psi_set_exp_get_decl_var(sub_exp)->name, set_var); + return false; + } + func->handler = psi_set_to_array_counted; + return true; + + default: + complex: switch (psi_decl_type_get_real(set_var->arg->type)->type) { + case PSI_T_UNION: + case PSI_T_STRUCT: + break; + default: + data->error(data, func->token, PSI_WARNING, + "Expected struct or union type for complex to_array()" + " cast expression, got '%s'", + set_var->arg->type->name); + return false; + } + func->handler = psi_set_to_array; + return true; + } +} + +static inline bool psi_set_func_validate_to_recursive(struct psi_data *data, + struct psi_set_func *func, struct psi_set_exp *set, + struct psi_impl *impl) +{ + if (!set->outer + || set->outer->kind + != PSI_SET_FUNC|| set->outer->data.func->type != PSI_T_TO_ARRAY) { + data->error(data, func->token, PSI_WARNING, + "Expected to_array() as parent to recursion in `set` statement" + " of implementation '%s'", + impl->func->name); + return false; + } + + func->handler = psi_set_to_recursive; + set->inner = set->outer->inner; + // FIXME validate recursive type + return true; +} + +bool psi_set_func_validate(struct psi_data *data, struct psi_set_func *func, + struct psi_set_exp *set, struct psi_impl *impl, struct psi_decl *cb_decl) +{ + if (!psi_decl_var_validate(data, func->var, impl->decl, NULL, set) + && !psi_decl_var_validate(data, func->var, cb_decl, NULL, NULL) + && !psi_impl_get_temp_let_arg(impl, func->var)) { + data->error(data, func->var->token, PSI_WARNING, + "Unknown variable '%s' in implementation %s", + func->var->name, impl->func->name); + return false; + } + + if (set->outer) { + if (set->outer->kind != PSI_SET_FUNC) { + data->error(data, func->token, PSI_WARNING, + "Unexpected sub-expression, expected to_type() cast"); + return false; + } + } + + if (func->inner && (!set->outer || set->outer->inner != func->inner)) { + + size_t i = 0; + struct psi_set_exp *inner; + + while (psi_plist_get(func->inner, i++, &inner)) { + struct psi_decl_var *sub_var; + struct psi_plist *sub_args; + + inner->outer = set; + + sub_var = psi_set_exp_get_decl_var(inner); + sub_args = psi_decl_type_get_args(func->var->arg->type, NULL); + if (sub_var && sub_args && !psi_decl_arg_get_by_var(sub_var, sub_args, NULL)) { + /* remove expr for portability with different struct members */ + psi_plist_del(func->inner, --i, NULL); + psi_set_exp_free(&inner); + } else if (!psi_set_exp_validate(data, inner, impl, cb_decl)) { + /* remove exp for portability */ + psi_plist_del(func->inner, --i, NULL); + } + } + } + + switch (func->type) { + case PSI_T_VOID: + func->handler = psi_set_void; + break; + case PSI_T_ZVAL: + func->handler = psi_set_zval; + break; + case PSI_T_TO_BOOL: + func->handler = psi_set_to_bool; + break; + case PSI_T_TO_INT: + func->handler = psi_set_to_int; + break; + case PSI_T_TO_FLOAT: + func->handler = psi_set_to_float; + break; + case PSI_T_TO_OBJECT: + func->handler = psi_set_to_object; + break; + case PSI_T_TO_STRING: + if (!psi_set_func_validate_to_string(data, func, set, impl)) { + return false; + } + break; + case PSI_T_TO_ARRAY: + if (!psi_set_func_validate_to_array(data, func, set, impl)) { + return false; + } + break; + case PSI_T_ELLIPSIS: + abort(); + if (!psi_set_func_validate_to_recursive(data, func, set, impl)) { + return false; + } + break; + default: + data->error(data, func->token, PSI_WARNING, + "Unknown cast '%s' in `set` statement of implementation '%s'", + func->name, impl->func->name); + return false; + } + + return true; } diff --git a/src/types/set_func.h b/src/types/set_func.h index f774114..4a81b20 100644 --- a/src/types/set_func.h +++ b/src/types/set_func.h @@ -27,18 +27,25 @@ #define PSI_TYPES_SET_FUNC_H #include "token.h" -#include "impl_val.h" +#include "marshal.h" -struct set_value; +struct psi_plist; +struct psi_decl_var; -typedef struct set_func { +struct psi_set_func { struct psi_token *token; token_t type; char *name; - void (*handler)(zval *, struct set_value *set, impl_val *ret_val); -} set_func; - -set_func *init_set_func(token_t type, const char *name); -void free_set_func(set_func *func); + struct psi_decl_var *var; + psi_marshal_set handler; + struct psi_plist *inner; + unsigned recursive:1; +}; + +struct psi_set_func *psi_set_func_init(token_t type, const char *name, struct psi_decl_var *var); +void psi_set_func_free(struct psi_set_func **func_ptr); +void psi_set_func_dump(int fd, struct psi_set_func *func, unsigned level); +bool psi_set_func_validate(struct psi_data *data, struct psi_set_func *func, + struct psi_set_exp *set, struct psi_impl *impl, struct psi_decl *cb_decl); #endif diff --git a/src/types/set_stmt.c b/src/types/set_stmt.c index 8827063..e9f957b 100644 --- a/src/types/set_stmt.c +++ b/src/types/set_stmt.c @@ -5,11 +5,11 @@ 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. + * 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 @@ -21,104 +21,85 @@ 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. -*******************************************************************************/ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif - -#include -#include + *******************************************************************************/ +#include "php_psi_stdinc.h" #include "data.h" +#include "call.h" -set_stmt *init_set_stmt(impl_var *var, set_value *val) { - set_stmt *set = calloc(1, sizeof(*set)); - set->var = var; - set->val = val; +struct psi_set_stmt *psi_set_stmt_init(struct psi_set_exp *exp) +{ + struct psi_set_stmt *set = calloc(1, sizeof(*set)); + set->exp = exp; return set; } -void free_set_stmt(set_stmt *set) { - free_impl_var(set->var); - free_set_value(set->val); - free(set); +void psi_set_stmt_exec(struct psi_set_stmt *set, struct psi_call_frame *frame) +{ + psi_set_exp_exec(set->exp, frame); } -void dump_set_stmt(int fd, set_stmt *set) { - dprintf(fd, "\tset %s = ", set->var->name); - dump_set_value(fd, set->val, 1, 0); +void psi_set_stmt_free(struct psi_set_stmt **set_ptr) +{ + if (*set_ptr) { + struct psi_set_stmt *set = *set_ptr; + + *set_ptr = NULL; + psi_set_exp_free(&set->exp); + if (set->token) { + free(set->token); + } + free(set); + } } -int validate_set_stmts(struct psi_data *data, impl *impl) { - size_t i, j, k; - /* we can have any count of set stmts; processing out vars */ - /* check that set stmts reference known variables */ - for (i = 0; i < impl->stmts->set.count; ++i) { - set_stmt *set = impl->stmts->set.list[i]; - int check = 0; +void psi_set_stmt_dump(int fd, struct psi_set_stmt *set) +{ + dprintf(fd, "\tset "); + psi_set_exp_dump(fd, set->exp, 1, 1); + dprintf(fd, ";\n"); +} - if (impl->func->args) for (j = 0; j < impl->func->args->count; ++j) { - impl_arg *iarg = impl->func->args->args[j]; - if (!strcmp(set->var->name, iarg->var->name)) { - set->arg = iarg; - check = 1; - break; - } +bool psi_set_stmts_validate(struct psi_data *data, struct psi_impl *impl) +{ + size_t i = 0; + struct psi_set_stmt *set; + + /* we can have any count of set stmts; processing out vars */ + /* check that set stmts reference known variables */ + while (psi_plist_get(impl->stmts.set, i++, &set)) { + if (!set->exp->var) { + data->error(data, set->token, PSI_WARNING, + "Missing variable of `set` statement of implementation '%s'", + impl->func->name); + return false; } - if (!check) { - data->error(data, set->var->token, PSI_WARNING, "Unknown variable '$%s' of `set` statement" - " of implementation '%s'", - set->var->name, impl->func->name); - return 0; + if (!psi_impl_get_arg(impl, set->exp->var)) { + data->error(data, set->token, PSI_WARNING, + "Unknown variable '%s' of `set` statement of implementation '%s'", + set->exp->var->name, impl->func->name); + return false; } - for (j = 0; j < set->val->vars->count; ++j) { - decl_var *set_var = set->val->vars->vars[j]; - - check = 0; - if (impl->decl->args) { - for (k = 0; k < impl->decl->args->count; ++k) { - decl_arg *set_arg = impl->decl->args->args[k]; - - if (!strcmp(set_var->name, set_arg->var->name)) { - check = 1; - set_var->arg = set_arg; - if (!validate_set_value(data, set->val, 1, &set_arg, 1, &impl->decl->func, impl->decl->args->count, impl->decl->args->args, 0)) { - return 0; - } - break; - } - } - } - if (!check) { - for (k = 0; k < impl->stmts->let.count; ++k) { - let_stmt *let = impl->stmts->let.list[k]; - - /* check temp vars */ - if (let->val && let->val->kind == PSI_LET_TMP) { - if (!strcmp(set_var->name, let->val->var->name)) { - check = 1; - set_var->arg = let->val->var->arg; - if (!validate_set_value(data, set->val, 1, &set_var->arg, 1, &impl->decl->func, impl->decl->args->count, impl->decl->args->args, 0)) { - return 0; - } - break; - } - } + switch (set->exp->kind) { + case PSI_SET_NUMEXP: + break; + case PSI_SET_FUNC: + if (!psi_decl_get_arg(impl->decl, set->exp->data.func->var)) { + if (!psi_impl_get_temp_let_arg(impl, set->exp->data.func->var)) { + data->error(data, set->token, PSI_WARNING, + "Unknown variable '%s' of `set` statement of implementation '%s'", + set->exp->data.func->var, impl->func->name); + return false; } } - - if (!check) { - data->error(data, set_var->token, PSI_WARNING, "Unknown value '%s' of `set` statement" - " for variable '$%s' of implementation '%s'", - set_var->name, set->arg->var->name, impl->func->name); - return 0; - } + } + /* validate the expression itself */ + if (!psi_set_exp_validate(data, set->exp, impl, NULL)) { + return false; } } - return 1; + + return true; } diff --git a/src/types/set_stmt.h b/src/types/set_stmt.h index 8c96d43..4b361cb 100644 --- a/src/types/set_stmt.h +++ b/src/types/set_stmt.h @@ -26,23 +26,21 @@ #ifndef PSI_TYPES_SET_STMT_H #define PSI_TYPES_SET_STMT_H -#include "impl_var.h" -#include "impl_arg.h" -#include "set_value.h" - -typedef struct set_stmt { - impl_var *var; - set_value *val; - impl_arg *arg; -} set_stmt; - -set_stmt *init_set_stmt(impl_var *var, set_value *val); -void free_set_stmt(set_stmt *set); -void dump_set_stmt(int fd, set_stmt *set); - struct psi_data; -struct impl; - -int validate_set_stmts(struct psi_data *data, struct impl *impl); +struct psi_token; +struct psi_call_frame; +struct psi_impl; +struct psi_set_exp; + +struct psi_set_stmt { + struct psi_token *token; + struct psi_set_exp *exp; +}; + +struct psi_set_stmt *psi_set_stmt_init(struct psi_set_exp *val); +void psi_set_stmt_free(struct psi_set_stmt **set_ptr); +void psi_set_stmt_dump(int fd, struct psi_set_stmt *set); +void psi_set_stmt_exec(struct psi_set_stmt *set, struct psi_call_frame *frame); +bool psi_set_stmts_validate(struct psi_data *data, struct psi_impl *impl); #endif diff --git a/src/types/set_value.c b/src/types/set_value.c deleted file mode 100644 index 5defbd7..0000000 --- a/src/types/set_value.c +++ /dev/null @@ -1,251 +0,0 @@ -/******************************************************************************* - Copyright (c) 2016, Michael Wallner . - 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. -*******************************************************************************/ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif - -#include -#include - -#include "data.h" -#include "marshal.h" - -set_value *init_set_value(set_func *func, decl_vars *vars) { - set_value *val = calloc(1, sizeof(*val)); - val->func = func; - val->vars = vars; - return val; -} - -set_value *add_inner_set_value(set_value *val, set_value *inner) { - val->inner = add_set_value(val->inner, inner); - inner->outer.set = val; - return val; -} - -void free_set_value(set_value *val) { - if (val->func) { - free_set_func(val->func); - } - if (val->vars) { - free_decl_vars(val->vars); - } - if (val->inner - && (!val->outer.set || val->outer.set->inner != val->inner)) { - free_set_values(val->inner); - } - if (val->num) { - free_num_exp(val->num); - } - free(val); -} - -void dump_set_value(int fd, set_value *set, unsigned level, int last) { - size_t i; - - if (level > 1) { - /* only if not directly after `set ...` */ - dprintf(fd, "%s", psi_t_indent(level)); - } - - if (set->func->type == PSI_T_ELLIPSIS) { - dprintf(fd, "%s(", set->outer.set->func->name); - } else { - dprintf(fd, "%s(", set->func->name); - } - - for (i = 0; i < set->vars->count; ++i) { - decl_var *svar = set->vars->vars[i]; - if (i) { - dprintf(fd, ", "); - } - dump_decl_var(fd, svar); - } - - if (set->func->type == PSI_T_ELLIPSIS) { - dprintf(fd, ", ..."); - } - if (set->num) { - dprintf(fd, ", "); - dump_num_exp(fd, set->num); - } - if (set->inner && set->inner->vals && set->func->type != PSI_T_ELLIPSIS) { - dprintf(fd, ",\n"); - for (i = 0; i < set->inner->count; ++i) { - dump_set_value(fd, set->inner->vals[i], level+1, i == (set->inner->count - 1)); - } - /* only if inner stmts, i.e. with new lines, were dumped */ - dprintf(fd, "%s", psi_t_indent(level)); - } - if (level > 1) { - dprintf(fd, ")%s\n", last ? "" : ","); - } else { - dprintf(fd, ");"); - } -} - -static inline void decl_var_arg_v(decl_args *args, va_list argp) { - int argc; - decl_arg **argv; - - memset(args, 0, sizeof(*args)); - - while ((argc = va_arg(argp, int))) { - argv = va_arg(argp, decl_arg **); - while (argc--) { - add_decl_arg(args, *argv++); - } - } -} - -static inline int validate_set_value_handler(set_value *set) { - switch (set->func->type) { - case PSI_T_TO_BOOL: set->func->handler = psi_to_bool; break; - case PSI_T_TO_INT: set->func->handler = psi_to_int; break; - case PSI_T_TO_FLOAT: set->func->handler = psi_to_double; break; - case PSI_T_TO_STRING: set->func->handler = psi_to_string; break; - case PSI_T_TO_ARRAY: set->func->handler = psi_to_array; break; - case PSI_T_TO_OBJECT: set->func->handler = psi_to_object; break; - case PSI_T_VOID: set->func->handler = psi_to_void; break; - case PSI_T_ZVAL: set->func->handler = psi_to_zval; break; - case PSI_T_ELLIPSIS: - if (set->outer.set && set->outer.set->func->type == PSI_T_TO_ARRAY) { - set->func->handler = psi_to_recursive; - set->inner = set->outer.set->inner; - break; - } - /* no break */ - default: - return 0; - } - return 1; -} - -int validate_set_value(struct psi_data *data, set_value *set, ...) { - va_list argp; - decl_args args = {0}; - int check; - - va_start(argp, set); - decl_var_arg_v(&args, argp); - va_end(argp); - - check = validate_set_value_ex(data, set, NULL, &args); - if (args.args) { - free(args.args); - } - return check; -} - -int validate_set_value_ex(struct psi_data *data, set_value *set, decl_arg *ref, decl_args *ref_list) { - size_t i; - decl_type *ref_type; - decl_var *set_var = set->vars->vars[0]; - - if (!validate_set_value_handler(set)) { - data->error(data, set->func->token, PSI_WARNING, "Invalid cast '%s' in `set` statement", set->func->name); - return 0; - } - - for (i = 0; i < set->vars->count; ++i) { - decl_var *svar = set->vars->vars[i]; - if (!svar->arg && !locate_decl_var_arg(svar, ref_list, NULL)) { - data->error(data, svar->token, PSI_WARNING, "Unknown variable '%s' in `set` statement", svar->name); - return 0; - } - } - - if (!ref) { - ref = set_var->arg; - } - ref_type = real_decl_type(ref->type); - - if (set->inner && set->inner->count) { - int is_to_array = (set->func->type == PSI_T_TO_ARRAY); - int is_pointer_to_struct = (ref_type->type == PSI_T_STRUCT && ref->var->pointer_level); - - if (!is_to_array && !is_pointer_to_struct) { - data->error(data, set->func->token, E_WARNING, "Inner `set` statement casts only work with " - "to_array() casts on structs or pointers: %s(%s...", set->func->name, set->vars->vars[0]->name); - return 0; - } - } - if (set->num) { - if (!validate_num_exp(data, set->num, ref_list, ref, NULL)) { - return 0; - } - } - - if (set->inner && (ref_type->type == PSI_T_STRUCT || ref_type->type == PSI_T_UNION)) { - /* to_array(struct, to_...) */ - if (!set->outer.set || set->outer.set->inner->vals != set->inner->vals) { - for (i = 0; i < set->inner->count; ++i) { - decl_var *sub_var = set->inner->vals[i]->vars->vars[0]; - decl_arg *sub_ref; - - switch (ref_type->type) { - case PSI_T_STRUCT: - sub_ref = locate_decl_struct_member(ref_type->real.strct, sub_var); - break; - case PSI_T_UNION: - sub_ref = locate_decl_union_member(ref_type->real.unn, sub_var); - break; - } - - if (sub_ref) { - if (!validate_set_value_ex(data, set->inner->vals[i], sub_ref, ref_type->real.strct->args)) { - return 0; - } - } - } - } - } else if (set->inner && set->inner->count == 1) { - /* to_array(ptr, to_string(*ptr)) */ - decl_var *sub_var = set->inner->vals[0]->vars->vars[0]; - decl_arg *sub_ref = locate_decl_var_arg(sub_var, ref_list, ref); - - if (sub_ref) { - if (strcmp(sub_var->name, set_var->name)) { - data->error(data, sub_var->token, E_WARNING, "Inner `set` statement casts on pointers must reference the same variable"); - return 0; - } - if (!validate_set_value_ex(data, set->inner->vals[0], sub_ref, ref_list)) { - return 0; - } - } - } else if (set->inner && set->inner->count > 1) { - data->error(data, set->func->token, E_WARNING, - "Inner `set` statement casts on pointers may only occur once, " - "unless the outer type is a struct or union, got '%s%s'", - ref_type->name, psi_t_indirection(ref->var->pointer_level)); - return 0; - } - - return 1; -} - diff --git a/src/types/set_value.h b/src/types/set_value.h deleted file mode 100644 index 6a5ee82..0000000 --- a/src/types/set_value.h +++ /dev/null @@ -1,58 +0,0 @@ -/******************************************************************************* - Copyright (c) 2016, Michael Wallner . - 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_TYPES_SET_VALUE_H -#define PSI_TYPES_SET_VALUE_H - -#include "set_func.h" -#include "decl_vars.h" -#include "decl_args.h" -#include "num_exp.h" -#include "impl_val.h" - -typedef struct set_value { - set_func *func; - decl_vars *vars; - num_exp *num; - struct { - struct set_value *set; - impl_val *val; - } outer; - struct set_values *inner; -} set_value; - -set_value *init_set_value(set_func *func, decl_vars *vars); -set_value *add_inner_set_value(set_value *val, set_value *inner); -void free_set_value(set_value *val); -void dump_set_value(int fd, set_value *set, unsigned level, int last); - -#include - -struct psi_data; - -int validate_set_value(struct psi_data *data, set_value *set, ...); -int validate_set_value_ex(struct psi_data *data, set_value *set, decl_arg *ref, decl_args *ref_list); - -#endif diff --git a/src/types/set_values.c b/src/types/set_values.c deleted file mode 100644 index 4cbd97d..0000000 --- a/src/types/set_values.c +++ /dev/null @@ -1,66 +0,0 @@ -/******************************************************************************* - Copyright (c) 2016, Michael Wallner . - 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. -*******************************************************************************/ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# include "php_config.h" -#endif - -#include -#include - -#include "set_values.h" - -set_values *init_set_values(set_value *val) { - set_values *vals = calloc(1, sizeof(*vals)); - if (val) { - vals->count = 1; - vals->vals = calloc(1, sizeof(val)); - vals->vals[0] = val; - } - return vals; -} - -set_values *add_set_value(set_values *vals, set_value *val) { - if (!vals) { - vals = calloc(1, sizeof(*vals)); - } - vals->vals = realloc(vals->vals, ++vals->count * sizeof(val)); - vals->vals[vals->count - 1] = val; - return vals; -} - -void free_set_values(set_values *vals) { - if (vals->vals) { - size_t i; - for (i = 0; i < vals->count; ++i) { - free_set_value(vals->vals[i]); - } - free(vals->vals); - } - free(vals); -} - diff --git a/src/types/set_values.h b/src/types/set_values.h deleted file mode 100644 index 8d78dc8..0000000 --- a/src/types/set_values.h +++ /dev/null @@ -1,40 +0,0 @@ -/******************************************************************************* - Copyright (c) 2016, Michael Wallner . - 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_TYPES_SET_VALUES_H -#define PSI_TYPES_SET_VALUES_H - -#include "set_value.h" - -typedef struct set_values { - set_value **vals; - size_t count; -} set_values; - -set_values *init_set_values(set_value *val); -set_values *add_set_value(set_values *vals, set_value *val); -void free_set_values(set_values *vals); - -#endif diff --git a/tests/getopt/getopt001.phpt b/tests/getopt/getopt001.phpt index 2209d09..71af2c7 100644 --- a/tests/getopt/getopt001.phpt +++ b/tests/getopt/getopt001.phpt @@ -3,9 +3,10 @@ getopt --INI-- psi.directory={PWD}:{PWD}/../../psi.d --SKIPIF-- - --ENV-- POSIXLY_CORRECT= @@ -19,29 +20,31 @@ $args = [ $opts = "v::x:s:"; -psi\opterr(0); +for ($i = 0; $i<3; ++$i) { + psi\opterr(0); + psi\optind\set(1); -while (($opt = chr(psi\getopt($args, $opts)))) { - switch ($opt) { - case "v": - printf("got v\n"); - break; - case "x": - case "s": - printf("got %s: %s\n", $opt, psi\optarg()); - break; - default: - printf("error '%s'\n", $opt); - case chr(-1): - break 2; + while (($opt = chr(psi\getopt($args, $opts)))) { + switch ($opt) { + case "v": + printf("got v\n"); + break; + case "x": + case "s": + printf("got %s: %s\n", $opt, psi\optarg()); + break; + default: + printf("error '%s'\n", $opt); + case chr(-1): + break 2; + } } -} -$pos = psi\optind(); -while ($pos < count($args)) { - printf("arg: %s\n", $args[$pos++]); + $pos = psi\optind\get(); + while ($pos < count($args)) { + printf("arg: %s\n", $args[$pos++]); + } } - var_dump($args); ?> @@ -55,6 +58,20 @@ arg: huh arg: -gotcha arg: --bar arg: baz +got v +got x: 1 +got s: foo +arg: huh +arg: -gotcha +arg: --bar +arg: baz +got v +got x: 1 +got s: foo +arg: huh +arg: -gotcha +arg: --bar +arg: baz array(11) { [0]=> string(8) "progname" diff --git a/tests/glob/glob001.phpt b/tests/glob/glob001.phpt index d85d8d5..0774821 100644 --- a/tests/glob/glob001.phpt +++ b/tests/glob/glob001.phpt @@ -10,13 +10,14 @@ extension_loaded("psi") or die("skip - need ext/psi"); ===TEST=== ===DONE=== --EXPECTF-- ===TEST=== int(0) -bool(true) ===DONE=== \ No newline at end of file diff --git a/tests/glob/glob003.phpt b/tests/glob/glob003.phpt index db92feb..edb7356 100644 --- a/tests/glob/glob003.phpt +++ b/tests/glob/glob003.phpt @@ -21,15 +21,15 @@ var_dump($glob); int(0) array(5) { ["gl_matchc"]=> - int(4) + int(5) ["gl_pathc"]=> - int(4) + int(5) ["gl_offs"]=> int(3) ["gl_flags"]=> int(386) ["gl_pathv"]=> - array(7) { + array(8) { [0]=> string(0) "" [1]=> @@ -44,6 +44,8 @@ array(5) { string(12) "glob002.phpt" [6]=> string(12) "glob003.phpt" + [7]=> + string(12) "glob004.phpt" } } ===DONE=== diff --git a/tests/ndbm/ndbm.psi b/tests/ndbm/ndbm.psi index fd132a9..92fa62b 100644 --- a/tests/ndbm/ndbm.psi +++ b/tests/ndbm/ndbm.psi @@ -26,8 +26,8 @@ function psi\dbm_fetch(object $db, array $key) : array { dsize = intval($dsize) ); return to_array(dbm_fetch, - to_string(dptr, dsize), - to_int(dsize) + to_int(dsize), + to_string(dptr, dsize) ); } diff --git a/tests/parser/dump/dump001.phpt b/tests/parser/dump/dump001.phpt index 8a504e7..13e8a2f 100644 --- a/tests/parser/dump/dump001.phpt +++ b/tests/parser/dump/dump001.phpt @@ -7,7 +7,7 @@ extension_loaded("psi") or die("skip - need ext/psi"); --FILE-- ===TEST=== ===DONE=== @@ -24,3 +24,7 @@ var_dump(psi_validate($fn)); bool(true) bool(true) ===DONE=== +--CLEAN-- + diff --git a/tests/parser/validate001.phpt b/tests/parser/validate001.phpt index 4cb8b2d..1f6113a 100644 --- a/tests/parser/validate001.phpt +++ b/tests/parser/validate001.phpt @@ -21,7 +21,7 @@ validate(false, "typedef void foo;"); validate(true, "typedef void *bar;"); validate(false, "typedef long int;"); validate(true, "typedef long foo;"); -validate(false, "typedef struct foo bar;"); +validate(true, "typedef struct foo bar;"); validate(true, "typedef struct {int a;} foo;"); validate(false, "struct a; \ntypedef struct a a_t;"); validate(true, "struct a::(8,8); \ntypedef struct a a_t;"); @@ -90,8 +90,6 @@ Warning: PSI syntax error: Unexpected token ';' at pos 17 in %s001.psi on line 1 Warning: PSI syntax error: Unexpected token 'int' at pos 14 in %s001.psi on line 1 -Warning: Type 'bar' cannot be aliased to struct 'foo' in %s001.psi on line 1 - Warning: Cannot compute size of empty struct 'a' in %s001.psi on line 1 Warning: Unknown variable 'X' in numeric expression in %s001.psi on line 4 diff --git a/tests/pipe/pipe.psi b/tests/pipe/pipe.psi index 24c5723..d1961da 100644 --- a/tests/pipe/pipe.psi +++ b/tests/pipe/pipe.psi @@ -4,5 +4,5 @@ function \pipe(array &$fds = null) : int { return to_int(pipe); let fildes = calloc(2, psi\SIZEOF_INT); - set $fds = to_array(fildes[2]); + set $fds = to_array(*fildes, 2, to_int(*fildes)); } diff --git a/tests/sqlite/sqlite.psi b/tests/sqlite/sqlite.psi index b2beb5c..06bdb89 100644 --- a/tests/sqlite/sqlite.psi +++ b/tests/sqlite/sqlite.psi @@ -42,16 +42,16 @@ function sqlite3\open(string $uri, object &$db) : int { typedef int (*sqlite3_callback)(void *data, int argc, char** argv, char** cols); -extern int sqlite3_exec(sqlite3 *db, const char *sql, sqlite3_callback callback, void *data, char **errmsg); +extern int sqlite3_exec(sqlite3 *db, const char *sql, sqlite3_callback cb, void *data, char **errmsg); function sqlite3\exec(object $db, string $sql, callable $cb, mixed $cd, string &$error = null) : int { let db = objval($db); let sql = strval($sql); - let callback = callback intval( + let cb = callback intval( $cb( zval(data), to_int(argc), - to_array(argv, argc, to_string(argv)), - to_array(cols, argc, to_string(cols)) + to_array(*argv, argc, to_string(*argv)), + to_array(*cols, argc, to_string(*cols)) ) ); let data = zval($cd); diff --git a/tests/sqlite/sqlite001.phpt b/tests/sqlite/sqlite001.phpt index e45d169..552c1d8 100644 --- a/tests/sqlite/sqlite001.phpt +++ b/tests/sqlite/sqlite001.phpt @@ -78,6 +78,7 @@ string(%d) "3.%d.%s" 2: data = three SQL logic error or missing database: 'no tables specified' +library routine called out of sequence: '' ===DONE=== --CLEAN-- getMessage(),"\n"; +} +var_dump(psi\gmtime(1)); var_dump(psi\asctime(psi\gmtime(1234567890))); var_dump(psi\asctime_r(psi\gmtime_r(1234567890))); ?> ===DONE=== --EXPECT-- ===TEST=== -string(25) "Sun Jan 0 00:00:00 1900 -" -string(25) "Sun Jan 0 00:00:00 1900 -" +psi\asctime() expects parameter 1 to be array, null given +array(9) { + ["tm_sec"]=> + int(1) + ["tm_min"]=> + int(0) + ["tm_hour"]=> + int(0) + ["tm_mday"]=> + int(1) + ["tm_mon"]=> + int(0) + ["tm_year"]=> + int(70) + ["tm_wday"]=> + int(4) + ["tm_yday"]=> + int(0) + ["tm_isdst"]=> + int(0) +} string(25) "Fri Feb 13 23:31:30 2009 " string(25) "Fri Feb 13 23:31:30 2009 diff --git a/tests/time/times001.phpt b/tests/time/times001.phpt index 816b0b5..0f7471c 100644 --- a/tests/time/times001.phpt +++ b/tests/time/times001.phpt @@ -8,7 +8,9 @@ extension_loaded("psi") or die("skip - need ext/psi"); ?> --FILE-- ===TEST=== - ===DONE=== -- 2.30.2