/* 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;
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;
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);
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;
}
} 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;
parser->reserved_version = NULL;
}
- parser->returns = NULL;
return 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);
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))
{