From be3ceffdd27422aae6ba44d31d868fb12d08957a Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Tue, 20 Oct 2015 15:19:55 +0200 Subject: [PATCH] flush --- Makefile.frag | 4 + TODO | 1 + config.m4 | 4 +- php_psi.h | 2 + src/context.c | 3 +- src/context.h | 21 ++- src/libjit.c | 390 +++++++++++++++++++++++++++++++++------------- src/libjit.h | 2 + src/module.c | 9 +- src/parser.h | 84 +++++++--- src/parser.re | 6 +- src/parser_proc.h | 25 +-- src/parser_proc.y | 39 +++-- src/validator.c | 101 ++++++++++-- 14 files changed, 510 insertions(+), 181 deletions(-) diff --git a/Makefile.frag b/Makefile.frag index 99f708a..d20403f 100644 --- a/Makefile.frag +++ b/Makefile.frag @@ -24,8 +24,12 @@ lemon.c: ./lemon: lemon.c | lempar.c $(CC) -o $@ $< +$(PHP_PSI_SRCDIR)/src/parser_proc.y: $(PHP_PSI_SRCDIR)/src/parser.h + touch $@ $(PHP_PSI_SRCDIR)/src/parser_proc.c: $(PHP_PSI_SRCDIR)/src/parser_proc.y $(LEMON) $(LEMON) -c $< +$(PHP_PSI_SRCDIR)/src/parser.re: $(PHP_PSI_SRCDIR)/src/parser.h $(PHP_PSI_SRCDIR)/src/parser_proc.h + touch $@ $(PHP_PSI_SRCDIR)/src/parser.c: $(PHP_PSI_SRCDIR)/src/parser.re $(RE2C) -o $@ $< diff --git a/TODO b/TODO index 22c7d40..76fbd27 100644 --- a/TODO +++ b/TODO @@ -2,3 +2,4 @@ * 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 diff --git a/config.m4 b/config.m4 index 816511f..fe5603f 100644 --- a/config.m4 +++ b/config.m4 @@ -32,8 +32,8 @@ if test "$PHP_PSI" != "no"; then PHP_ADD_BUILD_DIR($PHP_PSI_BUILDDIR/src) PHP_PSI_HEADERS=`(cd $PHP_PSI_SRCDIR/src && echo *.h)` - PHP_PSI_SOURCES=`(cd $PHP_PSI_SRCDIR && echo src/*.c)` - PHP_PSI_SOURCES=`(echo $PHP_PSI_SOURCES src/parser.c src/parser_proc.c | xargs -n1 | sort | uniq)` + PHP_PSI_SOURCES="src/parser_proc.c src/parser.c src/validator.c src/module.c src/context.c" + PHP_PSI_SOURCES="$PHP_PSI_SOURCES src/libjit.c" PHP_NEW_EXTENSION(psi, $PHP_PSI_SOURCES, $ext_shared) PHP_INSTALL_HEADERS(ext/psi, php_psi.h $PHP_PSI_HEADERS) diff --git a/php_psi.h b/php_psi.h index 4be4027..cce3503 100644 --- a/php_psi.h +++ b/php_psi.h @@ -19,6 +19,8 @@ extern zend_module_entry psi_module_entry; #include "TSRM.h" #endif +#include "context.h" + ZEND_BEGIN_MODULE_GLOBALS(psi) char *directory; PSI_Context context; diff --git a/src/context.c b/src/context.c index 2b91f43..825682d 100644 --- a/src/context.c +++ b/src/context.c @@ -6,6 +6,7 @@ #include "php.h" #include "php_scandir.h" #include "context.h" +#include "validator.h" PSI_Context *PSI_ContextInit(PSI_Context *C, PSI_ContextOps *ops, PSI_ContextErrorFunc error) { @@ -48,7 +49,7 @@ void PSI_ContextBuild(PSI_Context *C, const char *path) C->error(PSI_WARNING, "Path to PSI file too long: %s/%s", path, entries[i]->d_name); } - if (!PSI_ParserInit(&P, psi, psi_error, 0)) { + if (!PSI_ParserInit(&P, psi, C->error, 0)) { C->error(PSI_WARNING, "Failed to init PSI parser (%s): %s", psi, strerror(errno)); continue; diff --git a/src/context.h b/src/context.h index d75c19e..24bdb9c 100644 --- a/src/context.h +++ b/src/context.h @@ -1,24 +1,29 @@ #ifndef _PSI_CONTEXT_H #define _PSI_CONTEXT_H +#include "parser.h" + #define PSI_ERROR 16 #define PSI_WARNING 32 typedef void (*PSI_ContextErrorFunc)(int type, const char *msg, ...); -typedef struct PSI_ContextOps { - void (*init)(struct PSI_Context *C); - void (*dtor)(struct PSI_Context *C); - zend_function_entry *(*compile)(struct PSI_Context *C, struct PSI_Data *D); -} PSI_ContextOps; +typedef struct PSI_Context PSI_Context; +typedef struct PSI_ContextOps PSI_ContextOps; + +struct PSI_ContextOps { + void (*init)(PSI_Context *C); + void (*dtor)(PSI_Context *C); + zend_function_entry *(*compile)(PSI_Context *C, PSI_Data *D); +}; -typedef struct PSI_Context { - void *opaque; +struct PSI_Context { + void *context; PSI_ContextErrorFunc error; struct PSI_ContextOps *ops; struct PSI_Data *data; zend_function_entry **closures; size_t count; -} PSI_Context; +}; PSI_Context *PSI_ContextInit(PSI_Context *C, PSI_ContextOps *ops, PSI_ContextErrorFunc error); void PSI_ContextBuild(PSI_Context *C, const char *path); diff --git a/src/libjit.c b/src/libjit.c index 5c4a7b9..5dc011f 100644 --- a/src/libjit.c +++ b/src/libjit.c @@ -1,31 +1,19 @@ #include "php.h" #include "libjit.h" #include "parser_proc.h" +#include "parser.h" + +#include static void init(PSI_Context *C) { - C->opaque = jit_context_create(); + C->context = jit_context_create(); } static void dtor(PSI_Context *C) { - jit_context_destroy(C->opaque); -} - -typedef struct PSI_ClosureData { - void *context; - impl *impl; - jit_type_t signature; - zval return_value; -} PSI_ClosureData; - -static inline PSI_ClosureData *PSI_ClosureDataAlloc(void *context, impl *impl) { - PSI_ClosureData *data = malloc(sizeof(*data)); - - data->context = context; - data->impl = impl; - - return data; + jit_context_destroy(C->context); + C->context = NULL; } static inline size_t impl_num_min_args(impl *impl) { @@ -44,6 +32,9 @@ static inline jit_abi_t psi_jit_abi(const char *convention) { } static inline jit_type_t psi_jit_type(token_t t) { switch (t) { + default: + ZEND_ASSERT(0); + /* no break */ case PSI_T_VOID: return jit_type_void; case PSI_T_SINT8: @@ -76,8 +67,6 @@ static inline jit_type_t psi_jit_type(token_t t) { return jit_type_sys_float; case PSI_T_DOUBLE: return jit_type_sys_double; - default: - abort(); } } static inline jit_type_t psi_jit_decl_type(decl_type *type) { @@ -90,33 +79,95 @@ static inline jit_type_t psi_jit_decl_arg_type(decl_arg *darg) { return psi_jit_decl_type(darg->type); } } -static void handler(jit_type_t _sig, void *result, void **_args, void *_data) -{ - zend_execute_data *execute_data = *(zend_execute_data **)_args[0]; - zval *return_value = *(zval **)_args[1]; - PSI_ClosureData *data = _data; - impl_arg *iarg; - size_t i; - void **arg_ptr = NULL, **arg_prm = NULL; - impl_val ret_val, *arg_val = NULL; - jit_type_t signature, *sig_prm; - if (!data->impl->func->args->count) { - if (SUCCESS != zend_parse_parameters_none()) { - return; +typedef struct PSI_ClosureData { + void *context; + impl *impl; + jit_type_t signature; + jit_type_t params[1]; +} PSI_ClosureData; + +static inline PSI_ClosureData *PSI_ClosureDataAlloc(void *context, impl *impl) { + size_t i, c = impl->decl->args->count; + PSI_ClosureData *data = malloc(sizeof(*data) + (c ? c-1 : c) * sizeof(jit_type_t)); + + data->context = context; + data->impl = impl; + for (i = 0; i < c; ++i) { + data->params[i] = psi_jit_decl_arg_type(impl->decl->args->args[i]); + } + data->signature = jit_type_create_signature( + psi_jit_abi(data->impl->decl->abi->convention), + psi_jit_decl_arg_type(data->impl->decl->func), + data->params, + data->impl->decl->args->count, + 1); + return data; +} + + +static inline impl_val *deref(unsigned level, impl_val *ret_val, decl_arg *darg) { + unsigned i; + + for (i = level; i < darg->var->pointer_level; ++i) { + ret_val = *(void **)ret_val; + } + + return ret_val; +} +static void to_int(impl_val *ret_val, decl_arg *func, zval *return_value) { + switch (real_decl_type(func->type)->type) { + case PSI_T_FLOAT: + case PSI_T_DOUBLE: + RETVAL_DOUBLE(deref(0, ret_val, func)->dval); + convert_to_long(return_value); + break; + default: + RETVAL_LONG(deref(0, ret_val, func)->lval); + } +} +static void to_string(impl_val *ret_val, decl_arg *func, zval *return_value) { + switch (real_decl_type(func->type)->type) { + case PSI_T_CHAR: + case PSI_T_SINT8: + case PSI_T_UINT8: + if (!func->var->pointer_level) { + char chr = ret_val->lval; + RETVAL_STRINGL(&chr, 1); + } else { + RETVAL_STRING(deref(1, ret_val, func)->ptr); } - } else - ZEND_PARSE_PARAMETERS_START(impl_num_min_args(data->impl), data->impl->func->args->count) + break; + case PSI_T_FLOAT: + case PSI_T_DOUBLE: + RETVAL_DOUBLE(deref(0, ret_val, func)->dval); + convert_to_string(return_value); + break; + default: + RETVAL_LONG(deref(0, ret_val, func)->lval); + convert_to_string(return_value); + break; + } +} + +static ZEND_RESULT_CODE handle_args(zend_execute_data *execute_data, impl *impl) { + impl_arg *iarg; + + if (!impl->func->args->count) { + return zend_parse_parameters_none(); + } + + ZEND_PARSE_PARAMETERS_START(impl_num_min_args(impl), impl->func->args->count) nextarg: - iarg = data->impl->func->args->args[_i]; + iarg = impl->func->args->args[_i]; if (iarg->def) { Z_PARAM_OPTIONAL; } if (PSI_T_BOOL == iarg->type->type) { if (iarg->def) { - iarg->val.bval = iarg->def->type == PSI_T_TRUE ? 1 : 0; + iarg->val.cval = iarg->def->type == PSI_T_TRUE ? 1 : 0; } - Z_PARAM_BOOL(iarg->val.bval); + Z_PARAM_BOOL(iarg->val.cval); } else if (PSI_T_INT == iarg->type->type) { if (iarg->def) { iarg->val.lval = zend_atol(iarg->def->text, strlen(iarg->def->text)); @@ -128,12 +179,18 @@ static void handler(jit_type_t _sig, void *result, void **_args, void *_data) } Z_PARAM_DOUBLE(iarg->val.dval); } else if (PSI_T_STRING == iarg->type->type) { + struct {char *val; size_t len;} str; if (iarg->def) { /* FIXME */ - iarg->val.str.len = strlen(iarg->def->text) - 2; - iarg->val.str.val = &iarg->def->text[1]; + str.len = strlen(iarg->def->text) - 2; + str.val = &iarg->def->text[1]; + } + Z_PARAM_STR_EX(iarg->val.str, 1, 0); + if (iarg->val.str) { + zend_string_addref(iarg->val.str); + } else if (iarg->def) { + iarg->val.str = zend_string_init(str.val, str.len, 0); } - Z_PARAM_STRING(iarg->val.str.val, iarg->val.str.len); } else { error_code = ZPP_ERROR_FAILURE; break; @@ -142,79 +199,202 @@ static void handler(jit_type_t _sig, void *result, void **_args, void *_data) if (_i < _max_num_args) { goto nextarg; } - ZEND_PARSE_PARAMETERS_END(); + ZEND_PARSE_PARAMETERS_END_EX(return FAILURE); + + return SUCCESS; +} + +static impl_val *handle_let(decl_arg *darg, impl_arg *iarg) { + impl_val *arg_val = &darg->let->out; + + if (!iarg) { + /* let foo = NULL */ + memset(arg_val, 0, sizeof(*arg_val)); + return arg_val; + } + switch (darg->let->val->func->type) { + case PSI_T_BOOLVAL: + if (iarg->type->type == PSI_T_BOOL) { + arg_val->cval = iarg->val.cval; + } else { + arg_val->cval = zend_is_true(iarg->_zv); + } + break; + case PSI_T_INTVAL: + if (iarg->type->type == PSI_T_INT) { + arg_val->lval = iarg->val.lval; + } else { + arg_val->lval = zval_get_long(iarg->_zv); + } + break; + case PSI_T_STRVAL: + if (iarg->type->type == PSI_T_STRING) { + arg_val->ptr = estrdup(iarg->val.str->val); + darg->let->mem = arg_val->ptr; + zend_string_release(iarg->val.str); + } else { + zend_string *zs = zval_get_string(iarg->_zv); + arg_val->ptr = estrdup(zs->val); + darg->let->mem = arg_val->ptr; + zend_string_release(zs); + } + break; + case PSI_T_STRLEN: + if (iarg->type->type == PSI_T_STRING) { + arg_val->lval = iarg->val.str->len; + zend_string_release(iarg->val.str); + } else { + zend_string *zs = zval_get_string(iarg->_zv); + arg_val->lval = zs->len; + zend_string_release(zs); + } + break; + EMPTY_SWITCH_DEFAULT_CASE(); + } + + return arg_val; +} + +static void handle_rval(impl *impl, impl_val *ret_val, zval *return_value) { + switch (impl->stmts->ret.list[0]->func->type) { + case PSI_T_TO_STRING: + to_string(ret_val, impl->decl->func, return_value); + break; + case PSI_T_TO_INT: + to_int(ret_val, impl->decl->func, return_value); + break; + EMPTY_SWITCH_DEFAULT_CASE(); + } +} + +static void handle_set(zval *return_value, set_func *func, decl_vars *vars) { + impl_val *val = &vars->vars[0]->arg->let->ptr; + + zval_dtor(return_value); + + switch (func->type) { + case PSI_T_TO_STRING: + to_string(val, vars->vars[0]->arg, return_value); + break; + EMPTY_SWITCH_DEFAULT_CASE(); + } +} + +static void handle_free(free_stmt *fre) { + size_t i; + + for (i = 0; i < fre->vars->count; ++i) { + decl_var *dvar = fre->vars->vars[i]; + + if (dvar->arg && dvar->arg->let->out.ptr) { + free(dvar->arg->let->out.ptr); + dvar->arg->let->out.ptr = NULL; + } + } +} + +static void handler(jit_type_t _sig, void *result, void **_args, void *_data) +{ + PSI_ClosureData *data = _data; + size_t i; + void **arg_ptr = NULL, **arg_prm = NULL; + impl_val ret_val; + + if (SUCCESS != handle_args(*(zend_execute_data **)_args[0], data->impl)) { + return; + } if (data->impl->decl->args->count) { arg_ptr = malloc(data->impl->decl->args->count * sizeof(*arg_ptr)); arg_prm = malloc(data->impl->decl->args->count * sizeof(*arg_prm)); - arg_val = malloc(data->impl->decl->args->count * sizeof(*arg_val)); - sig_prm = malloc(data->impl->decl->args->count * sizeof(*sig_prm)); for (i = 0; i < data->impl->decl->args->count; ++i) { decl_arg *darg = data->impl->decl->args->args[i]; - impl_arg *iarg = darg->let->arg; - - switch (darg->let->val->func->type) { - case PSI_T_BOOLVAL: - if (iarg->type->type == PSI_T_BOOL) { - arg_val[i].bval = iarg->val.bval; - } else { - arg_val[i].bval = zend_is_true(iarg->_zv); - } - break; - case PSI_T_INTVAL: - if (iarg->type->type == PSI_T_INT) { - arg_val[i].lval = iarg->val.lval; - } else { - arg_val[i].lval = zval_get_long(iarg->_zv); - } - break; - case PSI_T_STRVAL: - if (iarg->type->type == PSI_T_STRING) { - arg_val[i].str.val = estrndup(iarg->val.str.val, iarg->val.str.len); - } else { - zend_string *zs = zval_get_string(iarg->_zv); - arg_val[i].str.val = estrndup(zs->val, zs->len); - zend_string_release(zs); - } - break; - case PSI_T_STRLEN: - if (iarg->type->type == PSI_T_STRING) { - arg_val[i].lval =iarg->val.str.len; - } else { - zend_string *zs = zval_get_string(iarg->_zv); - arg_val[i].lval = zs->len; - zend_string_release(zs); - } - break; - } - arg_ptr[i] = &arg_val[i]; + impl_arg *iarg = darg->let ? darg->let->arg : NULL; + + arg_ptr[i] = handle_let(darg, iarg); arg_prm[i] = darg->let->val->is_reference ? &arg_ptr[i] : arg_ptr[i]; - sig_prm[i] = psi_jit_decl_arg_type(darg); + + darg->let->ptr = arg_ptr[i]; } } - signature = jit_type_create_signature( - psi_jit_abi(data->impl->decl->abi->convention), - psi_jit_decl_arg_type(data->impl->decl->func), - sig_prm, - data->impl->decl->args->count, - 1); - jit_apply(signature, data->impl->decl->dlptr, arg_prm, data->impl->decl->args->count, &ret_val); + jit_apply(data->signature, data->impl->decl->dlptr, arg_prm, data->impl->decl->args->count, &ret_val); - switch (data->impl->stmts->ret.list[0]->func->type) { - case PSI_T_TO_STRING: - if (data->impl->decl->func->var->pointer_level) { - switch (real_decl_type(data->impl->decl->func->type)->type) { - case PSI_T_CHAR: - case PSI_T_SINT8: - case PSI_T_UINT8: - RETVAL_STRING(ret_val.str.val); - break; + handle_rval(data->impl, &ret_val, *(zval **)_args[1]); + + for (i = 0; i < data->impl->stmts->set.count; ++i) { + set_stmt *set = data->impl->stmts->set.list[i]; + + handle_set(set->arg->_zv, set->val->func, set->val->vars); + } + + if (data->impl->decl->args->count) { + for (i = 0; i < data->impl->decl->args->count; ++i) { + decl_arg *darg = data->impl->decl->args->args[i]; + + if (darg->let && darg->let->mem) { + efree(darg->let->mem); + darg->let->mem = NULL; } } - break; + free(arg_ptr); + free(arg_prm); } + + for (i = 0; i < data->impl->stmts->fre.count; ++i) { + free_stmt *fre = data->impl->stmts->fre.list[i]; + + handle_free(fre); + } +} + +static inline int fill_type_hint(impl_type *type) { + switch (type->type) { + case PSI_T_BOOL: + return _IS_BOOL; + case PSI_T_INT: + case PSI_T_LONG: + 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; + } +} + +static inline zend_internal_arg_info *fill_arginfo(impl *impl) { + size_t i; + zend_internal_arg_info *aip; + zend_internal_function_info *fi; + + aip = calloc(impl->func->args->count + 1, sizeof(*aip)); + + fi = (zend_internal_function_info *) &aip[0]; + fi->required_num_args = impl_num_min_args(impl); + fi->return_reference = impl->func->return_reference; + fi->type_hint = fill_type_hint(impl->func->return_type); + + 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 = fill_type_hint(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; } static zend_function_entry *compile(PSI_Context *C, PSI_Data *D) @@ -226,24 +406,26 @@ static zend_function_entry *compile(PSI_Context *C, PSI_Data *D) }; zend_function_entry *zfe = calloc(D->impls->count + 1, sizeof(*zfe)); - jit_context_build_start(C->opaque); + jit_context_build_start(C->context); for (i = 0; i < D->impls->count; ++i) { - zend_function_entry *zf; + zend_function_entry *zf = &zfe[j]; PSI_ClosureData *data; if (!D->impls->list[i]->decl) { continue; } - zf = &zfe[j++]; data = PSI_ClosureDataAlloc(C, D->impls->list[i]); signature = jit_type_create_signature(jit_abi_cdecl, jit_type_void, params, 2, 1); zf->fname = D->impls->list[i]->func->name + (D->impls->list[i]->func->name[0] == '\\'); - zf->handler = jit_closure_create(C->opaque, signature, &handler, data); + zf->handler = jit_closure_create(C->context, signature, &handler, data); + zf->num_args = D->impls->list[i]->func->args->count; + zf->arg_info = fill_arginfo(D->impls->list[i]); + ++j; } - jit_context_build_end(C->opaque); + jit_context_build_end(C->context); return zfe; } diff --git a/src/libjit.h b/src/libjit.h index 78012a6..e5464a6 100644 --- a/src/libjit.h +++ b/src/libjit.h @@ -1,6 +1,8 @@ #ifndef _PSI_LIBJIT_H #define _PSI_LIBJIT_H +#include "context.h" + PSI_ContextOps *PSI_Libjit(void); #endif diff --git a/src/module.c b/src/module.c index b8109b3..4df3e11 100644 --- a/src/module.c +++ b/src/module.c @@ -3,17 +3,13 @@ #include "config.h" #endif -#include - #include "php.h" #include "php_ini.h" #include "ext/standard/info.h" #include "php_psi.h" -#include "parser.h" -#include "validator.h" -#include "compiler.h" +#include "libjit.h" ZEND_DECLARE_MODULE_GLOBALS(psi); @@ -44,8 +40,7 @@ PHP_MINIT_FUNCTION(psi) } PHP_MSHUTDOWN_FUNCTION(psi) { - jit_context_t ctx = PSI_G(context); - jit_context_destroy(ctx); + PSI_ContextDtor(&PSI_G(context)); UNREGISTER_INI_ENTRIES(); diff --git a/src/parser.h b/src/parser.h index 8506acd..0ed55ca 100644 --- a/src/parser.h +++ b/src/parser.h @@ -89,9 +89,20 @@ static void free_decl_typedefs(decl_typedefs *defs) { free(defs); } +typedef union impl_val { + char cval; + short sval; + int ival; + double dval; + zend_long lval; + zend_string *str; + void *ptr; +} impl_val; + typedef struct decl_var { char *name; unsigned pointer_level; + struct decl_arg *arg; } decl_var; static inline decl_var *init_decl_var(char *name, unsigned pl) { @@ -297,16 +308,6 @@ static inline void free_impl_def_val(impl_def_val *def) { free(def); } -typedef union impl_val { - unsigned char bval; - zend_long lval; - double dval; - struct { - char *val; - size_t len; - } str; -} impl_val; - typedef struct impl_arg { impl_type *type; impl_var *var; @@ -370,13 +371,15 @@ typedef struct impl_func { char *name; impl_args *args; impl_type *return_type; + unsigned return_reference:1; } impl_func; -static inline impl_func *init_impl_func(char *name, impl_args *args, impl_type *type) { +static inline impl_func *init_impl_func(char *name, impl_args *args, impl_type *type, int ret_reference) { impl_func *func = malloc(sizeof(*func)); func->name = strdup(name); func->args = args ? args : init_impl_args(NULL); func->return_type = type; + func->return_reference = ret_reference; return func; } @@ -432,13 +435,15 @@ typedef struct let_stmt { decl_var *var; let_value *val; impl_arg *arg; + impl_val out; + void *ptr; + void *mem; } let_stmt; static inline let_stmt *init_let_stmt(decl_var *var, let_value *val) { - let_stmt *let = malloc(sizeof(*let)); + let_stmt *let = calloc(1, sizeof(*let)); let->var = var; let->val = val; - let->arg = NULL; return let; } @@ -486,6 +491,7 @@ static inline void free_set_value(set_value *val) { typedef struct set_stmt { impl_var *var; set_value *val; + impl_arg *arg; } set_stmt; static inline set_stmt *init_set_stmt(impl_var *var, set_value *val) { @@ -501,30 +507,46 @@ static inline void free_set_stmt(set_stmt *set) { free(set); } -typedef struct ret_stmt { +typedef struct return_stmt { set_func *func; decl_var *decl; -} ret_stmt; +} return_stmt; -static inline ret_stmt *init_ret_stmt(set_func *func, decl_var *decl) { - ret_stmt *ret = malloc(sizeof(*ret)); +static inline return_stmt *init_return_stmt(set_func *func, decl_var *decl) { + return_stmt *ret = malloc(sizeof(*ret)); ret->func = func; ret->decl = decl; return ret; } -static inline void free_ret_stmt(ret_stmt *ret) { +static inline void free_return_stmt(return_stmt *ret) { free_set_func(ret->func); free_decl_var(ret->decl); free(ret); } +typedef struct free_stmt { + decl_vars *vars; +} free_stmt; + +static inline free_stmt *init_free_stmt(decl_vars *vars) { + free_stmt *free_ = malloc(sizeof(*free_)); + free_->vars = vars; + return free_; +} + +static inline void free_free_stmt(free_stmt *free_) { + free_decl_vars(free_->vars); + free(free_); +} + typedef struct impl_stmt { token_t type; union { let_stmt *let; set_stmt *set; - ret_stmt *ret; + return_stmt *ret; + free_stmt *fre; void *ptr; } s; } impl_stmt; @@ -544,8 +566,11 @@ static inline void free_impl_stmt(impl_stmt *stmt) { case PSI_T_SET: free_set_stmt(stmt->s.set); break; - case PSI_T_RET: - free_ret_stmt(stmt->s.ret); + case PSI_T_RETURN: + free_return_stmt(stmt->s.ret); + break; + case PSI_T_FREE: + free_free_stmt(stmt->s.fre); break; } free(stmt); @@ -553,7 +578,7 @@ static inline void free_impl_stmt(impl_stmt *stmt) { typedef struct impl_stmts { struct { - ret_stmt **list; + return_stmt **list; size_t count; } ret; struct { @@ -564,6 +589,10 @@ typedef struct impl_stmts { set_stmt **list; size_t count; } set; + struct { + free_stmt **list; + size_t count; + } fre; } impl_stmts; static inline void *add_impl_stmt_ex(void *list, size_t count, void *stmt) { @@ -574,7 +603,7 @@ static inline void *add_impl_stmt_ex(void *list, size_t count, void *stmt) { static inline impl_stmts *add_impl_stmt(impl_stmts *stmts, impl_stmt *stmt) { switch (stmt->type) { - case PSI_T_RET: + 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: @@ -583,6 +612,9 @@ static inline impl_stmts *add_impl_stmt(impl_stmts *stmts, impl_stmt *stmt) { 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; } return stmts; } @@ -600,13 +632,17 @@ static inline void free_impl_stmts(impl_stmts *stmts) { } free(stmts->let.list); for (i = 0; i < stmts->ret.count; ++i) { - free_ret_stmt(stmts->ret.list[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); } diff --git a/src/parser.re b/src/parser.re index 4cabb45..d0daecb 100644 --- a/src/parser.re +++ b/src/parser.re @@ -204,7 +204,8 @@ token_t PSI_ParserScan(PSI_Parser *P) LIB = 'lib'; LET = 'let'; SET = 'set'; - RET = 'ret'; + RETURN = 'return'; + FREE = 'free'; STRLEN = 'strlen'; STRVAL = 'strval'; INTVAL = 'intval'; @@ -257,7 +258,8 @@ token_t PSI_ParserScan(PSI_Parser *P) LIB {RETURN(PSI_T_LIB);} LET {RETURN(PSI_T_LET);} SET {RETURN(PSI_T_SET);} - RET {RETURN(PSI_T_RET);} + RETURN {RETURN(PSI_T_RETURN);} + FREE {RETURN(PSI_T_FREE);} STRLEN {RETURN(PSI_T_STRLEN);} STRVAL {RETURN(PSI_T_STRVAL);} INTVAL {RETURN(PSI_T_INTVAL);} diff --git a/src/parser_proc.h b/src/parser_proc.h index d1ba3cf..e5d418a 100644 --- a/src/parser_proc.h +++ b/src/parser_proc.h @@ -27,12 +27,12 @@ #define PSI_T_FUNCTION 27 #define PSI_T_NSNAME 28 #define PSI_T_COLON 29 -#define PSI_T_NULL 30 -#define PSI_T_NUMBER 31 -#define PSI_T_TRUE 32 -#define PSI_T_FALSE 33 -#define PSI_T_DOLLAR 34 -#define PSI_T_REFERENCE 35 +#define PSI_T_REFERENCE 30 +#define PSI_T_NULL 31 +#define PSI_T_NUMBER 32 +#define PSI_T_TRUE 33 +#define PSI_T_FALSE 34 +#define PSI_T_DOLLAR 35 #define PSI_T_EQUALS 36 #define PSI_T_LET 37 #define PSI_T_STRLEN 38 @@ -45,9 +45,10 @@ #define PSI_T_TO_INT 45 #define PSI_T_TO_FLOAT 46 #define PSI_T_TO_BOOL 47 -#define PSI_T_RET 48 -#define PSI_T_MIXED 49 -#define PSI_T_BOOL 50 -#define PSI_T_STRING 51 -#define PSI_T_ARRAY 52 -#define PSI_T_POINTER 53 +#define PSI_T_RETURN 48 +#define PSI_T_FREE 49 +#define PSI_T_MIXED 50 +#define PSI_T_BOOL 51 +#define PSI_T_STRING 52 +#define PSI_T_ARRAY 53 +#define PSI_T_POINTER 54 diff --git a/src/parser_proc.y b/src/parser_proc.y index c619e55..3dc06e2 100644 --- a/src/parser_proc.y +++ b/src/parser_proc.y @@ -163,12 +163,12 @@ impl(impl) ::= impl_func(func) LBRACE impl_stmts(stmts) RBRACE. { } %type impl_func {impl_func*} -impl_func(func) ::= FUNCTION NSNAME(NAME) LPAREN impl_args(args) RPAREN COLON impl_type(type). { - func = init_impl_func(NAME->text, args, type); +impl_func(func) ::= FUNCTION NSNAME(NAME) impl_args(args) COLON impl_type(type). { + func = init_impl_func(NAME->text, args, type, 0); free(NAME); } -impl_func(func) ::= FUNCTION NSNAME(NAME) LPAREN RPAREN COLON impl_type(type). { - func = init_impl_func(NAME->text, NULL, type); +impl_func(func) ::= FUNCTION REFERENCE NSNAME(NAME) impl_args(args) COLON impl_type(type). { + func = init_impl_func(NAME->text, args, type, 1); free(NAME); } @@ -208,10 +208,17 @@ impl_arg(arg) ::= impl_type(type) impl_var(var) EQUALS impl_def_val(def). { } %type impl_args {impl_args*} -impl_args(args) ::= impl_arg(arg). { +impl_args(args) ::= LPAREN RPAREN. { + args = NULL; +} +impl_args(args) ::= LPAREN impl_arg_list(args_) RPAREN. { + args = args_; +} +%type impl_arg_list {impl_args*} +impl_arg_list(args) ::= impl_arg(arg). { args = init_impl_args(arg); } -impl_args(args) ::= impl_args(args_) COMMA impl_arg(arg). { +impl_arg_list(args) ::= impl_arg_list(args_) COMMA impl_arg(arg). { args = add_impl_arg(args_, arg); } @@ -230,8 +237,11 @@ impl_stmt(stmt) ::= let_stmt(let). { impl_stmt(stmt) ::= set_stmt(set). { stmt = init_impl_stmt(PSI_T_SET, set); } -impl_stmt(stmt) ::= ret_stmt(ret). { - stmt = init_impl_stmt(PSI_T_RET, ret); +impl_stmt(stmt) ::= return_stmt(ret). { + stmt = init_impl_stmt(PSI_T_RETURN, ret); +} +impl_stmt(stmt) ::= free_stmt(free). { + stmt = init_impl_stmt(PSI_T_FREE, free); } %type let_stmt {let_stmt*} @@ -307,9 +317,14 @@ set_func(func) ::= VOID(T). { free(T); } -%type ret_stmt {ret_stmt*} -ret_stmt(ret) ::= RET set_func(func) LPAREN decl_var(var) RPAREN EOS. { - ret = init_ret_stmt(func, var); +%type return_stmt {return_stmt*} +return_stmt(ret) ::= RETURN set_func(func) LPAREN decl_var(var) RPAREN EOS. { + ret = init_return_stmt(func, var); +} + +%type free_stmt {free_stmt*} +free_stmt(free) ::= FREE decl_vars(vars) EOS. { + free = init_free_stmt(vars); } %type impl_type {impl_type*} @@ -344,4 +359,4 @@ impl_type(type_) ::= ARRAY(T). { %type pointers {unsigned} pointers(p) ::= POINTER. {++p;} -pointers(p) ::= pointers(P) POINTER. {p = ++P;} +pointers(p) ::= pointers(P) POINTER. {p = P+1;} diff --git a/src/validator.c b/src/validator.c index 4e38929..5a6f5d9 100644 --- a/src/validator.c +++ b/src/validator.c @@ -124,13 +124,23 @@ static inline int validate_decl_func(PSI_Validator *V, decl *decl, decl_arg *fun } return 1; } +static const char * const abi_ccs[] = { + "default", /* \ */ + "extern", /* > - all the same */ + "cdecl", /* / */ + "stdcall", + "fastcall", +}; static inline int validate_decl_abi(PSI_Validator *V, decl_abi *abi) { - if (strcasecmp(abi->convention, "default")) { - V->error(PSI_WARNING, "Invalid calling convention: '%s'", abi->convention); - return 0; + size_t i; + + for (i = 0; i < sizeof(abi_ccs)/sizeof(char*); ++ i) { + if (strcasecmp(abi->convention, abi_ccs[i])) { + return 1; + } } - /* FIXME */ - return 1; + V->error(PSI_WARNING, "Invalid calling convention: '%s'", abi->convention); + return 0; } static inline int validate_decl_arg(PSI_Validator *V, decl *decl, decl_arg *arg) { if (!validate_decl_type(V, arg, arg->type)) { @@ -198,7 +208,7 @@ static inline int validate_impl_func(PSI_Validator *V, impl *impl, impl_func *fu } return 1; } -static inline decl *locate_impl_decl(decls *decls, ret_stmt *ret) { +static inline decl *locate_impl_decl(decls *decls, return_stmt *ret) { size_t i; for (i = 0; i < decls->count; ++i) { @@ -213,10 +223,11 @@ static inline int validate_impl_stmts(PSI_Validator *V, impl *impl, impl_stmts * /* okay, * - we must have exactly one ret stmt delcaring the native func to call and which type cast to apply * - we can have multiple let stmts; every arg of the ret stmts var (the function to call) must have one - * - we can have any count of set stmts; processing out vars, etc. + * - we can have any count of set stmts; processing out vars + * - we can have any count of free stmts; freeing any out vars */ - size_t i, j; - ret_stmt *ret; + size_t i, j, k; + return_stmt *ret; decl *decl; if (!stmts) { @@ -289,6 +300,78 @@ static inline int validate_impl_stmts(PSI_Validator *V, impl *impl, impl_stmts * } } } + /* check that set stmts reference known variables */ + for (i = 0; i < stmts->set.count; ++i) { + set_stmt *set = stmts->set.list[i]; + int check = 0; + + 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; + } + } + if (!check) { + V->error(PSI_WARNING, "Unknown variable '$%s' of `set` statement" + " of implementation '%s'", + set->var->name, impl->func->name); + return 0; + } + + for (j = 0; j < set->val->vars->count; ++j) { + decl_var *set_var = set->val->vars->vars[j]; + + check = 0; + for (k = 0; k < decl->args->count; ++k) { + decl_arg *set_arg = decl->args->args[k]; + + if (!strcmp(set_var->name, set_arg->var->name)) { + check = 1; + set_var->arg = set_arg; + break; + } + } + + if (!check) { + V->error(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; + } + } + } + /* check free stmts */ + for (i = 0; i < stmts->fre.count; ++i) { + free_stmt *fre = stmts->fre.list[i]; + + for (j = 0; j < fre->vars->count; ++j) { + decl_var *free_var = fre->vars->vars[j]; + int check = 0; + + if (!strcmp(free_var->name, decl->func->var->name)) { + continue; + } + for (k = 0; k < decl->args->count; ++k) { + decl_arg *free_arg = decl->args->args[k]; + + if (!strcmp(free_var->name, free_arg->var->name)) { + check = 1; + free_var->arg = free_arg; + break; + } + } + + if (!check) { + V->error(PSI_WARNING, "Unknown variable '%s' of `free` statement" + " of implementation '%s'", + free_var->name, impl->func->name); + return 0; + } + } + } impl->decl = decl; -- 2.30.2