From: Jürg Billeter Date: Wed, 26 Apr 2006 20:16:44 +0000 (+0000) Subject: support OVERRIDE, VIRTUAL add virtual methods support virtual methods, X-Git-Tag: VALA_0_0_1~72 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d108bf36a46575532998711770643e39b7d2d80c;p=thirdparty%2Fvala.git support OVERRIDE, VIRTUAL add virtual methods support virtual methods, 2006-04-26 Jürg Billeter * 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 --- diff --git a/vala/ChangeLog b/vala/ChangeLog index 68c5afce6..bede5aced 100644 --- a/vala/ChangeLog +++ b/vala/ChangeLog @@ -1,3 +1,12 @@ +2006-04-26 Jürg Billeter + + * 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 * 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 index 000000000..0187db996 --- /dev/null +++ b/vala/tests/test-007.vala @@ -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); + } + } +} diff --git a/vala/valac/context.c b/vala/valac/context.c index 92bd39f0c..b7179fa37 100644 --- a/vala/valac/context.c +++ b/vala/valac/context.c @@ -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; } } diff --git a/vala/valac/context.h b/vala/valac/context.h index 8e68ac51c..e2cb67914 100644 --- a/vala/valac/context.h +++ b/vala/valac/context.h @@ -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; }; diff --git a/vala/valac/generator.c b/vala/valac/generator.c index 0508261f2..5df0dc1c1 100644 --- a/vala/valac/generator.c +++ b/vala/valac/generator.c @@ -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"); diff --git a/vala/valac/parser.y b/vala/valac/parser.y index 33951196a..8bd853dd6 100644 --- a/vala/valac/parser.y +++ b/vala/valac/parser.y @@ -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 IDENTIFIER "identifier" %token 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; } ; diff --git a/vala/valac/scanner.l b/vala/valac/scanner.l index 050af0660..9d254c535 100644 --- a/vala/valac/scanner.l +++ b/vala/valac/scanner.l @@ -67,9 +67,11 @@ "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; }