]> git.rm.cloudns.org Git - xonotic/gmqcc.git/commitdiff
stashing sample ast iteration functionality in this branch
authorWolfgang Bumiller <wry.git@bumiller.com>
Sat, 23 Nov 2013 15:45:05 +0000 (16:45 +0100)
committerWolfgang Bumiller <wry.git@bumiller.com>
Sat, 23 Nov 2013 15:45:05 +0000 (16:45 +0100)
ast.c
ast.h
parser.c

diff --git a/ast.c b/ast.c
index 3c70a73721e49e726c1e010b3bbc0b77e94bc225..8bf43d60a916eda0286d2d1c960ee56f57b313af 100644 (file)
--- a/ast.c
+++ b/ast.c
 #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;     \
+    if (iterfn) {                                                   \
+        ( (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 +107,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 +208,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, NULL);
     ast_expression_init(self, NULL);
     self->codegen = NULL;
     self->next    = NULL;
@@ -195,7 +226,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, NULL);
         ast_expression_init(self, NULL);
 
         fromex = ex;
@@ -345,7 +376,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,7 +469,7 @@ 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);
 
     self->op = op;
@@ -484,7 +515,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,7 +543,7 @@ 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;
@@ -556,7 +587,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;
@@ -586,7 +617,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);
@@ -615,7 +646,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;
@@ -678,7 +709,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) {
@@ -720,7 +751,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;
@@ -737,7 +768,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);
@@ -771,7 +802,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);
@@ -812,7 +843,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;
@@ -856,7 +887,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;
@@ -873,7 +904,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;
@@ -902,7 +933,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;
@@ -930,7 +961,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);
@@ -955,7 +986,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);
@@ -1094,7 +1125,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;
@@ -1118,7 +1149,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);
 
@@ -1172,7 +1203,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");
@@ -3397,3 +3428,201 @@ error:
     vec_free(params);
     return false;
 }
+
+/* iterator functions */
+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;
+}
diff --git a/ast.h b/ast.h
index 52858ac7f132ce14372fe7e92570593e11d2071f..fabb9eddee26404f02ab7c698659a65a2b02a43f 100644 (file)
--- a/ast.h
+++ b/ast.h
@@ -102,6 +102,31 @@ enum {
     TYPE_ast_argpipe      /* 21 */
 };
 
+static const char *ast_node_type_name[] = {
+    "node",
+    "expression",
+    "value",
+    "function",
+    "block",
+    "binary",
+    "store",
+    "binstore",
+    "entfield",
+    "ifthen",
+    "ternary",
+    "loop",
+    "call",
+    "unary",
+    "return",
+    "member",
+    "array_index",
+    "breakcont",
+    "switch",
+    "label",
+    "goto",
+    "argpipe"
+};
+
 #define ast_istype(x, t) ( ((ast_node*)x)->nodetype == (TYPE_##t) )
 #define ast_ctx(node) (((ast_node*)(node))->context)
 #define ast_side_effects(node) (((ast_node*)(node))->side_effects)
@@ -109,12 +134,14 @@ enum {
 /* Node interface with common components
  */
 typedef void ast_node_delete(ast_node*);
+typedef ast_node* ast_node_next_child(ast_node*,ast_node*);
 struct ast_node_common
 {
-    lex_ctx_t          context;
+    lex_ctx_t            context;
     /* I don't feel comfortable using keywords like 'delete' as names... */
-    ast_node_delete *destroy;
-    int              nodetype;
+    ast_node_delete     *destroy;
+    ast_node_next_child *next_child;
+    int                  nodetype;
     /* keep: if a node contains this node, 'keep'
      * prevents its dtor from destroying this node as well.
      */
@@ -129,6 +156,8 @@ struct ast_node_common
         ast_delete(x);                 \
     }                                  \
 } while(0)
+#define ast_next_child(x,y) \
+    (*( ((ast_node*)(x))->next_child ))((ast_node*)(x),(ast_node*)(y))
 
 /* Expression interface
  *
index f03057266d3c71bc37233ffc3e012086192f9451..f100730cb0d5276db6d267848a5a6fa3eb21feb3 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -6118,6 +6118,60 @@ void parser_cleanup(parser_t *parser)
     mem_d(parser);
 }
 
+typedef struct {
+    ast_node **path;
+    ast_node *at;
+} ast_iterator;
+
+static void ast_iterator_begin(ast_iterator *iter, ast_node *start)
+{
+    iter->at = start;
+    vec_push(iter->path, start);
+}
+
+static void ast_iterator_delete(ast_iterator *iter)
+{
+    if (iter->path) {
+        vec_free(iter->path);
+    }
+}
+
+static 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;
+        }
+        /* back up */
+        iter->at = last;
+        vec_pop(iter->path);
+        --depth;
+    }
+    return NULL;
+}
+
+static void traverse_that_thing(ast_function *fun)
+{
+    ast_iterator iter = { NULL, (ast_node*)fun };
+    ast_iterator_begin(&iter, (ast_node*)fun);
+
+    for (ast_node *at = (ast_node*)fun;
+         at;
+         at = ast_iterator_next(&iter))
+    {
+        for (size_t depth = vec_size(iter.path); depth; --depth)
+            con_out("> ");
+        con_out("ast_%s\n", ast_node_type_name[at->nodetype]);
+    }
+
+    ast_iterator_delete(&iter);
+}
+
 bool parser_finish(parser_t *parser, const char *output)
 {
     size_t i;
@@ -6264,7 +6318,9 @@ bool parser_finish(parser_t *parser, const char *output)
             ir_builder_delete(ir);
             return false;
         }
+        traverse_that_thing(parser->functions[i]);
     }
+
     parser_remove_ast(parser);
 
     if (compile_Werrors) {