]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
support OVERRIDE, VIRTUAL add virtual methods support virtual methods,
authorJürg Billeter <j@bitron.ch>
Wed, 26 Apr 2006 20:16:44 +0000 (20:16 +0000)
committerJürg Billeter <juergbi@src.gnome.org>
Wed, 26 Apr 2006 20:16:44 +0000 (20:16 +0000)
2006-04-26  Jürg Billeter  <j@bitron.ch>

* valac/scanner.l: support OVERRIDE, VIRTUAL
* valac/parser.y: add virtual methods
* valac/context.h: support virtual methods, improve init and class_init
* valac/context.c: set symbol in ValaMethod struct
* valac/generator.c: support virtual methods
* tests/test-007.vala: test virtual method declaration and invocation

svn path=/trunk/; revision=7

vala/ChangeLog
vala/tests/test-007.vala [new file with mode: 0644]
vala/valac/context.c
vala/valac/context.h
vala/valac/generator.c
vala/valac/parser.y
vala/valac/scanner.l

index 68c5afce6ba3496e8f16e40866f4585643e762b6..bede5acede4c7f0cb6263dbb3b305eebcfa553f5 100644 (file)
@@ -1,3 +1,12 @@
+2006-04-26  Jürg Billeter  <j@bitron.ch>
+
+       * valac/scanner.l: support OVERRIDE, VIRTUAL
+       * valac/parser.y: add virtual methods
+       * valac/context.h: support virtual methods, improve init and class_init
+       * valac/context.c: set symbol in ValaMethod struct
+       * valac/generator.c: support virtual methods
+       * tests/test-007.vala: test virtual method declaration and invocation
+
 2006-04-26  Jürg Billeter  <j@bitron.ch>
 
        * valac/scanner.l: support OPEN_BRACKET, CLOSE_BRACKET, OP_INC, OP_DEC,
