]> git.rm.cloudns.org Git - xonotic/gmqcc.git/commitdiff
assignable return value now lives in ast_function, as globals can get overwritten...
authorWolfgang Bumiller <wry.git@bumiller.com>
Wed, 29 May 2013 14:51:59 +0000 (16:51 +0200)
committerWolfgang Bumiller <wry.git@bumiller.com>
Wed, 29 May 2013 14:51:59 +0000 (16:51 +0200)
ast.c
ast.h
parser.c

diff --git a/ast.c b/ast.c
index 50396538a32cba1d1a0e4f699bfd3c80d20a9afc..4af3e3cafbd894c7b3beda8e736c0f48aec743ff 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -1104,6 +1104,7 @@ ast_function* ast_function_new(lex_ctx ctx, const char *name, ast_value *vtype)
     self->varargs          = NULL;
     self->argc             = NULL;
     self->fixedparams      = NULL;
+    self->return_value     = NULL;
 
     return self;
 }
@@ -1133,6 +1134,8 @@ void ast_function_delete(ast_function *self)
         ast_delete(self->argc);
     if (self->fixedparams)
         ast_unref(self->fixedparams);
+    if (self->return_value)
+        ast_unref(self->return_value);
     mem_d(self);
 }
 
@@ -1625,6 +1628,12 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir)
         return true;
     }
 
+    // have a local return value variable?
+    if (self->return_value) {
+        if (!ast_local_codegen(self->return_value, self->ir_func, false))
+            return false;
+    }
+
     if (!vec_size(self->blocks)) {
         compile_error(ast_ctx(self), "function `%s` has no body", self->name);
         return false;
diff --git a/ast.h b/ast.h
index c624a1fb1dc24e88738a532b9a84a71a9c8f0239..a0fa14defca70bfadeeee0224bf5936d6f6249b4 100644 (file)
--- a/ast.h
+++ b/ast.h
@@ -622,6 +622,7 @@ struct ast_function_s
     ast_value   *varargs;
     ast_value   *argc;
     ast_value   *fixedparams;
+    ast_value   *return_value;
 };
 ast_function* ast_function_new(lex_ctx ctx, const char *name, ast_value *vtype);
 /* This will NOT delete the underlying ast_value */
index d0563c1ac43fbb21fd34705b8cd27798767b2cf7..582379374a62f613b05f9e190bdbcfcf3c483de9 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -106,13 +106,6 @@ typedef struct parser_s {
 
     /* code generator */
     code_t     *code;
-    
-    /* vector of global return vars.
-     * for example, you can return string, float, vector, or other
-     * things, hese will be created as globals here instead of
-     * locals in a function (saves space).
-     */
-    ast_value     **returns;
 } parser_t;
 
 static ast_expression * const intrinsic_debug_typestring = (ast_expression*)0x1;
@@ -352,29 +345,6 @@ static ast_expression* parser_find_global(parser_t *parser, const char *name)
     return (ast_expression*)util_htget(parser->htglobals, name);
 }
 
