mirror of
https://github.com/DarkPlacesEngine/gmqcc.git
synced 2024-11-23 20:33:05 +00:00
Implemented [[accumulate]] attribute. This will hopefully be used by Xonotic to replace it's ACCUMULATE_FUNCTION stuff.
This commit is contained in:
parent
1b14c49815
commit
2c975bb344
3 changed files with 66 additions and 7 deletions
13
ast.c
13
ast.c
|
@ -1183,6 +1183,7 @@ ast_function* ast_function_new(lex_ctx_t ctx, const char *name, ast_value *vtype
|
|||
if (!vtype) {
|
||||
compile_error(ast_ctx(self), "internal error: ast_function_new condition 0");
|
||||
goto cleanup;
|
||||
} else if (vtype->hasvalue || vtype->expression.vtype != TYPE_FUNCTION) {
|
||||
} else if (vtype->hasvalue || vtype->expression.vtype != TYPE_FUNCTION) {
|
||||
compile_error(ast_ctx(self), "internal error: ast_function_new condition %i %i type=%i (probably 2 bodies?)",
|
||||
(int)!vtype,
|
||||
|
@ -1212,6 +1213,9 @@ ast_function* ast_function_new(lex_ctx_t ctx, const char *name, ast_value *vtype
|
|||
self->fixedparams = NULL;
|
||||
self->return_value = NULL;
|
||||
|
||||
self->accumulate = NULL;
|
||||
self->accumulation = 0;
|
||||
|
||||
return self;
|
||||
|
||||
cleanup:
|
||||
|
@ -1792,6 +1796,7 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir)
|
|||
ir_value *dummy;
|
||||
ast_expression *ec;
|
||||
ast_expression_codegen *cgen;
|
||||
|
||||
size_t i;
|
||||
|
||||
(void)ir;
|
||||
|
@ -1868,6 +1873,14 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir)
|
|||
}
|
||||
}
|
||||
|
||||
/* generate the call for any accumulation */
|
||||
if (self->accumulate) {
|
||||
ast_call *call = ast_call_new(ast_ctx(self), (ast_expression*)self->accumulate->vtype);
|
||||
for (i = 0; i < vec_size(ec->params); i++)
|
||||
vec_push(call->params, (ast_expression*)ec->params[i]);
|
||||
vec_push(vec_last(self->blocks)->exprs, (ast_expression*)call);
|
||||
}
|
||||
|
||||
for (i = 0; i < vec_size(self->blocks); ++i) {
|
||||
cgen = self->blocks[i]->expression.codegen;
|
||||
if (!(*cgen)((ast_expression*)self->blocks[i], self, false, &dummy))
|
||||
|
|
15
ast.h
15
ast.h
|
@ -156,10 +156,13 @@ struct ast_expression_common
|
|||
#define AST_FLAG_IS_VARARG (1<<6)
|
||||
#define AST_FLAG_ALIAS (1<<7)
|
||||
#define AST_FLAG_ERASEABLE (1<<8)
|
||||
/* An array declared as []
|
||||
* so that the size is taken from the initializer */
|
||||
#define AST_FLAG_ARRAY_INIT (1<<9)
|
||||
#define AST_FLAG_TYPE_MASK (AST_FLAG_VARIADIC | AST_FLAG_NORETURN)
|
||||
#define AST_FLAG_ACCUMULATE (1<<9)
|
||||
/*
|
||||
* An array declared as []
|
||||
* so that the size is taken from the initializer
|
||||
*/
|
||||
#define AST_FLAG_ARRAY_INIT (1<<10)
|
||||
#define AST_FLAG_TYPE_MASK (AST_FLAG_VARIADIC | AST_FLAG_NORETURN)
|
||||
|
||||
/* Value
|
||||
*
|
||||
|
@ -614,6 +617,10 @@ struct ast_function_s
|
|||
|
||||
int builtin;
|
||||
|
||||
/* function accumulation */
|
||||
ast_function *accumulate; /* pointer to the next function in the chain */
|
||||
size_t accumulation; /* base functions # of accumulations */
|
||||
|
||||
ir_function *ir_func;
|
||||
ir_block *curblock;
|
||||
ir_block **breakblocks;
|
||||
|
|
45
parser.c
45
parser.c
|
@ -2801,6 +2801,14 @@ static bool parse_qualifiers(parser_t *parser, bool with_local, int *cvq, bool *
|
|||
return false;
|
||||
}
|
||||
}
|
||||
else if (!strcmp(parser_tokval(parser), "accumulate")) {
|
||||
flags |= AST_FLAG_ACCUMULATE;
|
||||
if (!parser_next(parser) || parser->tok != TOKEN_ATTRIBUTE_CLOSE) {
|
||||
parseerror(parser, "`accumulate` attribute has no parameters, expected `]]`");
|
||||
*cvq = CV_WRONG;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!strcmp(parser_tokval(parser), "alias") && !(flags & AST_FLAG_ALIAS)) {
|
||||
flags |= AST_FLAG_ALIAS;
|
||||
*message = NULL;
|
||||
|
@ -3976,19 +3984,50 @@ static bool parse_function_body(parser_t *parser, ast_value *var)
|
|||
}
|
||||
}
|
||||
|
||||
if (var->hasvalue) {
|
||||
if (var->hasvalue && !(var->expression.flags & AST_FLAG_ACCUMULATE)) {
|
||||
parseerror(parser, "function `%s` declared with multiple bodies", var->name);
|
||||
ast_block_delete(block);
|
||||
goto enderr;
|
||||
}
|
||||
|
||||
func = ast_function_new(ast_ctx(var), var->name, var);
|
||||
/* accumulation? */
|
||||
if (var->hasvalue) {
|
||||
ast_value *accum = NULL;
|
||||
ast_function *previous = NULL;
|
||||
char acname[1024];
|
||||
|
||||
/* generate a new name increasing the accumulation count*/
|
||||
util_snprintf(acname, sizeof(acname), "$ACCUMULATE_%s_%d", var->name, var->constval.vfunc->accumulation++);
|
||||
accum = ast_value_new(parser_ctx(parser), acname, ((ast_expression*)var)->vtype);
|
||||
if (!accum)
|
||||
return false;
|
||||
|
||||
ast_type_adopt(accum, var);
|
||||
func = ast_function_new(ast_ctx(var), NULL, accum);
|
||||
if (!func)
|
||||
return false;
|
||||
|
||||
parser_addglobal(parser, acname, (ast_expression*)accum);
|
||||
vec_push(parser->functions, func);
|
||||
|
||||
/* update the previous calls accumulate pointer for the codegen */
|
||||
previous = var->constval.vfunc;
|
||||
while (previous->accumulate)
|
||||
previous = previous->accumulate;
|
||||
|
||||
if (ast_istype(previous, ast_function))
|
||||
previous->accumulate = func;
|
||||
|
||||
} else {
|
||||
func = ast_function_new(ast_ctx(var), var->name, var);
|
||||
vec_push(parser->functions, func);
|
||||
}
|
||||
|
||||
if (!func) {
|
||||
parseerror(parser, "failed to allocate function for `%s`", var->name);
|
||||
ast_block_delete(block);
|
||||
goto enderr;
|
||||
}
|
||||
vec_push(parser->functions, func);
|
||||
|
||||
parser_enterblock(parser);
|
||||
|
||||
|
|
Loading…
Reference in a new issue