]> de.git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - ast.c
Add test alias to check for make file
[xonotic/gmqcc.git] / ast.c
diff --git a/ast.c b/ast.c
index 89d738cd5d40cc060e9236f41f168275b7ae167a..2b4a456ebb08e5e388d79bbe9a910d49c51d1a9e 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -1,6 +1,7 @@
 /*
- * Copyright (C) 2012
+ * 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
@@ -203,14 +204,20 @@ ast_expression* ast_type_copy(lex_ctx ctx, const ast_expression *ex)
 
 bool ast_compare_type(ast_expression *a, ast_expression *b)
 {
+    if (a->expression.vtype == TYPE_NIL ||
+        b->expression.vtype == TYPE_NIL)
+        return true;
     if (a->expression.vtype != b->expression.vtype)
         return false;
     if (!a->expression.next != !b->expression.next)
         return false;
     if (vec_size(a->expression.params) != vec_size(b->expression.params))
         return false;
-    if (a->expression.flags != b->expression.flags)
+    if ((a->expression.flags & AST_FLAG_TYPE_MASK) !=
+        (b->expression.flags & AST_FLAG_TYPE_MASK) )
+    {
         return false;
+    }
     if (vec_size(a->expression.params)) {
         size_t i;
         for (i = 0; i < vec_size(a->expression.params); ++i) {
@@ -338,6 +345,7 @@ ast_value* ast_value_new(lex_ctx ctx, const char *name, int t)
 
     self->setter = NULL;
     self->getter = NULL;
+    self->desc   = NULL;
 
     return self;
 }
@@ -365,6 +373,10 @@ void ast_value_delete(ast_value* self)
     }
     if (self->ir_values)
         mem_d(self->ir_values);
+
+    if (self->desc)
+        mem_d(self->desc);
+
     ast_expression_delete((ast_expression*)self);
     mem_d(self);
 }
@@ -570,7 +582,8 @@ ast_member* ast_member_new(lex_ctx ctx, ast_expression *owner, unsigned int fiel
         self->expression.next = ast_shallow_type(ctx, TYPE_FLOAT);
     }
 
-    self->owner = owner;
+    self->rvalue = false;
+    self->owner  = owner;
     ast_propagate_effects(self, owner);
 
     self->field = field;
@@ -683,6 +696,7 @@ void ast_ifthen_delete(ast_ifthen *self)
 
 ast_ternary* ast_ternary_new(lex_ctx ctx, ast_expression *cond, ast_expression *ontrue, ast_expression *onfalse)
 {
+    ast_expression *exprtype = ontrue;
     ast_instantiate(ast_ternary, ctx, ast_ternary_delete);
     /* This time NEITHER must be NULL */
     if (!ontrue || !onfalse) {
@@ -698,7 +712,9 @@ ast_ternary* ast_ternary_new(lex_ctx ctx, ast_expression *cond, ast_expression *
     ast_propagate_effects(self, ontrue);
     ast_propagate_effects(self, onfalse);
 
-    if (!ast_type_adopt(self, ontrue)) {
+    if (ontrue->expression.vtype == TYPE_NIL)
+        exprtype = onfalse;
+    if (!ast_type_adopt(self, exprtype)) {
         ast_ternary_delete(self);
         return NULL;
     }
@@ -708,9 +724,12 @@ ast_ternary* ast_ternary_new(lex_ctx ctx, ast_expression *cond, ast_expression *
 
 void ast_ternary_delete(ast_ternary *self)
 {
-    ast_unref(self->cond);
-    ast_unref(self->on_true);
-    ast_unref(self->on_false);
+    /* the if()s are only there because computed-gotos can set them
+     * to NULL
+     */
+    if (self->cond)     ast_unref(self->cond);
+    if (self->on_true)  ast_unref(self->on_true);
+    if (self->on_false) ast_unref(self->on_false);
     ast_expression_delete((ast_expression*)self);
     mem_d(self);
 }
@@ -810,14 +829,17 @@ void ast_switch_delete(ast_switch *self)
     mem_d(self);
 }
 
-ast_label* ast_label_new(lex_ctx ctx, const char *name)
+ast_label* ast_label_new(lex_ctx ctx, const char *name, bool undefined)
 {
     ast_instantiate(ast_label, ctx, ast_label_delete);
     ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_label_codegen);
 
-    self->name    = util_strdup(name);
-    self->irblock = NULL;
-    self->gotos   = NULL;
+    self->expression.vtype = TYPE_NOEXPR;
+
+    self->name      = util_strdup(name);
+    self->irblock   = NULL;
+    self->gotos     = NULL;
+    self->undefined = undefined;
 
     return self;
 }
@@ -899,7 +921,8 @@ bool ast_call_check_types(ast_call *self)
         count = vec_size(func->expression.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->expression.params[i])))
+        {
             char texp[1024];
             char tgot[1024];
             ast_type_to_string(self->params[i], tgot, sizeof(tgot));
@@ -1829,6 +1852,7 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va
         }
 
         self->expression.outr = *out;
+        codegen_output_type(self, *out);
         return true;
     }
 
@@ -1845,6 +1869,7 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va
     if (!*out)
         return false;
     self->expression.outr = *out;
+    codegen_output_type(self, *out);
 
     return true;
 }
@@ -2082,14 +2107,17 @@ bool ast_member_codegen(ast_member *self, ast_function *func, bool lvalue, ir_va
     ir_value *vec;
 
     /* in QC this is always an lvalue */
-    (void)lvalue;
+    if (lvalue && self->rvalue) {
+        compile_error(ast_ctx(self), "not an l-value (member access)");
+        return false;
+    }
     if (self->expression.outl) {
         *out = self->expression.outl;
         return true;
     }
 
     cgen = self->owner->expression.codegen;
-    if (!(*cgen)((ast_expression*)(self->owner), func, true, &vec))
+    if (!(*cgen)((ast_expression*)(self->owner), func, false, &vec))
         return false;
 
     if (vec->vtype != TYPE_VECTOR &&
@@ -2379,15 +2407,18 @@ bool ast_ternary_codegen(ast_ternary *self, ast_function *func, bool lvalue, ir_
     /* Here, now, we need a PHI node
      * but first some sanity checking...
      */
-    if (trueval->vtype != falseval->vtype) {
+    if (trueval->vtype != falseval->vtype && trueval->vtype != TYPE_NIL && falseval->vtype != TYPE_NIL) {
         /* error("ternary with different types on the two sides"); */
+        compile_error(ast_ctx(self), "internal error: ternary operand types invalid");
         return false;
     }
 
     /* create PHI */
-    phi = ir_block_create_phi(merge, ast_ctx(self), ast_function_label(func, "phi"), trueval->vtype);
-    if (!phi)
+    phi = ir_block_create_phi(merge, ast_ctx(self), ast_function_label(func, "phi"), self->expression.vtype);
+    if (!phi) {
+        compile_error(ast_ctx(self), "internal error: failed to generate phi node");
         return false;
+    }
     ir_phi_add(phi, ontrue_out,  trueval);
     ir_phi_add(phi, onfalse_out, falseval);
 
@@ -2843,6 +2874,11 @@ bool ast_label_codegen(ast_label *self, ast_function *func, bool lvalue, ir_valu
     size_t i;
     ir_value *dummy;
 
+    if (self->undefined) {
+        compile_error(ast_ctx(self), "internal error: ast_label never defined");
+        return false;
+    }
+
     *out = NULL;
     if (lvalue) {
         compile_error(ast_ctx(self), "internal error: ast_label cannot be an lvalue");