-static ast_value* parser_find_returnvalue(parser_t *parser, int vtype)
-{
-    ast_value *out;
-    size_t     i;
-    char      *name = NULL;
-    
-    /* find existing global for the job */
-    for (i = 0; i < vec_size(parser->returns); i++)
-        if (parser->returns[i]->expression.vtype == vtype)
-            return parser->returns[i];
-            
-    util_asprintf(&name, "#ret_%s", type_name[vtype]);
-            
-    out           = ast_value_new(parser_ctx(parser), name, vtype);
-    out->hasvalue = false;
-    out->isimm    = false;
-    
-    vec_push(parser->returns, out);
-    
-    mem_d(name);
-    return out;
-}
-
 static ast_expression* parser_find_param(parser_t *parser, const char *name)
 {
     size_t i;
@@ -2926,7 +2896,7 @@ static bool parse_return(parser_t *parser, ast_block *block, ast_expression **ou
     ast_expression *exp      = NULL;
     ast_expression *var      = NULL;
     ast_return     *ret      = NULL;
-    ast_expression *find     = NULL;
+    ast_value      *retval   = parser->function->return_value;
     ast_value      *expected = parser->function->vtype;
 
     lex_ctx ctx = parser_ctx(parser);
@@ -2944,34 +2914,47 @@ static bool parse_return(parser_t *parser, ast_block *block, ast_expression **ou
             parseerror(parser, "return assignments not activated, try using -freturn-assigments");
             return false;
         }
-            
+
+        if (type_store_instr[expected->expression.next->vtype] == VINSTR_END) {
+            char ty1[1024];
+            ast_type_to_string(expected->expression.next, ty1, sizeof(ty1));
+            parseerror(parser, "invalid return type: `%s'", ty1);
+            return false;
+        }
+
         if (!parser_next(parser)) {
             parseerror(parser, "expected return assignment expression");
             return false;
         }
-        
+
         if (!(exp = parse_expression_leave(parser, false, false, false)))
             return false;
-            
-        if (exp->vtype != TYPE_NIL &&
-            exp->vtype != ((ast_expression*)expected)->next->vtype)
-        {
-            parseerror(parser, "return assignment with invalid expression");
+
+        /* prepare the return value */
+        if (!retval) {
+            retval = ast_value_new(ctx, "#LOCAL_RETURN", TYPE_VOID);
+            ast_type_adopt(retval, expected->expression.next);
+            parser->function->return_value = retval;
+        }
+
+        if (!ast_compare_type(exp, (ast_expression*)retval)) {
+            char ty1[1024], ty2[1024];
+            ast_type_to_string(exp, ty1, sizeof(ty1));
+            ast_type_to_string(&retval->expression, ty2, sizeof(ty2));
+            parseerror(parser, "invalid type for return value: `%s', expected `%s'", ty1, ty2);
         }
-        
+
         /* store to 'return' local variable */
         var = (ast_expression*)ast_store_new(
             ctx,
-            type_store_instr[exp->vtype],
-            (ast_expression*)parser_find_returnvalue(parser, exp->vtype),
-            (ast_expression*)exp
-        );
-        
+            type_store_instr[expected->expression.next->vtype],
+            (ast_expression*)retval, exp);
+
         if (!var) {
             ast_unref(exp);
             return false;
         }
-        
+
         *out = var;
         return true;
     }
@@ -2995,16 +2978,12 @@ static bool parse_return(parser_t *parser, ast_block *block, ast_expression **ou
     } else {
         if (!parser_next(parser))
             parseerror(parser, "parse error");
-            
-        /* build expression to return */
-        if ((find = (ast_expression*)parser_find_returnvalue(parser, expected->expression.next->vtype)) && OPTS_FLAG(RETURN_ASSIGNMENTS))
-            ret = ast_return_new(ctx, find);
-            
-        else if (expected->expression.next->vtype != TYPE_VOID)
+
+        if (!retval && expected->expression.next->vtype != TYPE_VOID)
         {
             (void)!parsewarning(parser, WARN_MISSING_RETURN_VALUES, "return without value");
-            ret = ast_return_new(ctx, NULL);
         }
+        ret = ast_return_new(ctx, (ast_expression*)retval);
     }
     *out = (ast_expression*)ret;
     return true;
@@ -6144,7 +6123,6 @@ parser_t *parser_create()
         parser->reserved_version = NULL;
     }
 
-    parser->returns = NULL;
     return parser;
 }
 
@@ -6226,9 +6204,6 @@ void parser_cleanup(parser_t *parser)
     for (i = 0; i < vec_size(parser->globals); ++i) {
         ast_delete(parser->globals[i]);
     }
-    for (i = 0; i < vec_size(parser->returns); ++i) {
-        ast_delete(parser->returns[i]);
-    }
     vec_free(parser->accessors);
     vec_free(parser->functions);
     vec_free(parser->imm_vector);
@@ -6420,13 +6395,6 @@ bool parser_finish(parser_t *parser, const char *output)
             return false;
         }
     }
-    for (i = 0; i < vec_size(parser->returns); ++i) {
-        if (!ast_global_codegen(parser->returns[i], ir, false)) {
-            con_out("internal error: failed to generate return assignment %s\n", parser->returns[i]->name);
-            ir_builder_delete(ir);
-            return false;
-        }
-    }
     if (parser->reserved_version &&
         !ast_global_codegen(parser->reserved_version, ir, false))
     {