assignable return value now lives in ast_function, as globals can get overwritten randomly; removed parser_find_retval; updated parse_return

This commit is contained in:
Wolfgang Bumiller 2013-05-29 16:51:59 +02:00
parent db6ca6c5f8
commit afdc0c9dc8
3 changed files with 41 additions and 63 deletions

9
ast.c
View file

@ -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;

1
ast.h
View file

@ -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 */

View file

@ -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))
{