]> git.xonotic.org Git - xonotic/gmqcc.git/commitdiff
type comparison, function prototypes
authorWolfgang (Blub) Bumiller <blub@speed.at>
Tue, 14 Aug 2012 12:14:56 +0000 (14:14 +0200)
committerWolfgang (Blub) Bumiller <blub@speed.at>
Tue, 14 Aug 2012 12:14:56 +0000 (14:14 +0200)
ast.c
ast.h
parser.c

diff --git a/ast.c b/ast.c
index cbeb274de3d138c9484edc1d7ac9bfb87594a8d6..c99a051b36fefb48a613f56d8348f6b6ed81874c 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -156,6 +156,27 @@ static ast_expression* ast_type_copy(lex_ctx ctx, const ast_expression *ex)
     }
 }
 
+bool ast_compare_type(ast_expression *a, ast_expression *b)
+{
+    if (a->expression.vtype != b->expression.vtype)
+        return false;
+    if (!a->expression.next != !b->expression.next)
+        return false;
+    if (a->expression.params_count != b->expression.params_count)
+        return false;
+    if (a->expression.params_count) {
+        size_t i;
+        for (i = 0; i < a->expression.params_count; ++i) {
+            if (!ast_compare_type((ast_expression*)a->expression.params[i],
+                                  (ast_expression*)b->expression.params[i]))
+                return false;
+        }
+    }
+    if (a->expression.next)
+        return ast_compare_type(a->expression.next, b->expression.next);
+    return true;
+}
+
 ast_value* ast_value_new(lex_ctx ctx, const char *name, int t)
 {
     ast_instantiate(ast_value, ctx, ast_value_delete);
diff --git a/ast.h b/ast.h
index 42a4b9ace87c4f4ba99c846e5f96614899e2497a..0059e823fa303c0bc895ea3e7d0a7db4c68e8ce1 100644 (file)
--- a/ast.h
+++ b/ast.h
@@ -160,6 +160,8 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir);
 
 bool GMQCC_WARN ast_value_params_add(ast_value*, ast_value*);
 
+bool ast_compare_type(ast_expression *a, ast_expression *b);
+
 /* Binary
  *
  * A value-returning binary expression.
index 6327d5858d7e33001595d4a2a84637d0167091bb..05c4313f8bb22ff127b2079e57e91104d32cf638 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -1398,8 +1398,9 @@ static bool parser_variable(parser_t *parser, ast_block *localblock)
             return false;
         }
 
-        isfunc = false;
-        func = NULL;
+        olddecl = NULL;
+        isfunc  = false;
+        func    = NULL;
         ctx = parser_ctx(parser);
         var = parser_parse_type(parser, basetype, &isfunc);
 
@@ -1411,18 +1412,20 @@ static bool parser_variable(parser_t *parser, ast_block *localblock)
             return false;
         }
 
-        if (!localblock && (olddecl = parser_find_global(parser, parser_tokval(parser)))) {
-            ast_value_delete(var);
-            parseerror(parser, "global %s already declared here: %s:%i\n",
-                       parser_tokval(parser), ast_ctx(olddecl).file, (int)ast_ctx(olddecl).line);
-            return false;
-        }
+        if (!isfunc) {
+            if (!localblock && (olddecl = parser_find_global(parser, parser_tokval(parser)))) {
+                ast_value_delete(var);
+                parseerror(parser, "global %s already declared here: %s:%i\n",
+                           parser_tokval(parser), ast_ctx(olddecl).file, (int)ast_ctx(olddecl).line);
+                return false;
+            }
 
-        if (localblock && parser_find_local(parser, parser_tokval(parser), parser->blocklocal)) {
-            ast_value_delete(var);
-            parseerror(parser, "local %s already declared here: %s:%i\n",
-                       parser_tokval(parser), ast_ctx(olddecl).file, (int)ast_ctx(olddecl).line);
-            return false;
+            if (localblock && parser_find_local(parser, parser_tokval(parser), parser->blocklocal)) {
+                ast_value_delete(var);
+                parseerror(parser, "local %s already declared here: %s:%i\n",
+                           parser_tokval(parser), ast_ctx(olddecl).file, (int)ast_ctx(olddecl).line);
+                return false;
+            }
         }
 
         if (!ast_value_set_name(var, parser_tokval(parser))) {
@@ -1434,6 +1437,30 @@ static bool parser_variable(parser_t *parser, ast_block *localblock)
         if (isfunc) {
             /* a function was defined */
             ast_value *fval;
+            ast_value *proto = NULL;
+
+            if (!localblock)
+                olddecl = parser_find_global(parser, parser_tokval(parser));
+            else
+                olddecl = parser_find_local(parser, parser_tokval(parser), parser->blocklocal);
+
+            if (olddecl) {
+                /* we had a prototype */
+                if (!ast_istype(olddecl, ast_value)) {
+                    /* theoretically not possible you think?
+                     * well:
+                     * vector v;
+                     * void() v_x = {}
+                     * got it?
+                     */
+                    parseerror(parser, "cannot declare a function with the same name as a vector's member: %s",
+                               parser_tokval(parser));
+                    ast_value_delete(var);
+                    return false;
+                }
+
+                proto = (ast_value*)olddecl;
+            }
 
             /* turn var into a value of TYPE_FUNCTION, with the old var
              * as return type
@@ -1450,11 +1477,29 @@ 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);
 
-            if (!parser_t_functions_add(parser, func)) {
-                ast_value_delete(var);
-                if (fval) ast_value_delete(fval);
-                if (func) ast_function_delete(func);
-                return false;
+            /* we compare the type late here, but it's easier than
+             * messing with the parameter-vector etc. earlier
+             */
+            if (proto) {
+                if (!ast_compare_type((ast_expression*)proto, (ast_expression*)fval)) {
+                    parseerror(parser, "prototype declared at %s:%i had a different type",
+                               ast_ctx(fval).file, ast_ctx(fval).line);
+                    ast_function_delete(func);
+                    ast_value_delete(fval);
+                    return false;
+                }
+                ast_function_delete(func);
+                ast_value_delete(fval);
+                var = proto;
+                func = var->constval.vfunc;
+            }
+            else
+            {
+                if (!parser_t_functions_add(parser, func)) {
+                    ast_function_delete(func);
+                    ast_value_delete(fval);
+                    return false;
+                }
             }
 
             var = fval;