diff --git a/vala/tests/test-007.vala b/vala/tests/test-007.vala
new file mode 100644 (file)
index 0000000..0187db9
--- /dev/null
@@ -0,0 +1,19 @@
+namespace Maman {
+       class Bar {
+               public virtual string do_action (int i) {
+                       return 1;
+               }
+       }
+       
+       class SubBar : Bar {
+               public override string do_action (int i) {
+                       return 2;
+               }
+       
+               public static int main (int argc, string[] argv) {
+                       Bar bar = new SubBar ();
+               
+                       return bar.do_action (1);
+               }
+       }
+}
index 92bd39f0c47e191056d0630863f02b2dac249f43..b7179fa3719b86ca72ac02c864d6aa4fcc97a357 100644 (file)
@@ -74,19 +74,17 @@ err (ValaLocation *location, const char *format, ...)
 static void
 vala_context_add_symbols_from_method (ValaContext *context, ValaSymbol *class_symbol, ValaMethod *method)
 {
-       ValaSymbol *method_symbol;
-       
-       method_symbol = g_hash_table_lookup (class_symbol->symbol_table, method->name);
-       if (method_symbol != NULL) {
+       method->symbol = g_hash_table_lookup (class_symbol->symbol_table, method->name);
+       if (method->symbol != NULL) {
                err (method->location, "error: class member ´%s.%s.%s´ already defined", class_symbol->class->namespace->name, class_symbol->class->name, method->name);
        }
 
-       method_symbol = vala_symbol_new (VALA_SYMBOL_TYPE_METHOD);
-       method_symbol->method = method;
-       g_hash_table_insert (class_symbol->symbol_table, method->name, method_symbol);
+       method->symbol = vala_symbol_new (VALA_SYMBOL_TYPE_METHOD);
+       method->symbol->method = method;
+       g_hash_table_insert (class_symbol->symbol_table, method->name, method->symbol);
        
        if (method->body != NULL) {
-               method->body->method = method_symbol;
+               method->body->method = method->symbol;
        }
 }
 
index 8e68ac51c4c1faf1faadf4d9f3b1977edb2ca6c5..e2cb679145ebd76488cb52c32deeb32f1a4d9da0 100644 (file)
@@ -56,8 +56,10 @@ enum _ValaSymbolType {
 };
 
 enum _ValaMethodFlags {
-       VALA_METHOD_PUBLIC = 0x01,
-       VALA_METHOD_STATIC = 0x02,
+       VALA_METHOD_PUBLIC = 1 << 0,
+       VALA_METHOD_STATIC = 1 << 1,
+       VALA_METHOD_VIRTUAL = 1 << 2,
+       VALA_METHOD_OVERRIDE = 1 << 3,
 };
 
 enum _ValaStatementType {
@@ -146,8 +148,8 @@ struct _ValaClass {
        char *cname;
        char *lower_case_cname;
        char *upper_case_cname;
-       gboolean has_init;
-       gboolean has_class_init;
+       ValaMethod *init_method;
+       ValaMethod *class_init_method;
 };
 
 struct _ValaStruct {
@@ -169,7 +171,7 @@ struct _ValaMethod {
        ValaMethodFlags modifiers;
        char *cname;
        char *cdecl1;
-       char *cdecl2;
+       char *cparameters;
        ValaStatement *body;
 };
 
index 0508261f2f98fa09a94e935ab3e4d4a34730d4df..5df0dc1c1aa74e8f351a2533264ece1c845e66cc 100644 (file)
@@ -108,24 +108,22 @@ vala_code_generator_process_methods1 (ValaCodeGenerator *generator, ValaClass *c
                }
                
                if (parameter_list == NULL) {
-                       parameters = g_strdup ("");
+                       method->cparameters = g_strdup ("");
                } else {
-                       parameters = parameter_list->data;
+                       method->cparameters = parameter_list->data;
                        GList *sl;
                        for (sl = parameter_list->next; sl != NULL; sl = sl->next) {
-                               parameters = g_strdup_printf ("%s, %s", parameters, sl->data);
+                               method->cparameters = g_strdup_printf ("%s, %s", method->cparameters, sl->data);
                                g_free (sl->data);
                        }
                        g_list_free (parameter_list);
                }
                
-               method->cdecl2 = g_strdup_printf ("%s (%s)", method->cname, parameters);
-
                if (method->modifiers & VALA_METHOD_PUBLIC) {
                        method->cdecl1 = g_strdup (method_return_type_cname);
                } else {
                        method->cdecl1 = g_strdup_printf ("static %s", method_return_type_cname);
-                       fprintf (generator->c_file, "%s %s;\n", method->cdecl1, method->cdecl2);
+                       fprintf (generator->c_file, "%s %s (%s);\n", method->cdecl1, method->cname, method->cparameters);
                }
 
                if (strcmp (method->name, "init") == 0) {
@@ -135,7 +133,7 @@ vala_code_generator_process_methods1 (ValaCodeGenerator *generator, ValaClass *c
                        if (method->formal_parameters != NULL) {
                                err (method->location, "error: instance initializer must not have any arguments");
                        }
-                       class->has_init = TRUE;
+                       class->init_method = method;
                } else if (strcmp (method->name, "class_init") == 0) {
                        if ((method->modifiers & VALA_METHOD_STATIC) == 0) {
                                err (method->location, "error: class initializer must be static");
@@ -143,7 +141,7 @@ vala_code_generator_process_methods1 (ValaCodeGenerator *generator, ValaClass *c
                        if (method->formal_parameters != NULL) {
                                err (method->location, "error: class initializer must not have any arguments");
                        }
-                       class->has_class_init = TRUE;
+                       class->class_init_method = method;
                }
        }
        fprintf (generator->c_file, "\n");
@@ -555,13 +553,22 @@ vala_code_generator_process_methods2 (ValaCodeGenerator *generator, ValaClass *c
 
        for (l = class->methods; l != NULL; l = l->next) {
                ValaMethod *method = l->data;
+               
+               if (strcmp (method->name, "init") == 0 || strcmp (method->name, "class_init") == 0) {
+                       continue;
+               }
 
-               if (method->modifiers & VALA_METHOD_PUBLIC) {
-                       fprintf (generator->h_file, "%s %s;\n", method->cdecl1, method->cdecl2);
+               if ((method->modifiers & VALA_METHOD_PUBLIC) && (method->modifiers & VALA_METHOD_OVERRIDE) == 0) {
+                       fprintf (generator->h_file, "%s %s (%s);\n", method->cdecl1, method->cname, method->cparameters);
                }
 
-               fprintf (generator->c_file, "%s\n", method->cdecl1);
-               fprintf (generator->c_file, "%s\n", method->cdecl2);
+               if ((method->modifiers & (VALA_METHOD_VIRTUAL | VALA_METHOD_OVERRIDE)) == 0) {
+                       fprintf (generator->c_file, "%s\n", method->cdecl1);
+                       fprintf (generator->c_file, "%s (%s)\n", method->cname, method->cparameters);
+               } else {
+                       fprintf (generator->c_file, "static %s\n", method->cdecl1);
+                       fprintf (generator->c_file, "%s%s_real_%s (%s)\n", ns_lower, lower_case, method->name, method->cparameters);
+               }
                
                if (method->body != NULL) {
                        generator->sym = vala_symbol_new (VALA_SYMBOL_TYPE_BLOCK);
@@ -583,6 +590,29 @@ vala_code_generator_process_methods2 (ValaCodeGenerator *generator, ValaClass *c
                
                fprintf (generator->c_file, "\n");
 
+               if (method->modifiers & VALA_METHOD_VIRTUAL) {
+                       fprintf (generator->c_file, "%s\n", method->cdecl1);
+                       fprintf (generator->c_file, "%s (%s)\n", method->cname, method->cparameters);
+                       fprintf (generator->c_file, "{\n");
+                       fprintf (generator->c_file, "\t");
+                       if (method->return_type->symbol->type != VALA_SYMBOL_TYPE_VOID) {
+                               fprintf (generator->c_file, "return ");
+                       }
+                       fprintf (generator->c_file, "%s%s_GET_CLASS (self)->%s (self", ns_upper, upper_case, method->name);
+                       
+                       GList *pl;
+                       
+                       for (pl = method->formal_parameters; pl != NULL; pl = pl->next) {
+                               ValaFormalParameter *param = pl->data;
+                               
+                               fprintf (generator->c_file, ", %s", param->name);
+                       }
+                       
+                       fprintf (generator->c_file, ");\n");
+                       fprintf (generator->c_file, "}\n");
+                       fprintf (generator->c_file, "\n");
+               }
+
                if ((method->modifiers & VALA_METHOD_STATIC) && strcmp (method->name, "main") == 0 && strcmp (method->return_type->type_name, "int") == 0) {
                        if (g_list_length (method->formal_parameters) == 2) {
                                /* main method */
@@ -600,20 +630,99 @@ vala_code_generator_process_methods2 (ValaCodeGenerator *generator, ValaClass *c
        fprintf (generator->h_file, "\n");
 
        /* constructors */
-       if (!class->has_init) {
-               fprintf (generator->c_file, "static void\n");
-               fprintf (generator->c_file, "%s%s_init (%s%s *self)\n", ns_lower, lower_case, namespace->name, class->name);
-               fprintf (generator->c_file, "{\n");
-               fprintf (generator->c_file, "}\n");
-               fprintf (generator->c_file, "\n");
+       fprintf (generator->c_file, "static void\n");
+       fprintf (generator->c_file, "%s%s_init (%s%s *self)\n", ns_lower, lower_case, namespace->name, class->name);
+       fprintf (generator->c_file, "{\n");
+
+       if (class->init_method != NULL) {
+               generator->sym = vala_symbol_new (VALA_SYMBOL_TYPE_BLOCK);
+               generator->sym->stmt = class->init_method->body;
+
+               vala_code_generator_process_block (generator, class->init_method->body);
        }
 
-       if (!class->has_class_init) {
-               fprintf (generator->c_file, "static void\n");
-               fprintf (generator->c_file, "%s%s_class_init (%s%sClass *klass)\n", ns_lower, lower_case, namespace->name, class->name);
-               fprintf (generator->c_file, "{\n");
-               fprintf (generator->c_file, "}\n");
-               fprintf (generator->c_file, "\n");
+       fprintf (generator->c_file, "}\n");
+       fprintf (generator->c_file, "\n");
+
+       fprintf (generator->c_file, "static void\n");
+       fprintf (generator->c_file, "%s%s_class_init (%s%sClass *klass)\n", ns_lower, lower_case, namespace->name, class->name);
+       fprintf (generator->c_file, "{\n");
+
+       /* chain virtual functions */
+       for (l = class->methods; l != NULL; l = l->next) {
+               ValaMethod *method = l->data;
+               
+               if (method->modifiers & (VALA_METHOD_VIRTUAL | VALA_METHOD_OVERRIDE)) {
+                       fprintf (generator->c_file, "\t");
+                       if (method->modifiers & VALA_METHOD_OVERRIDE) {
+                               ValaClass *super_class = class->base_class;
+                               while (super_class != NULL) {
+                                       GList *vml;
+                                       for (vml = super_class->methods; vml != NULL; vml = vml->next) {
+                                               ValaMethod *vmethod = vml->data;
+                                               if (strcmp (vmethod->name, method->name) == 0 && (vmethod->modifiers & VALA_METHOD_VIRTUAL)) {
+                                                       break;
+                                               }
+                                       }
+                                       if (vml != NULL) {
+                                               break;
+                                       }
+                                       super_class = super_class->base_class;
+                               }
+                               if (super_class == NULL) {
+                                       err (method->location, "error: no overridable method ´%s´ found", method->name);
+                               }
+                               fprintf (generator->c_file, "%s%s_CLASS (klass)", super_class->namespace->upper_case_cname, super_class->upper_case_cname);
+                       } else {
+                               fprintf (generator->c_file, "klass");
+                       }
+                       fprintf (generator->c_file, "->%s = %s%s_real_%s;\n", method->name, ns_lower, lower_case, method->name);
+               }
+       }
+
+       if (class->class_init_method != NULL) {
+               generator->sym = vala_symbol_new (VALA_SYMBOL_TYPE_BLOCK);
+               generator->sym->stmt = class->class_init_method->body;
+
+               vala_code_generator_process_block (generator, class->class_init_method->body);
+       }
+
+       fprintf (generator->c_file, "}\n");
+       fprintf (generator->c_file, "\n");
+}
+
+static void
+vala_code_generator_process_virtual_method_pointers (ValaCodeGenerator *generator, ValaClass *class)
+{
+       GList *l;
+       gboolean first = TRUE;
+
+       char *ns_lower;
+       char *ns_upper;
+
+       ValaNamespace *namespace = class->namespace;
+
+       ns_lower = namespace->lower_case_cname;
+       ns_upper = namespace->upper_case_cname;
+       
+       char *lower_case = class->lower_case_cname;
+       char *upper_case = class->upper_case_cname;
+
+       for (l = class->methods; l != NULL; l = l->next) {
+               ValaMethod *method = l->data;
+
+               if ((method->modifiers & VALA_METHOD_VIRTUAL) == 0) {
+                       continue;
+               }
+               
+               if (first) {
+                       fprintf (generator->h_file, "\n");
+                       fprintf (generator->h_file, "\t/* virtual methods */\n");
+               } else {
+                       first = FALSE;
+               }
+
+               fprintf (generator->h_file, "\t%s(*%s) (%s);\n", get_cname_for_type_reference (method->return_type, method->location), method->name, method->cparameters);
        }
 }
 
@@ -674,6 +783,9 @@ vala_code_generator_process_class2 (ValaCodeGenerator *generator, ValaClass *cla
 
        fprintf (generator->h_file, "struct _%sClass {\n", camel_case);
        fprintf (generator->h_file, "\t%s%sClass parent;\n", class->base_class->namespace->name, class->base_class->name);
+       
+       vala_code_generator_process_virtual_method_pointers (generator, class);
+       
        fprintf (generator->h_file, "};\n");
        fprintf (generator->h_file, "\n");
 
index 33951196a9ca30f671185e58234cdea969a7d77b..8bd853dd60759a08e9b9cf33b641085ce911333f 100644 (file)
@@ -154,9 +154,11 @@ ValaLocation *get_location (int lineno, int colno)
 %token FOR "for"
 %token IF "if"
 %token NAMESPACE "namespace"
+%token OVERRIDE "override"
 %token PUBLIC "public"
 %token RETURN "return"
 %token STATIC "static"
+%token VIRTUAL "virtual"
 
 %token <str> IDENTIFIER "identifier"
 %token <str> LITERAL_INTEGER "integer"
@@ -413,7 +415,11 @@ method_modifiers
        ;
 
 method_modifier
-       : PUBLIC
+       : OVERRIDE
+         {
+               $$ = VALA_METHOD_OVERRIDE;
+         }
+       | PUBLIC
          {
                $$ = VALA_METHOD_PUBLIC;
          }
@@ -421,6 +427,10 @@ method_modifier
          {
                $$ = VALA_METHOD_STATIC;
          }
+       | VIRTUAL
+         {
+               $$ = VALA_METHOD_VIRTUAL;
+         }
        ;
 
 opt_formal_parameter_list
@@ -516,7 +526,7 @@ declaration_statement
                $$ = g_new0 (ValaStatement, 1);
                $$->type = VALA_STATEMENT_TYPE_VARIABLE_DECLARATION;
                $$->location = current_location (@1);
-               $$->variable_declaration = $1;;
+               $$->variable_declaration = $1;
          }
        ;
 
index 050af066051403b21cb93944485e9b8bfe44daf1..9d254c5353770db5427db17744a802819f325c6d 100644 (file)
 "for"          { uploc; return FOR; }
 "if"           { uploc; return IF; }
 "namespace"    { uploc; return NAMESPACE; }
+"override"     { uploc; return OVERRIDE; }
 "public"       { uploc; return PUBLIC; }
 "return"       { uploc; return RETURN; }
 "static"       { uploc; return STATIC; }
+"virtual"      { uploc; return VIRTUAL; }
 
 [[:digit:]]+   { uploc; yylval->str = strdup (yytext); return LITERAL_INTEGER; }