]> git.xonotic.org Git - xonotic/gmqcc.git/commitdiff
Merge branch 'union-replacement' into cooking
authorDale Weiler <killfieldengine@gmail.com>
Wed, 29 May 2013 03:43:49 +0000 (03:43 +0000)
committerDale Weiler <killfieldengine@gmail.com>
Wed, 29 May 2013 03:43:49 +0000 (03:43 +0000)
Conflicts:
ast.c

1  2 
ast.c
ast.h
parser.c

diff --combined ast.c
index 96f768fc578a2017c6993ba9b052e4fb4b73c38d,b104073889e8878e13fb4edd3f4f4f05c35a393a..01a08e5966072e3222a283c337483a718f453ed0
--- 1/ast.c
--- 2/ast.c
+++ b/ast.c
          return NULL;                                                \
      }                                                               \
      ast_node_init((ast_node*)self, ctx, TYPE_##T);                  \
-     ( (ast_node*)self )->node.destroy = (ast_node_delete*)destroyfn
+     ( (ast_node*)self )->destroy = (ast_node_delete*)destroyfn
  
 +/*
 + * 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 void ast_array_index_delete(ast_array_index*);
 +static bool ast_array_index_codegen(ast_array_index*, ast_function*, bool lvalue, ir_value**);
 +static void ast_store_delete(ast_store*);
 +static bool ast_store_codegen(ast_store*, ast_function*, bool lvalue, ir_value**);
 +static void ast_ifthen_delete(ast_ifthen*);
 +static bool ast_ifthen_codegen(ast_ifthen*, ast_function*, bool lvalue, ir_value**);
 +static void ast_ternary_delete(ast_ternary*);
 +static bool ast_ternary_codegen(ast_ternary*, ast_function*, bool lvalue, ir_value**);
 +static void ast_loop_delete(ast_loop*);
 +static bool ast_loop_codegen(ast_loop*, ast_function*, bool lvalue, ir_value**);
 +static void ast_breakcont_delete(ast_breakcont*);
 +static bool ast_breakcont_codegen(ast_breakcont*, ast_function*, bool lvalue, ir_value**);
 +static void ast_switch_delete(ast_switch*);
 +static bool ast_switch_codegen(ast_switch*, ast_function*, bool lvalue, ir_value**);
 +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 bool ast_goto_codegen(ast_goto*, ast_function*, bool lvalue, ir_value**);
 +static void ast_goto_delete(ast_goto*);
 +static void ast_call_delete(ast_call*);
 +static bool ast_call_codegen(ast_call*, ast_function*, bool lvalue, ir_value**);
 +static bool ast_block_codegen(ast_block*, ast_function*, bool lvalue, ir_value**);
 +static void ast_unary_delete(ast_unary*);
 +static bool ast_unary_codegen(ast_unary*, ast_function*, bool lvalue, ir_value**);
 +static void ast_entfield_delete(ast_entfield*);
 +static bool ast_entfield_codegen(ast_entfield*, ast_function*, bool lvalue, ir_value**);
 +static void ast_return_delete(ast_return*);
 +static bool ast_return_codegen(ast_return*, ast_function*, bool lvalue, ir_value**);
 +static void ast_binstore_delete(ast_binstore*);
 +static bool ast_binstore_codegen(ast_binstore*, ast_function*, bool lvalue, ir_value**);
 +static void ast_binary_delete(ast_binary*);
 +static bool ast_binary_codegen(ast_binary*, ast_function*, bool lvalue, ir_value**);
  
  /* It must not be possible to get here. */
  static GMQCC_NORETURN void _ast_node_destroy(ast_node *self)
  /* Initialize main ast node aprts */
  static void ast_node_init(ast_node *self, lex_ctx ctx, int nodetype)
  {
-     self->node.context = ctx;
-     self->node.destroy = &_ast_node_destroy;
-     self->node.keep    = false;
-     self->node.nodetype = nodetype;
-     self->node.side_effects = false;
+     self->context = ctx;
+     self->destroy = &_ast_node_destroy;
+     self->keep    = false;
+     self->nodetype = nodetype;
+     self->side_effects = false;
  }
  
  /* weight and side effects */
@@@ -104,28 -67,28 +104,28 @@@ static void _ast_propagate_effects(ast_
  static void ast_expression_init(ast_expression *self,
                                  ast_expression_codegen *codegen)
  {
-     self->expression.codegen  = codegen;
-     self->expression.vtype    = TYPE_VOID;
-     self->expression.next     = NULL;
-     self->expression.outl     = NULL;
-     self->expression.outr     = NULL;
-     self->expression.params   = NULL;
-     self->expression.count    = 0;
-     self->expression.flags    = 0;
-     self->expression.varparam = NULL;
+     self->codegen  = codegen;
+     self->vtype    = TYPE_VOID;
+     self->next     = NULL;
+     self->outl     = NULL;
+     self->outr     = NULL;
+     self->params   = NULL;
+     self->count    = 0;
+     self->flags    = 0;
+     self->varparam = NULL;
  }
  
  static void ast_expression_delete(ast_expression *self)
  {
      size_t i;
-     if (self->expression.next)
-         ast_delete(self->expression.next);
-     for (i = 0; i < vec_size(self->expression.params); ++i) {
-         ast_delete(self->expression.params[i]);
+     if (self->next)
+         ast_delete(self->next);
+     for (i = 0; i < vec_size(self->params); ++i) {
+         ast_delete(self->params[i]);
      }
-     vec_free(self->expression.params);
-     if (self->expression.varparam)
-         ast_delete(self->expression.varparam);
+     vec_free(self->params);
+     if (self->varparam)
+         ast_delete(self->varparam);
  }
  
  static void ast_expression_delete_full(ast_expression *self)
  ast_value* ast_value_copy(const ast_value *self)
  {
      size_t i;
-     const ast_expression_common *fromex;
-     ast_expression_common *selfex;
+     const ast_expression *fromex;
+     ast_expression       *selfex;
      ast_value *cp = ast_value_new(self->expression.node.context, self->name, self->expression.vtype);
      if (self->expression.next) {
          cp->expression.next = ast_type_copy(self->expression.node.context, self->expression.next);
  void ast_type_adopt_impl(ast_expression *self, const ast_expression *other)
  {
      size_t i;
-     const ast_expression_common *fromex;
-     ast_expression_common *selfex;
-     self->expression.vtype = other->expression.vtype;
-     if (other->expression.next) {
-         self->expression.next = (ast_expression*)ast_type_copy(ast_ctx(self), other->expression.next);
-     }
-     fromex   = &other->expression;
-     selfex = &self->expression;
+     const ast_expression *fromex;
+     ast_expression       *selfex;
+     self->vtype = other->vtype;
+     if (other->next) {
+         self->next = (ast_expression*)ast_type_copy(ast_ctx(self), other->next);
+     }
+     fromex = other;
+     selfex = self;
      selfex->count    = fromex->count;
      selfex->flags    = fromex->flags;
      for (i = 0; i < vec_size(fromex->params); ++i) {
@@@ -177,17 -140,17 +177,17 @@@ static ast_expression* ast_shallow_type
  {
      ast_instantiate(ast_expression, ctx, ast_expression_delete_full);
      ast_expression_init(self, NULL);
-     self->expression.codegen = NULL;
-     self->expression.next    = NULL;
-     self->expression.vtype   = vtype;
+     self->codegen = NULL;
+     self->next    = NULL;
+     self->vtype   = vtype;
      return self;
  }
  
  ast_expression* ast_type_copy(lex_ctx ctx, const ast_expression *ex)
  {
      size_t i;
-     const ast_expression_common *fromex;
-     ast_expression_common *selfex;
+     const ast_expression *fromex;
+     ast_expression       *selfex;
  
      if (!ex)
          return NULL;
          ast_instantiate(ast_expression, ctx, ast_expression_delete_full);
          ast_expression_init(self, NULL);
  
-         fromex   = &ex->expression;
-         selfex = &self->expression;
+         fromex = ex;
+         selfex = self;
  
          /* This may never be codegen()d */
          selfex->codegen = NULL;
  
  bool ast_compare_type(ast_expression *a, ast_expression *b)
  {
-     if (a->expression.vtype == TYPE_NIL ||
-         b->expression.vtype == TYPE_NIL)
+     if (a->vtype == TYPE_NIL ||
+         b->vtype == TYPE_NIL)
          return true;
-     if (a->expression.vtype != b->expression.vtype)
+     if (a->vtype != b->vtype)
          return false;
-     if (!a->expression.next != !b->expression.next)
+     if (!a->next != !b->next)
          return false;
-     if (vec_size(a->expression.params) != vec_size(b->expression.params))
+     if (vec_size(a->params) != vec_size(b->params))
          return false;
-     if ((a->expression.flags & AST_FLAG_TYPE_MASK) !=
-         (b->expression.flags & AST_FLAG_TYPE_MASK) )
+     if ((a->flags & AST_FLAG_TYPE_MASK) !=
+         (b->flags & AST_FLAG_TYPE_MASK) )
      {
          return false;
      }
-     if (vec_size(a->expression.params)) {
+     if (vec_size(a->params)) {
          size_t i;
-         for (i = 0; i < vec_size(a->expression.params); ++i) {
-             if (!ast_compare_type((ast_expression*)a->expression.params[i],
-                                   (ast_expression*)b->expression.params[i]))
+         for (i = 0; i < vec_size(a->params); ++i) {
+             if (!ast_compare_type((ast_expression*)a->params[i],
+                                   (ast_expression*)b->params[i]))
                  return false;
          }
      }
-     if (a->expression.next)
-         return ast_compare_type(a->expression.next, b->expression.next);
+     if (a->next)
+         return ast_compare_type(a->next, b->next);
      return true;
  }
  
@@@ -264,43 -227,43 +264,43 @@@ static size_t ast_type_to_string_impl(a
      if (pos + 1 >= bufsize)
          goto full;
  
-     switch (e->expression.vtype) {
+     switch (e->vtype) {
          case TYPE_VARIANT:
              util_strncpy(buf + pos, "(variant)", 9);
              return pos + 9;
  
          case TYPE_FIELD:
              buf[pos++] = '.';
-             return ast_type_to_string_impl(e->expression.next, buf, bufsize, pos);
+             return ast_type_to_string_impl(e->next, buf, bufsize, pos);
  
          case TYPE_POINTER:
              if (pos + 3 >= bufsize)
                  goto full;
              buf[pos++] = '*';
              buf[pos++] = '(';
-             pos = ast_type_to_string_impl(e->expression.next, buf, bufsize, pos);
+             pos = ast_type_to_string_impl(e->next, buf, bufsize, pos);
              if (pos + 1 >= bufsize)
                  goto full;
              buf[pos++] = ')';
              return pos;
  
          case TYPE_FUNCTION:
-             pos = ast_type_to_string_impl(e->expression.next, buf, bufsize, pos);
+             pos = ast_type_to_string_impl(e->next, buf, bufsize, pos);
              if (pos + 2 >= bufsize)
                  goto full;
-             if (!vec_size(e->expression.params)) {
+             if (!vec_size(e->params)) {
                  buf[pos++] = '(';
                  buf[pos++] = ')';
                  return pos;
              }
              buf[pos++] = '(';
-             pos = ast_type_to_string_impl((ast_expression*)(e->expression.params[0]), buf, bufsize, pos);
-             for (i = 1; i < vec_size(e->expression.params); ++i) {
+             pos = ast_type_to_string_impl((ast_expression*)(e->params[0]), buf, bufsize, pos);
+             for (i = 1; i < vec_size(e->params); ++i) {
                  if (pos + 2 >= bufsize)
                      goto full;
                  buf[pos++] = ',';
                  buf[pos++] = ' ';
-                 pos = ast_type_to_string_impl((ast_expression*)(e->expression.params[i]), buf, bufsize, pos);
+                 pos = ast_type_to_string_impl((ast_expression*)(e->params[i]), buf, bufsize, pos);
              }
              if (pos + 1 >= bufsize)
                  goto full;
              return pos;
  
          case TYPE_ARRAY:
-             pos = ast_type_to_string_impl(e->expression.next, buf, bufsize, pos);
+             pos = ast_type_to_string_impl(e->next, buf, bufsize, pos);
              if (pos + 1 >= bufsize)
                  goto full;
              buf[pos++] = '[';
-             pos += util_snprintf(buf + pos, bufsize - pos - 1, "%i", (int)e->expression.count);
+             pos += util_snprintf(buf + pos, bufsize - pos - 1, "%i", (int)e->count);
              if (pos + 1 >= bufsize)
                  goto full;
              buf[pos++] = ']';
              return pos;
  
          default:
-             typestr = type_name[e->expression.vtype];
+             typestr = type_name[e->vtype];
              typelen = strlen(typestr);
              if (pos + typelen >= bufsize)
                  goto full;
@@@ -340,7 -303,6 +340,7 @@@ void ast_type_to_string(ast_expression 
      buf[pos] = 0;
  }
  
 +static bool ast_value_codegen(ast_value *self, ast_function *func, bool lvalue, ir_value **out);
  ast_value* ast_value_new(lex_ctx ctx, const char *name, int t)
  {
      ast_instantiate(ast_value, ctx, ast_value_delete);
@@@ -402,7 -364,7 +402,7 @@@ void ast_value_delete(ast_value* self
          mem_d(self->desc);
  
      if (self->initlist) {
-         if (self->expression.next->expression.vtype == TYPE_STRING) {
+         if (self->expression.next->vtype == TYPE_STRING) {
              /* strings are allocated, free them */
              size_t i, len = vec_size(self->initlist);
              /* in theory, len should be expression.count
@@@ -460,7 -422,7 +460,7 @@@ ast_binary* ast_binary_new(lex_ctx ctx
      else if (op == INSTR_MUL_V)
          self->expression.vtype = TYPE_FLOAT;
      else
-         self->expression.vtype = left->expression.vtype;
+         self->expression.vtype = left->vtype;
  
      /* references all */
      self->refs = AST_REF_ALL;
@@@ -554,11 -516,11 +554,11 @@@ void ast_return_delete(ast_return *self
  
  ast_entfield* ast_entfield_new(lex_ctx ctx, ast_expression *entity, ast_expression *field)
  {
-     if (field->expression.vtype != TYPE_FIELD) {
+     if (field->vtype != TYPE_FIELD) {
          compile_error(ctx, "ast_entfield_new with expression not of type field");
          return NULL;
      }
-     return ast_entfield_new_force(ctx, entity, field, field->expression.next);
+     return ast_entfield_new_force(ctx, entity, field, field->next);
  }
  
  ast_entfield* ast_entfield_new_force(lex_ctx ctx, ast_expression *entity, ast_expression *field, const ast_expression *outtype)
@@@ -598,9 -560,9 +598,9 @@@ ast_member* ast_member_new(lex_ctx ctx
          return NULL;
      }
  
-     if (owner->expression.vtype != TYPE_VECTOR &&
-         owner->expression.vtype != TYPE_FIELD) {
-         compile_error(ctx, "member-access on an invalid owner of type %s", type_name[owner->expression.vtype]);
+     if (owner->vtype != TYPE_VECTOR &&
+         owner->vtype != TYPE_FIELD) {
+         compile_error(ctx, "member-access on an invalid owner of type %s", type_name[owner->vtype]);
          mem_d(self);
          return NULL;
      }
      ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_member_codegen);
      self->expression.node.keep = true; /* keep */
  
-     if (owner->expression.vtype == TYPE_VECTOR) {
+     if (owner->vtype == TYPE_VECTOR) {
          self->expression.vtype = TYPE_FLOAT;
          self->expression.next  = NULL;
      } else {
@@@ -657,7 -619,7 +657,7 @@@ ast_array_index* ast_array_index_new(le
      ast_expression *outtype;
      ast_instantiate(ast_array_index, ctx, ast_array_index_delete);
  
-     outtype = array->expression.next;
+     outtype = array->next;
      if (!outtype) {
          mem_d(self);
          /* Error: field has no type... */
      ast_propagate_effects(self, index);
  
      ast_type_adopt(self, outtype);
-     if (array->expression.vtype == TYPE_FIELD && outtype->expression.vtype == TYPE_ARRAY) {
+     if (array->vtype == TYPE_FIELD && outtype->vtype == TYPE_ARRAY) {
          if (self->expression.vtype != TYPE_ARRAY) {
              compile_error(ast_ctx(self), "array_index node on type");
              ast_array_index_delete(self);
@@@ -746,7 -708,7 +746,7 @@@ ast_ternary* ast_ternary_new(lex_ctx ct
      ast_propagate_effects(self, ontrue);
      ast_propagate_effects(self, onfalse);
  
-     if (ontrue->expression.vtype == TYPE_NIL)
+     if (ontrue->vtype == TYPE_NIL)
          exprtype = onfalse;
      ast_type_adopt(self, exprtype);
  
@@@ -883,7 -845,7 +883,7 @@@ void ast_label_delete(ast_label *self
      mem_d(self);
  }
  
 -void ast_label_register_goto(ast_label *self, ast_goto *g)
 +static void ast_label_register_goto(ast_label *self, ast_goto *g)
  {
      vec_push(self->gotos, g);
  }
@@@ -916,7 -878,7 +916,7 @@@ ast_call* ast_call_new(lex_ctx ctx
                         ast_expression *funcexpr)
  {
      ast_instantiate(ast_call, ctx, ast_call_delete);
-     if (!funcexpr->expression.next) {
+     if (!funcexpr->next) {
          compile_error(ctx, "not a function");
          mem_d(self);
          return NULL;
      self->func     = funcexpr;
      self->va_count = NULL;
  
-     ast_type_adopt(self, funcexpr->expression.next);
+     ast_type_adopt(self, funcexpr->next);
  
      return self;
  }
@@@ -959,14 -921,14 +959,14 @@@ bool ast_call_check_types(ast_call *sel
      bool   retval = true;
      const  ast_expression *func = self->func;
      size_t count = vec_size(self->params);
-     if (count > vec_size(func->expression.params))
-         count = vec_size(func->expression.params);
+     if (count > vec_size(func->params))
+         count = vec_size(func->params);
  
      for (i = 0; i < count; ++i) {
-         if (!ast_compare_type(self->params[i], (ast_expression*)(func->expression.params[i])))
+         if (!ast_compare_type(self->params[i], (ast_expression*)(func->params[i])))
          {
              ast_type_to_string(self->params[i], tgot, sizeof(tgot));
-             ast_type_to_string((ast_expression*)func->expression.params[i], texp, sizeof(texp));
+             ast_type_to_string((ast_expression*)func->params[i], texp, sizeof(texp));
              compile_error(ast_ctx(self), "invalid type for parameter %u in function call: expected %s, got %s",
                       (unsigned int)(i+1), texp, tgot);
              /* we don't immediately return */
          }
      }
      count = vec_size(self->params);
-     if (count > vec_size(func->expression.params) && func->expression.varparam) {
+     if (count > vec_size(func->params) && func->varparam) {
          for (; i < count; ++i) {
-             if (!ast_compare_type(self->params[i], func->expression.varparam))
+             if (!ast_compare_type(self->params[i], func->varparam))
              {
                  ast_type_to_string(self->params[i], tgot, sizeof(tgot));
-                 ast_type_to_string(func->expression.varparam, texp, sizeof(texp));
+                 ast_type_to_string(func->varparam, texp, sizeof(texp));
                  compile_error(ast_ctx(self), "invalid type for parameter %u in function call: expected %s, got %s",
                           (unsigned int)(i+1), texp, tgot);
                  /* we don't immediately return */
@@@ -1043,7 -1005,7 +1043,7 @@@ bool ast_block_add_expr(ast_block *self
  void ast_block_collect(ast_block *self, ast_expression *expr)
  {
      vec_push(self->collect, expr);
-     expr->expression.node.keep = true;
+     expr->node.keep = true;
  }
  
  void ast_block_delete(ast_block *self)
@@@ -1136,7 -1098,7 +1136,7 @@@ void ast_function_delete(ast_function *
      mem_d(self);
  }
  
 -const char* ast_function_label(ast_function *self, const char *prefix)
 +static const char* ast_function_label(ast_function *self, const char *prefix)
  {
      size_t id;
      size_t len;
   * But I can't imagine a pituation where the output is truly unnecessary.
   */
  
- static void _ast_codegen_output_type(ast_expression_common *self, ir_value *out)
 -void _ast_codegen_output_type(ast_expression *self, ir_value *out)
++static void _ast_codegen_output_type(ast_expression *self, ir_value *out)
  {
      if (out->vtype == TYPE_FIELD)
-         out->fieldtype = self->next->expression.vtype;
+         out->fieldtype = self->next->vtype;
      if (out->vtype == TYPE_FUNCTION)
-         out->outtype = self->next->expression.vtype;
+         out->outtype = self->next->vtype;
  }
  
  #define codegen_output_type(a,o) (_ast_codegen_output_type(&((a)->expression),(o)))
@@@ -1216,7 -1178,7 +1216,7 @@@ bool ast_global_codegen(ast_value *self
  
      if (self->hasvalue && self->expression.vtype == TYPE_FUNCTION)
      {
-         ir_function *func = ir_builder_create_function(ir, self->name, self->expression.next->expression.vtype);
+         ir_function *func = ir_builder_create_function(ir, self->name, self->expression.next->vtype);
          if (!func)
              return false;
          func->context = ast_ctx(self);
              goto error;
          }
  
-         if (fieldtype->expression.vtype == TYPE_ARRAY) {
+         if (fieldtype->vtype == TYPE_ARRAY) {
              size_t ai;
              char   *name;
              size_t  namelen;
  
-             ast_expression_common *elemtype;
-             int                    vtype;
-             ast_value             *array = (ast_value*)fieldtype;
+             ast_expression *elemtype;
+             int             vtype;
+             ast_value      *array = (ast_value*)fieldtype;
  
              if (!ast_istype(fieldtype, ast_value)) {
                  compile_error(ast_ctx(self), "internal error: ast_value required");
              if (!array->expression.count || array->expression.count > OPTS_OPTION_U32(OPTION_MAX_ARRAY_SIZE))
                  compile_error(ast_ctx(self), "Invalid array of size %lu", (unsigned long)array->expression.count);
  
-             elemtype = &array->expression.next->expression;
+             elemtype = array->expression.next;
              vtype = elemtype->vtype;
  
              v = ir_builder_create_field(ir, self->name, vtype);
          }
          else
          {
-             v = ir_builder_create_field(ir, self->name, self->expression.next->expression.vtype);
+             v = ir_builder_create_field(ir, self->name, self->expression.next->vtype);
              if (!v)
                  return false;
              v->context = ast_ctx(self);
          char   *name;
          size_t  namelen;
  
-         ast_expression_common *elemtype = &self->expression.next->expression;
+         ast_expression *elemtype = self->expression.next;
          int vtype = elemtype->vtype;
  
          /* same as with field arrays */
@@@ -1419,7 -1381,7 +1419,7 @@@ error: /* clean up *
      return false;
  }
  
 -bool ast_local_codegen(ast_value *self, ir_function *func, bool param)
 +static bool ast_local_codegen(ast_value *self, ir_function *func, bool param)
  {
      ir_value *v = NULL;
  
          char   *name;
          size_t  namelen;
  
-         ast_expression_common *elemtype = &self->expression.next->expression;
+         ast_expression *elemtype = self->expression.next;
          int vtype = elemtype->vtype;
  
          func->flags |= IR_FLAG_HAS_ARRAYS;
@@@ -1588,7 -1550,7 +1588,7 @@@ bool ast_function_codegen(ast_function 
  {
      ir_function *irf;
      ir_value    *dummy;
-     ast_expression_common  *ec;
+     ast_expression         *ec;
      ast_expression_codegen *cgen;
      size_t    i;
  
      for (i = 0; i < vec_size(ec->params); ++i)
      {
          if (ec->params[i]->expression.vtype == TYPE_FIELD)
-             vec_push(irf->params, ec->params[i]->expression.next->expression.vtype);
+             vec_push(irf->params, ec->params[i]->expression.next->vtype);
          else
              vec_push(irf->params, ec->params[i]->expression.vtype);
          if (!self->builtin) {
      if (!self->curblock->final)
      {
          if (!self->vtype->expression.next ||
-             self->vtype->expression.next->expression.vtype == TYPE_VOID)
+             self->vtype->expression.next->vtype == TYPE_VOID)
          {
              return ir_block_create_return(self->curblock, ast_ctx(self), NULL);
          }
@@@ -1739,7 -1701,7 +1739,7 @@@ bool ast_block_codegen(ast_block *self
                  return false;
              continue;
          }
-         gen = self->exprs[i]->expression.codegen;
+         gen = self->exprs[i]->codegen;
          if (!(*gen)(self->exprs[i], func, false, out))
              return false;
      }
@@@ -1803,7 -1765,7 +1803,7 @@@ bool ast_store_codegen(ast_store *self
          if (!(*cgen)((ast_expression*)(arr->setter), func, true, &funval))
              return false;
  
-         cgen = self->source->expression.codegen;
+         cgen = self->source->codegen;
          if (!(*cgen)((ast_expression*)(self->source), func, false, &right))
              return false;
  
      {
          /* regular code */
  
-         cgen = self->dest->expression.codegen;
+         cgen = self->dest->codegen;
          /* lvalue! */
          if (!(*cgen)((ast_expression*)(self->dest), func, true, &left))
              return false;
          self->expression.outl = left;
  
-         cgen = self->source->expression.codegen;
+         cgen = self->source->codegen;
          /* rvalue! */
          if (!(*cgen)((ast_expression*)(self->source), func, false, &right))
              return false;
@@@ -1876,7 -1838,7 +1876,7 @@@ bool ast_binary_codegen(ast_binary *sel
          merge    = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "sce_merge"));
  
          /* generate the left expression */
-         cgen = self->left->expression.codegen;
+         cgen = self->left->codegen;
          if (!(*cgen)((ast_expression*)(self->left), func, false, &left))
              return false;
          /* remember the block */
          /* enter the right-expression's block */
          func->curblock = other;
          /* generate */
-         cgen = self->right->expression.codegen;
+         cgen = self->right->codegen;
          if (!(*cgen)((ast_expression*)(self->right), func, false, &right))
              return false;
          /* remember block */
          return true;
      }
  
-     cgen = self->left->expression.codegen;
+     cgen = self->left->codegen;
      if (!(*cgen)((ast_expression*)(self->left), func, false, &left))
          return false;
  
-     cgen = self->right->expression.codegen;
+     cgen = self->right->codegen;
      if (!(*cgen)((ast_expression*)(self->right), func, false, &right))
          return false;
  
@@@ -2017,12 -1979,12 +2017,12 @@@ bool ast_binstore_codegen(ast_binstore 
          if (!(*cgen)((ast_expression*)(idx), func, false, &iridx))
              return false;
      }
-     cgen = self->dest->expression.codegen;
+     cgen = self->dest->codegen;
      if (!(*cgen)((ast_expression*)(self->dest), func, false, &leftr))
          return false;
  
      /* source as rvalue only */
-     cgen = self->source->expression.codegen;
+     cgen = self->source->codegen;
      if (!(*cgen)((ast_expression*)(self->source), func, false, &right))
          return false;
  
          self->expression.outr = bin;
      } else {
          /* now store them */
-         cgen = self->dest->expression.codegen;
+         cgen = self->dest->codegen;
          /* lvalue of destination */
          if (!(*cgen)((ast_expression*)(self->dest), func, true, &leftl))
              return false;
@@@ -2099,7 -2061,7 +2099,7 @@@ bool ast_unary_codegen(ast_unary *self
          return true;
      }
  
-     cgen = self->operand->expression.codegen;
+     cgen = self->operand->codegen;
      /* lvalue! */
      if (!(*cgen)((ast_expression*)(self->operand), func, false, &operand))
          return false;
@@@ -2135,7 -2097,7 +2135,7 @@@ bool ast_return_codegen(ast_return *sel
      self->expression.outr = (ir_value*)1;
  
      if (self->operand) {
-         cgen = self->operand->expression.codegen;
+         cgen = self->operand->codegen;
          /* lvalue! */
          if (!(*cgen)((ast_expression*)(self->operand), func, false, &operand))
              return false;
@@@ -2170,11 -2132,11 +2170,11 @@@ bool ast_entfield_codegen(ast_entfield 
          return true;
      }
  
-     cgen = self->entity->expression.codegen;
+     cgen = self->entity->codegen;
      if (!(*cgen)((ast_expression*)(self->entity), func, false, &ent))
          return false;
  
-     cgen = self->field->expression.codegen;
+     cgen = self->field->codegen;
      if (!(*cgen)((ast_expression*)(self->field), func, false, &field))
          return false;
  
@@@ -2222,12 -2184,12 +2222,12 @@@ bool ast_member_codegen(ast_member *sel
          return true;
      }
  
-     cgen = self->owner->expression.codegen;
+     cgen = self->owner->codegen;
      if (!(*cgen)((ast_expression*)(self->owner), func, false, &vec))
          return false;
  
      if (vec->vtype != TYPE_VECTOR &&
-         !(vec->vtype == TYPE_FIELD && self->owner->expression.next->expression.vtype == TYPE_VECTOR))
+         !(vec->vtype == TYPE_FIELD && self->owner->next->vtype == TYPE_VECTOR))
      {
          return false;
      }
@@@ -2281,7 -2243,7 +2281,7 @@@ bool ast_array_index_codegen(ast_array_
              return false;
          }
  
-         cgen = self->index->expression.codegen;
+         cgen = self->index->codegen;
          if (!(*cgen)((ast_expression*)(self->index), func, false, &iridx))
              return false;
  
  
      if (idx->expression.vtype == TYPE_FLOAT) {
          unsigned int arridx = idx->constval.vfloat;
-         if (arridx >= self->array->expression.count)
+         if (arridx >= self->array->count)
          {
              compile_error(ast_ctx(self), "array index out of bounds: %i", arridx);
              return false;
      }
      else if (idx->expression.vtype == TYPE_INTEGER) {
          unsigned int arridx = idx->constval.vint;
-         if (arridx >= self->array->expression.count)
+         if (arridx >= self->array->count)
          {
              compile_error(ast_ctx(self), "array index out of bounds: %i", arridx);
              return false;
@@@ -2353,7 -2315,7 +2353,7 @@@ bool ast_ifthen_codegen(ast_ifthen *sel
      self->expression.outr = (ir_value*)1;
  
      /* generate the condition */
-     cgen = self->cond->expression.codegen;
+     cgen = self->cond->codegen;
      if (!(*cgen)((ast_expression*)(self->cond), func, false, &condval))
          return false;
      /* update the block which will get the jump - because short-logic or ternaries may have changed this */
          func->curblock = ontrue;
  
          /* generate */
-         cgen = self->on_true->expression.codegen;
+         cgen = self->on_true->codegen;
          if (!(*cgen)((ast_expression*)(self->on_true), func, false, &dummy))
              return false;
  
          func->curblock = onfalse;
  
          /* generate */
-         cgen = self->on_false->expression.codegen;
+         cgen = self->on_false->codegen;
          if (!(*cgen)((ast_expression*)(self->on_false), func, false, &dummy))
              return false;
  
@@@ -2460,7 -2422,7 +2460,7 @@@ bool ast_ternary_codegen(ast_ternary *s
  
      /* generate the condition */
      func->curblock = cond;
-     cgen = self->cond->expression.codegen;
+     cgen = self->cond->codegen;
      if (!(*cgen)((ast_expression*)(self->cond), func, false, &condval))
          return false;
      cond_out = func->curblock;
          func->curblock = ontrue;
  
          /* generate */
-         cgen = self->on_true->expression.codegen;
+         cgen = self->on_true->codegen;
          if (!(*cgen)((ast_expression*)(self->on_true), func, false, &trueval))
              return false;
  
          func->curblock = onfalse;
  
          /* generate */
-         cgen = self->on_false->expression.codegen;
+         cgen = self->on_false->codegen;
          if (!(*cgen)((ast_expression*)(self->on_false), func, false, &falseval))
              return false;
  
@@@ -2589,7 -2551,7 +2589,7 @@@ bool ast_loop_codegen(ast_loop *self, a
       */
      if (self->initexpr)
      {
-         cgen = self->initexpr->expression.codegen;
+         cgen = self->initexpr->codegen;
          if (!(*cgen)((ast_expression*)(self->initexpr), func, false, &dummy))
              return false;
      }
          func->curblock = bprecond;
  
          /* generate */
-         cgen = self->precond->expression.codegen;
+         cgen = self->precond->codegen;
          if (!(*cgen)((ast_expression*)(self->precond), func, false, &precond))
              return false;
  
  
          /* generate */
          if (self->body) {
-             cgen = self->body->expression.codegen;
+             cgen = self->body->codegen;
              if (!(*cgen)((ast_expression*)(self->body), func, false, &dummy))
                  return false;
          }
          func->curblock = bpostcond;
  
          /* generate */
-         cgen = self->postcond->expression.codegen;
+         cgen = self->postcond->codegen;
          if (!(*cgen)((ast_expression*)(self->postcond), func, false, &postcond))
              return false;
  
          func->curblock = bincrement;
  
          /* generate */
-         cgen = self->increment->expression.codegen;
+         cgen = self->increment->codegen;
          if (!(*cgen)((ast_expression*)(self->increment), func, false, &dummy))
              return false;
  
@@@ -2847,7 -2809,7 +2847,7 @@@ bool ast_switch_codegen(ast_switch *sel
      (void)lvalue;
      (void)out;
  
-     cgen = self->operand->expression.codegen;
+     cgen = self->operand->codegen;
      if (!(*cgen)((ast_expression*)(self->operand), func, false, &irop))
          return false;
  
          if (swcase->value) {
              /* A regular case */
              /* generate the condition operand */
-             cgen = swcase->value->expression.codegen;
+             cgen = swcase->value->codegen;
              if (!(*cgen)((ast_expression*)(swcase->value), func, false, &val))
                  return false;
              /* generate the condition */
  
              /* enter the case */
              func->curblock = bcase;
-             cgen = swcase->code->expression.codegen;
+             cgen = swcase->code->codegen;
              if (!(*cgen)((ast_expression*)swcase->code, func, false, &dummy))
                  return false;
  
          }
  
          /* Now generate the default code */
-         cgen = def_case->code->expression.codegen;
+         cgen = def_case->code->codegen;
          if (!(*cgen)((ast_expression*)def_case->code, func, false, &dummy))
              return false;
  
@@@ -3078,7 -3040,7 +3078,7 @@@ bool ast_call_codegen(ast_call *self, a
          return true;
      }
  
-     cgen = self->func->expression.codegen;
+     cgen = self->func->codegen;
      if (!(*cgen)((ast_expression*)(self->func), func, false, &funval))
          return false;
      if (!funval)
          ir_value *param;
          ast_expression *expr = self->params[i];
  
-         cgen = expr->expression.codegen;
+         cgen = expr->codegen;
          if (!(*cgen)(expr, func, false, &param))
              goto error;
          if (!param)
      if (self->va_count) {
          ir_value   *va_count;
          ir_builder *builder = func->curblock->owner->owner;
-         cgen = self->va_count->expression.codegen;
+         cgen = self->va_count->codegen;
          if (!(*cgen)((ast_expression*)(self->va_count), func, false, &va_count))
              return false;
          if (!ir_block_create_store_op(func->curblock, ast_ctx(self), INSTR_STORE_F,
  
      callinstr = ir_block_create_call(func->curblock, ast_ctx(self),
                                       ast_function_label(func, "call"),
-                                      funval, !!(self->func->expression.flags & AST_FLAG_NORETURN));
+                                      funval, !!(self->func->flags & AST_FLAG_NORETURN));
      if (!callinstr)
          goto error;
  
diff --combined ast.h
index f130fb45b2bea1ba3a5408e751474f4c13101170,26d0c0c3681a545896829d861be26db8b1ae88e5..c624a1fb1dc24e88738a532b9a84a71a9c8f0239
--- 1/ast.h
--- 2/ast.h
+++ b/ast.h
@@@ -1,7 -1,6 +1,7 @@@
  /*
   * Copyright (C) 2012, 2013
   *     Wolfgang Bumiller
 + *     Dale Weiler
   *
   * Permission is hereby granted, free of charge, to any person obtaining a copy of
   * this software and associated documentation files (the "Software"), to deal in
@@@ -29,8 -28,8 +29,8 @@@
   * "main" ast node types for now.
   */
  
- typedef union ast_node_u ast_node;
- typedef union ast_expression_u ast_expression;
+ typedef struct ast_node_common       ast_node;
+ typedef struct ast_expression_common ast_expression;
  
  typedef struct ast_value_s       ast_value;
  typedef struct ast_function_s    ast_function;
@@@ -76,14 -75,14 +76,14 @@@ enum 
      TYPE_ast_goto         /* 20 */
  };
  
- #define ast_istype(x, t) ( ((ast_node_common*)x)->nodetype == (TYPE_##t) )
- #define ast_ctx(node) (((ast_node_common*)(node))->context)
- #define ast_side_effects(node) (((ast_node_common*)(node))->side_effects)
+ #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)
  
  /* Node interface with common components
   */
  typedef void ast_node_delete(ast_node*);
- typedef struct
+ struct ast_node_common
  {
      lex_ctx          context;
      /* I don't feel comfortable using keywords like 'delete' as names... */
       */
      bool             keep;
      bool             side_effects;
- } ast_node_common;
- #define ast_delete(x) (*( ((ast_node*)(x))->node.destroy ))((ast_node*)(x))
- #define ast_unref(x) do                     \
- {                                           \
-     if (! (((ast_node*)(x))->node.keep) ) { \
-         ast_delete(x);                      \
-     }                                       \
+ };
+ #define ast_delete(x) (*( ((ast_node*)(x))->destroy ))((ast_node*)(x))
+ #define ast_unref(x) do                \
+ {                                      \
+     if (! (((ast_node*)(x))->keep) ) { \
+         ast_delete(x);                 \
+     }                                  \
  } while(0)
  
  /* Expression interface
@@@ -123,9 -122,9 +123,9 @@@ typedef bool ast_expression_codegen(ast
   * type `expression`, so the ast_ident's codegen would search for
   * variables through the environment (or functions, constants...).
   */
- typedef struct
+ struct ast_expression_common
  {
-     ast_node_common         node;
+     ast_node                node;
      ast_expression_codegen *codegen;
      int                     vtype;
      ast_expression         *next;
       */
      ir_value               *outl;
      ir_value               *outr;
- } ast_expression_common;
+ };
  #define AST_FLAG_VARIADIC     (1<<0)
  #define AST_FLAG_NORETURN     (1<<1)
  #define AST_FLAG_INLINE       (1<<2)
@@@ -173,7 -172,7 +173,7 @@@ typedef union 
  } basic_value_t;
  struct ast_value_s
  {
-     ast_expression_common expression;
+     ast_expression        expression;
  
      const char *name;
      const char *desc;
@@@ -215,11 -214,8 +215,11 @@@ void ast_value_delete(ast_value*)
  
  bool ast_value_set_name(ast_value*, const char *name);
  
 +/*
  bool ast_value_codegen(ast_value*, ast_function*, bool lvalue, ir_value**);
  bool ast_local_codegen(ast_value *self, ir_function *func, bool isparam);
 +*/
 +
  bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield);
  
  void ast_value_params_add(ast_value*, ast_value*);
@@@ -243,7 -239,7 +243,7 @@@ typedef enum ast_binary_ref_s 
   */
  struct ast_binary_s
  {
-     ast_expression_common expression;
+     ast_expression        expression;
  
      int             op;
      ast_expression *left;
@@@ -255,6 -251,9 +255,6 @@@ ast_binary* ast_binary_new(lex_ctx    c
                             int        op,
                             ast_expression *left,
                             ast_expression *right);
 -void ast_binary_delete(ast_binary*);
 -
 -bool ast_binary_codegen(ast_binary*, ast_function*, bool lvalue, ir_value**);
  
  /* Binstore
   *
   */
  struct ast_binstore_s
  {
-     ast_expression_common expression;
+     ast_expression        expression;
  
      int             opstore;
      int             opbin;
@@@ -277,6 -276,9 +277,6 @@@ ast_binstore* ast_binstore_new(lex_ct
                                 int        op,
                                 ast_expression *left,
                                 ast_expression *right);
 -void ast_binstore_delete(ast_binstore*);
 -
 -bool ast_binstore_codegen(ast_binstore*, ast_function*, bool lvalue, ir_value**);
  
  /* Unary
   *
   */
  struct ast_unary_s
  {
-     ast_expression_common expression;
+     ast_expression        expression;
  
      int             op;
      ast_expression *operand;
  ast_unary* ast_unary_new(lex_ctx    ctx,
                           int        op,
                           ast_expression *expr);
 -void ast_unary_delete(ast_unary*);
 -
 -bool ast_unary_codegen(ast_unary*, ast_function*, bool lvalue, ir_value**);
  
  /* Return
   *
   */
  struct ast_return_s
  {
-     ast_expression_common expression;
+     ast_expression        expression;
      ast_expression *operand;
  };
  ast_return* ast_return_new(lex_ctx    ctx,
                             ast_expression *expr);
 -void ast_return_delete(ast_return*);
 -
 -bool ast_return_codegen(ast_return*, ast_function*, bool lvalue, ir_value**);
  
  /* Entity-field
   *
   */
  struct ast_entfield_s
  {
-     ast_expression_common expression;
+     ast_expression        expression;
      /* The entity can come from an expression of course. */
      ast_expression *entity;
      /* As can the field, it just must result in a value of TYPE_FIELD */
  };
  ast_entfield* ast_entfield_new(lex_ctx ctx, ast_expression *entity, ast_expression *field);
  ast_entfield* ast_entfield_new_force(lex_ctx ctx, ast_expression *entity, ast_expression *field, const ast_expression *outtype);
 -void ast_entfield_delete(ast_entfield*);
 -
 -bool ast_entfield_codegen(ast_entfield*, ast_function*, bool lvalue, ir_value**);
  
  /* Member access:
   *
   */
  struct ast_member_s
  {
-     ast_expression_common expression;
+     ast_expression        expression;
      ast_expression *owner;
      unsigned int    field;
      const char     *name;
@@@ -348,6 -359,7 +348,6 @@@ ast_member* ast_member_new(lex_ctx ctx
  void ast_member_delete(ast_member*);
  bool ast_member_set_name(ast_member*, const char *name);
  
 -bool ast_member_codegen(ast_member*, ast_function*, bool lvalue, ir_value**);
  
  /* Array index access:
   *
   */
  struct ast_array_index_s
  {
-     ast_expression_common expression;
+     ast_expression        expression;
      ast_expression *array;
      ast_expression *index;
  };
  ast_array_index* ast_array_index_new(lex_ctx ctx, ast_expression *array, ast_expression *index);
 -void ast_array_index_delete(ast_array_index*);
 -
 -bool ast_array_index_codegen(ast_array_index*, ast_function*, bool lvalue, ir_value**);
  
  /* Store
   *
   */
  struct ast_store_s
  {
-     ast_expression_common expression;
+     ast_expression        expression;
      int             op;
      ast_expression *dest;
      ast_expression *source;
  };
  ast_store* ast_store_new(lex_ctx ctx, int op,
                           ast_expression *d, ast_expression *s);
 -void ast_store_delete(ast_store*);
 -
 -bool ast_store_codegen(ast_store*, ast_function*, bool lvalue, ir_value**);
  
  /* If
   *
   */
  struct ast_ifthen_s
  {
-     ast_expression_common expression;
+     ast_expression        expression;
      ast_expression *cond;
      /* It's all just 'expressions', since an ast_block is one too. */
      ast_expression *on_true;
      ast_expression *on_false;
  };
  ast_ifthen* ast_ifthen_new(lex_ctx ctx, ast_expression *cond, ast_expression *ontrue, ast_expression *onfalse);
 -void ast_ifthen_delete(ast_ifthen*);
 -
 -bool ast_ifthen_codegen(ast_ifthen*, ast_function*, bool lvalue, ir_value**);
  
  /* Ternary expressions...
   *
   */
  struct ast_ternary_s
  {
-     ast_expression_common expression;
+     ast_expression        expression;
      ast_expression *cond;
      /* It's all just 'expressions', since an ast_block is one too. */
      ast_expression *on_true;
      ast_expression *on_false;
  };
  ast_ternary* ast_ternary_new(lex_ctx ctx, ast_expression *cond, ast_expression *ontrue, ast_expression *onfalse);
 -void ast_ternary_delete(ast_ternary*);
 -
 -bool ast_ternary_codegen(ast_ternary*, ast_function*, bool lvalue, ir_value**);
  
  /* A general loop node
   *
@@@ -451,7 -475,7 +451,7 @@@ continue:      // a 'continue' will jum
   */
  struct ast_loop_s
  {
-     ast_expression_common expression;
+     ast_expression        expression;
      ast_expression *initexpr;
      ast_expression *precond;
      ast_expression *postcond;
@@@ -472,16 -496,22 +472,16 @@@ ast_loop* ast_loop_new(lex_ctx ctx
                         ast_expression *postcond, bool post_not,
                         ast_expression *increment,
                         ast_expression *body);
 -void ast_loop_delete(ast_loop*);
 -
 -bool ast_loop_codegen(ast_loop*, ast_function*, bool lvalue, ir_value**);
  
  /* Break/Continue
   */
  struct ast_breakcont_s
  {
-     ast_expression_common expression;
+     ast_expression        expression;
      bool         is_continue;
      unsigned int levels;
  };
  ast_breakcont* ast_breakcont_new(lex_ctx ctx, bool iscont, unsigned int levels);
 -void ast_breakcont_delete(ast_breakcont*);
 -
 -bool ast_breakcont_codegen(ast_breakcont*, ast_function*, bool lvalue, ir_value**);
  
  /* Switch Statements
   *
@@@ -499,13 -529,16 +499,13 @@@ typedef struct 
  } ast_switch_case;
  struct ast_switch_s
  {
-     ast_expression_common expression;
+     ast_expression        expression;
  
      ast_expression  *operand;
      ast_switch_case *cases;
  };
  
  ast_switch* ast_switch_new(lex_ctx ctx, ast_expression *op);
 -void ast_switch_delete(ast_switch*);
 -
 -bool ast_switch_codegen(ast_switch*, ast_function*, bool lvalue, ir_value**);
  
  /* Label nodes
   *
   */
  struct ast_label_s
  {
-     ast_expression_common expression;
+     ast_expression        expression;
      const char *name;
      ir_block   *irblock;
      ast_goto  **gotos;
  };
  
  ast_label* ast_label_new(lex_ctx ctx, const char *name, bool undefined);
 -void ast_label_delete(ast_label*);
 -void ast_label_register_goto(ast_label*, ast_goto*);
 -
 -bool ast_label_codegen(ast_label*, ast_function*, bool lvalue, ir_value**);
  
  /* GOTO nodes
   *
   */
  struct ast_goto_s
  {
-     ast_expression_common expression;
+     ast_expression        expression;
      const char *name;
      ast_label  *target;
      ir_block   *irblock_from;
  };
  
  ast_goto* ast_goto_new(lex_ctx ctx, const char *name);
 -void ast_goto_delete(ast_goto*);
  void ast_goto_set_label(ast_goto*, ast_label*);
  
 -bool ast_goto_codegen(ast_goto*, ast_function*, bool lvalue, ir_value**);
 -
  /* CALL node
   *
   * Contains an ast_expression as target, rather than an ast_function/value.
   */
  struct ast_call_s
  {
-     ast_expression_common expression;
+     ast_expression        expression;
      ast_expression *func;
      ast_expression* *params;
      ast_expression *va_count;
  };
  ast_call* ast_call_new(lex_ctx ctx,
                         ast_expression *funcexpr);
 -void ast_call_delete(ast_call*);
 -bool ast_call_codegen(ast_call*, ast_function*, bool lvalue, ir_value**);
  bool ast_call_check_types(ast_call*);
  
  /* Blocks
   */
  struct ast_block_s
  {
-     ast_expression_common expression;
+     ast_expression        expression;
  
      ast_value*      *locals;
      ast_expression* *exprs;
  ast_block* ast_block_new(lex_ctx ctx);
  void ast_block_delete(ast_block*);
  void ast_block_set_type(ast_block*, ast_expression *from);
 -
 -bool ast_block_codegen(ast_block*, ast_function*, bool lvalue, ir_value**);
  void ast_block_collect(ast_block*, ast_expression*);
  
  bool GMQCC_WARN ast_block_add_expr(ast_block*, ast_expression*);
   */
  struct ast_function_s
  {
-     ast_node_common node;
+     ast_node        node;
  
      ast_value  *vtype;
      const char *name;
@@@ -629,23 -673,9 +629,9 @@@ void ast_function_delete(ast_function*)
  /* For "optimized" builds this can just keep returning "foo"...
   * or whatever...
   */
 -const char* ast_function_label(ast_function*, const char *prefix);
 +/*const char* ast_function_label(ast_function*, const char *prefix);*/
  
  bool ast_function_codegen(ast_function *self, ir_builder *builder);
  bool ast_generate_accessors(ast_value *asvalue, ir_builder *ir);
  
- /* Expression union
-  */
- union ast_expression_u
- {
-     ast_expression_common expression;
- };
- /* Node union
-  */
- union ast_node_u
- {
-     ast_node_common node;
- };
  #endif
diff --combined parser.c
index a9fa3f63c6488766eae2227a8adbbaabdb10e81b,9fd94f6a4e990f0dc7a2e5dfdc1f1d17d4cbb630..482410677becfaeb2749bd79bfbdf81c389b1366
+++ b/parser.c
@@@ -185,7 -185,7 +185,7 @@@ vector vec3_mulvf(vector a, float b
   * parsing
   */
  
 -bool parser_next(parser_t *parser)
 +static bool parser_next(parser_t *parser)
  {
      /* lex_do kills the previous token */
      parser->tok = lex_do(parser->lex);
@@@ -585,7 -585,7 +585,7 @@@ static bool parser_sy_apply_operator(pa
          blocks[i] = sy->out[vec_size(sy->out)+i].block;
          asvalue[i] = (ast_value*)exprs[i];
  
-         if (exprs[i]->expression.vtype == TYPE_NOEXPR &&
+         if (exprs[i]->vtype == TYPE_NOEXPR &&
              !(i != 0 && op->id == opid2('?',':')) &&
              !(i == 1 && op->id == opid1('.')))
          {
      }
  
  #define NotSameType(T) \
-              (exprs[0]->expression.vtype != exprs[1]->expression.vtype || \
-               exprs[0]->expression.vtype != T)
+              (exprs[0]->vtype != exprs[1]->vtype || \
+               exprs[0]->vtype != T)
  #define CanConstFold1(A) \
               (ast_istype((A), ast_value) && ((ast_value*)(A))->hasvalue && (((ast_value*)(A))->cvq == CV_CONST) &&\
-               (A)->expression.vtype != TYPE_FUNCTION)
+               (A)->vtype != TYPE_FUNCTION)
  #define CanConstFold(A, B) \
               (CanConstFold1(A) && CanConstFold1(B))
  #define ConstV(i) (asvalue[(i)]->constval.vvec)
              return false;
  
          case opid1('.'):
-             if (exprs[0]->expression.vtype == TYPE_VECTOR &&
-                 exprs[1]->expression.vtype == TYPE_NOEXPR)
+             if (exprs[0]->vtype == TYPE_VECTOR &&
+                 exprs[1]->vtype == TYPE_NOEXPR)
              {
                  if      (exprs[1] == (ast_expression*)parser->const_vec[0])
                      out = (ast_expression*)ast_member_new(ctx, exprs[0], 0, NULL);
                      return false;
                  }
              }
-             else if (exprs[0]->expression.vtype == TYPE_ENTITY) {
-                 if (exprs[1]->expression.vtype != TYPE_FIELD) {
+             else if (exprs[0]->vtype == TYPE_ENTITY) {
+                 if (exprs[1]->vtype != TYPE_FIELD) {
                      compile_error(ast_ctx(exprs[1]), "type error: right hand of member-operand should be an entity-field");
                      return false;
                  }
                  out = (ast_expression*)ast_entfield_new(ctx, exprs[0], exprs[1]);
              }
-             else if (exprs[0]->expression.vtype == TYPE_VECTOR) {
+             else if (exprs[0]->vtype == TYPE_VECTOR) {
                  compile_error(ast_ctx(exprs[1]), "vectors cannot be accessed this way");
                  return false;
              }
              break;
  
          case opid1('['):
-             if (exprs[0]->expression.vtype != TYPE_ARRAY &&
-                 !(exprs[0]->expression.vtype == TYPE_FIELD &&
-                   exprs[0]->expression.next->expression.vtype == TYPE_ARRAY))
+             if (exprs[0]->vtype != TYPE_ARRAY &&
+                 !(exprs[0]->vtype == TYPE_FIELD &&
+                   exprs[0]->next->vtype == TYPE_ARRAY))
              {
                  ast_type_to_string(exprs[0], ty1, sizeof(ty1));
                  compile_error(ast_ctx(exprs[0]), "cannot index value of type %s", ty1);
                  return false;
              }
-             if (exprs[1]->expression.vtype != TYPE_FLOAT) {
+             if (exprs[1]->vtype != TYPE_FLOAT) {
                  ast_type_to_string(exprs[0], ty1, sizeof(ty1));
                  compile_error(ast_ctx(exprs[1]), "index must be of type float, not %s", ty1);
                  return false;
              out = exprs[0];
              break;
          case opid2('-','P'):
-             switch (exprs[0]->expression.vtype) {
+             switch (exprs[0]->vtype) {
                  case TYPE_FLOAT:
                      if (CanConstFold1(exprs[0]))
                          out = (ast_expression*)parser_const_float(parser, -ConstF(0));
                      break;
                  default:
                  compile_error(ctx, "invalid types used in expression: cannot negate type %s",
-                               type_name[exprs[0]->expression.vtype]);
+                               type_name[exprs[0]->vtype]);
                  return false;
              }
              break;
  
          case opid2('!','P'):
-             switch (exprs[0]->expression.vtype) {
+             switch (exprs[0]->vtype) {
                  case TYPE_FLOAT:
                      if (CanConstFold1(exprs[0]))
                          out = (ast_expression*)parser_const_float(parser, !ConstF(0));
                      break;
                  default:
                  compile_error(ctx, "invalid types used in expression: cannot logically negate type %s",
-                               type_name[exprs[0]->expression.vtype]);
+                               type_name[exprs[0]->vtype]);
                  return false;
              }
              break;
  
          case opid1('+'):
-             if (exprs[0]->expression.vtype != exprs[1]->expression.vtype ||
-                 (exprs[0]->expression.vtype != TYPE_VECTOR && exprs[0]->expression.vtype != TYPE_FLOAT) )
+             if (exprs[0]->vtype != exprs[1]->vtype ||
+                 (exprs[0]->vtype != TYPE_VECTOR && exprs[0]->vtype != TYPE_FLOAT) )
              {
                  compile_error(ctx, "invalid types used in expression: cannot add type %s and %s",
-                               type_name[exprs[0]->expression.vtype],
-                               type_name[exprs[1]->expression.vtype]);
+                               type_name[exprs[0]->vtype],
+                               type_name[exprs[1]->vtype]);
                  return false;
              }
-             switch (exprs[0]->expression.vtype) {
+             switch (exprs[0]->vtype) {
                  case TYPE_FLOAT:
                      if (CanConstFold(exprs[0], exprs[1]))
                      {
                      break;
                  default:
                      compile_error(ctx, "invalid types used in expression: cannot add type %s and %s",
-                                   type_name[exprs[0]->expression.vtype],
-                                   type_name[exprs[1]->expression.vtype]);
+                                   type_name[exprs[0]->vtype],
+                                   type_name[exprs[1]->vtype]);
                      return false;
              };
              break;
          case opid1('-'):
-             if (exprs[0]->expression.vtype != exprs[1]->expression.vtype ||
-                 (exprs[0]->expression.vtype != TYPE_VECTOR && exprs[0]->expression.vtype != TYPE_FLOAT) )
+             if (exprs[0]->vtype != exprs[1]->vtype ||
+                 (exprs[0]->vtype != TYPE_VECTOR && exprs[0]->vtype != TYPE_FLOAT) )
              {
                  compile_error(ctx, "invalid types used in expression: cannot subtract type %s from %s",
-                               type_name[exprs[1]->expression.vtype],
-                               type_name[exprs[0]->expression.vtype]);
+                               type_name[exprs[1]->vtype],
+                               type_name[exprs[0]->vtype]);
                  return false;
              }
-             switch (exprs[0]->expression.vtype) {
+             switch (exprs[0]->vtype) {
                  case TYPE_FLOAT:
                      if (CanConstFold(exprs[0], exprs[1]))
                          out = (ast_expression*)parser_const_float(parser, ConstF(0) - ConstF(1));
                      break;
                  default:
                      compile_error(ctx, "invalid types used in expression: cannot subtract type %s from %s",
-                                   type_name[exprs[1]->expression.vtype],
-                                   type_name[exprs[0]->expression.vtype]);
+                                   type_name[exprs[1]->vtype],
+                                   type_name[exprs[0]->vtype]);
                      return false;
              };
              break;
          case opid1('*'):
-             if (exprs[0]->expression.vtype != exprs[1]->expression.vtype &&
-                 !(exprs[0]->expression.vtype == TYPE_VECTOR &&
-                   exprs[1]->expression.vtype == TYPE_FLOAT) &&
-                 !(exprs[1]->expression.vtype == TYPE_VECTOR &&
-                   exprs[0]->expression.vtype == TYPE_FLOAT)
+             if (exprs[0]->vtype != exprs[1]->vtype &&
+                 !(exprs[0]->vtype == TYPE_VECTOR &&
+                   exprs[1]->vtype == TYPE_FLOAT) &&
+                 !(exprs[1]->vtype == TYPE_VECTOR &&
+                   exprs[0]->vtype == TYPE_FLOAT)
                  )
              {
                  compile_error(ctx, "invalid types used in expression: cannot multiply types %s and %s",
-                               type_name[exprs[1]->expression.vtype],
-                               type_name[exprs[0]->expression.vtype]);
+                               type_name[exprs[1]->vtype],
+                               type_name[exprs[0]->vtype]);
                  return false;
              }
-             switch (exprs[0]->expression.vtype) {
+             switch (exprs[0]->vtype) {
                  case TYPE_FLOAT:
-                     if (exprs[1]->expression.vtype == TYPE_VECTOR)
+                     if (exprs[1]->vtype == TYPE_VECTOR)
                      {
                          if (CanConstFold(exprs[0], exprs[1]))
                              out = (ast_expression*)parser_const_vector(parser, vec3_mulvf(ConstV(1), ConstF(0)));
                      }
                      break;
                  case TYPE_VECTOR:
-                     if (exprs[1]->expression.vtype == TYPE_FLOAT)
+                     if (exprs[1]->vtype == TYPE_FLOAT)
                      {
                          if (CanConstFold(exprs[0], exprs[1]))
                              out = (ast_expression*)parser_const_vector(parser, vec3_mulvf(ConstV(0), ConstF(1)));
                              if (!vec.y && !vec.z) { /* 'n 0 0' * v */
                                  ++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS];
                                  out = (ast_expression*)ast_member_new(ctx, exprs[1], 0, NULL);
-                                 out->expression.node.keep = false;
+                                 out->node.keep = false;
                                  ((ast_member*)out)->rvalue = true;
                                  if (vec.x != 1)
                                      out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, (ast_expression*)parser_const_float(parser, vec.x), out);
                              else if (!vec.x && !vec.z) { /* '0 n 0' * v */
                                  ++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS];
                                  out = (ast_expression*)ast_member_new(ctx, exprs[1], 1, NULL);
-                                 out->expression.node.keep = false;
+                                 out->node.keep = false;
                                  ((ast_member*)out)->rvalue = true;
                                  if (vec.y != 1)
                                      out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, (ast_expression*)parser_const_float(parser, vec.y), out);
                              else if (!vec.x && !vec.y) { /* '0 n 0' * v */
                                  ++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS];
                                  out = (ast_expression*)ast_member_new(ctx, exprs[1], 2, NULL);
-                                 out->expression.node.keep = false;
+                                 out->node.keep = false;
                                  ((ast_member*)out)->rvalue = true;
                                  if (vec.z != 1)
                                      out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, (ast_expression*)parser_const_float(parser, vec.z), out);
                              if (!vec.y && !vec.z) { /* v * 'n 0 0' */
                                  ++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS];
                                  out = (ast_expression*)ast_member_new(ctx, exprs[0], 0, NULL);
-                                 out->expression.node.keep = false;
+                                 out->node.keep = false;
                                  ((ast_member*)out)->rvalue = true;
                                  if (vec.x != 1)
                                      out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, out, (ast_expression*)parser_const_float(parser, vec.x));
                              else if (!vec.x && !vec.z) { /* v * '0 n 0' */
                                  ++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS];
                                  out = (ast_expression*)ast_member_new(ctx, exprs[0], 1, NULL);
-                                 out->expression.node.keep = false;
+                                 out->node.keep = false;
                                  ((ast_member*)out)->rvalue = true;
                                  if (vec.y != 1)
                                      out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, out, (ast_expression*)parser_const_float(parser, vec.y));
                              else if (!vec.x && !vec.y) { /* v * '0 n 0' */
                                  ++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS];
                                  out = (ast_expression*)ast_member_new(ctx, exprs[0], 2, NULL);
-                                 out->expression.node.keep = false;
+                                 out->node.keep = false;
                                  ((ast_member*)out)->rvalue = true;
                                  if (vec.z != 1)
                                      out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, out, (ast_expression*)parser_const_float(parser, vec.z));
                      break;
                  default:
                      compile_error(ctx, "invalid types used in expression: cannot multiply types %s and %s",
-                                   type_name[exprs[1]->expression.vtype],
-                                   type_name[exprs[0]->expression.vtype]);
+                                   type_name[exprs[1]->vtype],
+                                   type_name[exprs[0]->vtype]);
                      return false;
              };
              break;
          case opid1('/'):
-             if (exprs[1]->expression.vtype != TYPE_FLOAT) {
+             if (exprs[1]->vtype != TYPE_FLOAT) {
                  ast_type_to_string(exprs[0], ty1, sizeof(ty1));
                  ast_type_to_string(exprs[1], ty2, sizeof(ty2));
                  compile_error(ctx, "invalid types used in expression: cannot divide tyeps %s and %s", ty1, ty2);
                  return false;
              }
-             if (exprs[0]->expression.vtype == TYPE_FLOAT) {
+             if (exprs[0]->vtype == TYPE_FLOAT) {
                  if (CanConstFold(exprs[0], exprs[1]))
                      out = (ast_expression*)parser_const_float(parser, ConstF(0) / ConstF(1));
                  else
                      out = (ast_expression*)ast_binary_new(ctx, INSTR_DIV_F, exprs[0], exprs[1]);
              }
-             else if (exprs[0]->expression.vtype == TYPE_VECTOR) {
+             else if (exprs[0]->vtype == TYPE_VECTOR) {
                  if (CanConstFold(exprs[0], exprs[1]))
                      out = (ast_expression*)parser_const_vector(parser, vec3_mulvf(ConstV(0), 1.0/ConstF(1)));
                  else {
          case opid1('%'):
              if (NotSameType(TYPE_FLOAT)) {
                  compile_error(ctx, "invalid types used in expression: cannot perform modulo operation between types %s and %s",
-                     type_name[exprs[0]->expression.vtype],
-                     type_name[exprs[1]->expression.vtype]);
+                     type_name[exprs[0]->vtype],
+                     type_name[exprs[1]->vtype]);
                  return false;
              }
              if (CanConstFold(exprs[0], exprs[1])) {
          case opid1('&'):
              if (NotSameType(TYPE_FLOAT)) {
                  compile_error(ctx, "invalid types used in expression: cannot perform bit operations between types %s and %s",
-                               type_name[exprs[0]->expression.vtype],
-                               type_name[exprs[1]->expression.vtype]);
+                               type_name[exprs[0]->vtype],
+                               type_name[exprs[1]->vtype]);
                  return false;
              }
              if (CanConstFold(exprs[0], exprs[1]))
          case opid2('>','>'):
              if (CanConstFold(exprs[0], exprs[1]) && ! NotSameType(TYPE_FLOAT)) {
                  if (op->id == opid2('<','<'))
 -                    out = (ast_expression*)parser_const_float(parser, (double)((int)(ConstF(0)) << (int)(ConstF(1))));
 +                    out = (ast_expression*)parser_const_float(parser, (double)((unsigned int)(ConstF(0)) << (unsigned int)(ConstF(1))));
                  else
 -                    out = (ast_expression*)parser_const_float(parser, (double)((int)(ConstF(0)) >> (int)(ConstF(1))));
 +                    out = (ast_expression*)parser_const_float(parser, (double)((unsigned int)(ConstF(0)) >> (unsigned int)(ConstF(1))));
                  break;
              }
          case opid3('<','<','='):
                      return false;
                  }
                  for (i = 0; i < 2; ++i) {
-                     if (OPTS_FLAG(CORRECT_LOGIC) && exprs[i]->expression.vtype == TYPE_VECTOR) {
+                     if (OPTS_FLAG(CORRECT_LOGIC) && exprs[i]->vtype == TYPE_VECTOR) {
                          out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_V, exprs[i]);
                          if (!out) break;
                          out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_F, out);
                              break;
                          }
                      }
-                     else if (OPTS_FLAG(FALSE_EMPTY_STRINGS) && exprs[i]->expression.vtype == TYPE_STRING) {
+                     else if (OPTS_FLAG(FALSE_EMPTY_STRINGS) && exprs[i]->vtype == TYPE_STRING) {
                          out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_S, exprs[i]);
                          if (!out) break;
                          out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_F, out);
              generated_op += INSTR_LE;
              if (NotSameType(TYPE_FLOAT)) {
                  compile_error(ctx, "invalid types used in expression: cannot perform comparison between types %s and %s",
-                               type_name[exprs[0]->expression.vtype],
-                               type_name[exprs[1]->expression.vtype]);
+                               type_name[exprs[0]->vtype],
+                               type_name[exprs[1]->vtype]);
                  return false;
              }
              out = (ast_expression*)ast_binary_new(ctx, generated_op, exprs[0], exprs[1]);
              break;
          case opid2('!', '='):
-             if (exprs[0]->expression.vtype != exprs[1]->expression.vtype) {
+             if (exprs[0]->vtype != exprs[1]->vtype) {
                  compile_error(ctx, "invalid types used in expression: cannot perform comparison between types %s and %s",
-                               type_name[exprs[0]->expression.vtype],
-                               type_name[exprs[1]->expression.vtype]);
+                               type_name[exprs[0]->vtype],
+                               type_name[exprs[1]->vtype]);
                  return false;
              }
-             out = (ast_expression*)ast_binary_new(ctx, type_ne_instr[exprs[0]->expression.vtype], exprs[0], exprs[1]);
+             out = (ast_expression*)ast_binary_new(ctx, type_ne_instr[exprs[0]->vtype], exprs[0], exprs[1]);
              break;
          case opid2('=', '='):
-             if (exprs[0]->expression.vtype != exprs[1]->expression.vtype) {
+             if (exprs[0]->vtype != exprs[1]->vtype) {
                  compile_error(ctx, "invalid types used in expression: cannot perform comparison between types %s and %s",
-                               type_name[exprs[0]->expression.vtype],
-                               type_name[exprs[1]->expression.vtype]);
+                               type_name[exprs[0]->vtype],
+                               type_name[exprs[1]->vtype]);
                  return false;
              }
-             out = (ast_expression*)ast_binary_new(ctx, type_eq_instr[exprs[0]->expression.vtype], exprs[0], exprs[1]);
+             out = (ast_expression*)ast_binary_new(ctx, type_eq_instr[exprs[0]->vtype], exprs[0], exprs[1]);
              break;
  
          case opid1('='):
              if (ast_istype(exprs[0], ast_entfield)) {
                  ast_expression *field = ((ast_entfield*)exprs[0])->field;
                  if (OPTS_FLAG(ADJUST_VECTOR_FIELDS) &&
-                     exprs[0]->expression.vtype == TYPE_FIELD &&
-                     exprs[0]->expression.next->expression.vtype == TYPE_VECTOR)
+                     exprs[0]->vtype == TYPE_FIELD &&
+                     exprs[0]->next->vtype == TYPE_VECTOR)
                  {
                      assignop = type_storep_instr[TYPE_VECTOR];
                  }
                  else
-                     assignop = type_storep_instr[exprs[0]->expression.vtype];
-                 if (assignop == VINSTR_END || !ast_compare_type(field->expression.next, exprs[1]))
+                     assignop = type_storep_instr[exprs[0]->vtype];
+                 if (assignop == VINSTR_END || !ast_compare_type(field->next, exprs[1]))
                  {
-                     ast_type_to_string(field->expression.next, ty1, sizeof(ty1));
+                     ast_type_to_string(field->next, ty1, sizeof(ty1));
                      ast_type_to_string(exprs[1], ty2, sizeof(ty2));
                      if (OPTS_FLAG(ASSIGN_FUNCTION_TYPES) &&
-                         field->expression.next->expression.vtype == TYPE_FUNCTION &&
-                         exprs[1]->expression.vtype == TYPE_FUNCTION)
+                         field->next->vtype == TYPE_FUNCTION &&
+                         exprs[1]->vtype == TYPE_FUNCTION)
                      {
                          (void)!compile_warning(ctx, WARN_ASSIGN_FUNCTION_TYPES,
                                                 "invalid types in assignment: cannot assign %s to %s", ty2, ty1);
              else
              {
                  if (OPTS_FLAG(ADJUST_VECTOR_FIELDS) &&
-                     exprs[0]->expression.vtype == TYPE_FIELD &&
-                     exprs[0]->expression.next->expression.vtype == TYPE_VECTOR)
+                     exprs[0]->vtype == TYPE_FIELD &&
+                     exprs[0]->next->vtype == TYPE_VECTOR)
                  {
                      assignop = type_store_instr[TYPE_VECTOR];
                  }
                  else {
-                     assignop = type_store_instr[exprs[0]->expression.vtype];
+                     assignop = type_store_instr[exprs[0]->vtype];
                  }
  
                  if (assignop == VINSTR_END) {
                      ast_type_to_string(exprs[0], ty1, sizeof(ty1));
                      ast_type_to_string(exprs[1], ty2, sizeof(ty2));
                      if (OPTS_FLAG(ASSIGN_FUNCTION_TYPES) &&
-                         exprs[0]->expression.vtype == TYPE_FUNCTION &&
-                         exprs[1]->expression.vtype == TYPE_FUNCTION)
+                         exprs[0]->vtype == TYPE_FUNCTION &&
+                         exprs[1]->vtype == TYPE_FUNCTION)
                      {
                          (void)!compile_warning(ctx, WARN_ASSIGN_FUNCTION_TYPES,
                                                 "invalid types in assignment: cannot assign %s to %s", ty2, ty1);
          case opid3('+','+','P'):
          case opid3('-','-','P'):
              /* prefix ++ */
-             if (exprs[0]->expression.vtype != TYPE_FLOAT) {
+             if (exprs[0]->vtype != TYPE_FLOAT) {
                  ast_type_to_string(exprs[0], ty1, sizeof(ty1));
                  compile_error(ast_ctx(exprs[0]), "invalid type for prefix increment: %s", ty1);
                  return false;
          case opid3('S','+','+'):
          case opid3('S','-','-'):
              /* prefix ++ */
-             if (exprs[0]->expression.vtype != TYPE_FLOAT) {
+             if (exprs[0]->vtype != TYPE_FLOAT) {
                  ast_type_to_string(exprs[0], ty1, sizeof(ty1));
                  compile_error(ast_ctx(exprs[0]), "invalid type for suffix increment: %s", ty1);
                  return false;
              break;
          case opid2('+','='):
          case opid2('-','='):
-             if (exprs[0]->expression.vtype != exprs[1]->expression.vtype ||
-                 (exprs[0]->expression.vtype != TYPE_VECTOR && exprs[0]->expression.vtype != TYPE_FLOAT) )
+             if (exprs[0]->vtype != exprs[1]->vtype ||
+                 (exprs[0]->vtype != TYPE_VECTOR && exprs[0]->vtype != TYPE_FLOAT) )
              {
                  ast_type_to_string(exprs[0], ty1, sizeof(ty1));
                  ast_type_to_string(exprs[1], ty2, sizeof(ty2));
                  compile_error(ctx, "assignment to constant `%s`", asvalue[0]->name);
              }
              if (ast_istype(exprs[0], ast_entfield))
-                 assignop = type_storep_instr[exprs[0]->expression.vtype];
+                 assignop = type_storep_instr[exprs[0]->vtype];
              else
-                 assignop = type_store_instr[exprs[0]->expression.vtype];
-             switch (exprs[0]->expression.vtype) {
+                 assignop = type_store_instr[exprs[0]->vtype];
+             switch (exprs[0]->vtype) {
                  case TYPE_FLOAT:
                      out = (ast_expression*)ast_binstore_new(ctx, assignop,
                                                              (op->id == opid2('+','=') ? INSTR_ADD_F : INSTR_SUB_F),
                      break;
                  default:
                      compile_error(ctx, "invalid types used in expression: cannot add or subtract type %s and %s",
-                                   type_name[exprs[0]->expression.vtype],
-                                   type_name[exprs[1]->expression.vtype]);
+                                   type_name[exprs[0]->vtype],
+                                   type_name[exprs[1]->vtype]);
                      return false;
              };
              break;
          case opid2('*','='):
          case opid2('/','='):
-             if (exprs[1]->expression.vtype != TYPE_FLOAT ||
-                 !(exprs[0]->expression.vtype == TYPE_FLOAT ||
-                   exprs[0]->expression.vtype == TYPE_VECTOR))
+             if (exprs[1]->vtype != TYPE_FLOAT ||
+                 !(exprs[0]->vtype == TYPE_FLOAT ||
+                   exprs[0]->vtype == TYPE_VECTOR))
              {
                  ast_type_to_string(exprs[0], ty1, sizeof(ty1));
                  ast_type_to_string(exprs[1], ty2, sizeof(ty2));
                  compile_error(ctx, "assignment to constant `%s`", asvalue[0]->name);
              }
              if (ast_istype(exprs[0], ast_entfield))
-                 assignop = type_storep_instr[exprs[0]->expression.vtype];
+                 assignop = type_storep_instr[exprs[0]->vtype];
              else
-                 assignop = type_store_instr[exprs[0]->expression.vtype];
-             switch (exprs[0]->expression.vtype) {
+                 assignop = type_store_instr[exprs[0]->vtype];
+             switch (exprs[0]->vtype) {
                  case TYPE_FLOAT:
                      out = (ast_expression*)ast_binstore_new(ctx, assignop,
                                                              (op->id == opid2('*','=') ? INSTR_MUL_F : INSTR_DIV_F),
                      break;
                  default:
                      compile_error(ctx, "invalid types used in expression: cannot add or subtract type %s and %s",
-                                   type_name[exprs[0]->expression.vtype],
-                                   type_name[exprs[1]->expression.vtype]);
+                                   type_name[exprs[0]->vtype],
+                                   type_name[exprs[1]->vtype]);
                      return false;
              };
              break;
                  compile_error(ctx, "assignment to constant `%s`", asvalue[0]->name);
              }
              if (ast_istype(exprs[0], ast_entfield))
-                 assignop = type_storep_instr[exprs[0]->expression.vtype];
+                 assignop = type_storep_instr[exprs[0]->vtype];
              else
-                 assignop = type_store_instr[exprs[0]->expression.vtype];
+                 assignop = type_store_instr[exprs[0]->vtype];
              out = (ast_expression*)ast_binstore_new(ctx, assignop,
                                                      (op->id == opid2('&','=') ? INSTR_BITAND : INSTR_BITOR),
                                                      exprs[0], exprs[1]);
                  return false;
              }
              if (ast_istype(exprs[0], ast_entfield))
-                 assignop = type_storep_instr[exprs[0]->expression.vtype];
+                 assignop = type_storep_instr[exprs[0]->vtype];
              else
-                 assignop = type_store_instr[exprs[0]->expression.vtype];
+                 assignop = type_store_instr[exprs[0]->vtype];
              out = (ast_expression*)ast_binary_new(ctx, INSTR_BITAND, exprs[0], exprs[1]);
              if (!out)
                  return false;
              break;
  
          case opid2('~', 'P'):
-             if (exprs[0]->expression.vtype != TYPE_FLOAT) {
+             if (exprs[0]->vtype != TYPE_FLOAT) {
                  ast_type_to_string(exprs[0], ty1, sizeof(ty1));
                  compile_error(ast_ctx(exprs[0]), "invalid type for bit not: %s", ty1);
                  return false;
@@@ -1571,7 -1571,7 +1571,7 @@@ static bool parser_close_call(parser_t 
  
      if (ast_istype(fun, ast_value)) {
          funval = (ast_value*)fun;
-         if ((fun->expression.flags & AST_FLAG_VARIADIC) &&
+         if ((fun->flags & AST_FLAG_VARIADIC) &&
              !(/*funval->cvq == CV_CONST && */ funval->hasvalue && funval->constval.vfunc->builtin))
          {
              call->va_count = (ast_expression*)parser_const_float(parser, (double)paramcount);
      /* overwrite fid, the function, with a call */
      sy->out[fid] = syexp(call->expression.node.context, (ast_expression*)call);
  
-     if (fun->expression.vtype != TYPE_FUNCTION) {
-         parseerror(parser, "not a function (%s)", type_name[fun->expression.vtype]);
+     if (fun->vtype != TYPE_FUNCTION) {
+         parseerror(parser, "not a function (%s)", type_name[fun->vtype]);
          return false;
      }
  
-     if (!fun->expression.next) {
+     if (!fun->next) {
          parseerror(parser, "could not determine function return type");
          return false;
      } else {
          ast_value *fval = (ast_istype(fun, ast_value) ? ((ast_value*)fun) : NULL);
  
-         if (fun->expression.flags & AST_FLAG_DEPRECATED) {
+         if (fun->flags & AST_FLAG_DEPRECATED) {
              if (!fval) {
                  return !parsewarning(parser, WARN_DEPRECATED,
                          "call to function (which is marked deprecated)\n",
                      ast_ctx(fun).line);
          }
  
-         if (vec_size(fun->expression.params) != paramcount &&
-             !((fun->expression.flags & AST_FLAG_VARIADIC) &&
-               vec_size(fun->expression.params) < paramcount))
+         if (vec_size(fun->params) != paramcount &&
+             !((fun->flags & AST_FLAG_VARIADIC) &&
+               vec_size(fun->params) < paramcount))
          {
-             const char *fewmany = (vec_size(fun->expression.params) > paramcount) ? "few" : "many";
+             const char *fewmany = (vec_size(fun->params) > paramcount) ? "few" : "many";
              if (fval)
                  return !parsewarning(parser, WARN_INVALID_PARAMETER_COUNT,
                                       "too %s parameters for call to %s: expected %i, got %i\n"
                                       " -> `%s` has been declared here: %s:%i",
-                                      fewmany, fval->name, (int)vec_size(fun->expression.params), (int)paramcount,
+                                      fewmany, fval->name, (int)vec_size(fun->params), (int)paramcount,
                                       fval->name, ast_ctx(fun).file, (int)ast_ctx(fun).line);
              else
                  return !parsewarning(parser, WARN_INVALID_PARAMETER_COUNT,
                                       "too %s parameters for function call: expected %i, got %i\n"
                                       " -> it has been declared here: %s:%i",
-                                      fewmany, (int)vec_size(fun->expression.params), (int)paramcount,
+                                      fewmany, (int)vec_size(fun->params), (int)paramcount,
                                       ast_ctx(fun).file, (int)ast_ctx(fun).line);
          }
      }
@@@ -1881,7 -1881,7 +1881,7 @@@ static bool parse_sya_operand(parser_t 
              /* When adding more intrinsics, fix the above condition */
              prev = NULL;
          }
-         if (prev && prev->expression.vtype == TYPE_VECTOR && ctoken[0] >= 'x' && ctoken[0] <= 'z' && !ctoken[1])
+         if (prev && prev->vtype == TYPE_VECTOR && ctoken[0] >= 'x' && ctoken[0] <= 'z' && !ctoken[1])
          {
              var = (ast_expression*)parser->const_vec[ctoken[0]-'x'];
          } else {
@@@ -2363,13 -2363,13 +2363,13 @@@ static ast_expression* process_conditio
      ast_unary *unary;
      ast_expression *prev;
  
-     if (cond->expression.vtype == TYPE_VOID || cond->expression.vtype >= TYPE_VARIANT) {
+     if (cond->vtype == TYPE_VOID || cond->vtype >= TYPE_VARIANT) {
          char ty[1024];
          ast_type_to_string(cond, ty, sizeof(ty));
          compile_error(ast_ctx(cond), "invalid type for if() condition: %s", ty);
      }
  
-     if (OPTS_FLAG(FALSE_EMPTY_STRINGS) && cond->expression.vtype == TYPE_STRING)
+     if (OPTS_FLAG(FALSE_EMPTY_STRINGS) && cond->vtype == TYPE_STRING)
      {
          prev = cond;
          cond = (ast_expression*)ast_unary_new(ast_ctx(cond), INSTR_NOT_S, cond);
          }
          ifnot = !ifnot;
      }
-     else if (OPTS_FLAG(CORRECT_LOGIC) && cond->expression.vtype == TYPE_VECTOR)
+     else if (OPTS_FLAG(CORRECT_LOGIC) && cond->vtype == TYPE_VECTOR)
      {
          /* vector types need to be cast to true booleans */
          ast_binary *bin = (ast_binary*)cond;
@@@ -2911,8 -2911,8 +2911,8 @@@ static bool parse_return(parser_t *pars
          if (!exp)
              return false;
  
-         if (exp->expression.vtype != TYPE_NIL &&
-             exp->expression.vtype != expected->expression.next->expression.vtype)
+         if (exp->vtype != TYPE_NIL &&
+             exp->vtype != ((ast_expression*)expected)->next->vtype)
          {
              parseerror(parser, "return with invalid expression");
          }
      } else {
          if (!parser_next(parser))
              parseerror(parser, "parse error");
-         if (expected->expression.next->expression.vtype != TYPE_VOID) {
+         if (expected->expression.next->vtype != TYPE_VOID) {
              (void)!parsewarning(parser, WARN_MISSING_RETURN_VALUES, "return without value");
          }
          ret = ast_return_new(ctx, NULL);
@@@ -4067,9 -4067,9 +4067,9 @@@ static bool parse_function_body(parser_
              /* qc allows the use of not-yet-declared functions here
               * - this automatically creates a prototype */
              ast_value      *thinkfunc;
-             ast_expression *functype = fld_think->expression.next;
+             ast_expression *functype = fld_think->next;
  
-             thinkfunc = ast_value_new(parser_ctx(parser), parser_tokval(parser), functype->expression.vtype);
+             thinkfunc = ast_value_new(parser_ctx(parser), parser_tokval(parser), functype->vtype);
              if (!thinkfunc) { /* || !ast_type_adopt(thinkfunc, functype)*/
                  ast_unref(framenum);
                  parseerror(parser, "failed to create implicit prototype for `%s`", parser_tokval(parser));
  
          if (param->expression.vtype != TYPE_VECTOR &&
              (param->expression.vtype != TYPE_FIELD ||
-              param->expression.next->expression.vtype != TYPE_VECTOR))
+              param->expression.next->vtype != TYPE_VECTOR))
          {
              continue;
          }
@@@ -4354,7 -4354,7 +4354,7 @@@ static ast_expression *array_setter_nod
          ast_store       *st;
          int assignop = type_store_instr[value->expression.vtype];
  
-         if (value->expression.vtype == TYPE_FIELD && value->expression.next->expression.vtype == TYPE_VECTOR)
+         if (value->expression.vtype == TYPE_FIELD && value->expression.next->vtype == TYPE_VECTOR)
              assignop = INSTR_STORE_V;
  
          subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)parser_const_float(parser, from));
@@@ -4420,7 -4420,7 +4420,7 @@@ static ast_expression *array_field_sett
          ast_store       *st;
          int assignop = type_storep_instr[value->expression.vtype];
  
-         if (value->expression.vtype == TYPE_FIELD && value->expression.next->expression.vtype == TYPE_VECTOR)
+         if (value->expression.vtype == TYPE_FIELD && value->expression.next->vtype == TYPE_VECTOR)
              assignop = INSTR_STOREP_V;
  
          subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)parser_const_float(parser, from));
@@@ -5271,7 -5271,7 +5271,7 @@@ static bool parse_variable(parser_t *pa
              {
                  /* deal with other globals */
                  old = parser_find_global(parser, var->name);
-                 if (old && var->expression.vtype == TYPE_FUNCTION && old->expression.vtype == TYPE_FUNCTION)
+                 if (old && var->expression.vtype == TYPE_FUNCTION && old->vtype == TYPE_FUNCTION)
                  {
                      /* This is a function which had a prototype */
                      if (!ast_istype(old, ast_value)) {
              if (var->expression.vtype == TYPE_VECTOR)
                  isvector = true;
              else if (var->expression.vtype == TYPE_FIELD &&
-                      var->expression.next->expression.vtype == TYPE_VECTOR)
+                      var->expression.next->vtype == TYPE_VECTOR)
                  isvector = true;
  
              if (isvector) {
                              return false;
                          }
  
-                         if (var->expression.vtype != find->expression.vtype) {
+                         if (var->expression.vtype != find->vtype) {
                              char ty1[1024];
                              char ty2[1024];
  
          }
          else if (!localblock && !nofields &&
                   var->expression.vtype == TYPE_FIELD &&
-                  var->expression.next->expression.vtype == TYPE_ARRAY)
+                  var->expression.next->vtype == TYPE_ARRAY)
          {
              char name[1024];
              ast_expression *telem;
@@@ -5814,7 -5814,6 +5814,7 @@@ static ast_expression* parse_expression
                  }
                  vec_free(sy.out);
                  vec_free(sy.ops);
 +                vec_free(sy.argc);
                  var->cvq = cvq;
              }
          }
@@@ -5985,7 -5984,7 +5985,7 @@@ static void generate_checksum(parser_t 
          if (!ast_istype(parser->fields[i], ast_value))
              continue;
          value = (ast_value*)(parser->fields[i]);
-         switch (value->expression.next->expression.vtype) {
+         switch (value->expression.next->vtype) {
              case TYPE_FLOAT:    crc = progdefs_crc_both(crc, "\tfloat\t"); break;
              case TYPE_VECTOR:   crc = progdefs_crc_both(crc, "\tvec3_t\t"); break;
              case TYPE_STRING:   crc = progdefs_crc_both(crc, "\tstring_t\t"); break;
@@@ -6070,7 -6069,7 +6070,7 @@@ parser_t *parser_create(
      return parser;
  }
  
 -bool parser_compile(parser_t *parser)
 +static bool parser_compile(parser_t *parser)
  {
      /* initial lexer/parser state */
      parser->lex->flags.noops = true;
@@@ -6236,11 -6235,11 +6236,11 @@@ bool parser_finish(parser_t *parser, co
              ast_expression *subtype;
              field->hasvalue = true;
              subtype = field->expression.next;
-             ifld = ir_builder_create_field(ir, field->name, subtype->expression.vtype);
-             if (subtype->expression.vtype == TYPE_FIELD)
-                 ifld->fieldtype = subtype->expression.next->expression.vtype;
-             else if (subtype->expression.vtype == TYPE_FUNCTION)
-                 ifld->outtype = subtype->expression.next->expression.vtype;
+             ifld = ir_builder_create_field(ir, field->name, subtype->vtype);
+             if (subtype->vtype == TYPE_FIELD)
+                 ifld->fieldtype = subtype->next->vtype;
+             else if (subtype->vtype == TYPE_FUNCTION)
+                 ifld->outtype = subtype->next->vtype;
              (void)!ir_value_set_field(field->ir_v, ifld);
          }
      }
      }
      for (i = 0; i < vec_size(parser->fields); ++i) {
          ast_value *asvalue;
-         asvalue = (ast_value*)(parser->fields[i]->expression.next);
+         asvalue = (ast_value*)(parser->fields[i]->next);
  
          if (!ast_istype((ast_expression*)asvalue, ast_value))
              continue;