From: Jürg Billeter Date: Sat, 22 Apr 2006 11:19:34 +0000 (+0000) Subject: support DOT, COLON, and COMMA save lower and upper case cnames in X-Git-Tag: VALA_0_0_1~77 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=1fa55b31951795f79e3edf32fc5f9ef3f77f821d;p=platform%2Fupstream%2Fvala.git support DOT, COLON, and COMMA save lower and upper case cnames in 2006-04-22 Jürg Billeter * valac/scanner.l: support DOT, COLON, and COMMA * valac/parser.y: save lower and upper case cnames in namespace and class objects, support base classes * valac/context.h: add ValaSymbol and ValaTypeReference structs, add cnames to ValaNamespace and ValaClass structs * valac/context.c: add symbol handling, type resolving, set cnames in root namespace * valac/generator.c: remove cname generation, support base classes * valac/driver.c: add symbols and resolve types * tests/test-003.vala: test base class svn path=/trunk/; revision=2 --- diff --git a/vala/ChangeLog b/vala/ChangeLog index e69de29..9af11ba 100644 --- a/vala/ChangeLog +++ b/vala/ChangeLog @@ -0,0 +1,12 @@ +2006-04-22 Jürg Billeter + + * valac/scanner.l: support DOT, COLON, and COMMA + * valac/parser.y: save lower and upper case cnames in namespace and + class objects, support base classes + * valac/context.h: add ValaSymbol and ValaTypeReference structs, add + cnames to ValaNamespace and ValaClass structs + * valac/context.c: add symbol handling, type resolving, set cnames in + root namespace + * valac/generator.c: remove cname generation, support base classes + * valac/driver.c: add symbols and resolve types + * tests/test-003.vala: test base class diff --git a/vala/tests/test-003.vala b/vala/tests/test-003.vala new file mode 100644 index 0000000..054fd3b --- /dev/null +++ b/vala/tests/test-003.vala @@ -0,0 +1,7 @@ +namespace Maman { + class Bar { + } + + class SubBar : Bar { + } +} diff --git a/vala/valac/context.c b/vala/valac/context.c index 4c0f467..481e860 100644 --- a/vala/valac/context.c +++ b/vala/valac/context.c @@ -20,7 +20,9 @@ * Jürg Billeter */ +#include #include +#include #include @@ -47,6 +49,202 @@ vala_context_parse (ValaContext *context) } } +static ValaSymbol * +vala_symbol_new (ValaSymbolType type) +{ + ValaSymbol *symbol; + symbol = g_new0 (ValaSymbol, 1); + symbol->type = type; + symbol->symbol_table = g_hash_table_new (g_str_hash, g_str_equal); + return symbol; +} + +static void +vala_context_add_symbols_from_namespace (ValaContext *context, ValaNamespace *namespace) +{ + ValaSymbol *ns_symbol, *class_symbol; + GList *cl; + + if (strlen (namespace->name) == 0) { + ns_symbol = context->root; + } else { + ns_symbol = g_hash_table_lookup (context->root->symbol_table, namespace->name); + if (ns_symbol == NULL) { + ns_symbol = vala_symbol_new (VALA_SYMBOL_TYPE_NAMESPACE); + g_hash_table_insert (context->root->symbol_table, namespace->name, ns_symbol); + } + } + + namespace->symbol = ns_symbol; + + for (cl = namespace->classes; cl != NULL; cl = cl->next) { + ValaClass *class = cl->data; + + class_symbol = g_hash_table_lookup (ns_symbol->symbol_table, class->name); + if (class_symbol != NULL) { + fprintf (stderr, "Error: Class '%s.%s' defined twice.\n", namespace->name, class->name); + exit (1); + } + + class_symbol = vala_symbol_new (VALA_SYMBOL_TYPE_CLASS); + class_symbol->class = class; + g_hash_table_insert (ns_symbol->symbol_table, class->name, class_symbol); + } +} + +void +vala_context_add_fundamental_symbols (ValaContext *context) +{ + ValaSymbol *symbol; + ValaNamespace *namespace; + ValaClass *class; + + context->root = vala_symbol_new (VALA_SYMBOL_TYPE_ROOT); + + namespace = g_new0 (ValaNamespace, 1); + namespace->name = g_strdup ("G"); + namespace->lower_case_cname = g_strdup ("g_"); + namespace->upper_case_cname = g_strdup ("G_"); + + class = g_new0 (ValaClass, 1); + class->name = g_strdup ("Object"); + class->namespace = namespace; + class->lower_case_cname = g_strdup ("object"); + class->upper_case_cname = g_strdup ("OBJECT"); + namespace->classes = g_list_append (namespace->classes, class); + + vala_context_add_symbols_from_namespace (context, namespace); + + /* Add alias object = G.Object */ + symbol = g_hash_table_lookup (namespace->symbol->symbol_table, "Object"); + g_hash_table_insert (context->root->symbol_table, "object", symbol); +} + +void +vala_context_add_symbols_from_source_files (ValaContext *context) +{ + GList *fl; + + for (fl = context->source_files; fl != NULL; fl = fl->next) { + ValaSourceFile *source_file = fl->data; + GList *nsl; + + vala_context_add_symbols_from_namespace (context, source_file->root_namespace); + for (nsl = source_file->namespaces; nsl != NULL; nsl = nsl->next) { + vala_context_add_symbols_from_namespace (context, nsl->data); + } + } +} + +static void +vala_context_resolve_type_reference (ValaContext *context, ValaNamespace *namespace, ValaTypeReference *type_reference) +{ + ValaSymbol *type_symbol, *ns_symbol; + + if (type_reference->namespace_name == NULL) { + /* no namespace specified */ + + /* look in current namespace */ + type_symbol = g_hash_table_lookup (namespace->symbol->symbol_table, type_reference->type_name); + if (type_symbol != NULL) { + type_reference->namespace_name = namespace->name; + } else { + /* look in root namespace */ + type_symbol = g_hash_table_lookup (context->root->symbol_table, type_reference->type_name); + } + + /* FIXME: look in namespaces specified by using directives */ + + if (type_symbol == NULL) { + /* specified namespace not found */ + fprintf (stderr, "Error: Specified type '%s' not found.\n", type_reference->type_name); + exit (1); + } + } else { + /* namespace has been explicitly specified */ + ns_symbol = g_hash_table_lookup (context->root->symbol_table, type_reference->namespace_name); + if (ns_symbol == NULL) { + /* specified namespace not found */ + fprintf (stderr, "Error: Specified namespace '%s' not found.\n", type_reference->namespace_name); + exit (1); + } + + type_symbol = g_hash_table_lookup (namespace->symbol->symbol_table, type_reference->type_name); + if (type_symbol == NULL) { + /* specified namespace not found */ + fprintf (stderr, "Error: Specified type '%s' not found in namespace '%s'.\n", type_reference->type_name, type_reference->namespace_name); + exit (1); + } + } + + if (type_symbol->type == VALA_SYMBOL_TYPE_CLASS) { + type_reference->symbol = type_symbol; + } else { + fprintf (stderr, "Error: Specified symbol '%s' is not a type.\n", type_reference->type_name); + exit (1); + } +} + +static void +vala_context_resolve_types_in_class (ValaContext *context, ValaNamespace *namespace, ValaClass *class) +{ + GList *l; + + for (l = class->base_types; l != NULL; l = l->next) { + ValaTypeReference *type_reference = l->data; + + vala_context_resolve_type_reference (context, namespace, type_reference); + if (type_reference->symbol->type == VALA_SYMBOL_TYPE_CLASS) { + if (class->base_class != NULL) { + fprintf (stderr, "Error: More than one base class specified in class '%s.%s'.\n", class->namespace->name, class->name); + exit (1); + } + class->base_class = type_reference->symbol->class; + if (class->base_class == class) { + fprintf (stderr, "Error: '%s.%s' cannot be subtype of '%s.%s'.\n", class->namespace->name, class->name, class->namespace->name, class->name); + exit (1); + } + /* FIXME: check whether base_class is not a subtype of class */ + } else { + fprintf (stderr, "Error: '%s.%s' cannot be subtype of '%s.%s'.\n", class->namespace->name, class->name, type_reference->symbol->class->namespace->name, type_reference->symbol->class->name); + exit (1); + } + } + + if (class->base_class == NULL) { + ValaSymbol *symbol = g_hash_table_lookup (context->root->symbol_table, "object"); + class->base_class = symbol->class; + } +} + +static void +vala_context_resolve_types_in_namespace (ValaContext *context, ValaNamespace *namespace) +{ + GList *cl; + + for (cl = namespace->classes; cl != NULL; cl = cl->next) { + ValaClass *class = cl->data; + + vala_context_resolve_types_in_class (context, namespace, class); + } +} + +void +vala_context_resolve_types (ValaContext *context) +{ + GList *fl; + + for (fl = context->source_files; fl != NULL; fl = fl->next) { + ValaSourceFile *source_file = fl->data; + GList *nsl; + + vala_context_resolve_types_in_namespace (context, source_file->root_namespace); + for (nsl = source_file->namespaces; nsl != NULL; nsl = nsl->next) { + vala_context_resolve_types_in_namespace (context, nsl->data); + } + } +} + ValaSourceFile * vala_source_file_new (const char *filename) { @@ -54,6 +252,9 @@ vala_source_file_new (const char *filename) file->filename = filename; file->root_namespace = g_new0 (ValaNamespace, 1); + file->root_namespace->name = g_strdup (""); + file->root_namespace->lower_case_cname = g_strdup (""); + file->root_namespace->upper_case_cname = g_strdup (""); return file; } diff --git a/vala/valac/context.h b/vala/valac/context.h index 3392ef3..92daabe 100644 --- a/vala/valac/context.h +++ b/vala/valac/context.h @@ -20,13 +20,34 @@ * Jürg Billeter */ +#include + +typedef enum _ValaSymbolType ValaSymbolType; + typedef struct _ValaContext ValaContext; +typedef struct _ValaSymbol ValaSymbol; typedef struct _ValaSourceFile ValaSourceFile; typedef struct _ValaNamespace ValaNamespace; typedef struct _ValaClass ValaClass; +typedef struct _ValaTypeReference ValaTypeReference; + +enum _ValaSymbolType { + VALA_SYMBOL_TYPE_ROOT, + VALA_SYMBOL_TYPE_NAMESPACE, + VALA_SYMBOL_TYPE_CLASS, +}; struct _ValaContext { GList *source_files; + ValaSymbol *root; +}; + +struct _ValaSymbol { + ValaSymbolType type; + union { + ValaClass *class; + }; + GHashTable *symbol_table; }; struct _ValaSourceFile { @@ -37,16 +58,33 @@ struct _ValaSourceFile { struct _ValaNamespace { char *name; + ValaSymbol *symbol; GList *classes; + char *lower_case_cname; + char *upper_case_cname; }; struct _ValaClass { - char *name; + char *name; + ValaNamespace *namespace; + ValaClass *base_class; + GList *base_types; + char *lower_case_cname; + char *upper_case_cname; +}; + +struct _ValaTypeReference { + char *namespace_name; + char *type_name; + ValaSymbol *symbol; }; ValaContext *vala_context_new (); void vala_context_free (ValaContext *context); void vala_context_parse (ValaContext *context); +void vala_context_add_fundamental_symbols (ValaContext *context); +void vala_context_add_symbols_from_source_files (ValaContext *context); +void vala_context_resolve_types (ValaContext *context); ValaSourceFile *vala_source_file_new (const char *filename); diff --git a/vala/valac/driver.c b/vala/valac/driver.c index 04dc043..63d72e0 100644 --- a/vala/valac/driver.c +++ b/vala/valac/driver.c @@ -48,6 +48,9 @@ driver_main (char **sources, char *directory) sources = NULL; vala_context_parse (context); + vala_context_add_fundamental_symbols (context); + vala_context_add_symbols_from_source_files (context); + vala_context_resolve_types (context); ValaCodeGenerator *generator = vala_code_generator_new (context); generator->directory = directory; diff --git a/vala/valac/generator.c b/vala/valac/generator.c index 6f1118c..26153b6 100644 --- a/vala/valac/generator.c +++ b/vala/valac/generator.c @@ -39,52 +39,6 @@ vala_code_generator_new (ValaContext *context) } static char * -camel_case_to_lower_case (const char *camel_case) -{ - char *str = g_malloc0 (2 * strlen (camel_case)); - const char *i = camel_case; - char *p = str; - - while (*i != '\0') { - if (isupper (*i)) { - /* current character is upper case */ - if (i != camel_case) { - /* we're not at the beginning */ - const char *t = i - 1; - gboolean prev_upper = isupper (*t); - t = i + 1; - gboolean next_upper = isupper (*t); - if (!prev_upper || (*t != '\0' && !next_upper)) { - /* previous character wasn't upper case */ - *p = '_'; - p++; - } - } - } - - *p = tolower (*i); - i++; - p++; - } - - return str; -} - -static char * -camel_case_to_upper_case (const char *camel_case) -{ - char *str = camel_case_to_lower_case (camel_case); - - char *p; - - for (p = str; *p != '\0'; p++) { - *p = toupper (*p); - } - - return str; -} - -static char * filename_to_define (const char *filename) { char *define = g_path_get_basename (filename); @@ -101,31 +55,20 @@ filename_to_define (const char *filename) } static void -vala_code_generator_process_class (ValaCodeGenerator *generator, ValaNamespace *namespace, ValaClass *class) +vala_code_generator_process_class (ValaCodeGenerator *generator, ValaClass *class) { + ValaNamespace *namespace = class->namespace; + char *camel_case; char *ns_lower; char *ns_upper; - - if (namespace->name == NULL) { - camel_case = g_strdup (class->name); - - ns_lower = g_strdup (""); - ns_upper = g_strdup (""); - } else { - camel_case = g_strdup_printf ("%s%s", namespace->name, class->name); - - ns_lower = camel_case_to_lower_case (namespace->name); - /* we know that this is safe */ - ns_lower[strlen (ns_lower)] = '_'; - ns_upper = camel_case_to_upper_case (namespace->name); - /* we know that this is safe */ - ns_upper[strlen (ns_upper)] = '_'; - } + camel_case = g_strdup_printf ("%s%s", namespace->name, class->name); + ns_lower = namespace->lower_case_cname; + ns_upper = namespace->upper_case_cname; - char *lower_case = camel_case_to_lower_case (class->name); - char *upper_case = camel_case_to_upper_case (class->name); + char *lower_case = class->lower_case_cname; + char *upper_case = class->upper_case_cname; /* type macros */ fprintf (generator->h_file, "#define %sTYPE_%s\t(%s%s_get_type ())\n", ns_upper, upper_case, ns_lower, lower_case); @@ -142,12 +85,12 @@ vala_code_generator_process_class (ValaCodeGenerator *generator, ValaNamespace * fprintf (generator->h_file, "\n"); fprintf (generator->h_file, "struct _%s {\n", camel_case); - fprintf (generator->h_file, "\tGObject parent;\n"); + fprintf (generator->h_file, "\t%s%s parent;\n", class->base_class->namespace->name, class->base_class->name); fprintf (generator->h_file, "};\n"); fprintf (generator->h_file, "\n"); fprintf (generator->h_file, "struct _%sClass {\n", camel_case); - fprintf (generator->h_file, "\tGObjectClass parent;\n"); + fprintf (generator->h_file, "\t%s%sClass parent;\n", class->base_class->namespace->name, class->base_class->name); fprintf (generator->h_file, "};\n"); fprintf (generator->h_file, "\n"); @@ -185,7 +128,9 @@ vala_code_generator_process_class (ValaCodeGenerator *generator, ValaNamespace * fprintf (generator->c_file, "\t\t\t0, /* n_preallocs */\n"); fprintf (generator->c_file, "\t\t\t(GInstanceInitFunc) %s%s_init,\n", ns_lower, lower_case); fprintf (generator->c_file, "\t\t};\n"); - fprintf (generator->c_file, "\t\tg_define_type_id = g_type_register_static (%sTYPE_%s, \"%s\", &g_define_type_info, 0);\n", ns_upper, upper_case, camel_case); + + fprintf (generator->c_file, "\t\tg_define_type_id = g_type_register_static (%sTYPE_%s, \"%s\", &g_define_type_info, 0);\n", class->base_class->namespace->upper_case_cname, class->base_class->upper_case_cname, camel_case); + /* FIXME: add interfaces */ fprintf (generator->c_file, "\t}\n"); fprintf (generator->c_file, "\treturn g_define_type_id;\n"); @@ -198,7 +143,7 @@ vala_code_generator_process_namespace (ValaCodeGenerator *generator, ValaNamespa { GList *l; for (l = namespace->classes; l != NULL; l = l->next) { - vala_code_generator_process_class (generator, namespace, l->data); + vala_code_generator_process_class (generator, l->data); } } diff --git a/vala/valac/parser.y b/vala/valac/parser.y index d6be6d8..4dd5975 100644 --- a/vala/valac/parser.y +++ b/vala/valac/parser.y @@ -28,6 +28,64 @@ #include "context.h" +static char * +camel_case_to_lower_case (const char *camel_case) +{ + char *str = g_malloc0 (2 * strlen (camel_case)); + const char *i = camel_case; + char *p = str; + + /* + * This function tries to find word boundaries in camel case with the + * following constraints + * - words always begin with an upper case character + * - the remaining characters are either all upper case or all lower case + * - words have at least two characters + */ + + while (*i != '\0') { + if (isupper (*i)) { + /* current character is upper case */ + if (i != camel_case) { + /* we're not at the beginning */ + const char *t = i - 1; + gboolean prev_upper = isupper (*t); + t = i + 1; + gboolean next_upper = isupper (*t); + if (!prev_upper || (*t != '\0' && !next_upper)) { + /* previous character wasn't upper case */ + t = p - 2; + if (p - str != 1 && *t != '_') { + /* we're not creating 1 character words */ + *p = '_'; + p++; + } + } + } + } + + *p = tolower (*i); + i++; + p++; + } + + return str; +} + +static char * +camel_case_to_upper_case (const char *camel_case) +{ + char *str = camel_case_to_lower_case (camel_case); + + char *p; + + for (p = str; *p != '\0'; p++) { + *p = toupper (*p); + } + + return str; +} + ValaSourceFile *current_source_file; ValaNamespace *current_namespace; %} @@ -39,15 +97,25 @@ ValaNamespace *current_namespace; %glr-parser %union { char *str; + GList *list; + ValaTypeReference *type_reference; } %token OPEN_BRACE "{" %token CLOSE_BRACE "}" +%token DOT "." +%token COLON ":" +%token COMMA "," %token NAMESPACE "namespace" %token CLASS "class" %token IDENTIFIER "identifier" +%type opt_class_base +%type class_base +%type type_list +%type type_name + %% compilation_unit @@ -70,6 +138,14 @@ namespace_declaration { current_namespace = g_new0 (ValaNamespace, 1); current_namespace->name = $2; + current_namespace->lower_case_cname = camel_case_to_lower_case (current_namespace->name); + /* we know that this is safe */ + current_namespace->lower_case_cname[strlen (current_namespace->lower_case_cname)] = '_'; + + current_namespace->upper_case_cname = camel_case_to_upper_case (current_namespace->name); + /* we know that this is safe */ + current_namespace->upper_case_cname[strlen (current_namespace->upper_case_cname)] = '_'; + current_source_file->namespaces = g_list_append (current_source_file->namespaces, current_namespace); } namespace_body @@ -101,15 +177,64 @@ type_declaration ; class_declaration - : CLASS IDENTIFIER + : CLASS IDENTIFIER opt_class_base { ValaClass *class = g_new0 (ValaClass, 1); - class->name = $2; + class->name = g_strdup ($2); + class->base_types = $3; + class->namespace = current_namespace; + class->lower_case_cname = camel_case_to_lower_case (class->name); + class->upper_case_cname = camel_case_to_upper_case (class->name); current_namespace->classes = g_list_append (current_namespace->classes, class); } class_body ; +opt_class_base + : /* empty */ + { + $$ = NULL; + } + | class_base + { + $$ = $1; + } + ; + +class_base + : COLON type_list + { + $$ = $2; + } + ; + +type_list + : type_name + { + $$ = g_list_append (NULL, $1); + } + | type_list COMMA type_name + { + $$ = g_list_append ($1, $3); + } + ; + +type_name + : IDENTIFIER + { + ValaTypeReference *type_reference = g_new0 (ValaTypeReference, 1); + type_reference->type_name = g_strdup ($1); + $$ = type_reference; + } + | IDENTIFIER DOT IDENTIFIER + { + ValaTypeReference *type_reference = g_new0 (ValaTypeReference, 1); + type_reference->namespace_name = g_strdup ($1); + type_reference->type_name = g_strdup ($3); + $$ = type_reference; + } + ; + class_body : OPEN_BRACE CLOSE_BRACE ; diff --git a/vala/valac/scanner.l b/vala/valac/scanner.l index dd1df95..1d2a636 100644 --- a/vala/valac/scanner.l +++ b/vala/valac/scanner.l @@ -21,6 +21,7 @@ */ %{ +#include "context.h" #include "parser.h" %} @@ -33,6 +34,9 @@ "{" { return OPEN_BRACE; } "}" { return CLOSE_BRACE; } +"." { return DOT; } +":" { return COLON; } +"," { return COMMA; } "namespace" { return NAMESPACE; } "class" { return CLASS; }