X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-psi;a=blobdiff_plain;f=src%2Fbuiltin.c;fp=src%2Fbuiltin.c;h=e4e2e9bdd4348cdec0e7eaad857a754269aab5e4;hp=0000000000000000000000000000000000000000;hb=a7ac1c0a3c855321f21682c127a4b707de33a303;hpb=35060621f2fd5079502543d17942127c1a602f72 diff --git a/src/builtin.c b/src/builtin.c new file mode 100644 index 0000000..e4e2e9b --- /dev/null +++ b/src/builtin.c @@ -0,0 +1,180 @@ +/******************************************************************************* + Copyright (c) 2018, 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_psi.h" +#include "builtin.h" +#include "parser.h" +#include "cpp.h" + +#include + +HashTable psi_builtins; + +static bool has_include(struct psi_cpp *cpp, struct psi_token *target, struct psi_plist **args, struct psi_plist **res); +static bool has_include_next(struct psi_cpp *cpp, struct psi_token *target, struct psi_plist **args, struct psi_plist **res); +static bool builtin_constant_p(struct psi_cpp *cpp, struct psi_token *target, struct psi_plist **args, struct psi_plist **res); +static bool COUNTER__(struct psi_cpp *cpp, struct psi_token *target, struct psi_plist **args, struct psi_plist **res); + +static inline struct psi_plist *builtin_sig(token_t typ, ...) +{ + struct psi_plist *sig; + size_t n = 0; + va_list args; + + if (typ == (token_t) - 1) { + return NULL; + } + + sig = psi_plist_init((psi_plist_dtor) psi_token_free); + va_start(args, typ); + while (typ) { + char a = 'a' + n++; + struct psi_token *arg; + + arg = psi_token_init(typ, &a, 1, 0, 0, zend_empty_string); + sig = psi_plist_add(sig, &arg); + typ = va_arg(args, token_t); + } + va_end(args); + + return sig; +} + +static void free_builtin(zval *p) +{ + struct psi_builtin *b = Z_PTR_P(p); + + if (b) { + zend_string_release(b->name); + psi_cpp_macro_decl_free(&b->decl); + pefree(b, 1); + } +} + +PHP_MINIT_FUNCTION(psi_builtin) +{ +#define PSI_BUILTIN(builtin, ...) do { \ + struct psi_builtin entry; \ + struct psi_plist *sig = builtin_sig(__VA_ARGS__, 0); \ + struct psi_cpp_macro_decl *decl = psi_cpp_macro_decl_init(sig, NULL, NULL); \ + decl->token = psi_token_init(PSI_T_NAME, "__" #builtin, sizeof("__" #builtin)-1, \ + 0, 0, zend_empty_string); \ + entry.name = zend_string_copy(decl->token->text); \ + entry.func = &builtin; \ + entry.decl = decl; \ + zend_hash_add_mem(&psi_builtins, entry.name, &entry, sizeof(entry)); \ +} while(0) + + zend_hash_init(&psi_builtins, 0, NULL, free_builtin, 1); + PSI_BUILTIN(has_include, PSI_T_CPP_HEADER); + PSI_BUILTIN(has_include_next, PSI_T_CPP_HEADER); + PSI_BUILTIN(builtin_constant_p, PSI_T_NAME); + PSI_BUILTIN(COUNTER__, -1); + + return SUCCESS; +} + +PHP_MSHUTDOWN_FUNCTION(psi_builtin) +{ + zend_hash_destroy(&psi_builtins); + return SUCCESS; +} + +bool psi_builtin_exists(zend_string *name) +{ + return zend_hash_exists(&psi_builtins, name); +} + +struct psi_builtin *psi_builtin_get(zend_string *name) +{ + return zend_hash_find_ptr(&psi_builtins, name); +} + +static bool has_include(struct psi_cpp *cpp, struct psi_token *target, + struct psi_plist **args, struct psi_plist **res) +{ + struct psi_plist *arg = args[0]; + struct psi_token *tok; + + switch (psi_plist_count(arg)) { + case 1: + if (psi_plist_get(arg, 0, &tok)) { + const char *cpp_search = cpp->search; + bool has = psi_cpp_has_include(cpp, tok, 0, NULL); + cpp->search = cpp_search; + return has; + } + /* no break */ + default: + cpp->parser->error(PSI_DATA(cpp->parser), target, PSI_WARNING, + "Erroneous usage of builtin __%s", __FUNCTION__); + } + return false; +} + +static bool has_include_next(struct psi_cpp *cpp, struct psi_token *target, + struct psi_plist **args, struct psi_plist **res) +{ + struct psi_plist *arg = args[0]; + struct psi_token *tok; + + switch (psi_plist_count(arg)) { + case 1: + if (psi_plist_get(arg, 0, &tok)) { + const char *cpp_search = cpp->search; + bool has = psi_cpp_has_include(cpp, tok, PSI_CPP_INCLUDE_NEXT, NULL); + cpp->search = cpp_search; + return has; + } + /* no break */ + default: + cpp->parser->error(PSI_DATA(cpp->parser), target, PSI_WARNING, + "Erroneous usage of builtin __%s", __FUNCTION__); + } + return false; +} + +static bool builtin_constant_p(struct psi_cpp *cpp, struct psi_token *target, + struct psi_plist **args, struct psi_plist **res_ptr) +{ + /* we want functions, not macros for e.g. htonl() */ + return false; +} + +static bool COUNTER__(struct psi_cpp *cpp, struct psi_token *target, + struct psi_plist **args, struct psi_plist **res) +{ + struct psi_token *tok; + char buf[0x20]; + size_t len = sprintf(buf, "%u", cpp->counter++); + + tok = psi_token_init(PSI_T_NUMBER, buf, len, target->col, target->line, target->file); + *res = psi_plist_init((psi_plist_dtor) psi_token_free); + *res = psi_plist_add(*res, &tok); + + return true; +}