]> git.xonotic.org Git - xonotic/gmqcc.git/commitdiff
Variadic functions: works for builtins, warns for implemenetd functions, -Wvariadic...
authorWolfgang (Blub) Bumiller <blub@speed.at>
Thu, 23 Aug 2012 09:29:48 +0000 (11:29 +0200)
committerWolfgang (Blub) Bumiller <blub@speed.at>
Thu, 23 Aug 2012 09:29:48 +0000 (11:29 +0200)
ast.c
ast.h
data/functions.qc
data/parsing.qc
main.c
parser.c
warns.def

diff --git a/ast.c b/ast.c
index dda26ab7d047ae1ae0f12a2e6e733362e5446f28..a53aaa33d3c2f5e0d2e53881707150aa79bb1b18 100644 (file)
--- 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 55691eb473fa9d7cd3c5aa0011ad828acb3beacf..1d62ad9a903f8261051e31e7809e3122d7f509d5 100644 (file)
--- 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
index bf12f1dd43accf5b76ea3661b5c7f9c88eaad821..f4eb72c66f6d65bd961b1c3c0d2660ad14c9d6f3 100644 (file)
@@ -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();
 };
index b0bcfc12cab53add3269096c361166f9667acf4a..fb0f971c7a0f0d8e7d231b40c556f8a0055c78ea 100644 (file)
@@ -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 149ea46ab17681efbc208e7c9806fe986efc7d8c..853941debb97d6bb1f0c0c2b9f6079860dd8a30f 100644 (file)
--- 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();
index ef7b5154060dd28c33d0af1cc13c9adad8ef00fc..79b1d40dca344f799ee8a5d0fa15016e8d4ee381 100644 (file)
--- 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(&params, 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(&param->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, "<unnamed>", vtype);
     if (!var)
         goto on_error;
+    var->expression.variadic = variadic;
     MEM_VECTOR_MOVE(&params, 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;
             }
 
index 16a5f9996c45f423c5b74e2e06f8553b35a22b86..3b63b36a6f65c2e29e6c7ac11e53f7b000c68022 100644 (file)
--- 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)