X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=ast.c;h=3cd92b80d452873d9c3fe90da2e73be595d3cfd8;hb=refs%2Fheads%2Fgraphitemaster%2Fast-driven-debug;hp=2f1566bfc5700a26f7fb51f923b46c0a7ecdc700;hpb=a7c1f6f021f3c924c11b338e289b8ed636b8f7f6;p=xonotic%2Fgmqcc.git diff --git a/ast.c b/ast.c index 2f1566b..3cd92b8 100644 --- a/ast.c +++ b/ast.c @@ -28,53 +28,74 @@ #include "ast.h" #include "parser.h" -#define ast_instantiate(T, ctx, destroyfn) \ +#define ast_instantiate(T, ctx, destroyfn, iterfn) \ T* self = (T*)mem_a(sizeof(T)); \ if (!self) { \ return NULL; \ } \ ast_node_init((ast_node*)self, ctx, TYPE_##T); \ - ( (ast_node*)self )->destroy = (ast_node_delete*)destroyfn + ( (ast_node*)self )->destroy = (ast_node_delete*)destroyfn; \ + ( (ast_node*)self )->next_child = (ast_node_next_child*)iterfn /* * forward declarations, these need not be in ast.h for obvious * static reasons. */ static bool ast_member_codegen(ast_member*, ast_function*, bool lvalue, ir_value**); +static ast_node** ast_member_next_child(ast_member*,ast_node**); static void ast_array_index_delete(ast_array_index*); static bool ast_array_index_codegen(ast_array_index*, ast_function*, bool lvalue, ir_value**); +static ast_node** ast_array_index_next_child(ast_array_index*,ast_node**); static void ast_argpipe_delete(ast_argpipe*); static bool ast_argpipe_codegen(ast_argpipe*, ast_function*, bool lvalue, ir_value**); +static ast_node** ast_argpipe_next_child(ast_argpipe*,ast_node**); static void ast_store_delete(ast_store*); static bool ast_store_codegen(ast_store*, ast_function*, bool lvalue, ir_value**); +static ast_node** ast_store_next_child(ast_store*,ast_node**); static void ast_ifthen_delete(ast_ifthen*); static bool ast_ifthen_codegen(ast_ifthen*, ast_function*, bool lvalue, ir_value**); +static ast_node** ast_ifthen_next_child(ast_ifthen*,ast_node**); static void ast_ternary_delete(ast_ternary*); static bool ast_ternary_codegen(ast_ternary*, ast_function*, bool lvalue, ir_value**); +static ast_node** ast_ternary_next_child(ast_ternary*,ast_node**); static void ast_loop_delete(ast_loop*); static bool ast_loop_codegen(ast_loop*, ast_function*, bool lvalue, ir_value**); +static ast_node** ast_loop_next_child(ast_loop*,ast_node**); static void ast_breakcont_delete(ast_breakcont*); static bool ast_breakcont_codegen(ast_breakcont*, ast_function*, bool lvalue, ir_value**); +static ast_node** ast_breakcont_next_child(ast_breakcont*,ast_node**); static void ast_switch_delete(ast_switch*); static bool ast_switch_codegen(ast_switch*, ast_function*, bool lvalue, ir_value**); +static ast_node** ast_switch_next_child(ast_switch*,ast_node**); static void ast_label_delete(ast_label*); static void ast_label_register_goto(ast_label*, ast_goto*); static bool ast_label_codegen(ast_label*, ast_function*, bool lvalue, ir_value**); +static ast_node** ast_label_next_child(ast_label*,ast_node**); static bool ast_goto_codegen(ast_goto*, ast_function*, bool lvalue, ir_value**); static void ast_goto_delete(ast_goto*); +static ast_node** ast_goto_next_child(ast_goto*,ast_node**); static void ast_call_delete(ast_call*); static bool ast_call_codegen(ast_call*, ast_function*, bool lvalue, ir_value**); +static ast_node** ast_call_next_child(ast_call*,ast_node**); static bool ast_block_codegen(ast_block*, ast_function*, bool lvalue, ir_value**); +static ast_node** ast_block_next_child(ast_block*,ast_node**); static void ast_unary_delete(ast_unary*); static bool ast_unary_codegen(ast_unary*, ast_function*, bool lvalue, ir_value**); +static ast_node** ast_unary_next_child(ast_unary*,ast_node**); static void ast_entfield_delete(ast_entfield*); static bool ast_entfield_codegen(ast_entfield*, ast_function*, bool lvalue, ir_value**); +static ast_node** ast_entfield_next_child(ast_entfield*,ast_node**); static void ast_return_delete(ast_return*); static bool ast_return_codegen(ast_return*, ast_function*, bool lvalue, ir_value**); +static ast_node** ast_return_next_child(ast_return*,ast_node**); static void ast_binstore_delete(ast_binstore*); static bool ast_binstore_codegen(ast_binstore*, ast_function*, bool lvalue, ir_value**); +static ast_node** ast_binstore_next_child(ast_binstore*,ast_node**); static void ast_binary_delete(ast_binary*); static bool ast_binary_codegen(ast_binary*, ast_function*, bool lvalue, ir_value**); +static ast_node** ast_binary_next_child(ast_binary*,ast_node**); +static ast_node** ast_value_next_child(ast_value*,ast_node**); +static ast_node** ast_function_next_child(ast_function*,ast_node**); /* It must not be possible to get here. */ static GMQCC_NORETURN void _ast_node_destroy(ast_node *self) @@ -84,11 +105,19 @@ static GMQCC_NORETURN void _ast_node_destroy(ast_node *self) exit(EXIT_FAILURE); } +static ast_node** _ast_node_next_child(ast_node *self, ast_node **prev) +{ + (void)self; + (void)prev; + return NULL; +} + /* Initialize main ast node aprts */ static void ast_node_init(ast_node *self, lex_ctx_t ctx, int nodetype) { self->context = ctx; self->destroy = &_ast_node_destroy; + self->next_child = &_ast_node_next_child; self->keep = false; self->nodetype = nodetype; self->side_effects = false; @@ -177,7 +206,7 @@ void ast_type_adopt_impl(ast_expression *self, const ast_expression *other) static ast_expression* ast_shallow_type(lex_ctx_t ctx, int vtype) { - ast_instantiate(ast_expression, ctx, ast_expression_delete_full); + ast_instantiate(ast_expression, ctx, ast_expression_delete_full, _ast_node_next_child); ast_expression_init(self, NULL); self->codegen = NULL; self->next = NULL; @@ -195,7 +224,7 @@ ast_expression* ast_type_copy(lex_ctx_t ctx, const ast_expression *ex) return NULL; else { - ast_instantiate(ast_expression, ctx, ast_expression_delete_full); + ast_instantiate(ast_expression, ctx, ast_expression_delete_full, _ast_node_next_child); ast_expression_init(self, NULL); fromex = ex; @@ -345,7 +374,7 @@ void ast_type_to_string(ast_expression *e, char *buf, size_t bufsize) static bool ast_value_codegen(ast_value *self, ast_function *func, bool lvalue, ir_value **out); ast_value* ast_value_new(lex_ctx_t ctx, const char *name, int t) { - ast_instantiate(ast_value, ctx, ast_value_delete); + ast_instantiate(ast_value, ctx, ast_value_delete, ast_value_next_child); ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_value_codegen); self->expression.node.keep = true; /* keep */ @@ -438,9 +467,24 @@ bool ast_value_set_name(ast_value *self, const char *name) ast_binary* ast_binary_new(lex_ctx_t ctx, int op, ast_expression* left, ast_expression* right) { - ast_instantiate(ast_binary, ctx, ast_binary_delete); + ast_instantiate(ast_binary, ctx, ast_binary_delete, ast_binary_next_child); ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_binary_codegen); + if (ast_istype(right, ast_unary) && OPTS_OPTIMIZATION(OPTIM_PEEPHOLE)) { + ast_expression *normal = ((ast_unary*)right)->operand; + + /* make a-(-b) => a + b */ + if (op == INSTR_SUB_F) { + op = INSTR_ADD_F; + right = normal; + ++opts_optimizationcount[OPTIM_PEEPHOLE]; + } else if (op == INSTR_SUB_V) { + op = INSTR_ADD_V; + right = normal; + ++opts_optimizationcount[OPTIM_PEEPHOLE]; + } + } + self->op = op; self->left = left; self->right = right; @@ -484,7 +528,7 @@ void ast_binary_delete(ast_binary *self) ast_binstore* ast_binstore_new(lex_ctx_t ctx, int storop, int op, ast_expression* left, ast_expression* right) { - ast_instantiate(ast_binstore, ctx, ast_binstore_delete); + ast_instantiate(ast_binstore, ctx, ast_binstore_delete, ast_binstore_next_child); ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_binstore_codegen); ast_side_effects(self) = true; @@ -512,18 +556,37 @@ void ast_binstore_delete(ast_binstore *self) ast_unary* ast_unary_new(lex_ctx_t ctx, int op, ast_expression *expr) { - ast_instantiate(ast_unary, ctx, ast_unary_delete); + ast_instantiate(ast_unary, ctx, ast_unary_delete, ast_unary_next_child); ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_unary_codegen); - self->op = op; + self->op = op; self->operand = expr; + + if (ast_istype(expr, ast_unary) && OPTS_OPTIMIZATION(OPTIM_PEEPHOLE)) { + ast_unary *prev = (ast_unary*)((ast_unary*)expr)->operand; + + /* Handle for double negation */ + if (((ast_unary*)expr)->op == op) + prev = (ast_unary*)((ast_unary*)expr)->operand; + + if (ast_istype(prev, ast_unary)) { + ast_expression_delete((ast_expression*)self); + mem_d(self); + ++opts_optimizationcount[OPTIM_PEEPHOLE]; + return prev; + } + } + ast_propagate_effects(self, expr); - if (op >= INSTR_NOT_F && op <= INSTR_NOT_FNC) { + if ((op >= INSTR_NOT_F && op <= INSTR_NOT_FNC) || op == VINSTR_NEG_F) { self->expression.vtype = TYPE_FLOAT; - } else + } else if (op == VINSTR_NEG_V) { + self->expression.vtype = TYPE_VECTOR; + } else { compile_error(ctx, "cannot determine type of unary operation %s", util_instr_str[op]); + } return self; } @@ -537,7 +600,7 @@ void ast_unary_delete(ast_unary *self) ast_return* ast_return_new(lex_ctx_t ctx, ast_expression *expr) { - ast_instantiate(ast_return, ctx, ast_return_delete); + ast_instantiate(ast_return, ctx, ast_return_delete, ast_return_next_child); ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_return_codegen); self->operand = expr; @@ -567,7 +630,7 @@ ast_entfield* ast_entfield_new(lex_ctx_t ctx, ast_expression *entity, ast_expres ast_entfield* ast_entfield_new_force(lex_ctx_t ctx, ast_expression *entity, ast_expression *field, const ast_expression *outtype) { - ast_instantiate(ast_entfield, ctx, ast_entfield_delete); + ast_instantiate(ast_entfield, ctx, ast_entfield_delete, ast_entfield_next_child); if (!outtype) { mem_d(self); @@ -596,7 +659,7 @@ void ast_entfield_delete(ast_entfield *self) ast_member* ast_member_new(lex_ctx_t ctx, ast_expression *owner, unsigned int field, const char *name) { - ast_instantiate(ast_member, ctx, ast_member_delete); + ast_instantiate(ast_member, ctx, ast_member_delete, ast_member_next_child); if (field >= 3) { mem_d(self); return NULL; @@ -659,7 +722,7 @@ bool ast_member_set_name(ast_member *self, const char *name) ast_array_index* ast_array_index_new(lex_ctx_t ctx, ast_expression *array, ast_expression *index) { ast_expression *outtype; - ast_instantiate(ast_array_index, ctx, ast_array_index_delete); + ast_instantiate(ast_array_index, ctx, ast_array_index_delete, ast_array_index_next_child); outtype = array->next; if (!outtype) { @@ -701,7 +764,7 @@ void ast_array_index_delete(ast_array_index *self) ast_argpipe* ast_argpipe_new(lex_ctx_t ctx, ast_expression *index) { - ast_instantiate(ast_argpipe, ctx, ast_argpipe_delete); + ast_instantiate(ast_argpipe, ctx, ast_argpipe_delete, ast_argpipe_next_child); ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_argpipe_codegen); self->index = index; self->expression.vtype = TYPE_NOEXPR; @@ -718,7 +781,7 @@ void ast_argpipe_delete(ast_argpipe *self) ast_ifthen* ast_ifthen_new(lex_ctx_t ctx, ast_expression *cond, ast_expression *ontrue, ast_expression *onfalse) { - ast_instantiate(ast_ifthen, ctx, ast_ifthen_delete); + ast_instantiate(ast_ifthen, ctx, ast_ifthen_delete, ast_ifthen_next_child); if (!ontrue && !onfalse) { /* because it is invalid */ mem_d(self); @@ -752,7 +815,7 @@ void ast_ifthen_delete(ast_ifthen *self) ast_ternary* ast_ternary_new(lex_ctx_t ctx, ast_expression *cond, ast_expression *ontrue, ast_expression *onfalse) { ast_expression *exprtype = ontrue; - ast_instantiate(ast_ternary, ctx, ast_ternary_delete); + ast_instantiate(ast_ternary, ctx, ast_ternary_delete, ast_ternary_next_child); /* This time NEITHER must be NULL */ if (!ontrue || !onfalse) { mem_d(self); @@ -793,7 +856,7 @@ ast_loop* ast_loop_new(lex_ctx_t ctx, ast_expression *increment, ast_expression *body) { - ast_instantiate(ast_loop, ctx, ast_loop_delete); + ast_instantiate(ast_loop, ctx, ast_loop_delete, ast_loop_next_child); ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_loop_codegen); self->initexpr = initexpr; @@ -837,7 +900,7 @@ void ast_loop_delete(ast_loop *self) ast_breakcont* ast_breakcont_new(lex_ctx_t ctx, bool iscont, unsigned int levels) { - ast_instantiate(ast_breakcont, ctx, ast_breakcont_delete); + ast_instantiate(ast_breakcont, ctx, ast_breakcont_delete, ast_breakcont_next_child); ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_breakcont_codegen); self->is_continue = iscont; @@ -854,7 +917,7 @@ void ast_breakcont_delete(ast_breakcont *self) ast_switch* ast_switch_new(lex_ctx_t ctx, ast_expression *op) { - ast_instantiate(ast_switch, ctx, ast_switch_delete); + ast_instantiate(ast_switch, ctx, ast_switch_delete, ast_switch_next_child); ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_switch_codegen); self->operand = op; @@ -883,7 +946,7 @@ void ast_switch_delete(ast_switch *self) ast_label* ast_label_new(lex_ctx_t ctx, const char *name, bool undefined) { - ast_instantiate(ast_label, ctx, ast_label_delete); + ast_instantiate(ast_label, ctx, ast_label_delete, ast_label_next_child); ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_label_codegen); self->expression.vtype = TYPE_NOEXPR; @@ -911,7 +974,7 @@ static void ast_label_register_goto(ast_label *self, ast_goto *g) ast_goto* ast_goto_new(lex_ctx_t ctx, const char *name) { - ast_instantiate(ast_goto, ctx, ast_goto_delete); + ast_instantiate(ast_goto, ctx, ast_goto_delete, ast_goto_next_child); ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_goto_codegen); self->name = util_strdup(name); @@ -936,7 +999,7 @@ void ast_goto_set_label(ast_goto *self, ast_label *label) ast_call* ast_call_new(lex_ctx_t ctx, ast_expression *funcexpr) { - ast_instantiate(ast_call, ctx, ast_call_delete); + ast_instantiate(ast_call, ctx, ast_call_delete, ast_call_next_child); if (!funcexpr->next) { compile_error(ctx, "not a function"); mem_d(self); @@ -1075,7 +1138,7 @@ bool ast_call_check_types(ast_call *self, ast_expression *va_type) ast_store* ast_store_new(lex_ctx_t ctx, int op, ast_expression *dest, ast_expression *source) { - ast_instantiate(ast_store, ctx, ast_store_delete); + ast_instantiate(ast_store, ctx, ast_store_delete, ast_store_next_child); ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_store_codegen); ast_side_effects(self) = true; @@ -1099,7 +1162,7 @@ void ast_store_delete(ast_store *self) ast_block* ast_block_new(lex_ctx_t ctx) { - ast_instantiate(ast_block, ctx, ast_block_delete); + ast_instantiate(ast_block, ctx, ast_block_delete, ast_block_next_child); ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_block_codegen); @@ -1153,7 +1216,7 @@ void ast_block_set_type(ast_block *self, ast_expression *from) ast_function* ast_function_new(lex_ctx_t ctx, const char *name, ast_value *vtype) { - ast_instantiate(ast_function, ctx, ast_function_delete); + ast_instantiate(ast_function, ctx, ast_function_delete, ast_function_next_child); if (!vtype) { compile_error(ast_ctx(self), "internal error: ast_function_new condition 0"); @@ -1187,6 +1250,9 @@ ast_function* ast_function_new(lex_ctx_t ctx, const char *name, ast_value *vtype self->fixedparams = NULL; self->return_value = NULL; + self->static_names = NULL; + self->static_count = 0; + return self; cleanup: @@ -1208,6 +1274,9 @@ void ast_function_delete(ast_function *self) */ ast_unref(self->vtype); } + for (i = 0; i < vec_size(self->static_names); ++i) + mem_d(self->static_names[i]); + vec_free(self->static_names); for (i = 0; i < vec_size(self->blocks); ++i) ast_delete(self->blocks[i]); vec_free(self->blocks); @@ -1767,6 +1836,7 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir) ir_value *dummy; ast_expression *ec; ast_expression_codegen *cgen; + size_t i; (void)ir; @@ -1877,6 +1947,17 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir) return true; } +static bool starts_a_label(ast_expression *ex) +{ + while (ex && ast_istype(ex, ast_block)) { + ast_block *b = (ast_block*)ex; + ex = b->exprs[0]; + } + if (!ex) + return false; + return ast_istype(ex, ast_label); +} + /* Note, you will not see ast_block_codegen generate ir_blocks. * To the AST and the IR, blocks are 2 different things. * In the AST it represents a block of code, usually enclosed in @@ -1922,7 +2003,7 @@ bool ast_block_codegen(ast_block *self, ast_function *func, bool lvalue, ir_valu for (i = 0; i < vec_size(self->exprs); ++i) { ast_expression_codegen *gen; - if (func->curblock->final && !ast_istype(self->exprs[i], ast_label)) { + if (func->curblock->final && !starts_a_label(self->exprs[i])) { if (compile_warning(ast_ctx(self->exprs[i]), WARN_UNREACHABLE_CODE, "unreachable statement")) return false; continue; @@ -2571,8 +2652,8 @@ bool ast_ifthen_codegen(ast_ifthen *self, ast_function *func, bool lvalue, ir_va /* update the block which will get the jump - because short-logic or ternaries may have changed this */ cond = func->curblock; - /* try constant folding away the if */ - if ((fold = fold_cond(condval, func, self)) != -1) + /* try constant folding away the condition */ + if ((fold = fold_cond_ifthen(condval, func, self)) != -1) return fold; if (self->on_true) { @@ -2655,6 +2736,7 @@ bool ast_ternary_codegen(ast_ternary *self, ast_function *func, bool lvalue, ir_ ir_block *ontrue, *ontrue_out = NULL; ir_block *onfalse, *onfalse_out = NULL; ir_block *merge; + int fold = 0; /* Ternary can never create an lvalue... */ if (lvalue) @@ -2679,6 +2761,10 @@ bool ast_ternary_codegen(ast_ternary *self, ast_function *func, bool lvalue, ir_ return false; cond_out = func->curblock; + /* try constant folding away the condition */ + if ((fold = fold_cond_ternary(condval, func, self)) != -1) + return fold; + /* create on-true block */ ontrue = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "tern_T")); if (!ontrue) @@ -3360,3 +3446,230 @@ error: vec_free(params); return false; } + +/* AST iterator + iterator functions */ +void ast_iterator_begin(ast_iterator *iter, ast_node *start) { + iter->head = start; + iter->at = &iter->head; + iter->path = NULL; + vec_push(iter->path, iter->at); +} + +void ast_iterator_delete(ast_iterator *iter) { + if (iter->path) + vec_free(iter->path); +} + +ast_node *ast_iterator_next(ast_iterator *iter) { + size_t depth = vec_size(iter->path); + while (depth) { + ast_node **last = vec_last(iter->path); + ast_node **next = ast_next_child(*last, iter->at); + if (next) { + vec_push(iter->path, next); + iter->at = next; + return *next; + } + iter->at = last; + vec_pop(iter->path); + --depth; + } + return NULL; +} + +static ast_node** ast_member_next_child(ast_member *self, ast_node **cur) { + (void)self; (void)cur; + return NULL; +} + +static ast_node** ast_value_next_child(ast_value *self, ast_node **cur) { + (void)self; (void)cur; + return NULL; +} + +static ast_node** ast_array_index_next_child(ast_array_index *self, ast_node **cur) { + if (*cur == (ast_node*)self) + return (ast_node**)&self->array; + if (cur == (ast_node**)&self->array) + return (ast_node**)&self->index; + return NULL; +} + +static ast_node** ast_argpipe_next_child(ast_argpipe *self, ast_node **cur) { + if (*cur == (ast_node*)self) + return (ast_node**)&self->index; + return NULL; +} + +static ast_node** ast_store_next_child(ast_store *self, ast_node **cur) { + if (*cur == (ast_node*)self) + return (ast_node**)&self->dest; + if (cur == (ast_node**)&self->dest) + return (ast_node**)&self->source; + return NULL; +} + +static ast_node** ast_ifthen_next_child(ast_ifthen *self, ast_node **cur) { + if (*cur == (ast_node*)self) { + if (self->cond) return (ast_node**)&self->cond; + if (self->on_true) return (ast_node**)&self->on_true; + return (ast_node**)&self->on_false; + } + if (self->cond && cur == (ast_node**)&self->cond) { + if (self->on_true) return (ast_node**)&self->on_true; + return (ast_node**)&self->on_false; + } + if (self->on_true && cur == (ast_node**)&self->on_true) + return (ast_node**)&self->on_false; + return NULL; +} + +static ast_node** ast_ternary_next_child(ast_ternary *self, ast_node **cur) { + if (*cur == (ast_node*)self) + return (ast_node**)&self->cond; + if (self->cond && cur == (ast_node**)&self->cond) + return (ast_node**)&self->on_true; + if (self->on_true && cur == (ast_node**)&self->on_true) + return (ast_node**)&self->on_false; + return NULL; +} + +static ast_node** ast_loop_next_child(ast_loop *self, ast_node **cur) { + if (*cur == (ast_node*)self) { + /* If only we'd use ?: then this would be: return a ?: b ?: c ?: d; */ + if (self->initexpr) return (ast_node**)&self->initexpr; + if (self->precond) return (ast_node**)&self->precond; + if (self->body) return (ast_node**)&self->body; + if (self->postcond) return (ast_node**)&self->postcond; + return (ast_node**)&self->increment; + } + if (self->initexpr && cur == (ast_node**)&self->initexpr) { + if (self->precond) return (ast_node**)&self->precond; + if (self->body) return (ast_node**)&self->body; + if (self->postcond) return (ast_node**)&self->postcond; + return (ast_node**)&self->increment; + } + if (self->precond && cur == (ast_node**)&self->precond) { + if (self->body) return (ast_node**)&self->body; + if (self->postcond) return (ast_node**)&self->postcond; + return (ast_node**)&self->increment; + } + if (self->body && cur == (ast_node**)&self->body) { + if (self->postcond) return (ast_node**)&self->postcond; + return (ast_node**)&self->increment; + } + return NULL; +} + +static ast_node** ast_breakcont_next_child(ast_breakcont *self, ast_node **cur) { + (void)self; (void)cur; + return NULL; +} + +static ast_node** ast_switch_next_child(ast_switch *self, ast_node **cur) { + size_t i, cases; + if (*cur == (ast_node*)self) + return (ast_node**)&self->operand; + cases = vec_size(self->cases); + if (!cases) + return NULL; + if (cur == (ast_node**)&self->operand) + return (ast_node**)&self->cases[0].value; + for (i = 0; i != cases; ++i) { + if (cur == (ast_node**)&self->cases[i].value) + return (ast_node**)&self->cases[i].code; + if (cur == (ast_node**)&self->cases[i].code) { + return (i+1 != cases) ? (ast_node**)&self->cases[i+1].value + : NULL; + } + } + return NULL; +} + +static ast_node** ast_label_next_child(ast_label *self, ast_node **cur) { + (void)self; (void)cur; + return NULL; +} + +static ast_node** ast_goto_next_child(ast_goto *self, ast_node **cur) { + (void)self; (void)cur; + return NULL; +} + +static ast_node** ast_call_next_child(ast_call *self, ast_node **cur) { + size_t i, params; + if (*cur == (ast_node*)self) + return (ast_node**)&self->func; + params = vec_size(self->params); + if (!params) + return NULL; + if (cur == (ast_node**)&self->func) + return (ast_node**)&self->params[0]; + for (i = 1; i != params; ++i) { + if (cur == (ast_node**)&self->params[i-1]) + return (ast_node**)&self->params[i]; + } + return NULL; +} + +static ast_node** ast_block_next_child(ast_block *self, ast_node **cur) { + size_t i, exprs = vec_size(self->exprs); + if (!exprs) + return NULL; + if (*cur == (ast_node*)self) + return (ast_node**)&self->exprs[0]; + for (i = 1; i != exprs; ++i) { + if (cur == (ast_node**)&self->exprs[i-1]) + return (ast_node**)&self->exprs[i]; + } + return NULL; +} + +static ast_node** ast_unary_next_child(ast_unary *self, ast_node **cur) { + if (*cur == (ast_node*)self) + return (ast_node**)&self->operand; + return NULL; +} + +static ast_node** ast_entfield_next_child(ast_entfield *self, ast_node **cur) { + if (*cur == (ast_node*)self) + return (ast_node**)&self->entity; + if (cur == (ast_node**)&self->entity) + return (ast_node**)&self->field; + return NULL; +} + +static ast_node** ast_return_next_child(ast_return *self, ast_node **cur) { + if (*cur == (ast_node*)self) + return (ast_node**)&self->operand; + return NULL; +} + +static ast_node** ast_binstore_next_child(ast_binstore *self, ast_node **cur) { + if (*cur == (ast_node*)self) + return (ast_node**)&self->dest; + if (cur == (ast_node**)&self->dest) + return (ast_node**)&self->source; + return NULL; +} + +static ast_node** ast_binary_next_child(ast_binary *self, ast_node **cur) { + if (*cur == (ast_node*)self) + return (ast_node**)&self->left; + if (cur == (ast_node**)&self->left) + return (ast_node**)&self->right; + return NULL; +} + +static ast_node** ast_function_next_child(ast_function *self, ast_node **cur) { + size_t i, blocks = vec_size(self->blocks); + if (!blocks) + return NULL; + if (*cur == (ast_node*)self) + return (ast_node**)&self->blocks[0]; + for (i = 1; i != blocks; ++i) { + if (cur == (ast_node**)&self->blocks[i-1]) + return (ast_node**)&self->blocks[i]; + } + return NULL; +}