123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430 |
- /*
- +----------------------------------------------------------------------+
- | Zend Engine |
- +----------------------------------------------------------------------+
- | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
- +----------------------------------------------------------------------+
- | This source file is subject to version 2.00 of the Zend license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.zend.com/license/2_00.txt. |
- | If you did not receive a copy of the Zend license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@zend.com so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- | Authors: Bob Weinand <bwoebi@php.net> |
- | Dmitry Stogov <dmitry@php.net> |
- +----------------------------------------------------------------------+
- */
- #include "zend_ast.h"
- #include "zend_API.h"
- #include "zend_operators.h"
- #include "zend_language_parser.h"
- #include "zend_smart_str.h"
- #include "zend_exceptions.h"
- #include "zend_constants.h"
- #include "zend_enum.h"
- ZEND_API zend_ast_process_t zend_ast_process = NULL;
- static inline void *zend_ast_alloc(size_t size) {
- return zend_arena_alloc(&CG(ast_arena), size);
- }
- static inline void *zend_ast_realloc(void *old, size_t old_size, size_t new_size) {
- void *new = zend_ast_alloc(new_size);
- memcpy(new, old, old_size);
- return new;
- }
- static inline size_t zend_ast_list_size(uint32_t children) {
- return sizeof(zend_ast_list) - sizeof(zend_ast *) + sizeof(zend_ast *) * children;
- }
- ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_znode(znode *node) {
- zend_ast_znode *ast;
- ast = zend_ast_alloc(sizeof(zend_ast_znode));
- ast->kind = ZEND_AST_ZNODE;
- ast->attr = 0;
- ast->lineno = CG(zend_lineno);
- ast->node = *node;
- return (zend_ast *) ast;
- }
- static zend_always_inline zend_ast * zend_ast_create_zval_int(zval *zv, uint32_t attr, uint32_t lineno) {
- zend_ast_zval *ast;
- ast = zend_ast_alloc(sizeof(zend_ast_zval));
- ast->kind = ZEND_AST_ZVAL;
- ast->attr = attr;
- ZVAL_COPY_VALUE(&ast->val, zv);
- Z_LINENO(ast->val) = lineno;
- return (zend_ast *) ast;
- }
- ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_zval_with_lineno(zval *zv, uint32_t lineno) {
- return zend_ast_create_zval_int(zv, 0, lineno);
- }
- ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_zval_ex(zval *zv, zend_ast_attr attr) {
- return zend_ast_create_zval_int(zv, attr, CG(zend_lineno));
- }
- ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_zval(zval *zv) {
- return zend_ast_create_zval_int(zv, 0, CG(zend_lineno));
- }
- ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_zval_from_str(zend_string *str) {
- zval zv;
- ZVAL_STR(&zv, str);
- return zend_ast_create_zval_int(&zv, 0, CG(zend_lineno));
- }
- ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_zval_from_long(zend_long lval) {
- zval zv;
- ZVAL_LONG(&zv, lval);
- return zend_ast_create_zval_int(&zv, 0, CG(zend_lineno));
- }
- ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_constant(zend_string *name, zend_ast_attr attr) {
- zend_ast_zval *ast;
- ast = zend_ast_alloc(sizeof(zend_ast_zval));
- ast->kind = ZEND_AST_CONSTANT;
- ast->attr = attr;
- ZVAL_STR(&ast->val, name);
- Z_LINENO(ast->val) = CG(zend_lineno);
- return (zend_ast *) ast;
- }
- ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_class_const_or_name(zend_ast *class_name, zend_ast *name) {
- zend_string *name_str = zend_ast_get_str(name);
- if (zend_string_equals_literal_ci(name_str, "class")) {
- zend_string_release(name_str);
- return zend_ast_create(ZEND_AST_CLASS_NAME, class_name);
- } else {
- return zend_ast_create(ZEND_AST_CLASS_CONST, class_name, name);
- }
- }
- ZEND_API zend_ast *zend_ast_create_decl(
- zend_ast_kind kind, uint32_t flags, uint32_t start_lineno, zend_string *doc_comment,
- zend_string *name, zend_ast *child0, zend_ast *child1, zend_ast *child2, zend_ast *child3, zend_ast *child4
- ) {
- zend_ast_decl *ast;
- ast = zend_ast_alloc(sizeof(zend_ast_decl));
- ast->kind = kind;
- ast->attr = 0;
- ast->start_lineno = start_lineno;
- ast->end_lineno = CG(zend_lineno);
- ast->flags = flags;
- ast->lex_pos = LANG_SCNG(yy_text);
- ast->doc_comment = doc_comment;
- ast->name = name;
- ast->child[0] = child0;
- ast->child[1] = child1;
- ast->child[2] = child2;
- ast->child[3] = child3;
- ast->child[4] = child4;
- return (zend_ast *) ast;
- }
- #if ZEND_AST_SPEC
- ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_0(zend_ast_kind kind) {
- zend_ast *ast;
- ZEND_ASSERT(kind >> ZEND_AST_NUM_CHILDREN_SHIFT == 0);
- ast = zend_ast_alloc(zend_ast_size(0));
- ast->kind = kind;
- ast->attr = 0;
- ast->lineno = CG(zend_lineno);
- return ast;
- }
- ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_1(zend_ast_kind kind, zend_ast *child) {
- zend_ast *ast;
- uint32_t lineno;
- ZEND_ASSERT(kind >> ZEND_AST_NUM_CHILDREN_SHIFT == 1);
- ast = zend_ast_alloc(zend_ast_size(1));
- ast->kind = kind;
- ast->attr = 0;
- ast->child[0] = child;
- if (child) {
- lineno = zend_ast_get_lineno(child);
- } else {
- lineno = CG(zend_lineno);
- }
- ast->lineno = lineno;
- return ast;
- }
- ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_2(zend_ast_kind kind, zend_ast *child1, zend_ast *child2) {
- zend_ast *ast;
- uint32_t lineno;
- ZEND_ASSERT(kind >> ZEND_AST_NUM_CHILDREN_SHIFT == 2);
- ast = zend_ast_alloc(zend_ast_size(2));
- ast->kind = kind;
- ast->attr = 0;
- ast->child[0] = child1;
- ast->child[1] = child2;
- if (child1) {
- lineno = zend_ast_get_lineno(child1);
- } else if (child2) {
- lineno = zend_ast_get_lineno(child2);
- } else {
- lineno = CG(zend_lineno);
- }
- ast->lineno = lineno;
- return ast;
- }
- ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_3(zend_ast_kind kind, zend_ast *child1, zend_ast *child2, zend_ast *child3) {
- zend_ast *ast;
- uint32_t lineno;
- ZEND_ASSERT(kind >> ZEND_AST_NUM_CHILDREN_SHIFT == 3);
- ast = zend_ast_alloc(zend_ast_size(3));
- ast->kind = kind;
- ast->attr = 0;
- ast->child[0] = child1;
- ast->child[1] = child2;
- ast->child[2] = child3;
- if (child1) {
- lineno = zend_ast_get_lineno(child1);
- } else if (child2) {
- lineno = zend_ast_get_lineno(child2);
- } else if (child3) {
- lineno = zend_ast_get_lineno(child3);
- } else {
- lineno = CG(zend_lineno);
- }
- ast->lineno = lineno;
- return ast;
- }
- ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_4(zend_ast_kind kind, zend_ast *child1, zend_ast *child2, zend_ast *child3, zend_ast *child4) {
- zend_ast *ast;
- uint32_t lineno;
- ZEND_ASSERT(kind >> ZEND_AST_NUM_CHILDREN_SHIFT == 4);
- ast = zend_ast_alloc(zend_ast_size(4));
- ast->kind = kind;
- ast->attr = 0;
- ast->child[0] = child1;
- ast->child[1] = child2;
- ast->child[2] = child3;
- ast->child[3] = child4;
- if (child1) {
- lineno = zend_ast_get_lineno(child1);
- } else if (child2) {
- lineno = zend_ast_get_lineno(child2);
- } else if (child3) {
- lineno = zend_ast_get_lineno(child3);
- } else if (child4) {
- lineno = zend_ast_get_lineno(child4);
- } else {
- lineno = CG(zend_lineno);
- }
- ast->lineno = lineno;
- return ast;
- }
- ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_5(zend_ast_kind kind, zend_ast *child1, zend_ast *child2, zend_ast *child3, zend_ast *child4, zend_ast *child5) {
- zend_ast *ast;
- uint32_t lineno;
- ZEND_ASSERT(kind >> ZEND_AST_NUM_CHILDREN_SHIFT == 5);
- ast = zend_ast_alloc(zend_ast_size(5));
- ast->kind = kind;
- ast->attr = 0;
- ast->child[0] = child1;
- ast->child[1] = child2;
- ast->child[2] = child3;
- ast->child[3] = child4;
- ast->child[4] = child5;
- if (child1) {
- lineno = zend_ast_get_lineno(child1);
- } else if (child2) {
- lineno = zend_ast_get_lineno(child2);
- } else if (child3) {
- lineno = zend_ast_get_lineno(child3);
- } else if (child4) {
- lineno = zend_ast_get_lineno(child4);
- } else if (child5) {
- lineno = zend_ast_get_lineno(child5);
- } else {
- lineno = CG(zend_lineno);
- }
- ast->lineno = lineno;
- return ast;
- }
- ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_list_0(zend_ast_kind kind) {
- zend_ast *ast;
- zend_ast_list *list;
- ast = zend_ast_alloc(zend_ast_list_size(4));
- list = (zend_ast_list *) ast;
- list->kind = kind;
- list->attr = 0;
- list->lineno = CG(zend_lineno);
- list->children = 0;
- return ast;
- }
- ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_list_1(zend_ast_kind kind, zend_ast *child) {
- zend_ast *ast;
- zend_ast_list *list;
- uint32_t lineno;
- ast = zend_ast_alloc(zend_ast_list_size(4));
- list = (zend_ast_list *) ast;
- list->kind = kind;
- list->attr = 0;
- list->children = 1;
- list->child[0] = child;
- if (child) {
- lineno = zend_ast_get_lineno(child);
- if (lineno > CG(zend_lineno)) {
- lineno = CG(zend_lineno);
- }
- } else {
- lineno = CG(zend_lineno);
- }
- list->lineno = lineno;
- return ast;
- }
- ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_list_2(zend_ast_kind kind, zend_ast *child1, zend_ast *child2) {
- zend_ast *ast;
- zend_ast_list *list;
- uint32_t lineno;
- ast = zend_ast_alloc(zend_ast_list_size(4));
- list = (zend_ast_list *) ast;
- list->kind = kind;
- list->attr = 0;
- list->children = 2;
- list->child[0] = child1;
- list->child[1] = child2;
- if (child1) {
- lineno = zend_ast_get_lineno(child1);
- if (lineno > CG(zend_lineno)) {
- lineno = CG(zend_lineno);
- }
- } else if (child2) {
- lineno = zend_ast_get_lineno(child2);
- if (lineno > CG(zend_lineno)) {
- lineno = CG(zend_lineno);
- }
- } else {
- list->children = 0;
- lineno = CG(zend_lineno);
- }
- list->lineno = lineno;
- return ast;
- }
- #else
- static zend_ast *zend_ast_create_from_va_list(zend_ast_kind kind, zend_ast_attr attr, va_list va) {
- uint32_t i, children = kind >> ZEND_AST_NUM_CHILDREN_SHIFT;
- zend_ast *ast;
- ast = zend_ast_alloc(zend_ast_size(children));
- ast->kind = kind;
- ast->attr = attr;
- ast->lineno = (uint32_t) -1;
- for (i = 0; i < children; ++i) {
- ast->child[i] = va_arg(va, zend_ast *);
- if (ast->child[i] != NULL) {
- uint32_t lineno = zend_ast_get_lineno(ast->child[i]);
- if (lineno < ast->lineno) {
- ast->lineno = lineno;
- }
- }
- }
- if (ast->lineno == UINT_MAX) {
- ast->lineno = CG(zend_lineno);
- }
- return ast;
- }
- ZEND_API zend_ast *zend_ast_create_ex(zend_ast_kind kind, zend_ast_attr attr, ...) {
- va_list va;
- zend_ast *ast;
- va_start(va, attr);
- ast = zend_ast_create_from_va_list(kind, attr, va);
- va_end(va);
- return ast;
- }
- ZEND_API zend_ast *zend_ast_create(zend_ast_kind kind, ...) {
- va_list va;
- zend_ast *ast;
- va_start(va, kind);
- ast = zend_ast_create_from_va_list(kind, 0, va);
- va_end(va);
- return ast;
- }
- ZEND_API zend_ast *zend_ast_create_list(uint32_t init_children, zend_ast_kind kind, ...) {
- zend_ast *ast;
- zend_ast_list *list;
- ast = zend_ast_alloc(zend_ast_list_size(4));
- list = (zend_ast_list *) ast;
- list->kind = kind;
- list->attr = 0;
- list->lineno = CG(zend_lineno);
- list->children = 0;
- {
- va_list va;
- uint32_t i;
- va_start(va, kind);
- for (i = 0; i < init_children; ++i) {
- zend_ast *child = va_arg(va, zend_ast *);
- ast = zend_ast_list_add(ast, child);
- if (child != NULL) {
- uint32_t lineno = zend_ast_get_lineno(child);
- if (lineno < ast->lineno) {
- ast->lineno = lineno;
- }
- }
- }
- va_end(va);
- }
- return ast;
- }
- #endif
- static inline bool is_power_of_two(uint32_t n) {
- return ((n != 0) && (n == (n & (~n + 1))));
- }
- ZEND_API zend_ast * ZEND_FASTCALL zend_ast_list_add(zend_ast *ast, zend_ast *op) {
- zend_ast_list *list = zend_ast_get_list(ast);
- if (list->children >= 4 && is_power_of_two(list->children)) {
- list = zend_ast_realloc(list,
- zend_ast_list_size(list->children), zend_ast_list_size(list->children * 2));
- }
- list->child[list->children++] = op;
- return (zend_ast *) list;
- }
- static zend_result zend_ast_add_array_element(zval *result, zval *offset, zval *expr)
- {
- if (Z_TYPE_P(offset) == IS_UNDEF) {
- if (!zend_hash_next_index_insert(Z_ARRVAL_P(result), expr)) {
- zend_throw_error(NULL,
- "Cannot add element to the array as the next element is already occupied");
- return FAILURE;
- }
- return SUCCESS;
- }
- if (array_set_zval_key(Z_ARRVAL_P(result), offset, expr) == FAILURE) {
- return FAILURE;
- }
- zval_ptr_dtor_nogc(offset);
- zval_ptr_dtor_nogc(expr);
- return SUCCESS;
- }
- static zend_result zend_ast_add_unpacked_element(zval *result, zval *expr) {
- if (EXPECTED(Z_TYPE_P(expr) == IS_ARRAY)) {
- HashTable *ht = Z_ARRVAL_P(expr);
- zval *val;
- zend_string *key;
- ZEND_HASH_FOREACH_STR_KEY_VAL(ht, key, val) {
- if (key) {
- zend_hash_update(Z_ARRVAL_P(result), key, val);
- } else {
- if (!zend_hash_next_index_insert(Z_ARRVAL_P(result), val)) {
- zend_throw_error(NULL,
- "Cannot add element to the array as the next element is already occupied");
- return FAILURE;
- }
- }
- Z_TRY_ADDREF_P(val);
- } ZEND_HASH_FOREACH_END();
- return SUCCESS;
- }
- /* Objects or references cannot occur in a constant expression. */
- zend_throw_error(NULL, "Only arrays and Traversables can be unpacked");
- return FAILURE;
- }
- zend_class_entry *zend_ast_fetch_class(zend_ast *ast, zend_class_entry *scope)
- {
- return zend_fetch_class_with_scope(zend_ast_get_str(ast), (ast->attr >> ZEND_CONST_EXPR_NEW_FETCH_TYPE_SHIFT) | ZEND_FETCH_CLASS_EXCEPTION, scope);
- }
- ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate(zval *result, zend_ast *ast, zend_class_entry *scope)
- {
- zval op1, op2;
- zend_result ret = SUCCESS;
- switch (ast->kind) {
- case ZEND_AST_BINARY_OP:
- if (UNEXPECTED(zend_ast_evaluate(&op1, ast->child[0], scope) != SUCCESS)) {
- ret = FAILURE;
- } else if (UNEXPECTED(zend_ast_evaluate(&op2, ast->child[1], scope) != SUCCESS)) {
- zval_ptr_dtor_nogc(&op1);
- ret = FAILURE;
- } else {
- binary_op_type op = get_binary_op(ast->attr);
- ret = op(result, &op1, &op2);
- zval_ptr_dtor_nogc(&op1);
- zval_ptr_dtor_nogc(&op2);
- }
- break;
- case ZEND_AST_GREATER:
- case ZEND_AST_GREATER_EQUAL:
- if (UNEXPECTED(zend_ast_evaluate(&op1, ast->child[0], scope) != SUCCESS)) {
- ret = FAILURE;
- } else if (UNEXPECTED(zend_ast_evaluate(&op2, ast->child[1], scope) != SUCCESS)) {
- zval_ptr_dtor_nogc(&op1);
- ret = FAILURE;
- } else {
- /* op1 > op2 is the same as op2 < op1 */
- binary_op_type op = ast->kind == ZEND_AST_GREATER
- ? is_smaller_function : is_smaller_or_equal_function;
- ret = op(result, &op2, &op1);
- zval_ptr_dtor_nogc(&op1);
- zval_ptr_dtor_nogc(&op2);
- }
- break;
- case ZEND_AST_UNARY_OP:
- if (UNEXPECTED(zend_ast_evaluate(&op1, ast->child[0], scope) != SUCCESS)) {
- ret = FAILURE;
- } else {
- unary_op_type op = get_unary_op(ast->attr);
- ret = op(result, &op1);
- zval_ptr_dtor_nogc(&op1);
- }
- break;
- case ZEND_AST_ZVAL:
- {
- zval *zv = zend_ast_get_zval(ast);
- ZVAL_COPY(result, zv);
- break;
- }
- case ZEND_AST_CONSTANT:
- {
- zend_string *name = zend_ast_get_constant_name(ast);
- zval *zv = zend_get_constant_ex(name, scope, ast->attr);
- if (UNEXPECTED(zv == NULL)) {
- ZVAL_UNDEF(result);
- return FAILURE;
- }
- ZVAL_COPY_OR_DUP(result, zv);
- break;
- }
- case ZEND_AST_CONSTANT_CLASS:
- if (scope) {
- ZVAL_STR_COPY(result, scope->name);
- } else {
- ZVAL_EMPTY_STRING(result);
- }
- break;
- case ZEND_AST_CLASS_NAME:
- if (!scope) {
- zend_throw_error(NULL, "Cannot use \"self\" when no class scope is active");
- return FAILURE;
- }
- if (ast->attr == ZEND_FETCH_CLASS_SELF) {
- ZVAL_STR_COPY(result, scope->name);
- } else if (ast->attr == ZEND_FETCH_CLASS_PARENT) {
- if (!scope->parent) {
- zend_throw_error(NULL,
- "Cannot use \"parent\" when current class scope has no parent");
- return FAILURE;
- }
- ZVAL_STR_COPY(result, scope->parent->name);
- } else {
- ZEND_ASSERT(0 && "Should have errored during compilation");
- }
- break;
- case ZEND_AST_AND:
- if (UNEXPECTED(zend_ast_evaluate(&op1, ast->child[0], scope) != SUCCESS)) {
- ret = FAILURE;
- break;
- }
- if (zend_is_true(&op1)) {
- if (UNEXPECTED(zend_ast_evaluate(&op2, ast->child[1], scope) != SUCCESS)) {
- zval_ptr_dtor_nogc(&op1);
- ret = FAILURE;
- break;
- }
- ZVAL_BOOL(result, zend_is_true(&op2));
- zval_ptr_dtor_nogc(&op2);
- } else {
- ZVAL_FALSE(result);
- }
- zval_ptr_dtor_nogc(&op1);
- break;
- case ZEND_AST_OR:
- if (UNEXPECTED(zend_ast_evaluate(&op1, ast->child[0], scope) != SUCCESS)) {
- ret = FAILURE;
- break;
- }
- if (zend_is_true(&op1)) {
- ZVAL_TRUE(result);
- } else {
- if (UNEXPECTED(zend_ast_evaluate(&op2, ast->child[1], scope) != SUCCESS)) {
- zval_ptr_dtor_nogc(&op1);
- ret = FAILURE;
- break;
- }
- ZVAL_BOOL(result, zend_is_true(&op2));
- zval_ptr_dtor_nogc(&op2);
- }
- zval_ptr_dtor_nogc(&op1);
- break;
- case ZEND_AST_CONDITIONAL:
- if (UNEXPECTED(zend_ast_evaluate(&op1, ast->child[0], scope) != SUCCESS)) {
- ret = FAILURE;
- break;
- }
- if (zend_is_true(&op1)) {
- if (!ast->child[1]) {
- *result = op1;
- } else {
- if (UNEXPECTED(zend_ast_evaluate(result, ast->child[1], scope) != SUCCESS)) {
- zval_ptr_dtor_nogc(&op1);
- ret = FAILURE;
- break;
- }
- zval_ptr_dtor_nogc(&op1);
- }
- } else {
- if (UNEXPECTED(zend_ast_evaluate(result, ast->child[2], scope) != SUCCESS)) {
- zval_ptr_dtor_nogc(&op1);
- ret = FAILURE;
- break;
- }
- zval_ptr_dtor_nogc(&op1);
- }
- break;
- case ZEND_AST_COALESCE:
- if (UNEXPECTED(zend_ast_evaluate(&op1, ast->child[0], scope) != SUCCESS)) {
- ret = FAILURE;
- break;
- }
- if (Z_TYPE(op1) > IS_NULL) {
- *result = op1;
- } else {
- if (UNEXPECTED(zend_ast_evaluate(result, ast->child[1], scope) != SUCCESS)) {
- zval_ptr_dtor_nogc(&op1);
- ret = FAILURE;
- break;
- }
- zval_ptr_dtor_nogc(&op1);
- }
- break;
- case ZEND_AST_UNARY_PLUS:
- if (UNEXPECTED(zend_ast_evaluate(&op2, ast->child[0], scope) != SUCCESS)) {
- ret = FAILURE;
- } else {
- ZVAL_LONG(&op1, 0);
- ret = add_function(result, &op1, &op2);
- zval_ptr_dtor_nogc(&op2);
- }
- break;
- case ZEND_AST_UNARY_MINUS:
- if (UNEXPECTED(zend_ast_evaluate(&op2, ast->child[0], scope) != SUCCESS)) {
- ret = FAILURE;
- } else {
- ZVAL_LONG(&op1, 0);
- ret = sub_function(result, &op1, &op2);
- zval_ptr_dtor_nogc(&op2);
- }
- break;
- case ZEND_AST_ARRAY:
- {
- uint32_t i;
- zend_ast_list *list = zend_ast_get_list(ast);
- if (!list->children) {
- ZVAL_EMPTY_ARRAY(result);
- break;
- }
- array_init(result);
- for (i = 0; i < list->children; i++) {
- zend_ast *elem = list->child[i];
- if (elem->kind == ZEND_AST_UNPACK) {
- if (UNEXPECTED(zend_ast_evaluate(&op1, elem->child[0], scope) != SUCCESS)) {
- zval_ptr_dtor_nogc(result);
- return FAILURE;
- }
- if (UNEXPECTED(zend_ast_add_unpacked_element(result, &op1) != SUCCESS)) {
- zval_ptr_dtor_nogc(&op1);
- zval_ptr_dtor_nogc(result);
- return FAILURE;
- }
- zval_ptr_dtor_nogc(&op1);
- continue;
- }
- if (elem->child[1]) {
- if (UNEXPECTED(zend_ast_evaluate(&op1, elem->child[1], scope) != SUCCESS)) {
- zval_ptr_dtor_nogc(result);
- return FAILURE;
- }
- } else {
- ZVAL_UNDEF(&op1);
- }
- if (UNEXPECTED(zend_ast_evaluate(&op2, elem->child[0], scope) != SUCCESS)) {
- zval_ptr_dtor_nogc(&op1);
- zval_ptr_dtor_nogc(result);
- return FAILURE;
- }
- if (UNEXPECTED(zend_ast_add_array_element(result, &op1, &op2) != SUCCESS)) {
- zval_ptr_dtor_nogc(&op1);
- zval_ptr_dtor_nogc(&op2);
- zval_ptr_dtor_nogc(result);
- return FAILURE;
- }
- }
- }
- break;
- case ZEND_AST_DIM:
- if (ast->child[1] == NULL) {
- zend_error_noreturn(E_COMPILE_ERROR, "Cannot use [] for reading");
- }
- if (UNEXPECTED(zend_ast_evaluate(&op1, ast->child[0], scope) != SUCCESS)) {
- ret = FAILURE;
- break;
- }
- // DIM on objects is disallowed because it allows executing arbitrary expressions
- if (Z_TYPE(op1) == IS_OBJECT) {
- zval_ptr_dtor_nogc(&op1);
- zend_throw_error(NULL, "Cannot use [] on objects in constant expression");
- ret = FAILURE;
- break;
- }
- if (UNEXPECTED(zend_ast_evaluate(&op2, ast->child[1], scope) != SUCCESS)) {
- zval_ptr_dtor_nogc(&op1);
- ret = FAILURE;
- break;
- }
- zend_fetch_dimension_const(result, &op1, &op2, (ast->attr & ZEND_DIM_IS) ? BP_VAR_IS : BP_VAR_R);
- zval_ptr_dtor_nogc(&op1);
- zval_ptr_dtor_nogc(&op2);
- if (UNEXPECTED(EG(exception))) {
- return FAILURE;
- }
- break;
- case ZEND_AST_CONST_ENUM_INIT:
- {
- // Preloading will attempt to resolve constants but objects can't be stored in shm
- // Aborting here to store the const AST instead
- if (CG(in_compilation)) {
- return FAILURE;
- }
- zend_ast *class_name_ast = ast->child[0];
- zend_string *class_name = zend_ast_get_str(class_name_ast);
- zend_ast *case_name_ast = ast->child[1];
- zend_string *case_name = zend_ast_get_str(case_name_ast);
- zend_ast *case_value_ast = ast->child[2];
- zval *case_value_zv = case_value_ast != NULL
- ? zend_ast_get_zval(case_value_ast)
- : NULL;
- zend_class_entry *ce = zend_lookup_class(class_name);
- zend_enum_new(result, ce, case_name, case_value_zv);
- break;
- }
- case ZEND_AST_CLASS_CONST:
- {
- zend_string *class_name = zend_ast_get_str(ast->child[0]);
- zend_string *const_name = zend_ast_get_str(ast->child[1]);
- zval *zv = zend_get_class_constant_ex(class_name, const_name, scope, ast->attr);
- if (UNEXPECTED(zv == NULL)) {
- ZVAL_UNDEF(result);
- return FAILURE;
- }
- ZVAL_COPY_OR_DUP(result, zv);
- break;
- }
- case ZEND_AST_NEW:
- {
- zend_class_entry *ce = zend_ast_fetch_class(ast->child[0], scope);
- if (!ce) {
- return FAILURE;
- }
- if (object_init_ex(result, ce) != SUCCESS) {
- return FAILURE;
- }
- zend_ast_list *args_ast = zend_ast_get_list(ast->child[1]);
- if (args_ast->attr) {
- /* Has named arguments. */
- HashTable *args = zend_new_array(args_ast->children);
- for (uint32_t i = 0; i < args_ast->children; i++) {
- zend_ast *arg_ast = args_ast->child[i];
- zend_string *name = NULL;
- zval arg;
- if (arg_ast->kind == ZEND_AST_NAMED_ARG) {
- name = zend_ast_get_str(arg_ast->child[0]);
- arg_ast = arg_ast->child[1];
- }
- if (zend_ast_evaluate(&arg, arg_ast, scope) == FAILURE) {
- zend_array_destroy(args);
- zval_ptr_dtor(result);
- return FAILURE;
- }
- if (name) {
- if (!zend_hash_add(args, name, &arg)) {
- zend_throw_error(NULL,
- "Named parameter $%s overwrites previous argument",
- ZSTR_VAL(name));
- zend_array_destroy(args);
- zval_ptr_dtor(result);
- return FAILURE;
- }
- } else {
- zend_hash_next_index_insert(args, &arg);
- }
- }
- zend_function *ctor = Z_OBJ_HT_P(result)->get_constructor(Z_OBJ_P(result));
- if (ctor) {
- zend_call_known_function(
- ctor, Z_OBJ_P(result), Z_OBJCE_P(result), NULL, 0, NULL, args);
- }
- zend_array_destroy(args);
- } else {
- ALLOCA_FLAG(use_heap)
- zval *args = do_alloca(sizeof(zval) * args_ast->children, use_heap);
- for (uint32_t i = 0; i < args_ast->children; i++) {
- if (zend_ast_evaluate(&args[i], args_ast->child[i], scope) == FAILURE) {
- for (uint32_t j = 0; j < i; j++) {
- zval_ptr_dtor(&args[j]);
- }
- free_alloca(args, use_heap);
- zval_ptr_dtor(result);
- return FAILURE;
- }
- }
- zend_function *ctor = Z_OBJ_HT_P(result)->get_constructor(Z_OBJ_P(result));
- if (ctor) {
- zend_call_known_instance_method(
- ctor, Z_OBJ_P(result), NULL, args_ast->children, args);
- }
- for (uint32_t i = 0; i < args_ast->children; i++) {
- zval_ptr_dtor(&args[i]);
- }
- free_alloca(args, use_heap);
- }
- if (EG(exception)) {
- zend_object_store_ctor_failed(Z_OBJ_P(result));
- zval_ptr_dtor(result);
- return FAILURE;
- }
- return SUCCESS;
- }
- default:
- zend_throw_error(NULL, "Unsupported constant expression");
- ret = FAILURE;
- }
- return ret;
- }
- static size_t ZEND_FASTCALL zend_ast_tree_size(zend_ast *ast)
- {
- size_t size;
- if (ast->kind == ZEND_AST_ZVAL || ast->kind == ZEND_AST_CONSTANT) {
- size = sizeof(zend_ast_zval);
- } else if (zend_ast_is_list(ast)) {
- uint32_t i;
- zend_ast_list *list = zend_ast_get_list(ast);
- size = zend_ast_list_size(list->children);
- for (i = 0; i < list->children; i++) {
- if (list->child[i]) {
- size += zend_ast_tree_size(list->child[i]);
- }
- }
- } else {
- uint32_t i, children = zend_ast_get_num_children(ast);
- size = zend_ast_size(children);
- for (i = 0; i < children; i++) {
- if (ast->child[i]) {
- size += zend_ast_tree_size(ast->child[i]);
- }
- }
- }
- return size;
- }
- static void* ZEND_FASTCALL zend_ast_tree_copy(zend_ast *ast, void *buf)
- {
- if (ast->kind == ZEND_AST_ZVAL) {
- zend_ast_zval *new = (zend_ast_zval*)buf;
- new->kind = ZEND_AST_ZVAL;
- new->attr = ast->attr;
- ZVAL_COPY(&new->val, zend_ast_get_zval(ast));
- buf = (void*)((char*)buf + sizeof(zend_ast_zval));
- } else if (ast->kind == ZEND_AST_CONSTANT) {
- zend_ast_zval *new = (zend_ast_zval*)buf;
- new->kind = ZEND_AST_CONSTANT;
- new->attr = ast->attr;
- ZVAL_STR_COPY(&new->val, zend_ast_get_constant_name(ast));
- buf = (void*)((char*)buf + sizeof(zend_ast_zval));
- } else if (zend_ast_is_list(ast)) {
- zend_ast_list *list = zend_ast_get_list(ast);
- zend_ast_list *new = (zend_ast_list*)buf;
- uint32_t i;
- new->kind = list->kind;
- new->attr = list->attr;
- new->children = list->children;
- buf = (void*)((char*)buf + zend_ast_list_size(list->children));
- for (i = 0; i < list->children; i++) {
- if (list->child[i]) {
- new->child[i] = (zend_ast*)buf;
- buf = zend_ast_tree_copy(list->child[i], buf);
- } else {
- new->child[i] = NULL;
- }
- }
- } else {
- uint32_t i, children = zend_ast_get_num_children(ast);
- zend_ast *new = (zend_ast*)buf;
- new->kind = ast->kind;
- new->attr = ast->attr;
- buf = (void*)((char*)buf + zend_ast_size(children));
- for (i = 0; i < children; i++) {
- if (ast->child[i]) {
- new->child[i] = (zend_ast*)buf;
- buf = zend_ast_tree_copy(ast->child[i], buf);
- } else {
- new->child[i] = NULL;
- }
- }
- }
- return buf;
- }
- ZEND_API zend_ast_ref * ZEND_FASTCALL zend_ast_copy(zend_ast *ast)
- {
- size_t tree_size;
- zend_ast_ref *ref;
- ZEND_ASSERT(ast != NULL);
- tree_size = zend_ast_tree_size(ast) + sizeof(zend_ast_ref);
- ref = emalloc(tree_size);
- zend_ast_tree_copy(ast, GC_AST(ref));
- GC_SET_REFCOUNT(ref, 1);
- GC_TYPE_INFO(ref) = GC_CONSTANT_AST;
- return ref;
- }
- ZEND_API void ZEND_FASTCALL zend_ast_destroy(zend_ast *ast)
- {
- tail_call:
- if (!ast) {
- return;
- }
- if (EXPECTED(ast->kind >= ZEND_AST_VAR)) {
- uint32_t i, children = zend_ast_get_num_children(ast);
- for (i = 1; i < children; i++) {
- zend_ast_destroy(ast->child[i]);
- }
- ast = ast->child[0];
- goto tail_call;
- } else if (EXPECTED(ast->kind == ZEND_AST_ZVAL)) {
- zval_ptr_dtor_nogc(zend_ast_get_zval(ast));
- } else if (EXPECTED(zend_ast_is_list(ast))) {
- zend_ast_list *list = zend_ast_get_list(ast);
- if (list->children) {
- uint32_t i;
- for (i = 1; i < list->children; i++) {
- zend_ast_destroy(list->child[i]);
- }
- ast = list->child[0];
- goto tail_call;
- }
- } else if (EXPECTED(ast->kind == ZEND_AST_CONSTANT)) {
- zend_string_release_ex(zend_ast_get_constant_name(ast), 0);
- } else if (EXPECTED(ast->kind >= ZEND_AST_FUNC_DECL)) {
- zend_ast_decl *decl = (zend_ast_decl *) ast;
- if (decl->name) {
- zend_string_release_ex(decl->name, 0);
- }
- if (decl->doc_comment) {
- zend_string_release_ex(decl->doc_comment, 0);
- }
- zend_ast_destroy(decl->child[0]);
- zend_ast_destroy(decl->child[1]);
- zend_ast_destroy(decl->child[2]);
- zend_ast_destroy(decl->child[3]);
- ast = decl->child[4];
- goto tail_call;
- }
- }
- ZEND_API void ZEND_FASTCALL zend_ast_ref_destroy(zend_ast_ref *ast)
- {
- zend_ast_destroy(GC_AST(ast));
- efree(ast);
- }
- ZEND_API void zend_ast_apply(zend_ast *ast, zend_ast_apply_func fn, void *context) {
- if (zend_ast_is_list(ast)) {
- zend_ast_list *list = zend_ast_get_list(ast);
- uint32_t i;
- for (i = 0; i < list->children; ++i) {
- fn(&list->child[i], context);
- }
- } else {
- uint32_t i, children = zend_ast_get_num_children(ast);
- for (i = 0; i < children; ++i) {
- fn(&ast->child[i], context);
- }
- }
- }
- /*
- * Operator Precedence
- * ====================
- * priority associativity operators
- * ----------------------------------
- * 10 left include, include_once, eval, require, require_once
- * 20 left ,
- * 30 left or
- * 40 left xor
- * 50 left and
- * 60 right print
- * 70 right yield
- * 80 right =>
- * 85 right yield from
- * 90 right = += -= *= /= .= %= &= |= ^= <<= >>= **=
- * 100 left ? :
- * 110 right ??
- * 120 left ||
- * 130 left &&
- * 140 left |
- * 150 left ^
- * 160 left &
- * 170 non-associative == != === !==
- * 180 non-associative < <= > >= <=>
- * 185 left .
- * 190 left << >>
- * 200 left + -
- * 210 left * / %
- * 220 right !
- * 230 non-associative instanceof
- * 240 right + - ++ -- ~ (type) @
- * 250 right **
- * 260 left [
- * 270 non-associative clone new
- */
- static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int priority, int indent);
- static ZEND_COLD void zend_ast_export_str(smart_str *str, zend_string *s)
- {
- size_t i;
- for (i = 0; i < ZSTR_LEN(s); i++) {
- unsigned char c = ZSTR_VAL(s)[i];
- if (c == '\'' || c == '\\') {
- smart_str_appendc(str, '\\');
- smart_str_appendc(str, c);
- } else {
- smart_str_appendc(str, c);
- }
- }
- }
- static ZEND_COLD void zend_ast_export_qstr(smart_str *str, char quote, zend_string *s)
- {
- size_t i;
- for (i = 0; i < ZSTR_LEN(s); i++) {
- unsigned char c = ZSTR_VAL(s)[i];
- if (c < ' ') {
- switch (c) {
- case '\n':
- smart_str_appends(str, "\\n");
- break;
- case '\r':
- smart_str_appends(str, "\\r");
- break;
- case '\t':
- smart_str_appends(str, "\\t");
- break;
- case '\f':
- smart_str_appends(str, "\\f");
- break;
- case '\v':
- smart_str_appends(str, "\\v");
- break;
- #ifdef ZEND_WIN32
- case VK_ESCAPE:
- #else
- case '\e':
- #endif
- smart_str_appends(str, "\\e");
- break;
- default:
- smart_str_appends(str, "\\0");
- smart_str_appendc(str, '0' + (c / 8));
- smart_str_appendc(str, '0' + (c % 8));
- break;
- }
- } else {
- if (c == quote || c == '$' || c == '\\') {
- smart_str_appendc(str, '\\');
- }
- smart_str_appendc(str, c);
- }
- }
- }
- static ZEND_COLD void zend_ast_export_indent(smart_str *str, int indent)
- {
- while (indent > 0) {
- smart_str_appends(str, " ");
- indent--;
- }
- }
- static ZEND_COLD void zend_ast_export_name(smart_str *str, zend_ast *ast, int priority, int indent)
- {
- if (ast->kind == ZEND_AST_ZVAL) {
- zval *zv = zend_ast_get_zval(ast);
- if (Z_TYPE_P(zv) == IS_STRING) {
- smart_str_append(str, Z_STR_P(zv));
- return;
- }
- }
- zend_ast_export_ex(str, ast, priority, indent);
- }
- static ZEND_COLD void zend_ast_export_ns_name(smart_str *str, zend_ast *ast, int priority, int indent)
- {
- if (ast->kind == ZEND_AST_ZVAL) {
- zval *zv = zend_ast_get_zval(ast);
- if (Z_TYPE_P(zv) == IS_STRING) {
- if (ast->attr == ZEND_NAME_FQ) {
- smart_str_appendc(str, '\\');
- } else if (ast->attr == ZEND_NAME_RELATIVE) {
- smart_str_appends(str, "namespace\\");
- }
- smart_str_append(str, Z_STR_P(zv));
- return;
- }
- }
- zend_ast_export_ex(str, ast, priority, indent);
- }
- static ZEND_COLD bool zend_ast_valid_var_char(char ch)
- {
- unsigned char c = (unsigned char)ch;
- if (c != '_' && c < 127 &&
- (c < '0' || c > '9') &&
- (c < 'A' || c > 'Z') &&
- (c < 'a' || c > 'z')) {
- return 0;
- }
- return 1;
- }
- static ZEND_COLD bool zend_ast_valid_var_name(const char *s, size_t len)
- {
- unsigned char c;
- size_t i;
- if (len == 0) {
- return 0;
- }
- c = (unsigned char)s[0];
- if (c != '_' && c < 127 &&
- (c < 'A' || c > 'Z') &&
- (c < 'a' || c > 'z')) {
- return 0;
- }
- for (i = 1; i < len; i++) {
- c = (unsigned char)s[i];
- if (c != '_' && c < 127 &&
- (c < '0' || c > '9') &&
- (c < 'A' || c > 'Z') &&
- (c < 'a' || c > 'z')) {
- return 0;
- }
- }
- return 1;
- }
- static ZEND_COLD bool zend_ast_var_needs_braces(char ch)
- {
- return ch == '[' || zend_ast_valid_var_char(ch);
- }
- static ZEND_COLD void zend_ast_export_var(smart_str *str, zend_ast *ast, int priority, int indent)
- {
- if (ast->kind == ZEND_AST_ZVAL) {
- zval *zv = zend_ast_get_zval(ast);
- if (Z_TYPE_P(zv) == IS_STRING &&
- zend_ast_valid_var_name(Z_STRVAL_P(zv), Z_STRLEN_P(zv))) {
- smart_str_append(str, Z_STR_P(zv));
- return;
- }
- } else if (ast->kind == ZEND_AST_VAR) {
- zend_ast_export_ex(str, ast, 0, indent);
- return;
- }
- smart_str_appendc(str, '{');
- zend_ast_export_name(str, ast, 0, indent);
- smart_str_appendc(str, '}');
- }
- static ZEND_COLD void zend_ast_export_list(smart_str *str, zend_ast_list *list, bool separator, int priority, int indent)
- {
- uint32_t i = 0;
- while (i < list->children) {
- if (i != 0 && separator) {
- smart_str_appends(str, ", ");
- }
- zend_ast_export_ex(str, list->child[i], priority, indent);
- i++;
- }
- }
- static ZEND_COLD void zend_ast_export_encaps_list(smart_str *str, char quote, zend_ast_list *list, int indent)
- {
- uint32_t i = 0;
- zend_ast *ast;
- while (i < list->children) {
- ast = list->child[i];
- if (ast->kind == ZEND_AST_ZVAL) {
- zval *zv = zend_ast_get_zval(ast);
- ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
- zend_ast_export_qstr(str, quote, Z_STR_P(zv));
- } else if (ast->kind == ZEND_AST_VAR &&
- ast->child[0]->kind == ZEND_AST_ZVAL &&
- (i + 1 == list->children ||
- list->child[i + 1]->kind != ZEND_AST_ZVAL ||
- !zend_ast_var_needs_braces(
- *Z_STRVAL_P(
- zend_ast_get_zval(list->child[i + 1]))))) {
- zend_ast_export_ex(str, ast, 0, indent);
- } else {
- smart_str_appendc(str, '{');
- zend_ast_export_ex(str, ast, 0, indent);
- smart_str_appendc(str, '}');
- }
- i++;
- }
- }
- static ZEND_COLD void zend_ast_export_name_list_ex(smart_str *str, zend_ast_list *list, int indent, const char *separator)
- {
- uint32_t i = 0;
- while (i < list->children) {
- if (i != 0) {
- smart_str_appends(str, separator);
- }
- zend_ast_export_name(str, list->child[i], 0, indent);
- i++;
- }
- }
- #define zend_ast_export_name_list(s, l, i) zend_ast_export_name_list_ex(s, l, i, ", ")
- #define zend_ast_export_catch_name_list(s, l, i) zend_ast_export_name_list_ex(s, l, i, "|")
- static ZEND_COLD void zend_ast_export_var_list(smart_str *str, zend_ast_list *list, int indent)
- {
- uint32_t i = 0;
- while (i < list->children) {
- if (i != 0) {
- smart_str_appends(str, ", ");
- }
- if (list->child[i]->attr & ZEND_BIND_REF) {
- smart_str_appendc(str, '&');
- }
- smart_str_appendc(str, '$');
- zend_ast_export_name(str, list->child[i], 20, indent);
- i++;
- }
- }
- static ZEND_COLD void zend_ast_export_stmt(smart_str *str, zend_ast *ast, int indent)
- {
- if (!ast) {
- return;
- }
- if (ast->kind == ZEND_AST_STMT_LIST ||
- ast->kind == ZEND_AST_TRAIT_ADAPTATIONS) {
- zend_ast_list *list = (zend_ast_list*)ast;
- uint32_t i = 0;
- while (i < list->children) {
- ast = list->child[i];
- zend_ast_export_stmt(str, ast, indent);
- i++;
- }
- } else {
- zend_ast_export_indent(str, indent);
- zend_ast_export_ex(str, ast, 0, indent);
- switch (ast->kind) {
- case ZEND_AST_LABEL:
- case ZEND_AST_IF:
- case ZEND_AST_SWITCH:
- case ZEND_AST_WHILE:
- case ZEND_AST_TRY:
- case ZEND_AST_FOR:
- case ZEND_AST_FOREACH:
- case ZEND_AST_FUNC_DECL:
- case ZEND_AST_METHOD:
- case ZEND_AST_CLASS:
- case ZEND_AST_USE_TRAIT:
- case ZEND_AST_NAMESPACE:
- case ZEND_AST_DECLARE:
- break;
- default:
- smart_str_appendc(str, ';');
- break;
- }
- smart_str_appendc(str, '\n');
- }
- }
- static ZEND_COLD void zend_ast_export_if_stmt(smart_str *str, zend_ast_list *list, int indent)
- {
- uint32_t i;
- zend_ast *ast;
- tail_call:
- i = 0;
- while (i < list->children) {
- ast = list->child[i];
- ZEND_ASSERT(ast->kind == ZEND_AST_IF_ELEM);
- if (ast->child[0]) {
- if (i == 0) {
- smart_str_appends(str, "if (");
- } else {
- zend_ast_export_indent(str, indent);
- smart_str_appends(str, "} elseif (");
- }
- zend_ast_export_ex(str, ast->child[0], 0, indent);
- smart_str_appends(str, ") {\n");
- zend_ast_export_stmt(str, ast->child[1], indent + 1);
- } else {
- zend_ast_export_indent(str, indent);
- smart_str_appends(str, "} else ");
- if (ast->child[1] && ast->child[1]->kind == ZEND_AST_IF) {
- list = (zend_ast_list*)ast->child[1];
- goto tail_call;
- } else {
- smart_str_appends(str, "{\n");
- zend_ast_export_stmt(str, ast->child[1], indent + 1);
- }
- }
- i++;
- }
- zend_ast_export_indent(str, indent);
- smart_str_appendc(str, '}');
- }
- static ZEND_COLD void zend_ast_export_zval(smart_str *str, zval *zv, int priority, int indent)
- {
- ZVAL_DEREF(zv);
- switch (Z_TYPE_P(zv)) {
- case IS_NULL:
- smart_str_appends(str, "null");
- break;
- case IS_FALSE:
- smart_str_appends(str, "false");
- break;
- case IS_TRUE:
- smart_str_appends(str, "true");
- break;
- case IS_LONG:
- smart_str_append_long(str, Z_LVAL_P(zv));
- break;
- case IS_DOUBLE:
- smart_str_append_double(
- str, Z_DVAL_P(zv), (int) EG(precision), /* zero_fraction */ false);
- break;
- case IS_STRING:
- smart_str_appendc(str, '\'');
- zend_ast_export_str(str, Z_STR_P(zv));
- smart_str_appendc(str, '\'');
- break;
- case IS_ARRAY: {
- zend_long idx;
- zend_string *key;
- zval *val;
- bool first = true;
- smart_str_appendc(str, '[');
- ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(zv), idx, key, val) {
- if (first) {
- first = false;
- } else {
- smart_str_appends(str, ", ");
- }
- if (key) {
- smart_str_appendc(str, '\'');
- zend_ast_export_str(str, key);
- smart_str_appends(str, "' => ");
- } else {
- smart_str_append_long(str, idx);
- smart_str_appends(str, " => ");
- }
- zend_ast_export_zval(str, val, 0, indent);
- } ZEND_HASH_FOREACH_END();
- smart_str_appendc(str, ']');
- break;
- }
- case IS_CONSTANT_AST:
- zend_ast_export_ex(str, Z_ASTVAL_P(zv), priority, indent);
- break;
- EMPTY_SWITCH_DEFAULT_CASE();
- }
- }
- static ZEND_COLD void zend_ast_export_class_no_header(smart_str *str, zend_ast_decl *decl, int indent) {
- if (decl->child[0]) {
- smart_str_appends(str, " extends ");
- zend_ast_export_ns_name(str, decl->child[0], 0, indent);
- }
- if (decl->child[1]) {
- smart_str_appends(str, " implements ");
- zend_ast_export_ex(str, decl->child[1], 0, indent);
- }
- smart_str_appends(str, " {\n");
- zend_ast_export_stmt(str, decl->child[2], indent + 1);
- zend_ast_export_indent(str, indent);
- smart_str_appends(str, "}");
- }
- static ZEND_COLD void zend_ast_export_attribute_group(smart_str *str, zend_ast *ast, int indent) {
- zend_ast_list *list = zend_ast_get_list(ast);
- for (uint32_t i = 0; i < list->children; i++) {
- zend_ast *attr = list->child[i];
- if (i) {
- smart_str_appends(str, ", ");
- }
- zend_ast_export_ns_name(str, attr->child[0], 0, indent);
- if (attr->child[1]) {
- smart_str_appendc(str, '(');
- zend_ast_export_ex(str, attr->child[1], 0, indent);
- smart_str_appendc(str, ')');
- }
- }
- }
- static ZEND_COLD void zend_ast_export_attributes(smart_str *str, zend_ast *ast, int indent, bool newlines) {
- zend_ast_list *list = zend_ast_get_list(ast);
- uint32_t i;
- for (i = 0; i < list->children; i++) {
- smart_str_appends(str, "#[");
- zend_ast_export_attribute_group(str, list->child[i], indent);
- smart_str_appends(str, "]");
- if (newlines) {
- smart_str_appendc(str, '\n');
- zend_ast_export_indent(str, indent);
- } else {
- smart_str_appendc(str, ' ');
- }
- }
- }
- static ZEND_COLD void zend_ast_export_visibility(smart_str *str, uint32_t flags) {
- if (flags & ZEND_ACC_PUBLIC) {
- smart_str_appends(str, "public ");
- } else if (flags & ZEND_ACC_PROTECTED) {
- smart_str_appends(str, "protected ");
- } else if (flags & ZEND_ACC_PRIVATE) {
- smart_str_appends(str, "private ");
- }
- }
- static ZEND_COLD void zend_ast_export_type(smart_str *str, zend_ast *ast, int indent) {
- if (ast->kind == ZEND_AST_TYPE_UNION) {
- zend_ast_list *list = zend_ast_get_list(ast);
- for (uint32_t i = 0; i < list->children; i++) {
- if (i != 0) {
- smart_str_appendc(str, '|');
- }
- zend_ast_export_type(str, list->child[i], indent);
- }
- return;
- }
- if (ast->kind == ZEND_AST_TYPE_INTERSECTION) {
- zend_ast_list *list = zend_ast_get_list(ast);
- for (uint32_t i = 0; i < list->children; i++) {
- if (i != 0) {
- smart_str_appendc(str, '&');
- }
- zend_ast_export_type(str, list->child[i], indent);
- }
- return;
- }
- if (ast->attr & ZEND_TYPE_NULLABLE) {
- smart_str_appendc(str, '?');
- }
- zend_ast_export_ns_name(str, ast, 0, indent);
- }
- #define BINARY_OP(_op, _p, _pl, _pr) do { \
- op = _op; \
- p = _p; \
- pl = _pl; \
- pr = _pr; \
- goto binary_op; \
- } while (0)
- #define PREFIX_OP(_op, _p, _pl) do { \
- op = _op; \
- p = _p; \
- pl = _pl; \
- goto prefix_op; \
- } while (0)
- #define FUNC_OP(_op) do { \
- op = _op; \
- goto func_op; \
- } while (0)
- #define POSTFIX_OP(_op, _p, _pl) do { \
- op = _op; \
- p = _p; \
- pl = _pl; \
- goto postfix_op; \
- } while (0)
- #define APPEND_NODE_1(_op) do { \
- op = _op; \
- goto append_node_1; \
- } while (0)
- #define APPEND_STR(_op) do { \
- op = _op; \
- goto append_str; \
- } while (0)
- #define APPEND_DEFAULT_VALUE(n) do { \
- p = n; \
- goto append_default_value; \
- } while (0)
- static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int priority, int indent)
- {
- zend_ast_decl *decl;
- int p, pl, pr;
- const char *op;
- tail_call:
- if (!ast) {
- return;
- }
- switch (ast->kind) {
- /* special nodes */
- case ZEND_AST_ZVAL:
- zend_ast_export_zval(str, zend_ast_get_zval(ast), priority, indent);
- break;
- case ZEND_AST_CONSTANT: {
- zend_string *name = zend_ast_get_constant_name(ast);
- smart_str_appendl(str, ZSTR_VAL(name), ZSTR_LEN(name));
- break;
- }
- case ZEND_AST_CONSTANT_CLASS:
- smart_str_appendl(str, "__CLASS__", sizeof("__CLASS__")-1);
- break;
- case ZEND_AST_ZNODE:
- /* This AST kind is only used for temporary nodes during compilation */
- ZEND_UNREACHABLE();
- break;
- /* declaration nodes */
- case ZEND_AST_FUNC_DECL:
- case ZEND_AST_CLOSURE:
- case ZEND_AST_ARROW_FUNC:
- case ZEND_AST_METHOD:
- decl = (zend_ast_decl *) ast;
- if (decl->child[4]) {
- bool newlines = !(ast->kind == ZEND_AST_CLOSURE || ast->kind == ZEND_AST_ARROW_FUNC);
- zend_ast_export_attributes(str, decl->child[4], indent, newlines);
- }
- zend_ast_export_visibility(str, decl->flags);
- if (decl->flags & ZEND_ACC_STATIC) {
- smart_str_appends(str, "static ");
- }
- if (decl->flags & ZEND_ACC_ABSTRACT) {
- smart_str_appends(str, "abstract ");
- }
- if (decl->flags & ZEND_ACC_FINAL) {
- smart_str_appends(str, "final ");
- }
- if (decl->kind == ZEND_AST_ARROW_FUNC) {
- smart_str_appends(str, "fn");
- } else {
- smart_str_appends(str, "function ");
- }
- if (decl->flags & ZEND_ACC_RETURN_REFERENCE) {
- smart_str_appendc(str, '&');
- }
- if (ast->kind != ZEND_AST_CLOSURE && ast->kind != ZEND_AST_ARROW_FUNC) {
- smart_str_appendl(str, ZSTR_VAL(decl->name), ZSTR_LEN(decl->name));
- }
- smart_str_appendc(str, '(');
- zend_ast_export_ex(str, decl->child[0], 0, indent);
- smart_str_appendc(str, ')');
- zend_ast_export_ex(str, decl->child[1], 0, indent);
- if (decl->child[3]) {
- smart_str_appends(str, ": ");
- zend_ast_export_type(str, decl->child[3], indent);
- }
- if (decl->child[2]) {
- if (decl->kind == ZEND_AST_ARROW_FUNC) {
- ZEND_ASSERT(decl->child[2]->kind == ZEND_AST_RETURN);
- smart_str_appends(str, " => ");
- zend_ast_export_ex(str, decl->child[2]->child[0], 0, indent);
- break;
- }
- smart_str_appends(str, " {\n");
- zend_ast_export_stmt(str, decl->child[2], indent + 1);
- zend_ast_export_indent(str, indent);
- smart_str_appendc(str, '}');
- if (ast->kind != ZEND_AST_CLOSURE) {
- smart_str_appendc(str, '\n');
- }
- } else {
- smart_str_appends(str, ";\n");
- }
- break;
- case ZEND_AST_CLASS:
- decl = (zend_ast_decl *) ast;
- if (decl->child[3]) {
- zend_ast_export_attributes(str, decl->child[3], indent, 1);
- }
- if (decl->flags & ZEND_ACC_INTERFACE) {
- smart_str_appends(str, "interface ");
- } else if (decl->flags & ZEND_ACC_TRAIT) {
- smart_str_appends(str, "trait ");
- } else if (decl->flags & ZEND_ACC_ENUM) {
- smart_str_appends(str, "enum ");
- } else {
- if (decl->flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS) {
- smart_str_appends(str, "abstract ");
- }
- if (decl->flags & ZEND_ACC_FINAL) {
- smart_str_appends(str, "final ");
- }
- smart_str_appends(str, "class ");
- }
- smart_str_appendl(str, ZSTR_VAL(decl->name), ZSTR_LEN(decl->name));
- if (decl->flags & ZEND_ACC_ENUM && decl->child[4]) {
- smart_str_appends(str, ": ");
- zend_ast_export_type(str, decl->child[4], indent);
- }
- zend_ast_export_class_no_header(str, decl, indent);
- smart_str_appendc(str, '\n');
- break;
- /* list nodes */
- case ZEND_AST_ARG_LIST:
- case ZEND_AST_EXPR_LIST:
- case ZEND_AST_PARAM_LIST:
- simple_list:
- zend_ast_export_list(str, (zend_ast_list*)ast, 1, 20, indent);
- break;
- case ZEND_AST_ARRAY:
- smart_str_appendc(str, '[');
- zend_ast_export_list(str, (zend_ast_list*)ast, 1, 20, indent);
- smart_str_appendc(str, ']');
- break;
- case ZEND_AST_ENCAPS_LIST:
- smart_str_appendc(str, '"');
- zend_ast_export_encaps_list(str, '"', (zend_ast_list*)ast, indent);
- smart_str_appendc(str, '"');
- break;
- case ZEND_AST_STMT_LIST:
- case ZEND_AST_TRAIT_ADAPTATIONS:
- zend_ast_export_stmt(str, ast, indent);
- break;
- case ZEND_AST_IF:
- zend_ast_export_if_stmt(str, (zend_ast_list*)ast, indent);
- break;
- case ZEND_AST_SWITCH_LIST:
- case ZEND_AST_CATCH_LIST:
- case ZEND_AST_MATCH_ARM_LIST:
- zend_ast_export_list(str, (zend_ast_list*)ast, 0, 0, indent);
- break;
- case ZEND_AST_CLOSURE_USES:
- smart_str_appends(str, " use(");
- zend_ast_export_var_list(str, (zend_ast_list*)ast, indent);
- smart_str_appendc(str, ')');
- break;
- case ZEND_AST_PROP_GROUP: {
- zend_ast *type_ast = ast->child[0];
- zend_ast *prop_ast = ast->child[1];
- if (ast->child[2]) {
- zend_ast_export_attributes(str, ast->child[2], indent, 1);
- }
- zend_ast_export_visibility(str, ast->attr);
- if (ast->attr & ZEND_ACC_STATIC) {
- smart_str_appends(str, "static ");
- }
- if (ast->attr & ZEND_ACC_READONLY) {
- smart_str_appends(str, "readonly ");
- }
- if (type_ast) {
- zend_ast_export_type(str, type_ast, indent);
- smart_str_appendc(str, ' ');
- }
- ast = prop_ast;
- goto simple_list;
- }
- case ZEND_AST_CONST_DECL:
- smart_str_appends(str, "const ");
- goto simple_list;
- case ZEND_AST_CLASS_CONST_GROUP:
- if (ast->child[1]) {
- zend_ast_export_attributes(str, ast->child[1], indent, 1);
- }
- zend_ast_export_visibility(str, ast->attr);
- smart_str_appends(str, "const ");
- ast = ast->child[0];
- goto simple_list;
- case ZEND_AST_NAME_LIST:
- zend_ast_export_name_list(str, (zend_ast_list*)ast, indent);
- break;
- case ZEND_AST_USE:
- smart_str_appends(str, "use ");
- if (ast->attr == T_FUNCTION) {
- smart_str_appends(str, "function ");
- } else if (ast->attr == T_CONST) {
- smart_str_appends(str, "const ");
- }
- goto simple_list;
- /* 0 child nodes */
- case ZEND_AST_MAGIC_CONST:
- switch (ast->attr) {
- case T_LINE: APPEND_STR("__LINE__");
- case T_FILE: APPEND_STR("__FILE__");
- case T_DIR: APPEND_STR("__DIR__");
- case T_TRAIT_C: APPEND_STR("__TRAIT__");
- case T_METHOD_C: APPEND_STR("__METHOD__");
- case T_FUNC_C: APPEND_STR("__FUNCTION__");
- case T_NS_C: APPEND_STR("__NAMESPACE__");
- case T_CLASS_C: APPEND_STR("__CLASS__");
- EMPTY_SWITCH_DEFAULT_CASE();
- }
- break;
- case ZEND_AST_TYPE:
- switch (ast->attr & ~ZEND_TYPE_NULLABLE) {
- case IS_ARRAY: APPEND_STR("array");
- case IS_CALLABLE: APPEND_STR("callable");
- case IS_STATIC: APPEND_STR("static");
- case IS_MIXED: APPEND_STR("mixed");
- EMPTY_SWITCH_DEFAULT_CASE();
- }
- break;
- /* 1 child node */
- case ZEND_AST_VAR:
- smart_str_appendc(str, '$');
- zend_ast_export_var(str, ast->child[0], 0, indent);
- break;
- case ZEND_AST_CONST:
- zend_ast_export_ns_name(str, ast->child[0], 0, indent);
- break;
- case ZEND_AST_UNPACK:
- smart_str_appends(str, "...");
- ast = ast->child[0];
- goto tail_call;
- case ZEND_AST_UNARY_PLUS: PREFIX_OP("+", 240, 241);
- case ZEND_AST_UNARY_MINUS: PREFIX_OP("-", 240, 241);
- case ZEND_AST_CAST:
- switch (ast->attr) {
- case IS_NULL: PREFIX_OP("(unset)", 240, 241);
- case _IS_BOOL: PREFIX_OP("(bool)", 240, 241);
- case IS_LONG: PREFIX_OP("(int)", 240, 241);
- case IS_DOUBLE: PREFIX_OP("(double)", 240, 241);
- case IS_STRING: PREFIX_OP("(string)", 240, 241);
- case IS_ARRAY: PREFIX_OP("(array)", 240, 241);
- case IS_OBJECT: PREFIX_OP("(object)", 240, 241);
- EMPTY_SWITCH_DEFAULT_CASE();
- }
- break;
- case ZEND_AST_EMPTY:
- FUNC_OP("empty");
- case ZEND_AST_ISSET:
- FUNC_OP("isset");
- case ZEND_AST_SILENCE:
- PREFIX_OP("@", 240, 241);
- case ZEND_AST_SHELL_EXEC:
- smart_str_appendc(str, '`');
- if (ast->child[0]->kind == ZEND_AST_ENCAPS_LIST) {
- zend_ast_export_encaps_list(str, '`', (zend_ast_list*)ast->child[0], indent);
- } else {
- zval *zv;
- ZEND_ASSERT(ast->child[0]->kind == ZEND_AST_ZVAL);
- zv = zend_ast_get_zval(ast->child[0]);
- ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
- zend_ast_export_qstr(str, '`', Z_STR_P(zv));
- }
- smart_str_appendc(str, '`');
- break;
- case ZEND_AST_CLONE:
- PREFIX_OP("clone ", 270, 271);
- case ZEND_AST_EXIT:
- if (ast->child[0]) {
- FUNC_OP("exit");
- } else {
- APPEND_STR("exit");
- }
- break;
- case ZEND_AST_PRINT:
- PREFIX_OP("print ", 60, 61);
- case ZEND_AST_INCLUDE_OR_EVAL:
- switch (ast->attr) {
- case ZEND_INCLUDE_ONCE: FUNC_OP("include_once");
- case ZEND_INCLUDE: FUNC_OP("include");
- case ZEND_REQUIRE_ONCE: FUNC_OP("require_once");
- case ZEND_REQUIRE: FUNC_OP("require");
- case ZEND_EVAL: FUNC_OP("eval");
- EMPTY_SWITCH_DEFAULT_CASE();
- }
- break;
- case ZEND_AST_UNARY_OP:
- switch (ast->attr) {
- case ZEND_BW_NOT: PREFIX_OP("~", 240, 241);
- case ZEND_BOOL_NOT: PREFIX_OP("!", 240, 241);
- EMPTY_SWITCH_DEFAULT_CASE();
- }
- break;
- case ZEND_AST_PRE_INC:
- PREFIX_OP("++", 240, 241);
- case ZEND_AST_PRE_DEC:
- PREFIX_OP("--", 240, 241);
- case ZEND_AST_POST_INC:
- POSTFIX_OP("++", 240, 241);
- case ZEND_AST_POST_DEC:
- POSTFIX_OP("--", 240, 241);
- case ZEND_AST_GLOBAL:
- APPEND_NODE_1("global");
- case ZEND_AST_UNSET:
- FUNC_OP("unset");
- case ZEND_AST_RETURN:
- APPEND_NODE_1("return");
- case ZEND_AST_LABEL:
- zend_ast_export_name(str, ast->child[0], 0, indent);
- smart_str_appendc(str, ':');
- break;
- case ZEND_AST_REF:
- smart_str_appendc(str, '&');
- ast = ast->child[0];
- goto tail_call;
- case ZEND_AST_HALT_COMPILER:
- APPEND_STR("__HALT_COMPILER()");
- case ZEND_AST_ECHO:
- APPEND_NODE_1("echo");
- case ZEND_AST_THROW:
- APPEND_NODE_1("throw");
- case ZEND_AST_GOTO:
- smart_str_appends(str, "goto ");
- zend_ast_export_name(str, ast->child[0], 0, indent);
- break;
- case ZEND_AST_BREAK:
- APPEND_NODE_1("break");
- case ZEND_AST_CONTINUE:
- APPEND_NODE_1("continue");
- /* 2 child nodes */
- case ZEND_AST_DIM:
- zend_ast_export_ex(str, ast->child[0], 260, indent);
- smart_str_appendc(str, '[');
- if (ast->child[1]) {
- zend_ast_export_ex(str, ast->child[1], 0, indent);
- }
- smart_str_appendc(str, ']');
- break;
- case ZEND_AST_PROP:
- case ZEND_AST_NULLSAFE_PROP:
- zend_ast_export_ex(str, ast->child[0], 0, indent);
- smart_str_appends(str, ast->kind == ZEND_AST_NULLSAFE_PROP ? "?->" : "->");
- zend_ast_export_var(str, ast->child[1], 0, indent);
- break;
- case ZEND_AST_STATIC_PROP:
- zend_ast_export_ns_name(str, ast->child[0], 0, indent);
- smart_str_appends(str, "::$");
- zend_ast_export_var(str, ast->child[1], 0, indent);
- break;
- case ZEND_AST_CALL:
- zend_ast_export_ns_name(str, ast->child[0], 0, indent);
- smart_str_appendc(str, '(');
- zend_ast_export_ex(str, ast->child[1], 0, indent);
- smart_str_appendc(str, ')');
- break;
- case ZEND_AST_CALLABLE_CONVERT:
- smart_str_appends(str, "...");
- break;
- case ZEND_AST_CLASS_CONST:
- zend_ast_export_ns_name(str, ast->child[0], 0, indent);
- smart_str_appends(str, "::");
- zend_ast_export_name(str, ast->child[1], 0, indent);
- break;
- case ZEND_AST_CLASS_NAME:
- if (ast->child[0] == NULL) {
- /* The const expr representation stores the fetch type instead. */
- switch (ast->attr) {
- case ZEND_FETCH_CLASS_SELF:
- smart_str_appends(str, "self");
- break;
- case ZEND_FETCH_CLASS_PARENT:
- smart_str_appends(str, "parent");
- break;
- EMPTY_SWITCH_DEFAULT_CASE()
- }
- } else {
- zend_ast_export_ns_name(str, ast->child[0], 0, indent);
- }
- smart_str_appends(str, "::class");
- break;
- case ZEND_AST_ASSIGN: BINARY_OP(" = ", 90, 91, 90);
- case ZEND_AST_ASSIGN_REF: BINARY_OP(" =& ", 90, 91, 90);
- case ZEND_AST_ASSIGN_OP:
- switch (ast->attr) {
- case ZEND_ADD: BINARY_OP(" += ", 90, 91, 90);
- case ZEND_SUB: BINARY_OP(" -= ", 90, 91, 90);
- case ZEND_MUL: BINARY_OP(" *= ", 90, 91, 90);
- case ZEND_DIV: BINARY_OP(" /= ", 90, 91, 90);
- case ZEND_MOD: BINARY_OP(" %= ", 90, 91, 90);
- case ZEND_SL: BINARY_OP(" <<= ", 90, 91, 90);
- case ZEND_SR: BINARY_OP(" >>= ", 90, 91, 90);
- case ZEND_CONCAT: BINARY_OP(" .= ", 90, 91, 90);
- case ZEND_BW_OR: BINARY_OP(" |= ", 90, 91, 90);
- case ZEND_BW_AND: BINARY_OP(" &= ", 90, 91, 90);
- case ZEND_BW_XOR: BINARY_OP(" ^= ", 90, 91, 90);
- case ZEND_POW: BINARY_OP(" **= ", 90, 91, 90);
- EMPTY_SWITCH_DEFAULT_CASE();
- }
- break;
- case ZEND_AST_ASSIGN_COALESCE: BINARY_OP(" \?\?= ", 90, 91, 90);
- case ZEND_AST_BINARY_OP:
- switch (ast->attr) {
- case ZEND_ADD: BINARY_OP(" + ", 200, 200, 201);
- case ZEND_SUB: BINARY_OP(" - ", 200, 200, 201);
- case ZEND_MUL: BINARY_OP(" * ", 210, 210, 211);
- case ZEND_DIV: BINARY_OP(" / ", 210, 210, 211);
- case ZEND_MOD: BINARY_OP(" % ", 210, 210, 211);
- case ZEND_SL: BINARY_OP(" << ", 190, 190, 191);
- case ZEND_SR: BINARY_OP(" >> ", 190, 190, 191);
- case ZEND_CONCAT: BINARY_OP(" . ", 185, 185, 186);
- case ZEND_BW_OR: BINARY_OP(" | ", 140, 140, 141);
- case ZEND_BW_AND: BINARY_OP(" & ", 160, 160, 161);
- case ZEND_BW_XOR: BINARY_OP(" ^ ", 150, 150, 151);
- case ZEND_IS_IDENTICAL: BINARY_OP(" === ", 170, 171, 171);
- case ZEND_IS_NOT_IDENTICAL: BINARY_OP(" !== ", 170, 171, 171);
- case ZEND_IS_EQUAL: BINARY_OP(" == ", 170, 171, 171);
- case ZEND_IS_NOT_EQUAL: BINARY_OP(" != ", 170, 171, 171);
- case ZEND_IS_SMALLER: BINARY_OP(" < ", 180, 181, 181);
- case ZEND_IS_SMALLER_OR_EQUAL: BINARY_OP(" <= ", 180, 181, 181);
- case ZEND_POW: BINARY_OP(" ** ", 250, 251, 250);
- case ZEND_BOOL_XOR: BINARY_OP(" xor ", 40, 40, 41);
- case ZEND_SPACESHIP: BINARY_OP(" <=> ", 180, 181, 181);
- EMPTY_SWITCH_DEFAULT_CASE();
- }
- break;
- case ZEND_AST_GREATER: BINARY_OP(" > ", 180, 181, 181);
- case ZEND_AST_GREATER_EQUAL: BINARY_OP(" >= ", 180, 181, 181);
- case ZEND_AST_AND: BINARY_OP(" && ", 130, 130, 131);
- case ZEND_AST_OR: BINARY_OP(" || ", 120, 120, 121);
- case ZEND_AST_ARRAY_ELEM:
- if (ast->child[1]) {
- zend_ast_export_ex(str, ast->child[1], 80, indent);
- smart_str_appends(str, " => ");
- }
- if (ast->attr)
- smart_str_appendc(str, '&');
- zend_ast_export_ex(str, ast->child[0], 80, indent);
- break;
- case ZEND_AST_NEW:
- smart_str_appends(str, "new ");
- if (ast->child[0]->kind == ZEND_AST_CLASS) {
- zend_ast_decl *decl = (zend_ast_decl *) ast->child[0];
- if (decl->child[3]) {
- zend_ast_export_attributes(str, decl->child[3], indent, 0);
- }
- smart_str_appends(str, "class");
- if (!zend_ast_is_list(ast->child[1])
- || zend_ast_get_list(ast->child[1])->children) {
- smart_str_appendc(str, '(');
- zend_ast_export_ex(str, ast->child[1], 0, indent);
- smart_str_appendc(str, ')');
- }
- zend_ast_export_class_no_header(str, decl, indent);
- } else {
- zend_ast_export_ns_name(str, ast->child[0], 0, indent);
- smart_str_appendc(str, '(');
- zend_ast_export_ex(str, ast->child[1], 0, indent);
- smart_str_appendc(str, ')');
- }
- break;
- case ZEND_AST_INSTANCEOF:
- zend_ast_export_ex(str, ast->child[0], 0, indent);
- smart_str_appends(str, " instanceof ");
- zend_ast_export_ns_name(str, ast->child[1], 0, indent);
- break;
- case ZEND_AST_YIELD:
- if (priority > 70) smart_str_appendc(str, '(');
- smart_str_appends(str, "yield ");
- if (ast->child[0]) {
- if (ast->child[1]) {
- zend_ast_export_ex(str, ast->child[1], 70, indent);
- smart_str_appends(str, " => ");
- }
- zend_ast_export_ex(str, ast->child[0], 70, indent);
- }
- if (priority > 70) smart_str_appendc(str, ')');
- break;
- case ZEND_AST_YIELD_FROM:
- PREFIX_OP("yield from ", 85, 86);
- case ZEND_AST_COALESCE: BINARY_OP(" ?? ", 110, 111, 110);
- case ZEND_AST_STATIC:
- smart_str_appends(str, "static $");
- zend_ast_export_name(str, ast->child[0], 0, indent);
- APPEND_DEFAULT_VALUE(1);
- case ZEND_AST_WHILE:
- smart_str_appends(str, "while (");
- zend_ast_export_ex(str, ast->child[0], 0, indent);
- smart_str_appends(str, ") {\n");
- zend_ast_export_stmt(str, ast->child[1], indent + 1);
- zend_ast_export_indent(str, indent);
- smart_str_appendc(str, '}');
- break;
- case ZEND_AST_DO_WHILE:
- smart_str_appends(str, "do {\n");
- zend_ast_export_stmt(str, ast->child[0], indent + 1);
- zend_ast_export_indent(str, indent);
- smart_str_appends(str, "} while (");
- zend_ast_export_ex(str, ast->child[1], 0, indent);
- smart_str_appendc(str, ')');
- break;
- case ZEND_AST_IF_ELEM:
- if (ast->child[0]) {
- smart_str_appends(str, "if (");
- zend_ast_export_ex(str, ast->child[0], 0, indent);
- smart_str_appends(str, ") {\n");
- zend_ast_export_stmt(str, ast->child[1], indent + 1);
- } else {
- smart_str_appends(str, "else {\n");
- zend_ast_export_stmt(str, ast->child[1], indent + 1);
- }
- zend_ast_export_indent(str, indent);
- smart_str_appendc(str, '}');
- break;
- case ZEND_AST_SWITCH:
- smart_str_appends(str, "switch (");
- zend_ast_export_ex(str, ast->child[0], 0, indent);
- smart_str_appends(str, ") {\n");
- zend_ast_export_ex(str, ast->child[1], 0, indent + 1);
- zend_ast_export_indent(str, indent);
- smart_str_appendc(str, '}');
- break;
- case ZEND_AST_SWITCH_CASE:
- zend_ast_export_indent(str, indent);
- if (ast->child[0]) {
- smart_str_appends(str, "case ");
- zend_ast_export_ex(str, ast->child[0], 0, indent);
- smart_str_appends(str, ":\n");
- } else {
- smart_str_appends(str, "default:\n");
- }
- zend_ast_export_stmt(str, ast->child[1], indent + 1);
- break;
- case ZEND_AST_MATCH:
- smart_str_appends(str, "match (");
- zend_ast_export_ex(str, ast->child[0], 0, indent);
- smart_str_appends(str, ") {\n");
- zend_ast_export_ex(str, ast->child[1], 0, indent + 1);
- zend_ast_export_indent(str, indent);
- smart_str_appendc(str, '}');
- break;
- case ZEND_AST_MATCH_ARM:
- zend_ast_export_indent(str, indent);
- if (ast->child[0]) {
- zend_ast_export_list(str, (zend_ast_list*)ast->child[0], 1, 0, indent);
- smart_str_appends(str, " => ");
- } else {
- smart_str_appends(str, "default => ");
- }
- zend_ast_export_ex(str, ast->child[1], 0, 0);
- smart_str_appends(str, ",\n");
- break;
- case ZEND_AST_DECLARE:
- smart_str_appends(str, "declare(");
- ZEND_ASSERT(ast->child[0]->kind == ZEND_AST_CONST_DECL);
- zend_ast_export_list(str, (zend_ast_list*)ast->child[0], 1, 0, indent);
- smart_str_appendc(str, ')');
- if (ast->child[1]) {
- smart_str_appends(str, " {\n");
- zend_ast_export_stmt(str, ast->child[1], indent + 1);
- zend_ast_export_indent(str, indent);
- smart_str_appendc(str, '}');
- } else {
- smart_str_appendc(str, ';');
- }
- break;
- case ZEND_AST_PROP_ELEM:
- smart_str_appendc(str, '$');
- ZEND_FALLTHROUGH;
- case ZEND_AST_CONST_ELEM:
- zend_ast_export_name(str, ast->child[0], 0, indent);
- APPEND_DEFAULT_VALUE(1);
- case ZEND_AST_USE_TRAIT:
- smart_str_appends(str, "use ");
- zend_ast_export_ex(str, ast->child[0], 0, indent);
- if (ast->child[1]) {
- smart_str_appends(str, " {\n");
- zend_ast_export_ex(str, ast->child[1], 0, indent + 1);
- zend_ast_export_indent(str, indent);
- smart_str_appends(str, "}");
- } else {
- smart_str_appends(str, ";");
- }
- break;
- case ZEND_AST_TRAIT_PRECEDENCE:
- zend_ast_export_ex(str, ast->child[0], 0, indent);
- smart_str_appends(str, " insteadof ");
- zend_ast_export_ex(str, ast->child[1], 0, indent);
- break;
- case ZEND_AST_METHOD_REFERENCE:
- if (ast->child[0]) {
- zend_ast_export_name(str, ast->child[0], 0, indent);
- smart_str_appends(str, "::");
- }
- zend_ast_export_name(str, ast->child[1], 0, indent);
- break;
- case ZEND_AST_NAMESPACE:
- smart_str_appends(str, "namespace");
- if (ast->child[0]) {
- smart_str_appendc(str, ' ');
- zend_ast_export_name(str, ast->child[0], 0, indent);
- }
- if (ast->child[1]) {
- smart_str_appends(str, " {\n");
- zend_ast_export_stmt(str, ast->child[1], indent + 1);
- zend_ast_export_indent(str, indent);
- smart_str_appends(str, "}\n");
- } else {
- smart_str_appendc(str, ';');
- }
- break;
- case ZEND_AST_USE_ELEM:
- case ZEND_AST_TRAIT_ALIAS:
- zend_ast_export_name(str, ast->child[0], 0, indent);
- if (ast->attr & ZEND_ACC_PUBLIC) {
- smart_str_appends(str, " as public");
- } else if (ast->attr & ZEND_ACC_PROTECTED) {
- smart_str_appends(str, " as protected");
- } else if (ast->attr & ZEND_ACC_PRIVATE) {
- smart_str_appends(str, " as private");
- } else if (ast->child[1]) {
- smart_str_appends(str, " as");
- }
- if (ast->child[1]) {
- smart_str_appendc(str, ' ');
- zend_ast_export_name(str, ast->child[1], 0, indent);
- }
- break;
- case ZEND_AST_NAMED_ARG:
- smart_str_append(str, zend_ast_get_str(ast->child[0]));
- smart_str_appends(str, ": ");
- ast = ast->child[1];
- goto tail_call;
- /* 3 child nodes */
- case ZEND_AST_METHOD_CALL:
- case ZEND_AST_NULLSAFE_METHOD_CALL:
- zend_ast_export_ex(str, ast->child[0], 0, indent);
- smart_str_appends(str, ast->kind == ZEND_AST_NULLSAFE_METHOD_CALL ? "?->" : "->");
- zend_ast_export_var(str, ast->child[1], 0, indent);
- smart_str_appendc(str, '(');
- zend_ast_export_ex(str, ast->child[2], 0, indent);
- smart_str_appendc(str, ')');
- break;
- case ZEND_AST_STATIC_CALL:
- zend_ast_export_ns_name(str, ast->child[0], 0, indent);
- smart_str_appends(str, "::");
- zend_ast_export_var(str, ast->child[1], 0, indent);
- smart_str_appendc(str, '(');
- zend_ast_export_ex(str, ast->child[2], 0, indent);
- smart_str_appendc(str, ')');
- break;
- case ZEND_AST_CONDITIONAL:
- if (priority > 100) smart_str_appendc(str, '(');
- zend_ast_export_ex(str, ast->child[0], 100, indent);
- if (ast->child[1]) {
- smart_str_appends(str, " ? ");
- zend_ast_export_ex(str, ast->child[1], 101, indent);
- smart_str_appends(str, " : ");
- } else {
- smart_str_appends(str, " ?: ");
- }
- zend_ast_export_ex(str, ast->child[2], 101, indent);
- if (priority > 100) smart_str_appendc(str, ')');
- break;
- case ZEND_AST_TRY:
- smart_str_appends(str, "try {\n");
- zend_ast_export_stmt(str, ast->child[0], indent + 1);
- zend_ast_export_indent(str, indent);
- zend_ast_export_ex(str, ast->child[1], 0, indent);
- if (ast->child[2]) {
- smart_str_appends(str, "} finally {\n");
- zend_ast_export_stmt(str, ast->child[2], indent + 1);
- zend_ast_export_indent(str, indent);
- }
- smart_str_appendc(str, '}');
- break;
- case ZEND_AST_CATCH:
- smart_str_appends(str, "} catch (");
- zend_ast_export_catch_name_list(str, zend_ast_get_list(ast->child[0]), indent);
- if (ast->child[1]) {
- smart_str_appends(str, " $");
- zend_ast_export_var(str, ast->child[1], 0, indent);
- }
- smart_str_appends(str, ") {\n");
- zend_ast_export_stmt(str, ast->child[2], indent + 1);
- zend_ast_export_indent(str, indent);
- break;
- case ZEND_AST_PARAM:
- if (ast->child[3]) {
- zend_ast_export_attributes(str, ast->child[3], indent, 0);
- }
- if (ast->child[0]) {
- zend_ast_export_type(str, ast->child[0], indent);
- smart_str_appendc(str, ' ');
- }
- if (ast->attr & ZEND_PARAM_REF) {
- smart_str_appendc(str, '&');
- }
- if (ast->attr & ZEND_PARAM_VARIADIC) {
- smart_str_appends(str, "...");
- }
- smart_str_appendc(str, '$');
- zend_ast_export_name(str, ast->child[1], 0, indent);
- APPEND_DEFAULT_VALUE(2);
- case ZEND_AST_ENUM_CASE:
- if (ast->child[3]) {
- zend_ast_export_attributes(str, ast->child[3], indent, 1);
- }
- smart_str_appends(str, "case ");
- zend_ast_export_name(str, ast->child[0], 0, indent);
- if (ast->child[1]) {
- smart_str_appends(str, " = ");
- zend_ast_export_ex(str, ast->child[1], 0, indent);
- }
- break;
- /* 4 child nodes */
- case ZEND_AST_FOR:
- smart_str_appends(str, "for (");
- zend_ast_export_ex(str, ast->child[0], 0, indent);
- smart_str_appendc(str, ';');
- if (ast->child[1]) {
- smart_str_appendc(str, ' ');
- zend_ast_export_ex(str, ast->child[1], 0, indent);
- }
- smart_str_appendc(str, ';');
- if (ast->child[2]) {
- smart_str_appendc(str, ' ');
- zend_ast_export_ex(str, ast->child[2], 0, indent);
- }
- smart_str_appends(str, ") {\n");
- zend_ast_export_stmt(str, ast->child[3], indent + 1);
- zend_ast_export_indent(str, indent);
- smart_str_appendc(str, '}');
- break;
- case ZEND_AST_FOREACH:
- smart_str_appends(str, "foreach (");
- zend_ast_export_ex(str, ast->child[0], 0, indent);
- smart_str_appends(str, " as ");
- if (ast->child[2]) {
- zend_ast_export_ex(str, ast->child[2], 0, indent);
- smart_str_appends(str, " => ");
- }
- zend_ast_export_ex(str, ast->child[1], 0, indent);
- smart_str_appends(str, ") {\n");
- zend_ast_export_stmt(str, ast->child[3], indent + 1);
- zend_ast_export_indent(str, indent);
- smart_str_appendc(str, '}');
- break;
- EMPTY_SWITCH_DEFAULT_CASE();
- }
- return;
- binary_op:
- if (priority > p) smart_str_appendc(str, '(');
- zend_ast_export_ex(str, ast->child[0], pl, indent);
- smart_str_appends(str, op);
- zend_ast_export_ex(str, ast->child[1], pr, indent);
- if (priority > p) smart_str_appendc(str, ')');
- return;
- prefix_op:
- if (priority > p) smart_str_appendc(str, '(');
- smart_str_appends(str, op);
- zend_ast_export_ex(str, ast->child[0], pl, indent);
- if (priority > p) smart_str_appendc(str, ')');
- return;
- postfix_op:
- if (priority > p) smart_str_appendc(str, '(');
- zend_ast_export_ex(str, ast->child[0], pl, indent);
- smart_str_appends(str, op);
- if (priority > p) smart_str_appendc(str, ')');
- return;
- func_op:
- smart_str_appends(str, op);
- smart_str_appendc(str, '(');
- zend_ast_export_ex(str, ast->child[0], 0, indent);
- smart_str_appendc(str, ')');
- return;
- append_node_1:
- smart_str_appends(str, op);
- if (ast->child[0]) {
- smart_str_appendc(str, ' ');
- ast = ast->child[0];
- goto tail_call;
- }
- return;
- append_str:
- smart_str_appends(str, op);
- return;
- append_default_value:
- if (ast->child[p]) {
- smart_str_appends(str, " = ");
- ast = ast->child[p];
- goto tail_call;
- }
- return;
- }
- ZEND_API ZEND_COLD zend_string *zend_ast_export(const char *prefix, zend_ast *ast, const char *suffix)
- {
- smart_str str = {0};
- smart_str_appends(&str, prefix);
- zend_ast_export_ex(&str, ast, 0, 0);
- smart_str_appends(&str, suffix);
- smart_str_0(&str);
- return str.s;
- }
- zend_ast * ZEND_FASTCALL zend_ast_with_attributes(zend_ast *ast, zend_ast *attr)
- {
- ZEND_ASSERT(attr->kind == ZEND_AST_ATTRIBUTE_LIST);
- switch (ast->kind) {
- case ZEND_AST_FUNC_DECL:
- case ZEND_AST_CLOSURE:
- case ZEND_AST_METHOD:
- case ZEND_AST_ARROW_FUNC:
- ((zend_ast_decl *) ast)->child[4] = attr;
- break;
- case ZEND_AST_CLASS:
- ((zend_ast_decl *) ast)->child[3] = attr;
- break;
- case ZEND_AST_PROP_GROUP:
- ast->child[2] = attr;
- break;
- case ZEND_AST_PARAM:
- case ZEND_AST_ENUM_CASE:
- ast->child[3] = attr;
- break;
- case ZEND_AST_CLASS_CONST_GROUP:
- ast->child[1] = attr;
- break;
- EMPTY_SWITCH_DEFAULT_CASE()
- }
- return ast;
- }
|