]> git.xonotic.org Git - xonotic/gmqcc.git/commitdiff
Automatic prototyping of frame-functions
authorWolfgang (Blub) Bumiller <blub@speed.at>
Sun, 19 Aug 2012 17:24:43 +0000 (19:24 +0200)
committerWolfgang (Blub) Bumiller <blub@speed.at>
Sun, 19 Aug 2012 17:24:43 +0000 (19:24 +0200)
ast.c
ast.h
data/frames.qc
parser.c

diff --git a/ast.c b/ast.c
index 659818189ea965273926338c293f8f05cbc90a87..8bbce8f9ace654057a0f54ba98d143b9a24b612e 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -91,7 +91,6 @@ static void ast_expression_delete_full(ast_expression *self)
 
 MEM_VEC_FUNCTIONS(ast_expression_common, ast_value*, params)
 
-static ast_expression* ast_type_copy(lex_ctx ctx, const ast_expression *ex);
 ast_value* ast_value_copy(const ast_value *self)
 {
     size_t i;
@@ -117,8 +116,7 @@ ast_value* ast_value_copy(const ast_value *self)
     return cp;
 }
 
-#define ast_type_adopt(a, b) ast_type_adopt_impl((ast_expression*)(a), (ast_expression*)(b))
-static bool ast_type_adopt_impl(ast_expression *self, const ast_expression *other)
+bool ast_type_adopt_impl(ast_expression *self, const ast_expression *other)
 {
     size_t i;
     const ast_expression_common *fromex;
@@ -149,7 +147,7 @@ static ast_expression* ast_shallow_type(lex_ctx ctx, int vtype)
     return self;
 }
 
-static ast_expression* ast_type_copy(lex_ctx ctx, const ast_expression *ex)
+ast_expression* ast_type_copy(lex_ctx ctx, const ast_expression *ex)
 {
     size_t i;
     const ast_expression_common *fromex;
diff --git a/ast.h b/ast.h
index d118adbf6566668e59837d6deda1118ad7728528..55691eb473fa9d7cd3c5aa0011ad828acb3beacf 100644 (file)
--- a/ast.h
+++ b/ast.h
@@ -162,6 +162,9 @@ 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);
+ast_expression* ast_type_copy(lex_ctx ctx, const ast_expression *ex);
+#define ast_type_adopt(a, b) ast_type_adopt_impl((ast_expression*)(a), (ast_expression*)(b))
+bool ast_type_adopt_impl(ast_expression *self, const ast_expression *other);
 
 /* Binary
  *
index e62964c4dd64941ebffb7a434ba34dfe6819173b..ab19ad1c063dcb86f3febebfced185a5130b457e 100644 (file)
@@ -16,7 +16,7 @@ $frame stand1 stand2 standX
 entity self;
 float  time;
 
-void() stand2;
+// void() stand2; this is auto-prototyped
 void() stand1 = [ 0, stand2 ] {
     // expands to:
     //self.frame = 0;
index 621f98a353c533fb76e18cca5094aba0d79d6870..10bcd3747ce86e24a92cd2b57ce2c7a501637b7e 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -2151,6 +2151,8 @@ nextvar:
                  * self.nextthink = time + 0.1;
                  * self.think = nextthink;
                  */
+                nextthink = NULL;
+
                 fld_think     = parser_find_field(parser, "think");
                 fld_nextthink = parser_find_field(parser, "nextthink");
                 fld_frame     = parser_find_field(parser, "frame");
@@ -2193,11 +2195,54 @@ nextvar:
                     return false;
                 }
 
-                nextthink = parser_expression_leave(parser, true);
-                if (!nextthink) {
-                    ast_unref(framenum);
-                    parseerror(parser, "expected a think-function in [frame,think] notation");
-                    return false;
+                if (parser->tok == TOKEN_IDENT && !parser_find_var(parser, parser_tokval(parser)))
+                {
+                    /* qc allows the use of not-yet-declared functions here
+                     * - this automatically creates a prototype */
+                    varentry_t      varent;
+                    ast_value      *thinkfunc;
+                    ast_expression *functype = fld_think->expression.next;
+
+                    thinkfunc = ast_value_new(parser_ctx(parser), parser_tokval(parser), functype->expression.vtype);
+                    if (!thinkfunc || !ast_type_adopt(nextthink, functype)) {
+                        ast_unref(framenum);
+                        parseerror(parser, "failed to create implicit prototype for `%s`", parser_tokval(parser));
+                        return false;
+                    }
+
+                    if (!parser_next(parser)) {
+                        ast_unref(framenum);
+                        return false;
+                    }
+
+                    varent.var = (ast_expression*)thinkfunc;
+                    varent.name = util_strdup(thinkfunc->name);
+                    if (nextthink->expression.vtype == TYPE_FUNCTION)
+                    {
+                        ast_function *func;
+
+                        func = ast_function_new(parser_ctx(parser), thinkfunc->name, thinkfunc);
+                        if (!func) {
+                            ast_delete(nextthink);
+                            ast_unref(framenum);
+                            parseerror(parser, "failed to create function for implicit prototype for `%s`",
+                                       thinkfunc->name);
+                            return false;
+                        }
+                        (void)!parser_t_functions_add(parser, func);
+                        (void)!parser_t_globals_add(parser, varent);
+                    }
+                    else
+                        (void)!parser_t_globals_add(parser, varent);
+                    nextthink = (ast_expression*)thinkfunc;
+
+                } else {
+                    nextthink = parser_expression_leave(parser, true);
+                    if (!nextthink) {
+                        ast_unref(framenum);
+                        parseerror(parser, "expected a think-function in [frame,think] notation");
+                        return false;
+                    }
                 }
 
                 if (!ast_istype(nextthink, ast_value) || !( (ast_value*)nextthink )->isconst) {