mirror of
https://github.com/DarkPlacesEngine/gmqcc.git
synced 2025-03-23 11:11:22 +00:00
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:
parent
db6ca6c5f8
commit
afdc0c9dc8
3 changed files with 41 additions and 63 deletions
9
ast.c
9
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;
|
||||
|
|
1
ast.h
1
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 */
|
||||
|
|
94
parser.c
94
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))
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue