From f22112bcb826abb9bee6af73e9773efd96f7684a Mon Sep 17 00:00:00 2001 From: "Wolfgang (Blub) Bumiller" Date: Thu, 23 Aug 2012 11:29:48 +0200 Subject: [PATCH] Variadic functions: works for builtins, warns for implemenetd functions, -Wvariadic-function, on by default --- ast.c | 16 +++++++++++----- ast.h | 1 + data/functions.qc | 4 ++++ data/parsing.qc | 9 ++++++--- main.c | 1 + parser.c | 41 ++++++++++++++++++++++++++++++++++++----- warns.def | 1 + 7 files changed, 60 insertions(+), 13 deletions(-) diff --git a/ast.c b/ast.c index dda26ab..a53aaa3 100644 --- a/ast.c +++ b/ast.c @@ -64,11 +64,12 @@ static void ast_node_init(ast_node *self, lex_ctx ctx, int nodetype) static void ast_expression_init(ast_expression *self, ast_expression_codegen *codegen) { - self->expression.codegen = codegen; - self->expression.vtype = TYPE_VOID; - self->expression.next = NULL; - self->expression.outl = NULL; - self->expression.outr = NULL; + self->expression.codegen = codegen; + self->expression.vtype = TYPE_VOID; + self->expression.next = NULL; + self->expression.outl = NULL; + self->expression.outr = NULL; + self->expression.variadic = false; MEM_VECTOR_INIT(&self->expression, params); } @@ -106,6 +107,7 @@ ast_value* ast_value_copy(const ast_value *self) } fromex = &self->expression; selfex = &cp->expression; + selfex->variadic = fromex->variadic; for (i = 0; i < fromex->params_count; ++i) { ast_value *v = ast_value_copy(fromex->params[i]); if (!v || !ast_expression_common_params_add(selfex, v)) { @@ -129,6 +131,7 @@ bool ast_type_adopt_impl(ast_expression *self, const ast_expression *other) } fromex = &other->expression; selfex = &self->expression; + selfex->variadic = fromex->variadic; for (i = 0; i < fromex->params_count; ++i) { ast_value *v = ast_value_copy(fromex->params[i]); if (!v || !ast_expression_common_params_add(selfex, v)) @@ -178,6 +181,7 @@ ast_expression* ast_type_copy(lex_ctx ctx, const ast_expression *ex) else selfex->next = NULL; + selfex->variadic = fromex->variadic; for (i = 0; i < fromex->params_count; ++i) { ast_value *v = ast_value_copy(fromex->params[i]); if (!v || !ast_expression_common_params_add(selfex, v)) { @@ -198,6 +202,8 @@ bool ast_compare_type(ast_expression *a, ast_expression *b) return false; if (a->expression.params_count != b->expression.params_count) return false; + if (a->expression.variadic != b->expression.variadic) + return false; if (a->expression.params_count) { size_t i; for (i = 0; i < a->expression.params_count; ++i) { diff --git a/ast.h b/ast.h index 55691eb..1d62ad9 100644 --- a/ast.h +++ b/ast.h @@ -107,6 +107,7 @@ typedef struct int vtype; ast_expression *next; MEM_VECTOR_MAKE(ast_value*, params); + bool variadic; /* The codegen functions should store their output values * so we can call it multiple times without re-evaluating. * Store lvalue and rvalue seperately though. So that diff --git a/data/functions.qc b/data/functions.qc index bf12f1d..f4eb72c 100644 --- a/data/functions.qc +++ b/data/functions.qc @@ -23,6 +23,8 @@ void(void() callback) testcallback = { callback(); }; +void(float) has1param = {}; + void() main = { local entity pawn, pawn2; @@ -36,4 +38,6 @@ void() main = { print("Yes\n"); testcallback(printworking); + + has1param(); }; diff --git a/data/parsing.qc b/data/parsing.qc index b0bcfc1..fb0f971 100644 --- a/data/parsing.qc +++ b/data/parsing.qc @@ -1,7 +1,7 @@ /* this is the WIP test for the parser... * constantly adding stuff here to see if things break */ -void(string) print = #1; +void(string,...) print = #1; void(string,string) print2 = #1; void(string,string,string) print3 = #1; string(float) ftos = #2; @@ -18,6 +18,9 @@ $frame stand3 $modelname foobar $modelname foobar3 +void(string a, ...) hasvaria = { +}; + void() main = { entity pawn; vector vec; @@ -40,8 +43,8 @@ void() main = { pawn = spawn(); pawn.mema = 3; pawn.memb = 5; - print2(ftos(pawn.mema), "\n"); - print2(ftos(pawn.memb), "\n"); + print(ftos(pawn.mema), "\n"); + print(ftos(pawn.memb), "\n"); print("SECOND TEST\n"); for (a = 0; a < 3; a = a + 1) { diff --git a/main.c b/main.c index 149ea46..853941d 100644 --- a/main.c +++ b/main.c @@ -395,6 +395,7 @@ int main(int argc, char **argv) { options_set(opts_warn, WARN_LOCAL_CONSTANTS, true); options_set(opts_warn, WARN_VOID_VARIABLES, true); options_set(opts_warn, WARN_IMPLICIT_FUNCTION_POINTER, true); + options_set(opts_warn, WARN_VARIADIC_FUNCTION, true); if (!options_parse(argc, argv)) { return usage(); diff --git a/parser.c b/parser.c index ef7b515..79b1d40 100644 --- a/parser.c +++ b/parser.c @@ -306,6 +306,7 @@ static ast_value *parser_parse_type(parser_t *parser, int basetype, bool *isfunc int vtype = basetype; int temptype; size_t i; + bool variadic = false; MEM_VECTOR_INIT(¶ms, p); @@ -333,6 +334,18 @@ static ast_value *parser_parse_type(parser_t *parser, int basetype, bool *isfunc } } + if (parser->tok == TOKEN_DOTS) { + /* variadic args */ + variadic = true; + if (!parser_next(parser)) + goto on_error; + if (parser->tok != ')') { + parseerror(parser, "`...` must be the last parameter of a variadic function declaration"); + goto on_error; + } + break; + } + temptype = parser_token(parser)->constval.t; if (!parser_next(parser)) goto on_error; @@ -359,6 +372,7 @@ static ast_value *parser_parse_type(parser_t *parser, int basetype, bool *isfunc } fval->expression.next = (ast_expression*)param; MEM_VECTOR_MOVE(¶m->expression, params, &fval->expression, params); + fval->expression.variadic = param->expression.variadic; param = fval; } @@ -387,6 +401,7 @@ static ast_value *parser_parse_type(parser_t *parser, int basetype, bool *isfunc var = ast_value_new(ctx, "", vtype); if (!var) goto on_error; + var->expression.variadic = variadic; MEM_VECTOR_MOVE(¶ms, p, &var->expression, params); return var; on_error: @@ -952,16 +967,21 @@ static bool parser_close_call(parser_t *parser, shunt *sy) parseerror(parser, "could not determine function return type"); return false; } else { - if (fun->expression.params_count != paramcount) { + if (fun->expression.params_count != paramcount && + !(fun->expression.variadic && + fun->expression.params_count < paramcount)) + { ast_value *fval; + const char *fewmany = (fun->expression.params_count > paramcount) ? "few" : "many"; + fval = (ast_istype(fun, ast_value) ? ((ast_value*)fun) : NULL); if (opts_standard == COMPILER_GMQCC) { if (fval) - parseerror(parser, "too few parameters for call to %s: expected %i, got %i", + parseerror(parser, "too %s parameters for call to %s: expected %i, got %i", fewmany, fval->name, (int)fun->expression.params_count, paramcount); else - parseerror(parser, "too few parameters for function call: expected %i, got %i", + parseerror(parser, "too %s parameters for function call: expected %i, got %i", fewmany, (int)fun->expression.params_count, paramcount); return false; } @@ -969,11 +989,11 @@ static bool parser_close_call(parser_t *parser, shunt *sy) { if (fval) return !parsewarning(parser, WARN_TOO_FEW_PARAMETERS, - "too few parameters for call to %s: expected %i, got %i", + "too %s parameters for call to %s: expected %i, got %i", fewmany, fval->name, (int)fun->expression.params_count, paramcount); else return !parsewarning(parser, WARN_TOO_FEW_PARAMETERS, - "too few parameters for function call: expected %i, got %i", + "too %s parameters for function call: expected %i, got %i", fewmany, (int)fun->expression.params_count, paramcount); } } @@ -2024,6 +2044,7 @@ static bool parser_variable(parser_t *parser, ast_block *localblock) fval->expression.next = (ast_expression*)var; MEM_VECTOR_MOVE(&var->expression, params, &fval->expression, params); + fval->expression.variadic = var->expression.variadic; /* we compare the type late here, but it's easier than * messing with the parameter-vector etc. earlier @@ -2217,6 +2238,15 @@ nextvar: has_frame_think = false; old = parser->function; + if (var->expression.variadic) { + if (parsewarning(parser, WARN_VARIADIC_FUNCTION, + "variadic function with implementation will not be able to access additional parameters")) + { + ast_value_delete(typevar); + return false; + } + } + if (localblock) { parseerror(parser, "cannot declare functions within functions"); ast_value_delete(typevar); @@ -2579,6 +2609,7 @@ static bool parser_do(parser_t *parser) } fval->expression.next = (ast_expression*)var; MEM_VECTOR_MOVE(&var->expression, params, &fval->expression, params); + fval->expression.variadic = var->expression.variadic; var = fval; } diff --git a/warns.def b/warns.def index 16a5f99..3b63b36 100644 --- a/warns.def +++ b/warns.def @@ -14,3 +14,4 @@ GMQCC_DEFINE_FLAG(LOCAL_SHADOWS) GMQCC_DEFINE_FLAG(LOCAL_CONSTANTS) GMQCC_DEFINE_FLAG(VOID_VARIABLES) GMQCC_DEFINE_FLAG(IMPLICIT_FUNCTION_POINTER) +GMQCC_DEFINE_FLAG(VARIADIC_FUNCTION) -- 2.39.2